> This is part 1 of 2 of the full documentation (pages 1–100 of 104).
> The content is paginated: fetch every part to see all of it.
> Next part: https://docs.mediamelon.com/mediamelon/llms-full.txt/1
> Page index: https://docs.mediamelon.com/mediamelon/llms.txt

# Product Features

At Media Melon we revolutionise the world of video analytics. As a leading innovator in the field, we're committed to providing businesses with the most powerful insights to thrive in the digital age.

## SmartSight Dashboard

Outstanding customer experience is critical to customer retention. OTT service providers need a clear understanding of end-user satisfaction, usage behavior, and experience - through reporting and analytics - in order to optimize their services. MediaMelon SmartSight is a comprehensive cloud-based analytics solution that provides in-depth, unparalleled reporting using a patent-pending analytics engine.

SmartSight Analytics provides new, previously unavailable insights regarding Quality of Service (QoS), Quality of Experience (QoE) and cost control with quantifiable results that can extend viewer engagement and help monetize viewer behavior with relevant advertising partnerships. MediaMelon’s SmartSight™ Analytics technology collects and mines extensive real-time performance data and offers this data in the form of analytics reports to customers.

Available as a cloud-based service from MediaMelon SmartSight Analytics is a highly scalable and resilient platform with fully redundant software and hardware compo­nents. This comprehensive OTT monitoring solution enables service providers to develop deeper insights into user behavior, and engagement while providing the intelligence to forecast future requirements, make more effective business decisions and leverage this data to generate new revenue streams.

**Following are the core feature of our product suite.**

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><mark style="color:purple;"><strong>Analysis Dashboard</strong></mark></td><td>Introducing our comprehensive Analytics Dashboard – your command center for data-driven decision-making in the realm of video analytics. Boasting an extensive array of over 25 essential metrics, this dashboard provides an in-depth and holistic view of your video performance. With intuitive visualizations and customizable displays, you can effortlessly monitor key aspects such as Startup delays, EBVS, Errors, and more. </td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2F6A0OsbNAaJkRgJ9dlvr4%2FScreenshot%202025-07-14%20at%209.47.59%E2%80%AFPM.png?alt=media&amp;token=9ae56467-1c2b-4e8d-8ee6-f25b4ab0d718">Screenshot 2025-07-14 at 9.47.59 PM.png</a></td></tr><tr><td><mark style="color:purple;"><strong>Microscope dashboard</strong></mark></td><td>Microscope is your window to session-level insights. It delves deep into user interactions and product usage, with precision metrics. Visualizations simplify data, revealing user patterns and optimization opportunities. From session durations to feature adoption, Microscope enhances your product strategy. Dive into session analytics, uncover potential, and refine your product with Microscope.</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FytOmRBX4erKWomRi8Ibh%2FMicroscope.jpg?alt=media&amp;token=30aa05cf-caae-421b-b1a1-ae8e15c1d5d5">Microscope.jpg</a></td></tr><tr><td><mark style="color:purple;"><strong>Trends Dashboard</strong></mark></td><td>Our Trends Dashboard is the heartbeat of your video analytics strategy. It's your window into the dynamic world of video content. With real-time data and intuitive visualizations, our Trends Dashboard transforms raw video metrics into actionable insights. Track audience engagement, content performance, and emerging trends effortlessly. Stay ahead of the curve, make data-driven decisions, and drive your video strategy to new heights with our Trends Dashboard.</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FULBZQAXxX3jGcVn3eL5H%2FScreenshot%202025-07-14%20at%209.45.50%E2%80%AFPM%201.png?alt=media&amp;token=ee2d95f7-50fb-4149-b528-143ddf2e2932">Screenshot 2025-07-14 at 9.45.50 PM 1.png</a></td></tr><tr><td><mark style="color:purple;"><strong>Monitoring dashboard</strong></mark></td><td>MediaMelon’s Real-Time Monitoring Dashboard provides instant visibility into key QoE metrics, playback errors, and live viewing activity across your OTT platform. Track startup time, buffering, bitrate changes, and content being watched — all in real time. With built-in drill-down tools, you can quickly isolate issues by region, device, ISP, or CDN, enabling your teams to debug problems as they happen and ensure a seamless streaming experience.</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FZTcpeitWyDZFBCKPMG8L%2FScreenshot%202025-07-14%20at%209.51.21%E2%80%AFPM.png?alt=media&amp;token=d20313af-7187-4694-a4e9-248c89f9a0f9">Screenshot 2025-07-14 at 9.51.21 PM.png</a></td></tr><tr><td><mark style="color:purple;"><strong>Geographic dashboard</strong></mark></td><td>The ultimate tool for gaining insightful perspectives on video analytics across different locations. This dashboard effortlessly compiles a wealth of metrics, allowing you to analyze performance by geography with ease. Through intuitive visualizations, it simplifies data interpretation, enabling you to identify regional trends, correlations, and optimization opportunities effortlessly. Whether you're monitoring audience engagement by city, region, or country, our Geographic Dashboard provides a comprehensive view that enhances your decision-making.</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FsdSUIiGuJjBXBLZfDuzT%2FScreenshot%202025-07-14%20at%209.53.56%E2%80%AFPM.png?alt=media&amp;token=b24786c4-e1e2-4670-8731-cbfda695deb3">Screenshot 2025-07-14 at 9.53.56 PM.png</a></td></tr><tr><td><mark style="color:purple;"><strong>Eyesight dashboard</strong></mark></td><td>Meet Eyesight, your viewer insights hub. With curated metrics, it deciphers viewer behavior, demographics, and preferences. Visualizations simplify data, revealing trends and boosting content strategy. From watch times to demographics, EyeSite streamlines viewer analytics. Uncover potential, fine-tune your strategy, and revolutionize content engagement with EyeSight.</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FKNmhN5npHZhuTPQAcX0J%2FScreenshot%202025-07-14%20at%209.56.33%E2%80%AFPM.png?alt=media&amp;token=575ef543-db4d-4952-b8f6-9dd0830623f5">Screenshot 2025-07-14 at 9.56.33 PM.png</a></td></tr><tr><td><mark style="color:purple;"><strong>Custom dashboards</strong></mark></td><td>MediaMelon’s Custom Dashboard lets you build fully tailored analytics views to monitor the metrics that matter most to your OTT business. Choose from a rich set of configurable widgets — including KPIs, time-series charts, grids, and statistical plots — to visualize performance across regions, devices, ISPs, and more. Apply global filters, compare time ranges, and share dashboards across teams for consistent, focused insights. With AI-assisted dashboard creation and real-time updates, it’s never been easier to track, analyze, and act on your streaming data.</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2F5A8xxlxTnRQ1b22jgfdZ%2FScreenshot%202025-07-14%20at%2011.02.27%E2%80%AFPM.png?alt=media&amp;token=05244fb3-c374-4306-b99e-8b9a60665f33">Screenshot 2025-07-14 at 11.02.27 PM.png</a></td></tr><tr><td><mark style="color:purple;"><strong>Alerting dashboard</strong></mark></td><td>MediaMelon’s Real-Time Alerting Dashboard empowers OTT teams to detect and respond to streaming issues instantly, with smart alerts and AI-driven analysis. Set up multi-dimensional alerts that automatically monitor all values across regions, ISPs, CDNs, devices, and content — no need to define each condition manually. When anomalies occur, AI instantly analyzes the data to surface the likely root cause, reducing time-to-resolution and helping teams stay ahead of quality-impacting events.</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FkN7XdTEMA8zh5uMNZGmQ%2FScreenshot%202025-07-14%20at%2011.03.08%E2%80%AFPM.png?alt=media&amp;token=14a2d586-586d-438b-9d5e-4f1d49d06e40">Screenshot 2025-07-14 at 11.03.08 PM.png</a></td></tr></tbody></table>

### Insights Dashboard

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><mark style="color:purple;"><strong>Error Insights</strong></mark></td><td>Video Player Error Heat Map – your visual guide to player performance. This innovative tool captures both fatal and non-fatal errors, quantifying their frequency and severity. Get an instant snapshot of issues affecting your video playback experience. Navigate errors with clarity and optimize your player's performance effortlessly. Elevate your video delivery with the Error Heat Map today.</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FVJovSN5dA6Er5B5f6Yop%2FScreenshot%202025-07-14%20at%209.58.47%E2%80%AFPM.png?alt=media&amp;token=83424023-a072-4a31-acea-27aaa3b15fca">Screenshot 2025-07-14 at 9.58.47 PM.png</a></td></tr><tr><td><mark style="color:purple;"><strong>Real time Session Visualizer</strong></mark></td><td>Real Time Session Visualizer – your integration and validation ally. Designed for seamless use, this tool employs user IP addresses for debugging and validation. It's your go-to for ensuring smooth integrations and pinpointing validation issues. Elevate your process with precision debugging at latencies of 1 -2s.</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FIZTRSP3kKfVl1jNvJgAc%2FScreenshot%202025-07-14%20at%2010.05.39%E2%80%AFPM.png?alt=media&amp;token=4b3d2053-ab83-47e2-908f-32413f4050ad">Screenshot 2025-07-14 at 10.05.39 PM.png</a></td></tr><tr><td><mark style="color:purple;"><strong>Content Insights</strong></mark></td><td>This precision tool lets you zoom in on specific content or content sets. With it, you can dissect data across dimensions, extract key metrics, spot trends, and optimize your strategy with pinpoint accuracy. It's your secret weapon for turning content data into actionable insights.</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FtJf6T9X6oAqlLe6FfQtH%2FScreenshot%202025-07-14%20at%2010.01.31%E2%80%AFPM.png?alt=media&amp;token=2b84b9e9-2fcc-48d8-a6f9-888bb39c567c">Screenshot 2025-07-14 at 10.01.31 PM.png</a></td></tr><tr><td><mark style="color:purple;"><strong>AI Insights</strong></mark></td><td>MediaMelon AI Insights delivers a powerful suite of AI-driven tools designed to accelerate troubleshooting and enhance operational intelligence. With features like the AI Session Summarizer, AI Alert Analyzer, and AI Error Root Cause Tool, teams can quickly understand complex issues without digging through raw data. At the core is a QOE-optimized, MCP-compatible Agentic Query Engine that interprets natural language prompts to investigate problems, surface insights, and explain streaming performance in real time — making advanced analytics accessible to everyone.</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FqmC6FXHnbTj9uYWgGNZ7%2FQueryEngine.jpg?alt=media&amp;token=6f90e98b-048a-4052-b327-a17bd0188dd8">QueryEngine.jpg</a></td></tr><tr><td><mark style="color:purple;"><strong>Content Paths</strong></mark></td><td><p>Content Paths are your pathway to a deeper understanding of user journeys within your content, asset paths, and series paths. This intuitive tool lets you follow the trail of user interactions, analyzing how viewers navigate through individual content pieces, assets, and entire series.</p><p>But that's not all – the Content Path Explorer also offers a heatmap feature, allowing you to visually map and comprehend user paths across assets and series. Uncover valuable insights, refine your content strategy, and enhance user experiences with the Content Path Explorer. Explore the journey, optimize content, and elevate your results with ease.</p></td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2Fftc84m1Fpc4nIVmd092a%2FScreenshot_2023-08-25_10-33-00.png?alt=media&amp;token=1ef30422-0646-41fd-8280-8c9a47135e95">Screenshot_2023-08-25_10-33-00.png</a></td></tr></tbody></table>

***

### Additional Product Features

### Multi-dimensional analysis

Capability to conduct elaborate analysis with respect to several attributes of the video stream, such as the video asset, the device used to play the stream, the viewer location etc. The analytics APIs offer support to build complex queries across dimensions in order to provide precise, circumstantial information, such as the buffering ratio of assets played by a given player from a given type of device, by combining the asset, device and player dimensions.

### Aggregation

Provision to perform custom aggregation of data, based on a given metric or dimension. A combination of the following three Request Parameters can be used to control aggregation.

| Request Parameter | Description                                                                                                               |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------- |
| agg               | When set to 1, performs aggregation by grouping records with the same timestamp.                                          |
| aggby             | Performs aggregation by grouping unique values of the metric or dimension specified. Enabled only when count=1 and agg=1. |
| count             | When set to 1, performs aggregation by grouping records with the same primary key values.                                 |

### Filtering

Provision to filter results based on a given metric value.

| Request Parameter | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| filter            | <p>Simple filter</p><p><code>filter=\<metric>\<filter\_type><\<value></code> where \<filter\_type> is one of:</p><ul><li><code>=</code> equal to</li><li><code>!=</code> not equal to</li><li><code>\~</code> substring</li></ul><p>To search for multiple values of a metric, separate the values with  ,</p><p><code>filter=\<metric>=\<value1>,\<value2></code></p><p>To search on multiple metrics, seperate the searches with a \[]</p><p><code>filter=\[\<metric1>=\<value1>]\[\<metric2>=\<value2>]</code></p> |

### QoE Filtering

Metric filter to filter sessions based on metric values

| Request Parameter | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| qoefilter         | <p>Simple filter</p><p><code>qoefilter=\<metric>\<filter\_type><\<value></code> where \<filter\_type> is one of:</p><ul><li><code>=</code> equal to</li><li><code>>=</code> greater than or equal to</li><li><code><=</code> not equal to</li><li><code>></code> greater than</li><li><code><</code> Less than</li></ul><p></p><p>To filter on multiple metrics, seperate the searches with a \[]</p><p><code>filter=\[\<metric1>>\<value1>]\[\<metric2>>=\<value2>]</code></p> |

### Pagination

Provision to paginate results. The following two parameters are used to control pagination.

| Request Parameter | Description                                                                                                 |
| ----------------- | ----------------------------------------------------------------------------------------------------------- |
| limit             | The number of rows to be returned.                                                                          |
| offset            | The starting row index in the result. Valid values for index begin with 1. The value 0 disables pagination. |

### Sorting

Provision to sort results on a given metric or dimension. The following two parameters are used to control sorting.

| Request Parameter | Description                                                                                                                                           |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| orderas           | One of `ASC` or `DESC` to sort by ascending or descending order respectively. Defaults to ascending order if not specified.                           |
| orderby           | The name of metric or dimension to be sorted on. If the field mentioned is not present in the list of metrics queried, unsorted results are returned. |


# QBR Streaming

Traditional ABR streaming addresses the problem of video buffering by dynamically adapting to changes in network conditions. Because the ABR manifest contains only bitrate information the player is forced to assume that higher quality equals higher bitrate. It thus selects the highest bitrate allowed by network conditions. The relationship between quality and bitrate is complex and depends heavily on the content. For scenes with high motion or visual complexity there is a noticeable quality difference between bitrates. For simpler scenes, however, the quality difference between bitrates is often imperceptible. The result is that ABR streaming wastes bandwidth and increases costs to assure quality.

QBR solves this problem by adding quality information to the player’s decision-making process. The player’s use of both bitrate and quality information results in an increase in visual quality while reducing associated streaming costs.


# Use-case dictionary

Explore the endless possibilities of Media Melon's Video Analytics Product. Discover a multitude of use cases that can enhance your business and get realtime insights to take fast decisions.

Welcome to our comprehensive Video Analytics Use Cases page. Here, we've meticulously compiled an exhaustive list of all the ways our video analytics product can transform your business. From audience insights to content optimization, advertising effectiveness, and much more, you'll discover how our solution can be tailored to meet your specific needs. Explore the versatility and power of video analytics across various industries and applications. Dive into the world of possibilities and uncover the solutions that drive success for your organization.

Here are a list of most common use-cases that MediaMelon can help with.

1. **Buffering and Loading Delays**: Users frequently encounter buffering and loading issues, disrupting their viewing experience due to slow internet connections or congested networks.
2. **Video Quality Fluctuations**: Inconsistent video quality, such as sudden resolution changes or pixelation, can hinder user engagement and satisfaction.
3. **Video Startup Delays:** High video start time can cause frustations among users and will lead them to quick the playback.
4. **Exit Before Video Start:** Our platform can figure out videos that were abandoned before the first frame would get rendered intentionally or unintentionally.&#x20;
5. **Startup & Video Playback Failure:** Errors that lead to user drop-outs and app crashes. Our platform is able to categorise and group common errors so that SmartSight customers can understand which error has to be prioritised and fixed.
6. **Playback Interruptions**: Unexpected pauses, freezes, or complete playback interruptions disrupt the flow of content and lead to frustration.
7. **Data Consumption**: Streaming videos can consume significant Wifi & mobile data, causing users to worry about exceeding their data limits or incurring high costs.
8. **Compatibility Issues**: Videos might not play on certain devices or browsers, causing inconvenience for users who want to access content across different platforms.
9. **Limited Offline Access**: Some platforms restrict the ability to download videos for offline viewing, which can be inconvenient for users in areas with poor connectivity.
10. **Lack of Subtitles and Accessibility Features**: Users who require subtitles or other accessibility features might find that not all videos offer these options.
11. **Geographical Restrictions**: Geo-blocking prevents users from accessing certain content due to their geographic location, limiting their viewing options.
12. **Ad Disruption**: Excessive or poorly timed ads can disrupt the viewing experience, leading to annoyance among users.
13. **Limited Content Library**: Some platforms might not offer a diverse range of content, leading to user dissatisfaction.
14. **Inconsistent Subscriptions**: Users might experience issues related to canceled subscriptions, billing discrepancies, or unexpected charges.
15. **Limited Device Compatibility**: Some streaming platforms may not be available on all devices, limiting the options for users to access content.
16. **Content Discovery Challenges**: Users might struggle to discover new and relevant content due to inadequate recommendation algorithms or limited curation.
17. **Platform Crashes and Errors**: Frequent app crashes or error messages can disrupt the streaming experience and lead to frustration.
18. **Lack of Live Streaming Reliability**: Users watching live events may experience delays or interruptions during broadcasts.
19. **Limited Subtitle Language Options**: Users who require subtitles may not find their preferred language available for all content.
20. **Long Buffering Recovery**: After buffering, it can take a significant amount of time for the video to return to a smooth playback experience.
21. **Language Preferences**: Users may want to switch between audio languages or dubbing options, but this feature may not always be available..

### How can Media Melon help you?

1. **Buffering Optimization**: Ensure smooth video playback by minimizing buffering delays, especially in high-definition content, to improve user satisfaction and engagement.
2. **Adaptive Bitrate Streaming**: Implement adaptive bitrate streaming to adjust video quality in real-time based on users' network conditions, reducing interruptions and buffering.
3. **Viewer Experience Personalization**: Analyze user preferences and viewing habits to provide personalized recommendations, improving content discovery and engagement.
4. **Device Compatibility Testing**: Verify that video playback is seamless across a range of devices, including smartphones, tablets, smart TVs, and browsers.
5. **Latency Reduction**: Minimize latency for live streaming events, such as sports or live news, to enhance the real-time viewing experience.
6. **Content Localization**: Ensure accurate subtitles, dubbing, and translations to cater to a global audience, enhancing accessibility and user engagement.
7. **Quality Assurance and Testing**: Rigorously test video playback across different network conditions and devices to catch and fix issues before they impact users.
8. **Cross-Platform Consistency**: Ensure uniformity in video playback features and quality across various platforms and operating systems.
9. **Offline Viewing Enhancements**: Improve offline viewing options by extending the duration content can be downloaded or making it available on more devices.
10. **Seamless Transition Between Ads and Content**: Ensure that ad insertion and transitions between ads and content are smooth to prevent viewer frustration.
11. **Error Handling**: Implement effective error handling to provide clear and helpful messages when issues like connectivity problems or unsupported formats arise.
12. **Viewer Engagement Analytics**: Use viewer engagement data to optimize content recommendations, advertising targeting, and content creation to increase user satisfaction and retention.
13. **Caption and Subtitle Quality**: Ensure accurate and well-timed captions and subtitles to enhance accessibility for viewers with hearing impairments.
14. **Real-Time Monitoring**: Continuously monitor video quality and user feedback to promptly address any issues that may arise during playback.
15. **Ad Experience Customization**: Allow users to have some control over the ad experience, such as frequency capping or selecting ad categories.
16. **User Assistance and Support**: Provide easily accessible help resources, FAQs, and responsive customer support for users facing video playback issues.


# Overview

MediaMelon SmartSight provides a REST API for programmatic access to video and ad analytics.

Use these APIs to build dashboards, integrate with your data pipelines, generate reports, and investigate QoE issues.

### What the API Does

The SmartSight API lets you query aggregated set of metrics across any combination of dimensions, time ranges with multiple dimension filters and metric-level conditions — returning exactly the data you need in a single call.

<table><thead><tr><th width="292.01171875">Capability</th><th>Description</th></tr></thead><tbody><tr><td>Metric queries</td><td>Retrieve any video session or ad related metric, such as startup time, buffering ratio, ad impressions, and many others aggregated by time, dimension, or both</td></tr><tr><td>Dimension breakdowns</td><td>Break down any metric by combination of dimension including country, device, CDN, player, content, subscriber, and more. </td></tr><tr><td>Time-series trends</td><td>Get bucketed time-series data at minute, hour, or day granularity</td></tr><tr><td>Session-level data</td><td>Retrieve metrics and dimension values set on individual sessions along with the complete list of player sent events and errors for root-cause investigation. </td></tr><tr><td>Filtered queries</td><td>Scope any query to a subset of video sessions using dimension filters or metric-level conditions</td></tr></tbody></table>

### Getting Started

#### Step 1 — Get your Customer ID

Login to the MediaMelon SmartSight dashboard and navigate to `User Icon > Settings > Environments > Env Details`. Find the customer ID for the environment you want to make API requests.&#x20;

<figure><img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FqxRxOpY1IARGRsKg8JoJ%2Fimage.png?alt=media&amp;token=17f9600d-7ffe-4124-b85d-30c4cdc70237" alt=""><figcaption></figcaption></figure>

#### Step 2 — Obtain your API Key

Contact MediaMelon support or your account team to obtain your API key.

#### Step 3 — Choose an Endpoint

Use the metric query endpoint for aggregated analytics.

Use the session list endpoint for per-session video investigation.

#### Step 4 — Build Your Query

Every query must include `period` and `metrics`.

Add `aggby`, `filter`, `qoefilter`, `orderby`, and `limit` as needed.

#### Step 5 — Make the Request

**Base API Hostname** - `https://smartsight.mediamelon.com`&#x20;

**Authentication** - Add your API key to each request for authentication.

```http
X-API-Key: <your-api-key>
```

Use `curl` or similar tools to make the API request with the `X-API-Key` header. Below is an example of the API request to get Startup Time and Started Views count metrics over time to show these metrics in a time-series graph.&#x20;

{% code overflow="wrap" %}

```bash
curl --request GET \
  --url 'https://smartsight.mediamelon.com/mm-apis/metricquery/199493832?period=start=1775749920,end=1775836379&metrics=latency,viewercount&aggby=timestamp&granularity=hour&orderby=timestamp&order=asc' \
  --header 'X-API-Key: <your-api-key>'
```

{% endcode %}

### API Endpoints at a Glance

{% hint style="warning" %}
As of July 2025, `/mm-apis/qbrData/vod` and `/mm-apis/session` are deprecated. Use `/mm-apis/metricquery` instead. Backward compatibility remains available, but `/mm-apis/metricquery` provides access to newer features.
{% endhint %}

<table><thead><tr><th width="171.578125">Method</th><th width="330.71875">Endpoint</th><th width="159.15234375">Scope</th><th>Description</th></tr></thead><tbody><tr><td><code>GET</code></td><td><code>/mm-apis/metricquery/{customerId}</code></td><td>Video Sessions + Ad</td><td>Aggregated metrics for video sessions and ads for trend graphs, tables, KPI tiles, and comparisons.</td></tr></tbody></table>

### Common Query Parameters

<table><thead><tr><th width="162.0859375">Parameter</th><th width="116.8203125">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>period</code></td><td>Yes</td><td><code>start=&#x3C;epoch_seconds>,end=&#x3C;epoch_seconds></code></td></tr><tr><td><code>metrics</code></td><td>Yes</td><td>Comma-separated metric field names</td></tr><tr><td><code>aggby</code></td><td>No</td><td>Breakdown by a combination of dimension or <code>timestamp</code> for time-series</td></tr><tr><td><code>filter</code></td><td>No</td><td>Dimension filters, such as <code>[country=US|Canada][platform=Android]</code></td></tr><tr><td><code>qoefilter</code></td><td>No</td><td>Metric-level conditions to filter, such as <code>latency>3 AND bufferingratio>5</code></td></tr><tr><td><code>orderby</code></td><td>No</td><td>Sort by metric or dimension name</td></tr><tr><td><code>order</code></td><td>No</td><td>Sorting order - <code>asc</code> or <code>desc</code></td></tr><tr><td><code>limit</code></td><td>No</td><td>Number of records to include in the response, aka Page size. Default is <code>1000</code></td></tr><tr><td><code>offset</code></td><td>No</td><td>Record offset to include from in the response. Default is <code>0</code></td></tr></tbody></table>

### Response Structure

{% code lineNumbers="true" %}

```json
{
  "totalcount": 25,
  "pagecount": 4,
  "totalrecords": 100,
  "response": [
    {
      "country": "US",
      "latency": 1.82,
      "concurviewavg": 412
    },
    {
      "country": "GB",
      "latency": 2.14,
      "concurviewavg": 187
    }
  ]
}
```

{% endcode %}

<table><thead><tr><th width="201.2734375">Field</th><th>Description</th></tr></thead><tbody><tr><td><code>totalcount</code></td><td>Number of records in the current response</td></tr><tr><td><code>pagecount</code></td><td>Total number of pages in the full result set</td></tr><tr><td><code>totalrecords</code></td><td>Total matching records across all pages</td></tr><tr><td><code>response</code></td><td>Array of result objects that includes values for <code>metrics</code> and dimensions requested. Use the <a href="/mediamelon/smartsight-apis/metrics">Metric and Dimensions Dictionary</a> for the list video and ad related metrics, dimensions, and aggregate variants available such as <code>p95_latency</code>.</td></tr></tbody></table>

### Timestamps

Use Unix epoch seconds in UTC for all request time ranges and response timestamps.


# Authentication and query parameters

Authenticate requests and build metric and session queries.

Authenticate every request with your API key.

```http
X-API-Key: <your-api-key>
```

Contact MediaMelon support or your account team to obtain your API key.

### Example API request

This example uses the metric query endpoint with shared query parameters:

* `period=start=1775749920,end=1775836379`
* `metrics=latency,viewercount`
* `aggby=timestamp`
* `granularity=hour`
* `orderby=timestamp`
* `order=asc`

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/metricquery/199493832?period=start=1775749920,end=1775836379&metrics=latency,viewercount&aggby=timestamp&granularity=hour&orderby=timestamp&order=asc' \
  --header 'X-API-Key: <your-api-key>'
```

### Getting started

1. Get your customer ID from your SmartSight profile.
2. Obtain your API key.
3. Choose an endpoint.
4. Build a query with `period` and `metrics`.
5. Send the request with the `X-API-Key` header.

### Common query parameters

<table><thead><tr><th width="162.0859375">Parameter</th><th width="116.8203125">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>period</code></td><td>Yes</td><td><code>start=&#x3C;epoch_seconds>,end=&#x3C;epoch_seconds></code></td></tr><tr><td><code>metrics</code></td><td>Yes</td><td>Comma-separated metric field names</td></tr><tr><td><code>aggby</code></td><td>No</td><td>Breakdown by a combination of dimension or <code>timestamp</code> for time-series</td></tr><tr><td><code>filter</code></td><td>No</td><td>Dimension filters, such as <code>[country=US|Canada][platform=Android]</code></td></tr><tr><td><code>qoefilter</code></td><td>No</td><td>Metric-level conditions to filter, such as <code>latency>3 AND bufferingratio>5</code></td></tr><tr><td><code>orderby</code></td><td>No</td><td>Sort by metric or dimension name</td></tr><tr><td><code>order</code></td><td>No</td><td>Sorting order - <code>asc</code> or <code>desc</code></td></tr><tr><td><code>limit</code></td><td>No</td><td>Number of records to include in the response, aka Page size. Default is <code>1000</code></td></tr><tr><td><code>offset</code></td><td>No</td><td>Record offset to include from in the response. Default is <code>0</code></td></tr></tbody></table>

{% hint style="info" %}
Use `aggby=timestamp` with `granularity` for time-series queries. Use `aggby=<dimension>` for breakdown tables.
{% endhint %}

### Response structure

{% code lineNumbers="true" %}

```json
{
  "totalcount": 25,
  "pagecount": 4,
  "totalrecords": 100,
  "response": [
    {
      "country": "US",
      "latency": 1.82,
      "concurviewavg": 412
    },
    {
      "country": "GB",
      "latency": 2.14,
      "concurviewavg": 187
    }
  ]
}
```

{% endcode %}

| Field          | Description                                  |
| -------------- | -------------------------------------------- |
| `totalcount`   | Number of records in the current response    |
| `pagecount`    | Total number of pages in the full result set |
| `totalrecords` | Total matching records across all pages      |
| `response`     | Array of result objects                      |


# Bearer token authorization

Authenticate SmartSight API requests with a bearer token.

Use bearer token authentication if your workflow signs in through SmartSight identity services.

### Get a bearer token

Request a bearer token from the SmartSight identity server.

#### Token endpoint

`POST https://identity.mediamelon.com/realms/mediamelon/protocol/openid-connect/token`

#### Prerequisites

You need:

1. Your SmartSight username
2. Your SmartSight password

{% hint style="info" %}
If you do not have SmartSight identity credentials, contact your MediaMelon representative.
{% endhint %}

#### Example request

{% code overflow="wrap" lineNumbers="true" %}

```bash
curl 'https://identity.mediamelon.com/realms/mediamelon/protocol/openid-connect/token' \
-X POST \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=<email-id>' \
--data-urlencode 'password=<password>' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=smartsight-backend' \
--data-urlencode 'scope=openid'
```

{% endcode %}

#### Required form fields

| Field        | Type   | Description                  |
| ------------ | ------ | ---------------------------- |
| `username`   | string | Your SmartSight username     |
| `password`   | string | Your SmartSight password     |
| `grant_type` | string | Must be `password`           |
| `client_id`  | string | Must be `smartsight-backend` |
| `scope`      | string | Use `openid`                 |

#### Example response

{% code lineNumbers="true" %}

```json
{
  "access_token": "<access_token>",
  "expires_in": 900,
  "refresh_expires_in": 1800,
  "refresh_token": "<refresh_token>",
  "token_type": "Bearer",
  "id_token": "<id_token>",
  "session_state": "<session_state>",
  "scope": "openid email profile"
}
```

{% endcode %}

### Use the bearer token

Send the `access_token` in the `Authorization` header.

```http
Authorization: Bearer <access_token>
```

{% hint style="info" %}
Use the `access_token` for API requests. Refresh or re-request a token when it expires.
{% endhint %}

### Example API request

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/metricquery/199493832?period=start=1775749920,end=1775836379&metrics=latency,viewercount&aggby=timestamp&granularity=hour&orderby=timestamp&order=asc' \
  --header 'Authorization: Bearer <access_token>'
```


# Metric and Dimensions Dictionary

Reference values for SmartSight video and ad metrics and dimensions.

List of metrics (`metrics`) and dimensions (`aggby`) available to use as query parameters.&#x20;

### Video Metrics & Dimensions

{% tabs %}
{% tab title="Video Metrics" %}

<table data-header-hidden="false" data-header-sticky data-first-column-sticky><thead><tr><th>Metric Name</th><th width="204.418701171875">Metric Key</th><th width="304.7999267578125">Description</th><th data-type="checkbox">Concurrency supported?</th><th>Metric Key for available aggregates (not supported in concurrency mode)</th><th data-hidden>Category</th></tr></thead><tbody><tr><td>Plays</td><td><code>viewercount</code></td><td>Playback attempts where the first video frame appears.</td><td>true</td><td>--</td><td>Engagement</td></tr><tr><td>Started views</td><td><code>attempts</code></td><td>Playback attempts recorded.</td><td>true</td><td>--</td><td>Engagement</td></tr><tr><td>Ended plays</td><td><code>endedplays</code></td><td><code>Plays</code> that gracefully ended.</td><td>true</td><td>--</td><td>Engagement</td></tr><tr><td>Concurrent views (CCV)<br>Ended Views</td><td><code>concurviewavg</code></td><td>Number of active playback sessions for CCV and Number of ended playback sessions for Ended Views. <br><br>This number includes distinct sessions active in the time range requested. The <code>status</code> of the view can be <code>RUNNING</code>, <code>ENDED</code>, <code>DROPPED</code> and others statues. </td><td>true</td><td>--</td><td>Engagement</td></tr><tr><td>Playtime (mins)</td><td><code>playdur</code></td><td>Total time viewers spent watching content and ads combined. </td><td>true</td><td>--</td><td>Engagement</td></tr><tr><td>Avg Audience Playtime (mins)</td><td><code>avg_playtime_by_audience</code></td><td>Average Playtime per distinct viewer for all the views active in the requested time range. </td><td>true</td><td>--</td><td>Engagement</td></tr><tr><td>Unique Subscribers</td><td><code>unique_subscribers</code></td><td>Number of distinct <code>subscrberId</code> values representing viewers. </td><td>true</td><td>--</td><td>Engagement</td></tr><tr><td>Unique Devices</td><td><code>unique_devices</code></td><td>Number of distinct devices calculated by counting unique <code>deviceid</code> or computed by combining  <code>brand</code>, <code>model</code> , and  <code>ipaddress</code></td><td>true</td><td>--</td><td>Engagement</td></tr><tr><td>Anonymous Viewers</td><td><code>anonymous_viewers</code></td><td>Number of distinct viewers with no <code>subscriberid</code> value set on sessions and the viewer is uniquely identified by combining <code>brand</code>, <code>model</code>, and <code>ipaddress</code>. <br><br>Typically, Anonymous Viewer is considered to be viewer who has not logged in / authenticated. </td><td>true</td><td>--</td><td>Engagement</td></tr><tr><td>Playback Score</td><td><code>qualityofexperience</code></td><td>Overall playback quality score from <code>0</code> to <code>100</code>, based on startup time and buffering and playback success. <br><br>The value of <code>0</code> signifies extremely bad playback experience and a score of <code>100</code> signifies perfect viewing experience.  </td><td>false</td><td>Average=<code>avg_qualityofexperience</code><br>Median=<code>median_qualityofexperience</code></td><td>Engagement</td></tr><tr><td>Startup time (sec)</td><td><code>latency</code></td><td>Time Duration of a view between when the view started to the first video frame displayed to the viewer.</td><td>true</td><td>Average=<code>avg_latency</code><br>Median=<code>median_latency</code><br>P95=<code>p95_latency</code><br>P99=<code>p99_latency</code></td><td>Startup and errors</td></tr><tr><td>Errors</td><td><code>errors</code></td><td>Number of errors encountered, including fatal and non-fatal error or business or technical error. </td><td>true</td><td>--</td><td>Startup and errors</td></tr><tr><td>Fatal errors</td><td><code>fatalerrors</code></td><td>Errors that end the playback session. </td><td>true</td><td>--</td><td>Startup and errors</td></tr><tr><td>Playback Failure %</td><td><code>fatalerrorpc</code></td><td>Percentage of playback sessions ended with a fatal error. <br><br>Playback failures can happen at any time during playback ie. before the first video frame is displayed or afterwards. </td><td>true</td><td>--</td><td>Startup and errors</td></tr><tr><td>Business Failure %</td><td><code>businesserrorpc</code></td><td>Percentage of playback sessions ended with a fatal error due to business rule exception. <br><br>Playback failures can happen at any time during playback ie. before the first video frame is displayed or afterwards. </td><td>true</td><td>--</td><td>Startup and errors</td></tr><tr><td>Startup Failure %</td><td><code>failurerate</code></td><td>Percentage of playback sessions ended with a fatal error before the first video frame is displayed. </td><td>true</td><td>--</td><td>Startup and errors</td></tr><tr><td>Business Startup Failure %</td><td><code>businessvsfpc</code></td><td>Percentage of playback sessions ended with a fatal error before the first video frame is displayed due to business rule exception. </td><td>true</td><td>--</td><td></td></tr><tr><td>Resumed Play %</td><td><code>resumedplaypct</code></td><td>Percentage of playback sessions that did not start playing from the beginning of the video. </td><td>true</td><td>--</td><td></td></tr><tr><td>Exit before video start %</td><td><code>startupabandonmentrate</code></td><td>Percetange of sessions abandoned by the viewer before the first video frame is displayed.</td><td>true</td><td>--</td><td>Startup and errors</td></tr><tr><td>Pause Count</td><td><code>pausecount</code></td><td>Number of times the video playback was paused.</td><td>true</td><td>Average=<code>avg_pausecount</code><br>Median=<code>median_pausecount</code><br>P95=<code>p95_pausecount</code><br>P99=<code>p99_pausecount</code></td><td>Interaction</td></tr><tr><td>Pause Time (sec)</td><td><code>pauseduration</code></td><td>Total time video playback spent in a paused state.</td><td>true</td><td>Average=<code>avg_pauseduration</code><br>Median=<code>median_pauseduration</code><br>P95=<code>p95_pauseduration</code><br>P99=<code>p99_pauseduration</code></td><td>Interaction</td></tr><tr><td>Buffer empty count</td><td><code>buffwaitcount</code></td><td>Total number of Buffer empty events.  The most common reasons whenn the video player send a Buffer empty event can be for network connection related interrupts, seeking to a different segment of the video and pausing of playback for sufficient amount of time. </td><td>true</td><td>Average=<code>avg_buffwaitcount</code><br>Median=<code>median_buffwaitcount</code><br>P95=<code>p95_buffwaitcount</code><br>P99=<code>p99_buffwaitcount</code></td><td>Buffering</td></tr><tr><td>Rebuffering Time (sec)</td><td><code>sumbuffwaitcirr</code></td><td>Total Interruption time caused by network connection issues. In other words, interruption not caused by any viewer action. </td><td>true</td><td>Average=<code>avg_sumbuffwaitcirr</code><br>Median=<code>median_sumbuffwaitcirr</code><br>P95=<code>p95_sumbuffwaitcirr</code><br>P99=<code>p99_sumbuffwaitcirr</code></td><td>Buffering</td></tr><tr><td>Rebuffering %</td><td><code>cirrbufferingratio</code></td><td>Percentage of Watch Time interrupted after video starts. <br><br>Interruptions due to viewer action like seeking to a different segment of the video or pausing the playback is not counted in calculating this metric. </td><td>true</td><td>--</td><td>Buffering</td></tr><tr><td>Rebuffering Rate</td><td><code>rebufferingrate</code></td><td>Number of network related interruptions per min of playtime.</td><td>true</td><td>--</td><td></td></tr><tr><td>Seek count</td><td><code>seekcount</code></td><td>Average number of seeks per session.</td><td>true</td><td>Average=<code>avg_seekcount</code><br>Median=<code>median_seekcount</code><br>P95=<code>p95_seekcount</code><br>P99=<code>p99_seekcount</code></td><td>Interaction</td></tr><tr><td>Seek Time (sec)</td><td><code>seektime</code></td><td>Time spent waiting for the video to resume when the viewer seeks to a different segment of the video. The time duration is inclusive of any time spend filling up the buffer (<code>sumbuffwaitvrt</code>) to resume playback. </td><td>true</td><td>Average=<code>avg_seektime</code><br>Median=<code>median_seektime</code><br>P95=<code>p95_seektime</code><br>P99=<code>p99_seektime</code></td><td></td></tr><tr><td>Seek Buffering Time %</td><td><code>vrtbufferingratio</code></td><td>Percentage of Watch Time spent waiting fill the buffer for the video to resume after the viewer seeks to the different segment of the video. </td><td>true</td><td>--</td><td></td></tr><tr><td>Buffering Time (sec)</td><td><code>sumbuffwait</code></td><td>Total Interruption time caused by any reason. For instance - network connection issues, viewer seeking, etc.  The interruption time is inclusive of <code>sumbuffwaitcirr</code> and <code>sumbuffwaitvrt</code></td><td>true</td><td>Average=<code>avg_sumbuffwait</code><br>Median=<code>median_sumbuffwait</code><br>P95=<code>p95_sumbuffwait</code><br>P99=<code>p99_sumbuffwait</code></td><td></td></tr><tr><td>Buffering Time %</td><td><code>bufferingratio</code></td><td>Percentage of Watch Time not watching the video after the video starts. <br><br>Any time spent due to a viewer action like seeking to a different segment of the video excluding pause time is also counted in calculating this metric. </td><td>true</td><td>--</td><td>Buffering</td></tr><tr><td>Views without Buffering %</td><td><code>sessionswithoutcirrbuffpc</code></td><td>Percentage of sessions with no interruptions due to network connection related issues. These sessions have <code>sumbuffwaitcirr</code> of 0s. </td><td>false</td><td>--</td><td>Buffering</td></tr><tr><td>Smoothness Score</td><td><code>smoothnessscore</code></td><td>A score from <code>0</code> to <code>100</code> indicating playback smoothness. Smoothness is based on <code>buffwaitcount</code> value and <code>sumbuffwait</code> value. <br><br>A score of <code>100</code> means zero buffering. </td><td>false</td><td>Average=<code>avg_smoothnessscore</code><br>Median=<code>median_smoothnessscore</code></td><td>Buffering</td></tr><tr><td>Weighted Avg Bitrate (Mbps)</td><td><code>qbrbitrate</code></td><td>Average delivered bitrate, weighted by playback time. The bitrate value used for this calculation is the advertized bitrate value in the Variant manifest file. </td><td>true</td><td>Average=<code>avg_qbrbitrate</code><br>Median=<code>median_qbrbitrate</code><br>P95=<code>p95_qbrbitrate</code><br>P99=<code>p99_qbrbitrate</code></td><td>Bitrate and rendition</td></tr><tr><td>Bitrate Upswitch Count</td><td><code>brupscale</code></td><td>Number of rendition changes where bitrate of the rendition increased.</td><td>false</td><td>Average=<code>avg_brupscale</code><br>Median=<code>median_brupscale</code><br>P95=<code>p95_brupscale</code><br>P99=<code>p99_brupscale</code></td><td>Bitrate and rendition</td></tr><tr><td>Bitrate Upswitch %</td><td>brupscalepct</td><td>Percentage representation of a new rendition's bitrate compared to the previous rendition's bitrate, weighted by the play duration. Because this metric strictly tracks upswitch rendition, the value is always greater than 100%.</td><td>false</td><td>--</td><td></td></tr><tr><td>Bitrate Downswitch Count</td><td><code>brdownscale</code></td><td>Number of rendition changes where bitrate of the rendition decreased.</td><td>false</td><td>Average=<code>avg_brdownscale</code><br>Median=<code>median_brdownscale</code><br>P95=<code>p95_brdownscale</code><br>P99=<code>p99_brdownscale</code></td><td>Bitrate and rendition</td></tr><tr><td>Bitrate Downswitch %</td><td><code>brdownscalepct</code></td><td>Percentage representation of a new rendition's bitrate compared to the previous rendition's bitrate, weighted by the play duration. Because this metric strictly tracks downswitch rendition, the value is always less than 100%.</td><td>false</td><td>--</td><td></td></tr><tr><td>Resolution Upswitch Count</td><td><code>resupscale</code></td><td>Number of rendition changes where resolution of the rendition increased.</td><td>false</td><td>Average=<code>avg_resupscale</code><br>Median=<code>median_resupscale</code><br>P95=<code>p95_resupscale</code><br>P99=<code>p99_resupscale</code></td><td></td></tr><tr><td>Resolution Upswitch %</td><td><code>resupscalepct</code></td><td>Percentage representation of a new rendition's resolution compared to the previous rendition's resolution, weighted by the play duration. Because this metric strictly tracks upswitch rendition, the value is always greater than 100%.<br><br>The resolution value used for the percentage calculation is video width pixel count multiplied by video height pixel count. </td><td>false</td><td>--</td><td></td></tr><tr><td>Resolution Downswitch Count</td><td><code>resdownscale</code></td><td>Number of rendition changes where resolution of the rendition decreased.</td><td>false</td><td>Average=<code>avg_resdownscale</code><br>Median=<code>median_resdownscale</code><br>P95=<code>p95_resdownscale</code><br>P99=<code>p99_resdownscale</code></td><td></td></tr><tr><td>Resolution Downswitch %</td><td><code>resdownscalepct</code></td><td>Percentage representation of a new rendition's resolution compared to the previous rendition's resolution, weighted by the play duration. Because this metric strictly tracks downswitch rendition, the value is always less than 100%.<br><br>The resolution value used for the percentage calculation is video width pixel count multiplied by video height pixel count. </td><td>false</td><td>--</td><td></td></tr><tr><td>Rendition Switches</td><td><code>renditionswitches</code></td><td>Number of rendition changes.</td><td>false</td><td>Average=<code>avg_renditionswitches</code><br>Median=<code>median_renditionswitches</code><br>P95=<code>p95_renditionswitches</code><br>P99=<code>p99_renditionswitches</code></td><td></td></tr><tr><td>Rendition Switch Rate</td><td><code>renditionswitchrate</code></td><td>Number of rendition changes per min of playtime.</td><td>false</td><td>--</td><td>Bitrate and rendition</td></tr><tr><td>Delivery Traffic (MB)</td><td><code>qbrsize</code></td><td>Total number of bytes delivered for playback.</td><td>true</td><td>Average=<code>avg_qbrsize</code><br>Median=<code>median_qbrsize</code><br>P95=<code>p95_qbrsize</code><br>P99=<code>p99_qbrsize</code></td><td>Delivery and CDN</td></tr><tr><td>CDN Change Count</td><td><code>cdn_change_count</code></td><td>Number of CDN switches.</td><td>true</td><td>Average=<code>avg_cdn_change_count</code><br>Median=<code>median_cdn_change_count</code><br>P95=<code>p95_cdn_change_count</code><br>P99=<code>p99_cdn_change_count</code></td><td>Delivery and CDN</td></tr><tr><td>CDN Change Rate</td><td><code>cdn_change_rate</code></td><td>Number of CDN switches per min of play duration.</td><td>true</td><td>--</td><td>Delivery and CDN</td></tr><tr><td>Video Chunk Request Failure Count</td><td><code>rfvideocount</code></td><td>Number of requests for video chunks (or segments) with 4xx &#x26; 5xx HTTP response status.</td><td>true</td><td><p>Average=<code>avg_rfvideocount</code><br>Median=<code>median_rfvideocount</code><br>P95=<code>p95_rfvideocount</code></p><p>P99=<code>p99_rfvideocount</code></p></td><td>Request failures</td></tr><tr><td>Audio Chunk Request Failure Count</td><td><code>rfaudiocount</code></td><td>Number of requests for audio chunks (or segments) with 4xx &#x26; 5xx HTTP response status.</td><td>true</td><td>Average=<code>avg_rfaudiocount</code><br>Median=<code>median_rfaudiocount</code><br>P95=<code>p95_rfaudiocount</code><br>P99=<code>p99_rfaudiocount</code></td><td>Request failures</td></tr><tr><td>Manifest Request Failure Count</td><td><code>rfmanifestcount</code></td><td>Number of requests for manifest with 4xx &#x26; 5xx HTTP response status. Both Variant and Rendition manifest requests failure are counted. </td><td>true</td><td>Average=<code>avg_rfmanifestcount</code><br>Median=<code>median_rfmanifestcount</code><br>P95=<code>p95_rfmanifestcount</code><br>P99=<code>p99_rfmanifestcount</code></td><td>Request failures</td></tr><tr><td>DRM Request Failure Count</td><td><code>rfencryptioncount</code></td><td>Number of requests for DRM Licenses with 4xx &#x26; 5xx HTTP response status.</td><td>true</td><td>Average=<code>avg_rfencryptioncount</code><br>Median=<code>median_rfencryptioncount</code><br>P95=<code>p95_rfencryptioncount</code><br>P99=<code>p99_rfencryptioncount</code></td><td>Request failures</td></tr><tr><td>Video Track Init Request Failure Count</td><td><code>rfvideoinitcount</code></td><td>Number of requests for video init segment with 4xx &#x26; 5xx HTTP response status.</td><td>true</td><td>Average=<code>avg_rfvideoinitcount</code><br>Median=<code>median_rfvideoinitcount</code><br>P95=<code>p95_rfvideoinitcount</code><br>P99=<code>p99_rfvideoinitcount</code></td><td></td></tr><tr><td>Audio Track Init Request Failure Count</td><td><code>rfaudioinitcount</code></td><td>Number of requests for audio init segment with 4xx &#x26; 5xx HTTP response status.</td><td>true</td><td>Average=<code>avg_rfaudioinitcount</code><br>Median=<code>median_rfaudioinitcount</code><br>P95=<code>p95_rfaudioinitcount</code><br>P99=<code>p99_rfaudioinitcount</code></td><td></td></tr><tr><td>PIR Request Failure Count</td><td><code>rfpircount</code></td><td>Number of requests for PIR object with 4xx &#x26; 5xx HTTP response status.<br><br>PIR stands for Playback information Request. Many applications makes API requests to get video playback information, like playback urls, player configuration and other control signals from the server before loading the video. This metric counts  failed requests of this resource. </td><td>true</td><td>Average=<code>avg_rfpircount</code><br>Median=<code>median_rfpircount</code><br>P95=<code>p95_rfpircount</code><br>P99=<code>p99_rfpircount</code></td><td></td></tr></tbody></table>
{% endtab %}

{% tab title="Video Dimensions" %}

<table data-header-hidden="false" data-header-sticky><thead><tr><th width="194.65234375">Dimension Name</th><th width="210.26904296875">Dimension Key</th><th>Description</th><th data-hidden>Category</th></tr></thead><tbody><tr><td>App Name</td><td><code>appname</code></td><td>Name of the client application used for playback</td><td>Player and app</td></tr><tr><td>App Version</td><td><code>appversion</code></td><td>Version string of the client application</td><td>Player and app</td></tr><tr><td>Browser Name</td><td><code>browser</code></td><td>Browser used for playback (e.g. Chrome, Safari, Firefox)</td><td>Player and app</td></tr><tr><td>Browser Version</td><td><code>browserversion</code></td><td>Version of the browser</td><td>Player and app</td></tr><tr><td>Player Name</td><td><code>player</code></td><td>Video player name used by the client application</td><td>Player and app</td></tr><tr><td>Player Version</td><td><code>playerversion</code></td><td>Version of the video player</td><td>Player and app</td></tr><tr><td>Base Player Name</td><td><code>baseplayername</code></td><td>Name of the underlying player when a wrapper or adapter is used (e.g. ExoPlayer beneath a custom wrapper)</td><td>Player and app</td></tr><tr><td>Base Player Version</td><td><code>baseplayerversion</code></td><td>Version of the underlying base player</td><td>Player and app</td></tr><tr><td>Domain Name</td><td><code>domainname</code></td><td>Domain of the page on which the player was embedded</td><td>Player and app</td></tr><tr><td>MediaMelon SDK Info</td><td><code>sdkversion</code></td><td>MediaMelon SDK Name and Version</td><td>Player and app</td></tr><tr><td>Subscriber ID</td><td><code>subscriberid</code></td><td>Unique identifier for each viewer</td><td>Subscriber</td></tr><tr><td>Subscriber Type</td><td><code>subscribertype</code></td><td>Name of Subscription tier or type (e.g. premium, free, trial)</td><td>Subscriber</td></tr><tr><td>Audience Type</td><td><code>audience_type</code></td><td>Type of Viewer. Possible Values are <code>Subscriber</code> or <code>Anonymous Viewer</code></td><td>Subscriber</td></tr><tr><td>Subscriber Tag</td><td><code>subscribertag</code></td><td>Custom label or tag associated with the subscriber</td><td>Subscriber</td></tr><tr><td>Asset ID</td><td><code>assetid</code></td><td>Unique identifier of the video asset</td><td>Content</td></tr><tr><td>Asset Name</td><td><code>assetname</code></td><td>Human-readable title of the video asset</td><td>Content</td></tr><tr><td>Video ID</td><td><code>videoid</code></td><td>Platform-level video identifier, distinct from the asset ID</td><td>Content</td></tr><tr><td>Content Type</td><td><code>contenttype</code></td><td>Type of content being played (e.g. episode, clip, movie)</td><td>Content</td></tr><tr><td>Series Title</td><td><code>seriestitle</code></td><td>Title of the show or series</td><td>Content</td></tr><tr><td>Episode Number</td><td><code>episodenumber</code></td><td>Episode number within a series</td><td>Content</td></tr><tr><td>Season</td><td><code>season</code></td><td>Season number of the series</td><td>Content</td></tr><tr><td>Genre</td><td><code>genre</code></td><td>Comma-separated genre list for the asset</td><td>Content</td></tr><tr><td>Media Type</td><td><code>mediatype</code></td><td>Typically used to indicate the stream type — <code>A</code> (Audio Only) or <code>AV</code> (Audio + Video). </td><td>Content</td></tr><tr><td>Property ID</td><td><code>subpropertyid</code></td><td>Digital Property or Business Unit or Market identifier to segment traffic within a single account</td><td>Content</td></tr><tr><td>Is Live Stream</td><td><code>islive</code></td><td>Boolean value indicating whether the session was a live stream (<code>true</code>) or VOD (<code>false</code>)</td><td>Content</td></tr><tr><td>Device Type</td><td><code>device</code></td><td>Category of the Device (e.g. mobile, tablet, TV, desktop, console)</td><td>Device</td></tr><tr><td>Device ID</td><td><code>deviceid</code></td><td>Unique identifier of the playback device</td><td>Device</td></tr><tr><td>Device Marketing Name</td><td><code>devicemarketingname</code></td><td>Consumer-facing marketing name of the device model</td><td>Device</td></tr><tr><td>Operating System</td><td><code>platform</code></td><td>Name of the operating system (e.g. Android, iOS, Windows, tvOS)</td><td>Device</td></tr><tr><td>Operating System Version</td><td><code>platformversion</code></td><td>Version string of the operating system.</td><td>Device</td></tr><tr><td>Device Brand</td><td><code>brand</code></td><td>Manufacturer brand of the playback device (e.g. Samsung, Apple)</td><td>Device</td></tr><tr><td>Device Model Name</td><td><code>model</code></td><td>Technical model identifier of the device</td><td>Device</td></tr><tr><td>Device capabilities</td><td><code>devicecapabilities</code></td><td>Comma separated list of device capability. Mediamelon SDK populates this dimension with the Video Dynamic Range (e.g SDR, HDR+,HDR10, HLG, etc.) supported on the device. </td><td>Device</td></tr><tr><td>Country</td><td><code>country</code></td><td>Name of the Country that the viewer is located in. </td><td>Network and geo</td></tr><tr><td>Region</td><td><code>region</code></td><td>Name of the Region (typically name of the State) that the viewer is located in. </td><td>Network and geo</td></tr><tr><td>City</td><td><code>city</code></td><td>Name of the City that the viewer is located in. </td><td>Network and geo</td></tr><tr><td>ISP</td><td><code>isp</code></td><td>Name of Internet Service Provider (ISP) that the viewer is connected to watch the video. </td><td>Network and geo</td></tr><tr><td>ASN</td><td><code>asn</code></td><td>Globally Unique Identifier assigned to an Autonomous System, typically a network or ISP, to control and route traffic across the internet. </td><td>Network and geo</td></tr><tr><td>Connection type</td><td><code>nwtype</code></td><td>Network type that the viewer is connected too (e.g. <code>cellular</code>, <code>wifi</code>, <code>satellite</code>, <code>cable/dsl</code>, etc.)</td><td>Network and geo</td></tr><tr><td>Initial CDN</td><td><code>starting_cdn</code></td><td>The Initial CDN used to start the playback of the session. <br><br>This dimension is not available in concurrency mode. </td><td></td></tr><tr><td>Last CDN</td><td><code>cdn</code></td><td>The Last CDN that delivered the last segment of the session. </td><td>Session attribute</td></tr><tr><td>Session ID</td><td><code>sessionid</code></td><td>Unique identifier assigned by the MediaMelon SDK for every session. </td><td>Session attribute</td></tr><tr><td>Experiment Name</td><td><code>experimentname</code></td><td>Name of the A/B test or experiment this session was assigned to</td><td>Session attribute</td></tr><tr><td>Fatal Error Category</td><td><code>fatal_error_category</code></td><td>Category of the fatal error. Possible Values are<br>- <code>Technical Startup Failure</code><br>- <code>Technical Mid-Stream Failure</code><br>- <code>Business Exception Startup Failure</code><br>- <code>Business Exception Mid-Stream Failure</code><br>- <code>No Fatal Failure</code></td><td>Session attribute</td></tr><tr><td>Error Code</td><td><code>errorcode</code></td><td>Last Error code captured when there are errors in a session. </td><td>Session attribute</td></tr><tr><td>Error Description</td><td><code>errordescription</code></td><td>Description of the Last Error Code. </td><td></td></tr><tr><td>DRM</td><td><code>drmprotection</code></td><td>DRM system used for playing the video (e.g. Widevine, FairPlay, PlayReady)</td><td>Session attribute</td></tr><tr><td>Source Format</td><td><code>sourcetype</code></td><td>Streaming format used to play the video (e.g. HLS, DASH, MP4)</td><td>Session attribute</td></tr><tr><td>View Status</td><td><code>status</code></td><td>Final status of the session. Possible values are <code>ENDED</code>, <code>DROPPED</code>, <code>RUNNING</code>, <code>STARTED</code> , <code>IN_AD</code>, <code>LOADED</code>, <code>IN_ERROR</code>, <code>STALLED</code></td><td>Session attribute</td></tr><tr><td>Contains Ads</td><td><code>hasad</code></td><td>Boolean value (<code>true</code> or <code>false</code> ) indicating whether the session played any ads. </td><td>Session attribute</td></tr><tr><td>Contains Pre-Roll Ads</td><td><code>hasprerollad</code></td><td>Boolean value (<code>true</code> or <code>false</code> ) indicating whether the session played pre-roll ads. </td><td></td></tr><tr><td>Contains Warning Errors</td><td><code>containswarning</code></td><td>Boolean value (<code>true</code> or <code>false</code> ) indicating whether the session had any errors marked as Warning. </td><td></td></tr><tr><td>Contains Ad Buffering</td><td><code>hasadbuffwait</code></td><td>Boolean value (<code>true</code> or <code>false</code> ) indicating whether the session had any interruptions when playing ads. </td><td></td></tr><tr><td>Video Codec</td><td><code>vcodec</code></td><td>Video codec of the video played. </td><td>Session attribute</td></tr><tr><td>Audio codec</td><td><code>acodec</code></td><td>Audio codec of the video played. </td><td>Session attribute</td></tr><tr><td>CDN Change Count Buckeet</td><td><code>cdn_change_count_bucket</code></td><td>Each Bucket indicating the corresponding number of <code>CDN_CHANGE</code> events occuring in a session. Possible values are <code>Once</code>, <code>Twice</code>, <code>Thrice</code>, <code>4-6 times</code> and <code>More than 6 times</code></td><td></td></tr><tr><td>Device Display Resolution</td><td><code>scrnres</code></td><td>Resolution of the display device used for playing the video. </td><td></td></tr><tr><td>DRM Level</td><td><code>drmlevel</code></td><td>Indicates the level of DRM protection used for the video played. </td><td></td></tr><tr><td>Encoding Service</td><td><code>encodingservice</code></td><td>Name of the encoding service used to encode/transcode the video content. </td><td></td></tr><tr><td>Exit Before Video Start</td><td><code>hasebvs</code></td><td>Whether the session ended as ebvs <code>1</code> or not <code>0</code></td><td></td></tr><tr><td>Player ID</td><td><code>playerid</code></td><td>Unique identifier for the video player instance. Typically this dimension is useful identifier for when the application or web page loads multiple player instances. </td><td></td></tr><tr><td>Preload</td><td><code>preload</code></td><td>Boolean value (<code>true</code> or <code>false</code> ) indicating whether the video was preloaded by the player before user-initiated play. </td><td></td></tr><tr><td>Resumed Play</td><td><code>resumedplay</code></td><td>Boolean value (<code>true</code> or <code>false</code> ) indicating whether the video playing started from the beginning of the content (<code>false</code>) or not (<code>true</code>). </td><td></td></tr><tr><td>View Session ID</td><td><code>viewsessionid</code></td><td>Customer defined unique identified for the session that can be correlated with the other datasets managed by the customer. </td><td></td></tr><tr><td>Custom tags 1-20</td><td><code>customtag1</code> to <code>customtag20</code></td><td>Custom metadata tag as defined by the customer. MediaMelon supports upto 20 custom tags. </td><td>Custom tag</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

### Ad Metrics & Dimensions

{% tabs %}
{% tab title="Ad Metrics" %}

<table data-header-hidden="false" data-header-sticky data-first-column-sticky><thead><tr><th width="186.73828125">Metric Name</th><th width="197.95703125">Metric Key</th><th>Description</th><th data-hidden>Category</th></tr></thead><tbody><tr><td>Ad Playtime (mins)</td><td><code>adviewtime</code></td><td>Total ad viewing time.</td><td>Engagement</td></tr><tr><td>Unique Subscribers</td><td><code>ad_unique_subscriber</code></td><td>Number of distinct <code>subscrberId</code> values representing viewers who initiated playing an ad.</td><td>Engagement</td></tr><tr><td>Unique Devices</td><td><code>ad_unique_devices</code></td><td>Number of distinct devices calculated by counting unique <code>deviceid</code> or computed by combining <code>brand</code>, <code>model</code> , and <code>ipaddress</code> that initiated playing an ad</td><td>Engagement</td></tr><tr><td>Anonymous viewers</td><td><code>ad_anonymous_viewers</code></td><td>Number of distinct viewers with no <code>subscriberid</code> value set on a session and the viewer is uniquely identified by combining <code>brand</code>, <code>model</code>, and <code>ipaddress</code> that initiated playing an ad. <br><br>Typically, Anonymous Viewer is considered to be viewer who has not logged in / authenticated. </td><td>Engagement</td></tr><tr><td>Unique Ads</td><td><code>unique_ads</code></td><td>Number of distinct Ads <code>adid</code> value.</td><td>Engagement</td></tr><tr><td>Ad Impression</td><td><code>adimpression</code></td><td>Number of Ad Impression events representing the number of times an ad playing was initiated. </td><td>Consumption</td></tr><tr><td>Ad Plays</td><td><code>adplay</code></td><td>Number of Ad Play events representing the number of times an ad started playing. An Ad is considered as started playing is when the first video frame of the ad is displayed to the viewer. </td><td>Consumption</td></tr><tr><td>Ad Breaks</td><td><code>adbreakcount</code></td><td>Number of Ad Breaks (<code>AD_BREAK_START</code>) events. </td><td>Consumption</td></tr><tr><td>Average Audience Ad Playtime</td><td><code>ad_playtime_by_audience</code></td><td>Avg Ad Playtime per Unique Viewer. A Viewer can be a valid subscriber or an anonymous viewer. </td><td>Consumption</td></tr><tr><td>Average Audience Ad Impressions</td><td><code>ad_impressions_by_audience</code></td><td>Avg Number of Ad Impressions per unique viewer. A Viewer can be a valid subscriber or an anonymous viewer. </td><td>Consumption</td></tr><tr><td>Average Device Ad Playtime</td><td><code>ad_playtime_by_device</code></td><td>Avg Ad Playtime per Unique Device. A Device is considerd unique when it has a distinct <code>deviceid</code> or computed by combining  <code>brand</code>, <code>model</code> , and  <code>ipaddress</code></td><td></td></tr><tr><td>Average Device Ad impressions</td><td><code>ad_impressions_by_device</code></td><td>Avg Ad Impressions per Unique Device. A Device is considerd unique when it has a distinct <code>deviceid</code> or computed by combining  <code>brand</code>, <code>model</code> , and  <code>ipaddress</code></td><td></td></tr><tr><td>Ad Fill Rate %</td><td><code>adfillrate</code></td><td>Ad Plays as a percentage of Ad Impressions. A value of <code>100%</code> indicates that every ad played. </td><td>Ad performance</td></tr><tr><td>Ad Errors</td><td><code>aderror</code></td><td>Number of errors during an ad's lifecycle.</td><td>Ad performance</td></tr><tr><td>Ad Startup Time (sec)</td><td><code>adlatency</code></td><td>Time between ad request or ad impression to the first video frame of the ad. <br><br>Ad Startup Time is available for Client-Side Ad Insertion (CSAI) or Pre-Roll Ad placement with Server-Side Ad Insertion (SSAI).  </td><td>Ad performance</td></tr><tr><td>Ad Rebuffering %</td><td><code>adbufferingratio</code></td><td>Percentage of Ad viewing time spent buffering. </td><td>Ad performance</td></tr><tr><td>Ad Completion %</td><td><code>adcompletionrate</code></td><td>Percentage of ads played to <code>100%</code></td><td>Ad playback</td></tr><tr><td>Ad First Quartile %</td><td><code>adfirstquartilepct</code></td><td>Percentage of ads played atleast <code>25%</code>  of the ad duration</td><td>Ad playback</td></tr><tr><td>Ad midpoint %</td><td><code>adsecondquartilepct</code></td><td>Percentage of ads played atleast <code>50%</code>  of the ad duration</td><td>Ad playback</td></tr><tr><td>Ad third quartile %</td><td><code>adthirdquartilepct</code></td><td>Percentage of ads played atleast <code>75%</code>  of the ad duration</td><td>Ad playback</td></tr><tr><td>Ad Skipped %</td><td><code>adskippercentage</code></td><td>Percentage of ads skipped before completion</td><td>Ad playback</td></tr><tr><td>Ad Click Through %</td><td><code>adclickthroughrate</code></td><td>Percentage of ads with a viewer clicking on the ad. </td><td>Ad playback</td></tr><tr><td>Exit Before Pre-Roll Ad %</td><td><code>exitbeforeprerollad</code></td><td>Percentage of sessions the viewer abandoned before the first video frame of a pre-roll ad was displayed.</td><td>Ad playback</td></tr></tbody></table>
{% endtab %}

{% tab title="Ad Dimensions" %}

<table data-header-hidden="false" data-header-sticky data-first-column-sticky><thead><tr><th width="147.0703125">Dimension Name</th><th width="176.37109375">Dimension Key</th><th>Description</th></tr></thead><tbody><tr><td>Ad ID</td><td><code>adid</code></td><td>Unique identifier of the ad. Typically the <code>adid</code> is unique to the Ad Server and it is not a globally unique identifier. </td></tr><tr><td>Ad Server Name</td><td><code>adserver</code></td><td>Name of the Ad Server used to deliver the ad. </td></tr><tr><td>Ad Break Placement</td><td><code>adposition</code></td><td>Position of the Ad. Possbile values are <code>pre</code> for pre-roll, <code>mid</code> for mid-roll and <code>post</code> for post-roll ads. </td></tr><tr><td>Ad Break Position Index</td><td><code>adpodindex</code></td><td>Position index of the Ad Break (aka Ad Pod) in a session. The index number starts with <code>0</code> typically representing pre-roll ad break. </td></tr><tr><td>Ad ID Position Index</td><td><code>adpodposition</code></td><td>Position of an ad in an Ad Break (aka Ad Pod). The position value starts with <code>0</code> indicating the ad is the first ad in the Ad Break. </td></tr></tbody></table>
{% endtab %}
{% endtabs %}


# Metric Query API

Use `metricquery` API endpoint to get video session & ad related metrics and breakdowns by dimension values.

### Endpoint

`GET /mm-apis/metricquery/{customerId}`

{% hint style="warning" %}
As of July 2025, `/mm-apis/qbrData/vod` and `/mm-apis/session` are deprecated. Use `/mm-apis/metricquery` instead. Backward compatibility remains available, but `/mm-apis/metricquery` provides access to newer features.
{% endhint %}

### Path parameters

<table><thead><tr><th width="166.953125">Parameter</th><th width="156.546875">Type</th><th width="155.13671875">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>customerId</code></td><td>integer</td><td>Yes</td><td>Numeric tenant identifier from your SmartSight profile</td></tr></tbody></table>

### Query parameters

<table data-first-column-sticky><thead><tr><th width="109.3671875">Name</th><th width="101.72265625">Type</th><th width="92.47265625">Required</th><th width="126.375">Default</th><th>Format / Possible Values</th><th>Description</th></tr></thead><tbody><tr><td><code>period</code></td><td>string</td><td>Yes</td><td>—</td><td><code>start=&#x3C;epoch>,end=&#x3C;epoch></code></td><td>Time range in Unix epoch seconds</td></tr><tr><td><code>metrics</code></td><td>string</td><td>Yes</td><td>—</td><td><code>metric1,metric2,...</code></td><td>Comma-separated metric field names</td></tr><tr><td><code>aggby</code></td><td>string</td><td>No</td><td>—</td><td><code>&#x3C;dimension></code>, <code>timestamp</code></td><td>Group by dimension or time</td></tr><tr><td><code>sessiontype</code></td><td>string</td><td>No</td><td><code>ended</code></td><td><code>ended</code> , <code>started</code></td><td><p>Sessions to include in the response. </p><ul><li><code>started</code>: Add sessions that started in the <code>period</code>  </li><li><code>ended</code>: Add sessions that ended in the <code>period</code> </li></ul></td></tr><tr><td><code>allstatus</code></td><td>integer</td><td>No</td><td><code>0</code></td><td><code>0</code> , <code>1</code></td><td><code>1</code> includes sessions with any <code>viewstatus</code> value including <code>RUNNING</code> and <code>LOADED</code> sessions</td></tr><tr><td><code>granularity</code></td><td>string</td><td>No</td><td><code>auto</code></td><td><code>auto</code>, <code>minute</code>, <code>5minute</code>, <code>10minute</code>, <code>hour</code>, <code>day</code></td><td><p>Time bucket size. <br></p><p>Set this parameter only with <code>aggby=timestamp</code></p></td></tr><tr><td><code>filter</code></td><td>string</td><td>No</td><td>—</td><td><code>[dimension=value]</code></td><td>Dimension-level filters</td></tr><tr><td><code>qoefilter</code></td><td>string</td><td>No</td><td>—</td><td><code>metric1>value1 AND metric2>value2</code></td><td>Session-level metric filters</td></tr><tr><td><code>orderby</code></td><td>string</td><td>No</td><td>—</td><td>metric or dimension</td><td>Sort reocrds by the value of the metric or dimension</td></tr><tr><td><code>order</code></td><td>string</td><td>No</td><td><code>desc</code></td><td><code>asc</code> or <code>desc</code></td><td>Sort direction</td></tr><tr><td><code>limit</code></td><td>integer</td><td>No</td><td><code>1000</code></td><td>integer</td><td>Max records per page/query</td></tr><tr><td><code>offset</code></td><td>integer</td><td>No</td><td><code>0</code></td><td>integer</td><td>Pagination offset</td></tr><tr><td><code>concurrency</code></td><td>integer</td><td>No</td><td><code>0</code></td><td><code>0</code> , <code>1</code></td><td><code>1</code> indicates the metric value calculated is based on the metric related event occurrence in the requested time range. <br><br><code>0</code> indicates the metric value calculated is cumulative of all the occurrences of that metric related events. </td></tr><tr><td><code>businesserror</code></td><td>boolean</td><td>No</td><td><code>false</code></td><td><code>true</code> , <code>false</code></td><td>Include business exception errors in error metrics</td></tr></tbody></table>

{% hint style="info" %}
Authenticate each request by adding `X-API-Key` HTTP request header to each request.
{% endhint %}

{% hint style="info" %}
Use the [Metric and Dimensions Dictionary](/mediamelon/smartsight-apis/metrics) for supported video and ad related metrics, dimensions, and aggregate variants available such as `p95_latency`.
{% endhint %}

### API Considerations

* Always request metric data for completed time buckets. For real-time monitoring, set the `period` start and end time interval to the most recently completed time bucket. For example, request `2026-05-25 10:00:00` to `2026-05-25 10:00:59` if the current time is `2026-05-25 10:01:35`.
* Set API response timeouts based on the requested time range. For example, use a `10s` timeout when the `period` covers `1 min` to `30 mins`. Use higher timeout values for longer ranges such as `1 day`, `7 days`, or `30 days`.
* Use pagination with `limit` and `offset`, especially for high-cardinality breakdown queries. For example, Rebuffering % breakdown by `cdn`, `asn`, and `region` can return `100k+` records. A good practice is to fetch `5k` to `10k` records per API call.<br>

### Example requests

#### Time-series graph - Rebuffering % over time

{% code overflow="wrap" %}

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/metricquery/199493832?  
    period=start=1775749920,end=1775836379&
    metrics=timestamp,cirrbufferingratio,concurviewavg&
    aggby=timestamp&
    granularity=5minute&
    orderby=timestamp& 
    order=asc&
    allstatus=0' \
  --header 'X-API-Key: <your-api-key>'
```

{% endcode %}

#### Dimension breakdown — Startup time by country (P95)

{% code overflow="wrap" %}

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/metricquery/199493832?  
    period=start=1775749920,end=1775836379&
    metrics=p95_latency,concurviewavg&
    aggby=country&
    orderby=p95_latency&
    order=desc&
    limit=25' \
  --header 'X-API-Key: <your-api-key>'
```

{% endcode %}

#### Filtered query — Buffering by CDN on Android

{% code overflow="wrap" %}

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/metricquery/199493832?  
    period=start=1775749920,end=1775836379&
    metrics=cirrbufferingratio,attempts&
    aggby=cdn&
    filter=[platform=Android]&
    orderby=cirrbufferingratio&
    order=desc' \
  --header 'X-API-Key: <your-api-key>'
```

{% endcode %}

### Example response

{% code lineNumbers="true" %}

```json
{
  "totalcount": 25,
  "pagecount": 4,
  "totalrecords": 100,
  "response": [
    {
      "country": "US",
      "latency": 1.82,
      "concurviewavg": 412
    },
    {
      "country": "GB",
      "latency": 2.14,
      "concurviewavg": 187
    }
  ]
}
```

{% endcode %}


# Video Session List API

Query paginated video session rows for drill-down and root-cause analysis.

Returns a paginated list of individual video sessions. Use it for drill-down analysis and root-cause investigation.

### Endpoint

`GET /mm-apis/listsessions/{customerId}`

{% hint style="info" %}
This endpoint is exclusive to Video Analysis. There is no session-list endpoint for ad analytics.
{% endhint %}

{% hint style="info" %}
Authenticate each request by adding  `X-API-Key`  HTTP Request header.&#x20;
{% endhint %}

### Query parameters

<table data-first-column-sticky><thead><tr><th width="109.3671875">Name</th><th width="101.72265625">Type</th><th width="92.47265625">Required</th><th width="126.375">Default</th><th>Format / Possible Values</th><th>Description</th></tr></thead><tbody><tr><td><code>period</code></td><td>string</td><td>Yes</td><td>—</td><td><code>start=&#x3C;epoch>,end=&#x3C;epoch></code></td><td>Time range in Unix epoch seconds</td></tr><tr><td><code>metrics</code></td><td>string</td><td>Yes</td><td>—</td><td><code>metric1,metric2,...</code></td><td>Comma-separated metric field names</td></tr><tr><td><code>aggby</code></td><td>string</td><td>No</td><td>—</td><td><code>&#x3C;dimension></code>, <code>timestamp</code></td><td>Group by dimension or time</td></tr><tr><td><code>sessiontype</code></td><td>string</td><td>No</td><td><code>ended</code></td><td><code>ended</code> , <code>started</code></td><td><p>Sessions to include in the response. </p><ul><li><code>started</code>: Add sessions that started in the <code>period</code>  </li><li><code>ended</code>: Add sessions that ended in the <code>period</code> </li></ul></td></tr><tr><td><code>allstatus</code></td><td>integer</td><td>No</td><td><code>0</code></td><td><code>0</code> , <code>1</code></td><td><code>1</code> includes sessions with any <code>viewstatus</code> value including <code>RUNNING</code> and <code>LOADED</code> sessions</td></tr><tr><td><code>granularity</code></td><td>string</td><td>No</td><td><code>auto</code></td><td><code>auto</code>, <code>minute</code>, <code>5minute</code>, <code>10minute</code>, <code>hour</code>, <code>day</code></td><td><p>Time bucket size. <br></p><p>Set this parameter only with <code>aggby=timestamp</code></p></td></tr><tr><td><code>filter</code></td><td>string</td><td>No</td><td>—</td><td><code>[dimension=value]</code></td><td>Dimension-level filters</td></tr><tr><td><code>qoefilter</code></td><td>string</td><td>No</td><td>—</td><td><code>metric1>value1 AND metric2>value2</code></td><td>Session-level metric filters</td></tr><tr><td><code>orderby</code></td><td>string</td><td>No</td><td>—</td><td>metric or dimension</td><td>Sort reocrds by the value of the metric or dimension</td></tr><tr><td><code>order</code></td><td>string</td><td>No</td><td><code>desc</code></td><td><code>asc</code> or <code>desc</code></td><td>Sort direction</td></tr><tr><td><code>limit</code></td><td>integer</td><td>No</td><td><code>1000</code></td><td>integer</td><td>Max records per page/query</td></tr><tr><td><code>offset</code></td><td>integer</td><td>No</td><td><code>0</code></td><td>integer</td><td>Pagination offset</td></tr><tr><td><code>concurrency</code></td><td>integer</td><td>No</td><td><code>0</code></td><td><code>0</code> , <code>1</code></td><td><code>1</code> indicates the metric value calculated is based on the metric related event occurrence in the requested time range. <br><br><code>0</code> indicates the metric value calculated is cumulative of all the occurrences of that metric related events. </td></tr><tr><td><code>businesserror</code></td><td>boolean</td><td>No</td><td><code>false</code></td><td><code>true</code> , <code>false</code></td><td>Include business exception errors in error metrics</td></tr></tbody></table>

<table data-header-hidden="false" data-header-sticky><thead><tr><th width="140.3828125">Name</th><th width="108.06640625">Type</th><th width="106.84765625">Required</th><th width="137.9140625">Default</th><th>Format / Possible Values</th><th>Description</th></tr></thead><tbody><tr><td><code>period</code></td><td>string</td><td>Yes</td><td>—</td><td><code>start=&#x3C;epoch>,end=&#x3C;epoch></code></td><td>Time range in Unix epoch seconds</td></tr><tr><td><code>metrics</code></td><td>string</td><td>Yes</td><td>—</td><td><code>metric1,metric2,...</code></td><td>List of Metrics and Dimensions to include</td></tr><tr><td><code>aggby</code></td><td>string</td><td>Yes</td><td><code>sessionid</code></td><td><code>sessionid</code></td><td>Group response records by <code>sessionid</code></td></tr><tr><td><code>sessiontype</code></td><td>string</td><td>No</td><td><code>ended</code></td><td><code>ended</code>, <code>started</code></td><td><p>Sessions to include in the response. </p><ul><li><code>started</code>: Add sessions that started in the <code>period</code>  </li><li><code>ended</code>: Add sessions that ended in the <code>period</code> </li></ul></td></tr><tr><td><code>allstatus</code></td><td>integer</td><td>No</td><td><code>0</code></td><td><code>0</code> , <code>1</code></td><td></td></tr><tr><td><code>filter</code></td><td>string</td><td>No</td><td>—</td><td></td><td>Dimension-level filters</td></tr><tr><td><code>qoefilter</code></td><td>string</td><td>No</td><td>—</td><td></td><td>Metric-level session filters</td></tr><tr><td><code>orderby</code></td><td>string</td><td>No</td><td>—</td><td></td><td>Sort by metric</td></tr><tr><td><code>order</code></td><td>string</td><td>No</td><td><code>desc</code></td><td><code>asc</code> , <code>desc</code></td><td></td></tr><tr><td><code>limit</code></td><td>integer</td><td>No</td><td><code>1000</code></td><td></td><td>Max records per page</td></tr><tr><td><code>offset</code></td><td>integer</td><td>No</td><td><code>0</code></td><td></td><td>Pagination offset</td></tr></tbody></table>

{% hint style="info" %}
Use any metric or dimension from [Metric and Dimensions Dictionary](/mediamelon/smartsight-apis/metrics) as the first field in `metrics`. Then add the session fields you want returned.
{% endhint %}

### Example requests

#### Sessions with highest startup delay

{% code overflow="wrap" %}

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/listsessions/199493832?period=start=1775749962,end=1775836362&metrics=latency,starttime,endtime,assetname,watchtime,sessionid,sourcetype&aggby=sessionid&orderby=latency&order=desc&limit=25' \
  --header 'X-API-Key: <your-api-key>'
```

{% endcode %}

#### Sessions with severe buffering on Android

{% code overflow="wrap" %}

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/listsessions/199493832?period=start=1775749962,end=1775836362&metrics=cirrbufferingratio,starttime,endtime,assetname,watchtime,sessionid,sourcetype&aggby=sessionid&filter=[platform=Android]&qoefilter=cirrbufferingratio>10&orderby=cirrbufferingratio&order=desc&limit=25' \
  --header 'X-API-Key: <your-api-key>'
```

{% endcode %}

#### Sessions for a specific subscriber

{% code overflow="wrap" %}

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/listsessions/199493832?period=start=1775749962,end=1775836362&metrics=qualityofexperience,starttime,endtime,assetname,watchtime,sessionid,sourcetype&aggby=sessionid&filter=[subscriberid=user-12345]&orderby=starttime&order=desc' \
  --header 'X-API-Key: <your-api-key>'
```

{% endcode %}

### Standard session fields

| Field        | Description                                       |
| ------------ | ------------------------------------------------- |
| `starttime`  | Session start time in epoch seconds               |
| `endtime`    | Session end time in epoch seconds                 |
| `assetname`  | Name of the video asset played                    |
| `watchtime`  | Total session watch time in seconds               |
| `sessionid`  | MediaMelon unique session identifier              |
| `sourcetype` | Streaming format, such as `HLS`, `DASH`, or `MP4` |

{% tabs %}
{% tab title="Common session metrics" %}

<table><thead><tr><th width="241.1328125">Metric</th><th width="186.609375">API value</th><th>Description</th></tr></thead><tbody><tr><td>Startup time (sec)</td><td><code>latency</code></td><td>Time from play attempt to first frame rendered for this session</td></tr><tr><td>Rebuffering percentage (%)</td><td><code>cirrbufferingratio</code></td><td>Percentage of this session's watch time spent rebuffering</td></tr><tr><td>Buffering time percentage (%)</td><td><code>bufferingratio</code></td><td>Percentage of watch time in any buffering state</td></tr><tr><td>Playback score</td><td><code>qualityofexperience</code></td><td>QoE score from <code>0</code> to <code>100</code> for this individual session</td></tr><tr><td>Playtime (mins)</td><td><code>playdur</code></td><td>Total content viewing time for this session</td></tr><tr><td>CDN change rate</td><td><code>cdn_change_rate</code></td><td>Frequency of CDN switches during this session</td></tr><tr><td>Errors</td><td><code>errors</code></td><td>Number of errors that occur during this session</td></tr><tr><td>Fatal errors</td><td><code>fatalerrors</code></td><td>Number of fatal errors during this session</td></tr></tbody></table>
{% endtab %}

{% tab title="Common session dimensions" %}

| Dimension        | API value       | Description                                        |
| ---------------- | --------------- | -------------------------------------------------- |
| Country          | `country`       | Country derived from the viewer's IP address       |
| Device type      | `device`        | Device category, such as mobile, TV, or desktop    |
| Operating system | `platform`      | OS name, such as Android, iOS, or Windows          |
| Player name      | `player`        | Video player library name                          |
| CDN              | `cdn`           | CDN that serves the session                        |
| Asset name       | `assetname`     | Name of the content asset                          |
| Source format    | `sourcetype`    | Streaming format, such as HLS or DASH              |
| Is live stream   | `islive`        | `true` for live streams and `false` for VOD        |
| View status      | `status`        | Final session status, such as `ended` or `dropped` |
| Subscriber ID    | `subscriberid`  | Specific subscriber to look up sessions for        |
| Error code       | `errorcode`     | Sessions that produce a specific error code        |
| DRM              | `drmprotection` | DRM system used during the session                 |
| {% endtab %}     |                 |                                                    |
| {% endtabs %}    |                 |                                                    |


# Copy of Video Session List API

Query paginated video session rows for drill-down and root-cause analysis.

Returns a paginated list of individual video sessions. Use it for drill-down analysis and root-cause investigation.

### Endpoint

`GET /mm-apis/listsessions/{customerId}`

{% hint style="info" %}
This endpoint is exclusive to Video Analysis. There is no session-list endpoint for ad analytics.
{% endhint %}

{% hint style="info" %}
Authenticate each request with `X-API-Key`.
{% endhint %}

### Query parameters

| Parameter     | Type    | Required | Default     | Description                                                                                                                        |
| ------------- | ------- | -------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `period`      | string  | Yes      | —           | `start=<epoch>,end=<epoch>`                                                                                                        |
| `metrics`     | string  | Yes      | —           | Lead with the metric under investigation. Include fields such as `starttime`, `endtime`, `assetname`, `watchtime`, and `sessionid` |
| `aggby`       | string  | Yes      | `sessionid` | Must be `sessionid`                                                                                                                |
| `sessiontype` | string  | No       | `ended`     | `ended` or `started`                                                                                                               |
| `allstatus`   | integer | No       | `0`         | `0` or `1`                                                                                                                         |
| `filter`      | string  | No       | —           | Dimension-level filters                                                                                                            |
| `qoefilter`   | string  | No       | —           | Metric-level session filters                                                                                                       |
| `orderby`     | string  | No       | —           | Sort by metric                                                                                                                     |
| `order`       | string  | No       | `desc`      | `asc` or `desc`                                                                                                                    |
| `limit`       | integer | No       | `1000`      | Max records per page                                                                                                               |
| `offset`      | integer | No       | `0`         | Pagination offset                                                                                                                  |

{% hint style="info" %}
Use any metric or dimension from [Metric and Dimensions Dictionary](/mediamelon/smartsight-apis/metrics) as the first field in `metrics`. Then add the session fields you want returned.
{% endhint %}

{% tabs %}
{% tab title="Common session metrics" %}

| Metric                        | API value             | Description                                                     |
| ----------------------------- | --------------------- | --------------------------------------------------------------- |
| Startup time (sec)            | `latency`             | Time from play attempt to first frame rendered for this session |
| Rebuffering percentage (%)    | `cirrbufferingratio`  | Percentage of this session's watch time spent rebuffering       |
| Buffering time percentage (%) | `bufferingratio`      | Percentage of watch time in any buffering state                 |
| Playback score                | `qualityofexperience` | QoE score from `0` to `100` for this individual session         |
| Playtime (mins)               | `playdur`             | Total content viewing time for this session                     |
| CDN change rate               | `cdn_change_rate`     | Frequency of CDN switches during this session                   |
| Errors                        | `errors`              | Number of errors that occur during this session                 |
| Fatal errors                  | `fatalerrors`         | Number of fatal errors during this session                      |
| {% endtab %}                  |                       |                                                                 |

{% tab title="Common session dimensions" %}

| Dimension        | API value       | Description                                        |
| ---------------- | --------------- | -------------------------------------------------- |
| Country          | `country`       | Country derived from the viewer's IP address       |
| Device type      | `device`        | Device category, such as mobile, TV, or desktop    |
| Operating system | `platform`      | OS name, such as Android, iOS, or Windows          |
| Player name      | `player`        | Video player library name                          |
| CDN              | `cdn`           | CDN that serves the session                        |
| Asset name       | `assetname`     | Name of the content asset                          |
| Source format    | `sourcetype`    | Streaming format, such as HLS or DASH              |
| Is live stream   | `islive`        | `true` for live streams and `false` for VOD        |
| View status      | `status`        | Final session status, such as `ended` or `dropped` |
| Subscriber ID    | `subscriberid`  | Specific subscriber to look up sessions for        |
| Error code       | `errorcode`     | Sessions that produce a specific error code        |
| DRM              | `drmprotection` | DRM system used during the session                 |
| {% endtab %}     |                 |                                                    |
| {% endtabs %}    |                 |                                                    |

### Standard session fields

| Field        | Description                                       |
| ------------ | ------------------------------------------------- |
| `starttime`  | Session start time in epoch seconds               |
| `endtime`    | Session end time in epoch seconds                 |
| `assetname`  | Name of the video asset played                    |
| `watchtime`  | Total session watch time in seconds               |
| `sessionid`  | MediaMelon unique session identifier              |
| `sourcetype` | Streaming format, such as `HLS`, `DASH`, or `MP4` |

### Example requests

#### Sessions with highest startup delay

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/listsessions/199493832?period=start=1775749962,end=1775836362&metrics=latency,starttime,endtime,assetname,watchtime,sessionid,sourcetype&aggby=sessionid&orderby=latency&order=desc&limit=25' \
  --header 'X-API-Key: <your-api-key>'
```

#### Sessions with severe buffering on Android

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/listsessions/199493832?period=start=1775749962,end=1775836362&metrics=cirrbufferingratio,starttime,endtime,assetname,watchtime,sessionid,sourcetype&aggby=sessionid&filter=[platform=Android]&qoefilter=cirrbufferingratio>10&orderby=cirrbufferingratio&order=desc&limit=25' \
  --header 'X-API-Key: <your-api-key>'
```

#### Sessions for a specific subscriber

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/listsessions/199493832?period=start=1775749962,end=1775836362&metrics=qualityofexperience,starttime,endtime,assetname,watchtime,sessionid,sourcetype&aggby=sessionid&filter=[subscriberid=user-12345]&orderby=starttime&order=desc' \
  --header 'X-API-Key: <your-api-key>'
```


# Ad Metric Query

Query aggregated ad metrics with the SmartSight metric query endpoint.

Use this endpoint for ad trend graphs, dimension breakdowns, comparison views, and KPI tiles.

### Endpoint

`GET /mm-apis/metricquery/{customerId}`

{% hint style="info" %}
This endpoint serves both video and ad analytics. Use ad-specific metrics for ad queries. There is no separate session-list endpoint for ad analytics.
{% endhint %}

### Path parameters

| Parameter    | Type    | Required | Description                                            |
| ------------ | ------- | -------- | ------------------------------------------------------ |
| `customerId` | integer | Yes      | Numeric tenant identifier from your SmartSight profile |

### Query parameters

<table><thead><tr><th>Parameter</th><th width="126.01171875">Type</th><th width="132.890625">Required</th><th width="124.61328125">Default</th><th>Format</th><th>Description</th></tr></thead><tbody><tr><td><code>period</code></td><td>string</td><td>Yes</td><td>—</td><td><code>start=&#x3C;epoch>,end=&#x3C;epoch></code></td><td>Time range in Unix epoch seconds</td></tr><tr><td><code>metrics</code></td><td>string</td><td>Yes</td><td>—</td><td><code>metric1,metric2,...</code></td><td>Comma-separated ad metric field names</td></tr><tr><td><code>aggby</code></td><td>string</td><td>No</td><td>—</td><td><code>&#x3C;dimension></code>, <code>timestamp</code>, or <code>sessionid</code></td><td>Group by dimension, time, or session for session-level ad rows</td></tr><tr><td><code>sessiontype</code></td><td>string</td><td>No</td><td><code>ended</code></td><td><code>ended</code> or <code>started</code></td><td>Session completion status</td></tr><tr><td><code>allstatus</code></td><td>integer</td><td>No</td><td><code>0</code></td><td><code>0</code> or <code>1</code></td><td><code>1</code> includes <code>RUNNING</code> and <code>LOADED</code> sessions</td></tr><tr><td><code>granularity</code></td><td>string</td><td>No</td><td><code>auto</code></td><td><code>auto</code>, <code>minute</code>, <code>5minute</code>, <code>10minute</code>, <code>hour</code>, <code>day</code></td><td>Time bucket size. Requires <code>aggby=timestamp</code></td></tr><tr><td><code>filter</code></td><td>string</td><td>No</td><td>—</td><td><code>[dimension=value]</code></td><td>Dimension-level filters</td></tr><tr><td><code>qoefilter</code></td><td>string</td><td>No</td><td>—</td><td><code>metric>value AND ...</code></td><td>Session-level metric filters</td></tr><tr><td><code>orderby</code></td><td>string</td><td>No</td><td>—</td><td>metric or dimension</td><td>Sort column</td></tr><tr><td><code>order</code></td><td>string</td><td>No</td><td><code>desc</code></td><td><code>asc</code> or <code>desc</code></td><td>Sort direction</td></tr><tr><td><code>limit</code></td><td>integer</td><td>No</td><td><code>1000</code></td><td>integer</td><td>Max records per page</td></tr><tr><td><code>offset</code></td><td>integer</td><td>No</td><td><code>0</code></td><td>integer</td><td>Pagination offset</td></tr><tr><td><code>businesserror</code></td><td>boolean</td><td>No</td><td><code>false</code></td><td><code>true</code> or <code>false</code></td><td>Include business exception errors in error metrics where applicable</td></tr></tbody></table>

{% hint style="info" %}
`concurrency` is not supported for ad queries. For rate-based ad reports, include `adimpression` and `totaladimpression` as context metrics.
{% endhint %}

{% hint style="info" %}
Use the [Metric and Dimensions Dictionary](/mediamelon/smartsight-apis/metrics) for ad metrics, ad dimensions, shared dimensions, percentile variants, and context metrics such as `adimpression` and `totaladimpression`.
{% endhint %}

{% tabs %}
{% tab title="Ad-specific dimensions" %}

| Dimension               | API value       | Description                      |
| ----------------------- | --------------- | -------------------------------- |
| Ad ID                   | `adid`          | Unique ad creative identifier    |
| Ad server name          | `adserver`      | Ad server that delivered the ad  |
| Ad break placement      | `adposition`    | `Pre`, `Mid`, or `Post`          |
| Ad break position index | `adpodindex`    | Numeric index of the ad break    |
| Ad position in pod      | `adpodposition` | Position within the ad pod       |
| Pod length              | `adpodlength`   | Total ad pod duration in seconds |
| {% endtab %}            |                 |                                  |

{% tab title="Common shared dimensions" %}
Most commonly used dimensions:

| Category          | Dimension        | API value        | Description                                        |
| ----------------- | ---------------- | ---------------- | -------------------------------------------------- |
| Network and geo   | Country          | `country`        | Country derived from the viewer's IP address       |
| Device            | Device type      | `device`         | Device category, such as mobile, TV, or desktop    |
| Device            | Operating system | `platform`       | OS name, such as Android, iOS, or Windows          |
| Player and app    | App name         | `appname`        | Name of the client application                     |
| Content           | Asset name       | `assetname`      | Name of the content asset where the ad ran         |
| Content           | Content type     | `contenttype`    | Type of content, such as episode or live event     |
| Subscriber        | Subscriber type  | `subscribertype` | Subscription tier, such as premium or free         |
| Session attribute | Is live stream   | `islive`         | Whether the ad ran in a live stream or VOD session |
| {% endtab %}      |                  |                  |                                                    |
| {% endtabs %}     |                  |                  |                                                    |

### Example requests

#### Trend graph — Ad playtime over time

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/metricquery/199493832?period=start=1775749920,end=1775836379&metrics=adviewtime,adimpression,totaladimpression,timestamp&aggby=timestamp&granularity=5minute&orderby=timestamp&order=asc' \
  --header 'X-API-Key: <your-api-key>'
```

#### Dimension breakdown — Ad startup time by ad server (P95)

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/metricquery/199493832?period=start=1775749920,end=1775836379&metrics=p95_adlatency,adimpression,totaladimpression,adserver&aggby=adserver&orderby=p95_adlatency&order=desc&limit=25' \
  --header 'X-API-Key: <your-api-key>'
```

#### Completion funnel — Ad completion by placement

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/metricquery/199493832?period=start=1775749920,end=1775836379&metrics=adfirstquartilepct,adsecondquartilepct,adthirdquartilepct,adcompletionrate&aggby=adposition&orderby=adcompletionrate&order=desc' \
  --header 'X-API-Key: <your-api-key>'
```

#### Click-through rate by country

```bash
curl --request GET \
  --url 'https://smartsight3.mediamelon.com/mm-apis/metricquery/199493832?period=start=1775749920,end=1775836379&metrics=adclickthroughrate,adimpression,totaladimpression,country&aggby=country&orderby=adclickthroughrate&order=desc&limit=25' \
  --header 'X-API-Key: <your-api-key>'
```

### Example response

{% code lineNumbers="true" %}

```json
{
  "totalcount": 2,
  "pagecount": 1,
  "totalrecords": 2,
  "response": [
    {
      "adserver": "FreeWheel",
      "p95_adlatency": 1.24,
      "adimpression": 12034,
      "totaladimpression": 19002
    },
    {
      "adserver": "Google Ad Manager",
      "p95_adlatency": 1.67,
      "adimpression": 6968,
      "totaladimpression": 19002
    }
  ]
}
```

{% endcode %}

***


# Errors

This guide will help you fetch metrics and dimensions used to compile Smartsight Errors dashboard. &#x20;

### Total Errors <mark style="color:green;">GET</mark>  <a href="#plays" id="plays"></a>

Returns the total errors for all the users .&#x20;

{% code overflow="wrap" lineNumbers="true" %}

```bash
curl 'https://smartsight3.mediamelon.com/mm-apis/session/<customer-id>?planlevel=<level>&period=start=1729666800,end=1730271600&metrics=errors,subscriberid&agg=1&aggby=subscriberid'
-x GET --header 'Authorization: Bearer <access_token>'
```

{% endcode %}

{% hint style="info" %}
If you run this request yourself it will not work,  you should replace the \<access\_token> in this example with your own Keycloak access\_token you get by running [Fetch Auth Token](https://docs.mediamelon.com/mediamelon/smartsight-apis/accessing-the-api#auth-token)
{% endhint %}

#### Required request path parameters

<table data-view="cards"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><code>customer-id</code> string</td><td>A path parameter in form of a string. This is the unique identifier and you will be able to find this Id on your user profile page.</td><td></td></tr></tbody></table>

#### Required request query parameters

<table data-view="cards"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><code>planlevel</code>string</td><td>A  query parameter in form of a string. This is the plan identifier number associated with CustomerID and you will be able to find this plan level using https://smartsight.mediamelon.com/planLevelByCustId/&#x3C;customer-id></td><td></td></tr><tr><td><code>period</code> string</td><td>A query parameter in comma-separated string format. It needs to in the format of start date and end date (eg: start=1729666800,end=1730271600) in epoch time. For reference, use this <a href="https://www.epochconverter.com/">Epoch Time converter</a></td><td></td></tr><tr><td><code>metrics</code>string</td><td>Combination of query parameters <code>metrics=concurviewavg,users</code> in string format. This request needs comma-separated metrics to retrieve the rquested data. </td><td></td></tr><tr><td><code>agg</code> string </td><td>A  query parameter in form of a string to return data by enabling or disabling aggregation (values: 1 or 2).    </td><td></td></tr></tbody></table>

#### Response&#x20;

<details>

<summary><mark style="color:green;">GET</mark>  <mark style="background-color:green;">200</mark></summary>

{% code overflow="wrap" lineNumbers="true" %}

```json
{
    "totalcount": 1,
    "pagecount": 1,
    "totalrecords": 1,
    "response": [
        {
            "errors": 334330,
            "subscriberid": "xxxxxxx",
            "totalpages": 2
        }.......
    ]
}
```

{% endcode %}

</details>

***

### Error Insights <mark style="color:green;">GET</mark>  <a href="#plays" id="plays"></a>

Returns the error insights with classifications.&#x20;

{% code overflow="wrap" lineNumbers="true" %}

```bash
curl 'https://smartsight3.mediamelon.com/mm-apis/session/<customer-id>?planlevel=<level>&period=start=1729666800,end=1730271600&metrics=category,key,errors,player&agg=1&aggby=category,key,player'
-x GET --header 'Authorization: Bearer <access_token>'
```

{% endcode %}

#### Required request path parameters

<table data-view="cards"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><code>customer-id</code> string</td><td>A path parameter in form of a string. This is the unique identifier and you will be able to find this Id on your user profile page.</td><td></td></tr></tbody></table>

#### Required request query parameters

<table data-view="cards"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><code>planlevel</code>string</td><td>A  query parameter in form of a string. This is the plan identifier number associated with CustomerID and you will be able to find this plan level using https://smartsight.mediamelon.com/planLevelByCustId/&#x3C;customer-id></td><td></td></tr><tr><td><code>period</code> string</td><td>A query parameter in comma-separated string format. It needs to in the format of start date and end date (eg: start=1729666800,end=1730271600) in epoch time. For reference, use this <a href="https://www.epochconverter.com/">Epoch Time converter</a></td><td></td></tr><tr><td><code>metrics</code>string</td><td>Combination of query parameters <code>metrics=category,key,errors,player</code> in string format. This request needs comma-separated metrics to retrieve the rquested data. </td><td></td></tr><tr><td><code>agg</code> string </td><td>A  query parameter in form of a string to return data by enabling or disabling aggregation (values: 1 or 2).    </td><td></td></tr><tr><td><code>aggby</code> string </td><td>Combinaton of query parameters<code>aggby=category,key,player</code> in string format. This request data will aggregated by given dimension query parameter.</td><td></td></tr></tbody></table>

#### Response&#x20;

<details>

<summary><mark style="color:green;">GET</mark>  <mark style="background-color:green;">200</mark></summary>

{% code overflow="wrap" lineNumbers="true" %}

```json
{
    "totalcount": 292,
    "pagecount": 292,
    "totalrecords": 292,
    "response": [
        {
            "category": "IN_STREAM_ERROR",
            "key": "NETWORK_HTTP50_ERROR",
            "errors": 2,
            "player": "svod-android-exoplayer",
            "totalpages": 292
        },
        {
            "category": "STARTUPFAILURE_ERROR",
            "key": "NETWORK_HTTP50_ERROR",
            "errors": 41,
            "player": "tve-firetv-exoplayer",
            "totalpages": 292
        },
        .
        ..
        ...
        ....
        .....
        ......
        {
            "category": "IN_STREAM_FATAL",
            "key": "PLAYBACK_ERROR",
            "errors": 3031,
            "player": "svod-ios-avplayer",
            "totalpages": 292
        }
    ]
}
```

{% endcode %}

</details>


# Alerts

This guide will help you fetch metrics and dimensions used to compile Smartsight Alerts dashboard. &#x20;

### AI Alerts <mark style="color:green;">GET</mark>  <a href="#plays" id="plays"></a>

Returns the AI alerts.&#x20;

{% code overflow="wrap" lineNumbers="true" %}

```bash
curl 'https://smartsight3.mediamelon.com/mm-apis/getAIAlerts/<customer-id>?planlevel=<level>&period=start=1729666800,end=1730271600'
-x GET --header 'Authorization: Bearer <access_token>'
```

{% endcode %}

{% hint style="info" %}
If you run this request yourself it will not work,  you should replace the \<access\_token> in this example with your own Keycloak access\_token you get by running [Fetch Auth Token](https://docs.mediamelon.com/mediamelon/smartsight-apis/accessing-the-api#auth-token)
{% endhint %}

#### Required request path parameters

<table data-view="cards"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><code>customer-id</code> string</td><td>A path parameter in form of a string. This is the unique identifier and you will be able to find this Id on your user profile page.</td><td></td></tr></tbody></table>

#### Required request query parameters

<table data-view="cards"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><code>planlevel</code>string</td><td>A  query parameter in form of a string. This is the plan identifier number associated with CustomerID and you will be able to find this plan level using https://smartsight.mediamelon.com/planLevelByCustId/&#x3C;customer-id></td><td></td></tr><tr><td><code>period</code> string</td><td>A query parameter in comma-separated string format. It needs to in the format of start date and end date (eg: start=1729666800,end=1730271600) in epoch time. For reference, use this <a href="https://www.epochconverter.com/">Epoch Time converter</a></td><td></td></tr></tbody></table>

#### Response

<details>

<summary><mark style="color:green;">GET</mark>  <mark style="background-color:green;">200</mark></summary>

{% code overflow="wrap" lineNumbers="true" %}

```json
[
    {
        "timestamp": 1727769181,
        "alertname": "BUFFERINGRATIO3",
        "qoename": "Buffering Ratio",
        "email_address": "vinayakd@mediamelon.com",
        "total_anomalies": 1,
        "starttime": 1727725976,
        "endtime": 1727769176,
        "totalsession": 300716,
        "totalaffectedsession": 7179,
        "anomalydate": "01-10-2024",
        "totalpages": 310
    },
    .
    ..
    ...
    ....
    .....
    {
        "timestamp": 1730233480,
        "alertname": "FATALERROR4",
        "qoename": "Fatal Errors",
        "email_address": "vinayakd@mediamelon.com",
        "total_anomalies": 1,
        "starttime": 1730190279,
        "endtime": 1730233479,
        "totalsession": 145606,
        "totalaffectedsession": 2328,
        "anomalydate": "29-10-2024",
        "totalpages": 310
    }
]
```

{% endcode %}

</details>


# Errors - Deprecated Page

The structure of the API is as follows

<mark style="color:blue;">`GET`</mark> `https://smartsight2.mediamelon.com/mm-apis/error/{customer-id}`

```
//Example
https://smartsight2.mediamelon.com/mm-apis/error/
<Customer ID>?period=start%3D<start epoch time stamp in mS> ,end%3D
<end epoch time stamp in mS>
&metrics=<error dimensions>
&dimension=error
&agg=1                 // For aggregtation
&aggby=<dimensionname> // Group by dimensions
&filter=<expression>   
```

An example would be&#x20;

```
// Example API call

https://smartsight.mediamelon.com/mm-apis/error/159268936?planlevel=2735
&metrics=videoid,key,category,errors
&dimension=error  // to be given for error analytics
&agg=1&period=start=1717085458,end=171717185
8&aggby=videoid,key,category
&offset=0
&limit=10
&filter=videoid=97542

// Sample Response
{
    "totalcount": 10,
    "pagecount": 24,
    "response": [
        {
            "videoid": "97542",
            "key": "PLAYLIST_ERROR",
            "category": "IN_STREAM_FATAL",
            "errors": 162,
            "totalpages": 24
        },
        {
            "videoid": "97542",
            "key": "AD_TAG_ERROR",
            "category": "AD_FATAL",
            "errors": 5,
            "totalpages": 24
        },
        {
            "videoid": "97542",
            "key": "AD_INVALID_ERROR",
            "category": "AD_FATAL",
            "errors": 5,
            "totalpages": 24
        },
        {
            "videoid": "97542",
            "key": "AD_PARSE_ERROR",
            "category": "AD_FATAL",
            "errors": 4,
            "totalpages": 24
        },
        {
            "videoid": "97542",
            "key": "AD_INCOMPATIBLE_ERROR",
            "category": "AD_FATAL",
            "errors": 1,
            "totalpages": 24
        },
        {
            "videoid": "97542",
            "key": "AD_NETWORK_TIMEOUT_ERROR",
            "category": "AD_ERROR",
            "errors": 9,
            "totalpages": 24
        },
        {
            "videoid": "97542",
            "key": "AD_REPLACEMENT_ERROR",
            "category": "AD_FATAL",
            "errors": 6,
            "totalpages": 24
        },
        {
            "videoid": "97542",
            "key": "AD_VPAID_CREATIVE_ERROR",
            "category": "AD_FATAL",
            "errors": 3,
            "totalpages": 24
        },
        {
            "videoid": "97542",
            "key": "AD_VAST_ERROR",
            "category": "AD_FATAL",
            "errors": 27,
            "totalpages": 24
        },
        {
            "videoid": "97542",
            "key": "AD_INCOMPATIBLE_CREATIVE_ERROR",
            "category": "AD_FATAL",
            "errors": 4,
            "totalpages": 24
        }
    ]
}


```

Error Metrics

| Metric Name   | Description                          |
| ------------- | ------------------------------------ |
| errors        | Total number of errors               |
| users         | Total number  of unique users        |
| concurviewavg | Number of distinct sessions affected |

Error Dimensions

<table><thead><tr><th width="370">Dimension </th><th>Description</th></tr></thead><tbody><tr><td>category</td><td>Error category</td></tr><tr><td>player</td><td>Player Name</td></tr><tr><td>device</td><td>Device Name</td></tr><tr><td>platform</td><td>OS Name</td></tr><tr><td>cdn</td><td>CDN Name</td></tr><tr><td>adserver</td><td>AD Server</td></tr><tr><td>adposition</td><td>Position of the ad POD where the error occurs ( only ad errors )</td></tr><tr><td>assetId</td><td>Asset ID</td></tr><tr><td>assetName</td><td>Asset Name</td></tr><tr><td>episodeNumber</td><td>Episode Number</td></tr><tr><td>season</td><td>Season Number</td></tr><tr><td>seriesTitle</td><td>Series Title</td></tr><tr><td>domainName</td><td>Domain Name</td></tr><tr><td>subscriberid</td><td>Subscriber ID</td></tr><tr><td>sessionid</td><td>Session ID</td></tr><tr><td>ipaddress</td><td>IP Address</td></tr><tr><td>streamURL</td><td>Stream URL</td></tr><tr><td>videoID</td><td>Video ID</td></tr></tbody></table>


# Stream Analytics - Deprecated Page

The following set of APIs are used to query analytical data from video streams

### API Calls

**Live and Video On-Demand (VOD) Stream Analytics**

**GET** /mm-apis/qbrData/vod/{customerId}

**Content-Type:** application/jsonRetrieves analytics of live and on-demand video streams sourced from video players.

**QBR-enabled Packager Analytics**

**GET** /mm-apis/qbrData/live/{customerId}

**Content-Type:** application/jsonRetrieves analytics of QBR-enabled streams sourced from Packagers/Transcoders. Available only when the encoder has been configured with the MediaMelon QBR SDK.

### Required Parameters

The following request parameters are common to both APIs and are required for all queries.

| Request Parameter | Data Type | Data Format                     | Description                                                                              | Example                                 |
| ----------------- | --------- | ------------------------------- | ---------------------------------------------------------------------------------------- | --------------------------------------- |
| dimension         | String    | Comma-separated                 | Required. The attribute(s) of video stream, such as the playback asset.                  | dimmension=asset                        |
| metrics           | String    | Comma-separated                 | Quantifiable attributes of a dimension, such as the number of times an asset was played. | metrics=viewercount                     |
| period            | String    | Comma-separated key-value pairs | The time range to be queried, with start and end in epoch timestamps.                    | period=start=1495599056, end=1495599116 |

### Optional Parameters

The following request parameters are common to both APIs and are optional.

| Request Parameter | Data Type | Data Format                      | Description                                | Example                  |                                                                                                                  |
| ----------------- | --------- | -------------------------------- | ------------------------------------------ | ------------------------ | ---------------------------------------------------------------------------------------------------------------- |
| agg               | Integer   | One of `0` or `1`                | See [Aggregation](/mediamelon#aggregation) | agg=1                    |                                                                                                                  |
| aggby             | String    | Single value                     | See [Aggregation](/mediamelon#aggregation) | aggby=device             |                                                                                                                  |
| count             | Integer   | One of `0` or `1`                | See [Aggregation](/mediamelon#aggregation) | count=0                  |                                                                                                                  |
| filter            | String    | Commma-separated key-value pairs | See [Filtering](/mediamelon#filtering)     | <p>filter=city=Bengaluru | SanDiego, device= Smartphone</p><p>\[Returns data for Smartphone devices in Bengaluru and San Diego cities.]</p> |
| limit             | Integer   | Single value                     | See [Pagination](/mediamelon#pagination)   | limit=10                 |                                                                                                                  |
| offset            | Integer   | Single value                     | See [Pagination](/mediamelon#pagination)   | offset=17                |                                                                                                                  |
| orderas           | String    | One of `ASC` or `DESC`           | See[ Sorting](/mediamelon#sorting)         | orderas=ASC              |                                                                                                                  |
| orderby           | String    | Single value                     | See [Sorting](/mediamelon#sorting)         | orderby=country          |                                                                                                                  |

### Response

The response is a JSON object containing the following fields.

| Response Field | Data Type | Description                                                                                                                                |
| -------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| totalcount     | Integer   | The total number of records in the result set.                                                                                             |
| pagecount      | Integer   | The number of records returned in the current result set. Will be the size of page in paginated requests. By default, returns all records. |
| response       | Array     | The response is an array of objects, where each object contains key-value pairs of the metrics that are queried for.                       |

**Sample Request and Response**

<https://smartsight.mediamelon.com/api/mm-apis/qbrData/vod/123456?period=start%3D1499773995%2Cend%3D1499775795\\&metrics=assetid\\&dimension=asset\\&agg=1\\&aggby=assetid>

```
{“totalcount”:8,”pagecount”:8,”response”:[{“assetid”:”X-Men”},{“assetid”:”PrisonBreak”},{“assetid”:”Simpsons”},{“assetid”:”GameOfThrones”},{“assetid”:”RaceCar”},{“assetid”:”TearsOfSteel”},{“assetid”:”BigBuckBunny”},{“assetid”:”RickAndMorty”}]}
```

## Old QBR Metrics and Dimensions Definitions

### Common Metrics (QBR-optimized video streams)

These metrics are available for QBR-enabled streams.

| Metric        | SmartSight UI            | Description                                                                                |
| ------------- | ------------------------ | ------------------------------------------------------------------------------------------ |
| Metric        | SmartSight UI            | Description                                                                                |
| cbrbitrate    | Bitrate                  | Original (CBR) bitrate in Mbps                                                             |
| countqualimp  | n/a                      | Count of instances where QBR selected a higher quality segment vs CBR                      |
| countqualred  | n/a                      | Count of instances where QBR selected a lower quality segment vs CBR                       |
| pctbitssaved  | Bits Saved               | Percentage of bandwidth saved by QBR                                                       |
| qbrbitrate    | QBR Bitrate              | QBR bitrate in Mbps                                                                        |
| qualcbr       | Original Avg iMOS        | Original (CBR) quality score (iMOS value)                                                  |
| qualperbitcbr | Original Quality Density | Original (CBR) quality density                                                             |
| qualperbitqbr | QBR Quality Density      | QBR quality density                                                                        |
| qualqbr       | QBR iMOS                 | QBR quality score (iMOS value)                                                             |
| qbrsize       | QBR Traffic              | Actual data downloaded (in MB) with QBR optimization; equal to `cbrsize` when QBR not used |

### Dimension-specific Metrics (QBR-optimized video sessions)

These metrics are available for QBR-enabled streams.

<table><thead><tr><th>Metric</th><th width="160.33333333333331">Dimension</th><th>Description</th></tr></thead><tbody><tr><td>Metric</td><td>Dimension</td><td>Description</td></tr><tr><td>profile</td><td>profile</td><td>Representation index of the video being played</td></tr><tr><td>res</td><td>res</td><td>Stream resolution of the video being played</td></tr></tbody></table>


# General Guidelines - Deprecated Page


# MediaMelon SDK Integration

Video streaming and advertising analytics for content, viewer and engagement insights.

MediaMelon provides streaming media intelligence and optimisation solutions for streaming services across the globe.

We offer a platform that helps streaming services monitor the performance of their content and make adjustments to improve the viewer experience.

MediaMelon's platform is designed to analyze various metrics related to streaming. This information is used to increase viewer engagement, experience and monetisation.

#### Select a platform from the list below to start your integration:&#x20;

<table data-column-title-hidden data-view="cards" data-full-width="false"><thead><tr><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-type="rating" data-max="5"></th><th data-hidden><select></select></th><th data-hidden data-type="users" data-multiple></th><th data-hidden data-type="users" data-multiple></th></tr></thead><tbody><tr><td>Covers all Web-based platforms and video players</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FBLkF0oIiUvv6S4eU5KpW%2FJS.png?alt=media&amp;token=893187bc-0d57-4b57-9deb-1165b857463d">JS.png</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/web">Web SDK</a></td><td>null</td><td></td><td></td><td></td></tr><tr><td>Covers all Android-based platforms and video players</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FmpvuqGMqXdrX1GHTroo5%2Fandroid.jpg?alt=media&amp;token=2eb88f81-2e11-40e8-94f4-76c4d1e46e87">android.jpg</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/android">Android SDK</a></td><td>null</td><td></td><td></td><td></td></tr><tr><td>Covers Roku native video player with RAF</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FgYPcwELAIiWGE1IFVbTJ%2FRoku.png?alt=media&amp;token=6a42653e-0c08-4cb5-ad6c-0edc3f1c58b3">Roku.png</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/roku">Roku SDK</a></td><td>null</td><td></td><td></td><td></td></tr><tr><td>Covers all Apple platforms and video player</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FKRD003isaRJuN2JcQgqk%2Fapple-logo.jpg?alt=media&amp;token=1d1847bc-84c4-4f7b-8db3-4a60682744ce">apple-logo.jpg</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/ios">Apple SDK</a></td><td>null</td><td></td><td></td><td></td></tr><tr><td>Covers all C++ supproted platforms</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FsxaD9oTbt1LOrt9ePQaN%2FC%2B%2B%20logo.png?alt=media&amp;token=751cd62f-cf6c-416c-a03f-6508d0e05dfc">C++ logo.png</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/c++-sdk">C++ SDK</a></td><td>null</td><td></td><td></td><td></td></tr><tr><td>Covers Mobile platforms with React Native Video Player</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FZ0lq8jB4yAgI5cxvoez4%2FScreenshot%202026-03-16%20at%2012.02.20%E2%80%AFPM.png?alt=media&amp;token=78eff59a-80ed-40e2-acbe-dc32c63a1911">Screenshot 2026-03-16 at 12.02.20 PM.png</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/react-native">React Native</a></td><td>null</td><td></td><td></td><td></td></tr></tbody></table>

#### MediaMelon also supports both client-side and server-side Ad Integrations for the following Providers.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td>Google video Ads are supported for both IMA and DAI</td><td><mark style="color:blue;">Read more -></mark></td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FeDZyZ0XTYwsET9N9Smxw%2Fgoogle%20Ads.png?alt=media&amp;token=ea031e07-ec79-4eab-be48-ccec3764c17e">google Ads.png</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/ad-integrations/google-ima">Google IMA</a></td></tr><tr><td>Freewheel Server-Side and Client Side Ads.<br>Contact Us for an SDK</td><td><mark style="color:blue;">Contact us for Integration</mark></td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FSLJ8mHFP6Da8sf3nyur3%2Ffreewheel.png?alt=media&amp;token=e23b9cde-1f70-403e-a44a-49e15ac4df73">freewheel.png</a></td><td></td></tr><tr><td>MediaMelon supports all providers using ServerSide AI</td><td><mark style="color:blue;">Contact us for Integration</mark></td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FCpCEExAphc6t2cPaNJsu%2FServerside.png?alt=media&amp;token=985c467f-da27-4150-a528-b81ec05de76e">Serverside.png</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/ad-integrations/serverside.ai">ServerSide.AI</a></td></tr></tbody></table>

#### How does integration work?

When you integrate MediaMelon-powered SDK, it automatically captures all supported video playback [events and metadata](/mediamelon/smartsight-apis/metrics) to the backend in the form of heartbeats. The backend then normalises the data received, adds more vital information, and converts all the events into [Metrics](/mediamelon/smartsight-apis/metrics#metrics) on the [SmartSight](/mediamelon) Dashboard.

<figure><img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FndYuxxv9ujKbFVft0sj9%2FMM%20SDK%20workflow.gif?alt=media&amp;token=19c50ab5-8f00-41c0-ae22-37428398b098" alt=""><figcaption></figcaption></figure>

Mediamelon has support for most of the popular video players in the market, and just in case you are using a video player that is not in our list, we have support for Custom Integration as well.&#x20;

<table data-view="cards"><thead><tr><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-type="content-ref"></th></tr></thead><tbody><tr><td>Custom SDK for all web based platforms</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2Fg7ZZmnBKkQc0SymuvkeC%2FJS.png?alt=media&amp;token=feb472be-0561-40d2-89e5-ef9b8c1e887f">JS.png</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/web/mediamelon-js-custom-sdk-integration-document">MediaMelon JS Custom SDK Integration Document</a></td></tr><tr><td>Custom SDK for all Android based platforms</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FmpvuqGMqXdrX1GHTroo5%2Fandroid.jpg?alt=media&amp;token=2eb88f81-2e11-40e8-94f4-76c4d1e46e87">android.jpg</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/android/mediamelon-android-custom-sdk-integration-document">MediaMelon Android Custom SDK Integration Document</a></td></tr><tr><td>Custom SDK for all Apple platforms</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FKRD003isaRJuN2JcQgqk%2Fapple-logo.jpg?alt=media&amp;token=1d1847bc-84c4-4f7b-8db3-4a60682744ce">apple-logo.jpg</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/ios/mediamelon-ios-custom-sdk-integration-document">MediaMelon iOS Custom SDK Integration Document</a></td></tr><tr><td>Custom SDK for all C++ based platforms</td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FsxaD9oTbt1LOrt9ePQaN%2FC%2B%2B%20logo.png?alt=media&amp;token=751cd62f-cf6c-416c-a03f-6508d0e05dfc">C++ logo.png</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/c++-sdk/mediamelon-c++-custom-sdk-integration-document">MediaMelon C++ Custom SDK Integration Document</a></td></tr></tbody></table>


# MediaMelon SDK Events

### Player Events:

<table><thead><tr><th width="74.32421875">No.</th><th width="260">Event Name</th><th>Event Description</th></tr></thead><tbody><tr><td>1</td><td>ONLOAD</td><td>Indicates that the player has attempted to load and start playback of the video.</td></tr><tr><td>2</td><td>MANIFEST_LOADED</td><td>Indicates that the manifest has been successfully loaded in the player.</td></tr><tr><td>3</td><td>START</td><td>Indicates that the video has actually started playing.</td></tr><tr><td>5</td><td>RENDITION_CHANGE</td><td>Indicates that the current video rendition has changed. Includes details such as bitrate, resolution, FPS, audio codec, and video codec.</td></tr><tr><td>6</td><td>PAUSE</td><td>Indicates that video playback has been paused.</td></tr><tr><td>7</td><td>RESUME</td><td>Indicates that video playback has resumed after being paused.</td></tr><tr><td>8</td><td>SEEK_START</td><td>Indicates that a seek operation has been initiated (jumping to a different timestamp).</td></tr><tr><td>9</td><td>SEEK_COMPLETE</td><td>Indicates that the seek operation completed successfully, and playback has resumed at the target timestamp.</td></tr><tr><td>10</td><td>BUFFERING_START</td><td>Indicates that the player runs out of enough data to continue smooth playback and starts buffering.</td></tr><tr><td>11</td><td>BUFFERING_COMPLETE</td><td>Indicates that the player has re-buffered enough content to resume smooth playback after a buffering interruption.</td></tr><tr><td>12</td><td>AUDIO_CHANGE</td><td>Indicates that the audio track of playback has changed.</td></tr><tr><td>13</td><td>SUBTITLE_CHANGE</td><td>Indicates that the subtitle track of playback has changed.</td></tr><tr><td>14</td><td>CDN_CHANGE</td><td>Indicates that the CDN used for video delivery has changed.</td></tr><tr><td>15</td><td>RC_&#x3C;REQUEST_TYPE></td><td>Indicates that a request was cancelled. Possible types: RC_PIR, RC_MANIFEST, RC_AUDIO, RC_VIDEO, RC_SUBTITLE, RC_DRM.</td></tr><tr><td>16</td><td>RF_&#x3C;REQUEST_TYPE></td><td>Indicates that a request failed. Possible types: RF_PIR, RF_MANIFEST, RF_AUDIO, RF_VIDEO, RF_SUBTITLE, RF_DRM.</td></tr><tr><td>17</td><td>ERROR</td><td>Indicates that an error occurred during the current playback session. This can include both fatal errors (playback cannot continue) and warning-level errors (playback continues but with degraded performance or missing features).</td></tr><tr><td>18</td><td>ENDED</td><td>Indicates that the playback session has ended (naturally, by stop, or due to user action).</td></tr><tr><td>19</td><td>COMPLETE</td><td>Indicates that the video playback reached the end of the content (played fully).</td></tr></tbody></table>

### Ad Events:

<table><thead><tr><th width="72.9375">No.</th><th width="342.31640625"> Event Name</th><th>Event Description</th></tr></thead><tbody><tr><td>1</td><td>AD_REQUEST</td><td>Indicates that an ad pod request has been made.</td></tr><tr><td>2</td><td>AD_RESPONSE</td><td>Indicates that an ad response was received for the ad request.</td></tr><tr><td>3</td><td>AD_IMPRESSION</td><td>Indicates that the ad has started rendering. In the case of SSAI, it is the same as the ad playback start.</td></tr><tr><td>4</td><td>AD_PLAY</td><td>Indicates that ad playback has started.</td></tr><tr><td>5</td><td>AD_PLAYING</td><td>Indicates that the ad is currently playing.</td></tr><tr><td>6</td><td>AD_PLAYED_FIRST_QUARTILE</td><td>Indicates that 25% of the ad has been played.</td></tr><tr><td>7</td><td>AD_PLAYED_SECOND_QUARTILE</td><td>Indicates that 50% of the ad has been played.</td></tr><tr><td>8</td><td>AD_PLAYED_THIRD_QUARTILE</td><td>Indicates that 75% of the ad has been played.</td></tr><tr><td>9</td><td>AD_PAUSED</td><td>Indicates that ad playback has been paused.</td></tr><tr><td>10</td><td>AD_RESUMED</td><td>Indicates that ad playback has resumed after being paused.</td></tr><tr><td>11</td><td>AD_BUFFERING_START</td><td>Indicates that buffering has started during ad playback.</td></tr><tr><td>12</td><td>AD_BUFFERING_COMPLETE</td><td>Indicates that ad playback has resumed after buffering.</td></tr><tr><td>13</td><td>AD_ERROR</td><td>Indicates that an error occurred during ad playback. This can include both fatal errors and warning-level errors.</td></tr><tr><td>14</td><td>AD_CLICK</td><td>Indicates that the user interacted with/clicked on the ad.</td></tr><tr><td>15</td><td>AD_ENDED</td><td>Indicates that ad playback has ended (either completed or skipped).</td></tr><tr><td>16</td><td>AD_COMPLETE</td><td>Indicates that ad playback was completed fully (played until the end).</td></tr><tr><td>17</td><td>AD_SKIPPED</td><td>Indicates that the user skipped the ad.</td></tr><tr><td>18</td><td>AD_BLOCK</td><td>Indicates that an advertisement was blocked or prevented from being displayed, either by an ad blocker or by another mechanism.</td></tr></tbody></table>

### Cu**sto**m Events:

For any events that are not included in the predefined event list, the Custom Events feature can be used to report additional events. For example, events such as DRM\_CHANGE, DISPLAY\_MODE, PLAYBACK\_MODE, or other platform-specific events can be reported as custom events. All platform SDKs support custom events, subject to the respective reporting guidelines. Custom events function similarly to predefined events and can be used for metric calculations, analysis, and filtering in the Analytics Dashboard.


# Metadata Configuration Guide for SDK Integration

Configure metadata fields with your SDK to enable accurate segmentation, filtering, and analysis of video performance metrics across your platform.

### Config Metadata

<table><thead><tr><th width="299.578125">Variable</th><th>Description</th></tr></thead><tbody><tr><td>Customer ID</td><td>Unique identifier assigned by MediaMelon to your organization. If unknown, contact MediaMelon Support.</td></tr><tr><td>Subscriber ID</td><td>Unique identifier of the subscriber or user consuming the video content.</td></tr><tr><td>Subscriber Type</td><td>Type of the subscriber. Common values include "Free", "Trial", or "Paid".</td></tr><tr><td>Subscriber Tag</td><td>Additional string metadata about the subscriber. Do not include sensitive data. Used for segmentation or custom tagging.</td></tr><tr><td>Hash Subscriber ID</td><td>Boolean value that determines whether the subscriber ID should be hashed before sending. Set to <code>true</code> to hash the value.</td></tr><tr><td>Domain Name</td><td>Logical partition to group your users, streams, or assets (e.g., regional or brand-specific domain name). This field is used for channel ID by many customers.</td></tr></tbody></table>

### Player Metadata

<table data-search="false"><thead><tr><th width="300.31640625">Variable</th><th>Description</th></tr></thead><tbody><tr><td>Player Name</td><td>Name of the <strong>custom player</strong> or <strong>application-level player wrapper</strong> used in your app (e.g., <code>"MyCustomPlayer"</code>). If you don’t use a custom wrapper, use the native/base player name (e.g., <code>"ExoPlayer"</code>, <code>"AVPlayer"</code>).</td></tr><tr><td>Player ID</td><td>A unique identifier for the player instance or integration. This can be used to distinguish between different player implementations or configurations within the same application.</td></tr><tr><td>Player Brand</td><td>Brand or organization maintaining the custom player. This could be your company name or the name of a third-party SDK vendor. Use the native player brand if no custom wrapper exists.</td></tr><tr><td>Player Model</td><td>Model or variant name of your custom player (e.g., <code>"MyCustomPlayerV2"</code>, <code>"PlayerAlpha"</code>). If not applicable, use a relevant descriptive value or copy the native player model (e.g., <code>"AVPlayer-iOS"</code>).</td></tr><tr><td>Player Version</td><td>Version of your custom player or wrapper. Helps distinguish between changes/releases. If no custom wrapper exists, specify the base player version (e.g., <code>"2.18.3"</code> for ExoPlayer).</td></tr><tr><td>Base Player Name</td><td>Native/base player used for actual playback (e.g., <code>"ExoPlayer"</code>, <code>"AVPlayer"</code>). This should always reflect the core media engine even if you have a custom player wrapper.</td></tr><tr><td>Base Player Version</td><td>Version of the underlying base player (e.g., <code>"2.18.3"</code> for ExoPlayer, or iOS system version for AVPlayer). If you don’t have a custom wrapper, this value will be the same as <strong>Player Version</strong>.</td></tr></tbody></table>

### Content Metadata

<table data-search="false"><thead><tr><th width="299.828125">Variable</th><th>Description</th></tr></thead><tbody><tr><td>Asset ID</td><td>Unique identifier for the video asset.</td></tr><tr><td>Asset Name</td><td>Human-readable name or title of the video asset.</td></tr><tr><td>Video ID</td><td>Unique identifier for the video content. It can be the same as <strong>Asset ID</strong> or a different logical ID used in your system.</td></tr><tr><td>Content Type</td><td>The category or type of content, e.g., "Movie", "Episode", "Clip", "LiveStream".</td></tr><tr><td>Genre</td><td>Genre of the content, such as "Drama", "Comedy", "Documentary", etc.</td></tr><tr><td>is Live</td><td>A boolean value that determines whether the content is live or on-demand. Set to true for live content (e.g., live events or broadcasts), and false for VOD content (e.g., movies, episodes).</td></tr><tr><td>Episode Number</td><td>Episode number within a season. Useful for TV series or episodic content.</td></tr><tr><td>Season</td><td>Name or number of the season (e.g., "Season 1", "S2").</td></tr><tr><td>Series Title</td><td>Title of the series to which the episode belongs.</td></tr></tbody></table>

### Playback Metadata

<table data-search="false"><thead><tr><th width="299.71484375">Variable</th><th>Text</th></tr></thead><tbody><tr><td>Stream URL</td><td>The URL of the current playing video stream (HLS or DASH). This is used for playback tracking and analytics.</td></tr><tr><td>DRM Type/Protection</td><td>DRM technology used (e.g., “Widevine”, “FairPlay”, “PlayReady”). Use “Unknown” if the content is protected, but the DRM type is unknown. Leave blank for clear (non-DRM) content.</td></tr><tr><td>DRM Level</td><td>Specifies the security level of DRM playback supported or enforced on the device (e.g., L1, L2, L3 for Widevine). This helps assess content protection strength and playback capabilities.</td></tr><tr><td>Experiment Name</td><td>Label used to segment views under different test experiments for analytics or A/B testing.</td></tr><tr><td>Sub Property ID</td><td>An identifier for sub-grouping under a single customer account. Useful for multi-brand or multi-service setups under the same customer.</td></tr><tr><td>View Session ID</td><td>Unique session identifier to correlate video playback with logs from other systems (e.g., CDN logs, backend services). Some customers put the application session ID to have a consolidated view.</td></tr><tr><td>Preload</td><td>Indicates whether the video content was preloaded before playback started. Typically a boolean value (<code>true</code>/<code>false</code>) used to analyze startup performance and buffering behavior.</td></tr><tr><td>Media Type</td><td>The type of video stream (e.g., <code>live</code> or <code>on-demand</code>)</td></tr><tr><td>Source Type</td><td>Indicates the streaming protocol used for playback. Common values include <code>HLS</code> or <code>DASH</code>, based on the stream URL type.</td></tr><tr><td>Stream Format</td><td>Describes the encoding variant or encoder configuration. Useful for comparing performance between different encoding settings. Examples: <code>x264</code>, <code>hevc</code>, <code>av1-0</code>, <code>av1-4</code>, <code>av1-8</code></td></tr><tr><td>Encoding Service</td><td>Specifies the service or platform used to encode the video content (e.g., AWS Elemental, Bitmovin, MediaConvert). Useful for analyzing performance variations across encoding providers.</td></tr><tr><td>CDN</td><td>Name or identifier of the Content Delivery Network (CDN) used to deliver the content (e.g., Akamai, CloudFront, Fastly)</td></tr><tr><td>Player Width</td><td>Integer value representing the width (in pixels) of the video player on the screen.</td></tr><tr><td>Player Height</td><td>Integer value representing the height (in pixels) of the video player on the screen.</td></tr></tbody></table>

### Ad Metadata

<table data-search="false"><thead><tr><th width="299.8046875">Variable</th><th>Description</th></tr></thead><tbody><tr><td>Ad Title</td><td>Title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>Ad ID</td><td>Unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>Ad Creative ID</td><td>Creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>Ad Creative Type</td><td>Format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>Ad Client</td><td>SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>Ad Position</td><td>Timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>Ad Server</td><td>Ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>Ad Resolution</td><td>Resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>Ad URL</td><td>URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>Ad Duration</td><td>Total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>Ad Pod Index</td><td>Index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>Ad Position in Pod</td><td>Position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>Ad Pod Length</td><td>Total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr><tr><td>Is Ad Bumper</td><td>Boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr></tbody></table>

### Device Metadata

<table data-search="false"><thead><tr><th width="299.8828125">Variable</th><th>Description</th></tr></thead><tbody><tr><td>Device Name</td><td>Name of the playback device (e.g., "iPhone 14", "Living Room TV").</td></tr><tr><td>Device Brand</td><td>Manufacturer of the playback device (e.g., "Apple", "Samsung", "Roku").</td></tr><tr><td>Device Model</td><td>Specific model of the playback device (e.g., "SM-G991U", "Fire TV Stick 4K").</td></tr><tr><td>Device ID</td><td>Unique identifier representing the user's playback device. This may be an anonymized or hashed string, depending on your privacy policy.</td></tr><tr><td>Device Type</td><td>Category or form factor of the device (e.g., "Mobile", "Tablet", "TV", "Desktop").</td></tr><tr><td>Device OS</td><td>Operating system running on the device (e.g., "iOS", "Android", "tvOS", "Roku OS").</td></tr><tr><td>Device OS Version</td><td>Version of the device's operating system (e.g., "17.4", "13").</td></tr><tr><td>Screen Width</td><td>Width of the device's screen, in pixels.</td></tr><tr><td>Screen Height</td><td>Height of the device's screen, in pixels.</td></tr><tr><td>Device Capabilities</td><td>Playback features supported by the device (e.g., HDR, HLG, supported codecs, max resolution).</td></tr></tbody></table>

### Application Metadata

<table><thead><tr><th width="300.37109375">Variable</th><th>Description</th></tr></thead><tbody><tr><td>Application Name</td><td>Name of the application or service through which the user is consuming the video content. This helps distinguish traffic and analytics across multiple apps or platforms under the same customer account (e.g., "MyOTTApp", "MyStreamingTV").</td></tr><tr><td>Application Version</td><td>Version of the application that the end user is using. This is useful for tracking analytics across different app releases, troubleshooting regressions, and correlating performance or playback issues to specific app builds (e.g., "1.2.3", "2025.07.15").</td></tr><tr><td>App Session ID</td><td>A unique identifier representing a single application lifecycle session (from app launch to termination). This helps correlate multiple playback sessions within the same app usage window.</td></tr></tbody></table>


# Custom Metadata Configuration Guide

Custom Metadata configuration and usage guide using SmartSight Dashboard.

### 🛠 Custom Metadata Overview

The SmartSight Dashboard offers numerous metadata dimensions to track information about video playback, including Asset Name, Asset ID, Content Type, and more. In addition to these built-in dimensions, **Custom Metadata** allows you to define, submit, and report on metadata that is unique to your business use case and not part of the standard metadata set. Examples include values such as the **Config Name**, **Page Type**, or **experiment cohort**.

### ⚙️ Defining Custom Metadata in the SmartSight Dashboard

Before custom metadata can be reported from your SDK, each key must be configured in the **SmartSight Dashboard**. This enables SmartSight to recognise, label, and display your custom dimensions in reports and analytics.

#### 📝 Steps to Define a Custom Metadata Field

1. **Log in** to the SmartSight dashboard and navigate to **Settings** under the Profile icon.
2. Select the appropriate **Environment** (e.g., `PROD`).
3. Click the **Custom Tag** tab.
4. Click **+ Add Tag** to create a new custom metadata field.
5. Choose the `Tag Name` (e.g., `custom_6`) from the dropdown list.
6. Enter a Display Name for the tag (e.g., `Auto Play`).
7. Click **Save** to register the tag.

<figure><img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2Fbo9bl5H11iBwwT5OWE1q%2FScreenshot%202025-07-29%20at%2012.08.12%E2%80%AFPM.png?alt=media&amp;token=3b9c3c7f-ec28-42eb-9b8b-1b6f7685fcee" alt=""><figcaption></figcaption></figure>

<figure><img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FuRBlvIJRbvHsWEk9TJIc%2FScreenshot%202025-07-29%20at%2012.08.52%E2%80%AFPM.png?alt=media&amp;token=bc02314a-b44e-44e2-a21b-d97d86001c4d" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Important Note:**

Ensure that all **custom tags** are configured **individually** for every applicable **environment**.
{% endhint %}

### 📲 Reporting Custom Metadata from SDKs

Once your custom tags (e.g., `custom_1`, `custom_2`, etc.) are defined in the **SmartSight Dashboard**, you can begin reporting their values from your application code using the respective SDK. Each SDK provides a method to send custom metadata as key-value pairs.

In the SDK, report keys as `"custom_1"`, `"custom_2"`, and so on, with their corresponding values as strings. The MediaMelon system will internally map these keys to their display names and present them accordingly in the dashboard.

**Example:**

```javascript
reportCustomMetadata("custom_1", "experimentLab-Debug");
```

### 📊 Using Custom Tags for Filtering and Analysis

Once custom metadata is reported via the SDK and configured in the SmartSight Dashboard, you can **filter, group, and analyse** video playback data based on those custom tags—just like any standard dimension.

These tags appear in **Global Dimension Filters** across SmartSight dashboards, enabling powerful segmentation tailored to your use case.

#### 🎯 How to Filter by Custom Tags

1. Navigate to any page in the dashboard (e.g., KPIs,  Analysis, etc.)
2. Open the **Global Filter** panel (on the top-left of the page).
3. Select your custom dimension (as defined by the display name, e.g., `Config Name`).
4. Choose the value(s) to include in your filter (e.g., `experimentLab-Debug`).

<figure><img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FKGCpgglTNQq36RjQArX2%2FScreenshot%202025-07-29%20at%2012.14.40%E2%80%AFPM.png?alt=media&amp;token=84be5685-0a28-4e83-afa2-4ccbaaa81a50" alt=""><figcaption></figcaption></figure>


# Web SDK


# MediaMelon JS Custom SDK Integration Document

This guide is for integrating the MediaMelon Custom SDK for the JavaScript-based Web Players

**Step 1:** [Add MediaMelon Player SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Register and Initialize MediaMelon Player SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Custom Metadata](#step-3-custom-metadata)

**Step 4:** [Stream and Network Information](#step-4-stream-and-network-information)

**Step 5:** [Chunk/Segment Information](#step-5-chunk-segment-information)

**Step 6:** [Player Events](#step-6-player-events)

**Step 7:** [Fallback & Request Status](#step-7-fallback-and-request-status)

**Step 8:** [Ad Data & Ad Events](#step-8-a-d-data-and-ad-events)

**Step 9:** [Custom Events](#step-9-custom-events)

[Release Notes](#release-notes)

### **Step 1: Add** MediaMelon SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

* **NPM (1.4.5):**

```bash
npm i mediamelon-js-custom-sdk
```

```javascript
import { mmJSCustomAdapter, MMPlayerState, RenditionInfo, RequestStatus} from 'mediamelon-js-custom-sdk'
```

### **Step 2: Register and Initialize** MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

#### Step 2.1: Instantiate and Register SDK:

```javascript
var mmJSPlugin = new mmJSCustomAdapter();
mmJSPlugin.registerMMSmartStreaming("PLAYER_NAME", 
    "CUSTOMER_ID", 
    "SUBSCRIBER_ID", 
    "DOMAIN_NAME", 
    "SUBSCRIBER_TYPE", 
    "SUBSCRIBER_TAG", 
    hashSubscriberId      //Boolean Value
);
```

{% hint style="info" %}
`hashSubscriberId`: Set it to `true` to hash the subscriber ID, and to `false` to process the subscriber ID without hashing.
{% endhint %}

#### Step 2.2: Report Player Information:

```javascript
mmJSPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");            
mmJSPlugin.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.3: Report Application Information:

```javascript
mmJSPlugin.reportAppInfo("APPLICATION_NAME","APPLICATION_VERSION");
mmJSPlugin.reportAppSessionId("APP_SESSION_ID");
```

#### Step 2.4: Report Device Information:

```javascript
var deviceInfo = {
    "deviceName": "DEVICE_NAME",
    "deviceBrand": "DEVICE_BRAND",      // Device Brand or Manufacturer
    "deviceModel": "DEVICE_MODEL",
    "deviceId": "DEVICE_ID",
    "deviceOS": "DEVICE_OS",
    "deviceOSVersion": "DEVICE_OS_VERSION",            
    "screenWidth": screen_width,        //Integer Value
    "screenHeight": screen_height       //Integer Value
};
mmJSPlugin.reportDeviceInfo(deviceInfo);
```

#### Step 2.5: Report Experiment Name & Sub Property ID:

```javascript
mmJSPlugin.reportExperimentName("EXPERIMENT_NAME");
mmJSPlugin.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.6: Initialize Session with Content Metadata:

```javascript
var contentMetaData = {
    "assetName": "ASSET_NAME",
    "assetId": "ASSET_ID",
    "videoId": "VIDEO_ID",
    "contentType": "CONTENT_TYPE",
    "genre": "GENRE",
    "drmProtection": "DRM_PROTECTION",
    "episodeNumber": "EPISODE_NUMBER",
    "season": "SEASON",
    "seriesTitle": "SERIES_TITLE"
};

mmJSPlugin.initializeSession(contentMetaData, "STREAM_URL");
mmJSPlugin.reportPreload(<boolean>);
mmJSPlugin.reportUserInitiatedPlayback();
```

{% hint style="info" %}
**Preload:** Report the preload attribute after `initializeSession` and before `reportUserInitiatedPlayback`. The preload value is reset inside `initializeSession`, so reporting it before this method will be ignored. If you report it after `reportUserInitiatedPlayback`, the first event will not contain the preload field.
{% endhint %}

#### Step 2.7: Report View Session ID:

```javascript
mmJSPlugin.reportViewSessionId("VIEW_SESSION_ID");
```

### Step 3: Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```javascript
mmJSPlugin.reportCustomMetadata("custom_1", "value1");
mmJSPlugin.reportCustomMetadata("custom_2", "value2");
```

### Step 4: Stream and Network Information

#### Step 4.1: Report Stream Information:

```javascript
mmJSPlugin.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE");
```

#### Step 4.2: Update Stream URL:

```javascript
mmJSPlugin.updateStreamURL("STREAM_URL");
```

#### Step 4.3: Report Presentation Info:

```javascript
mmJSPlugin.reportPresentationInfo(<is_live>, <video_duration>);
```

{% hint style="info" %}

* `is_live`: Set to `true` for live video stream and to `false` for the VOD stream.
* `video_duration`: Integer value in milliseconds.
  {% endhint %}

#### Step 4.4: Report Track Information

Call this API with initial values and every time there is a change in the track info. Call this API when the user enables/disables subtitles or when the user changes the audio track.

```javascript
mmJSPlugin.reportTrackinfo(<is_subtitle_active>, "SUBTITLE_TRACK", "AUDIO_TRACK", <is_vds_active>);
```

{% hint style="info" %}
`is_subtitle_active`: Set it to `true` if the subtitles are active; otherwise, set it to `false`.

`is_vds_active`: Set it to `true` if the type of audio is Virtual Dialogue Sound, otherwise, set it to `false`.
{% endhint %}

#### Step 4.5: Report Rendition:

At the start of the video, create a ReditionInfo object, assign initial rendition values to the object, and report it to the SDK. For any subsequent rendition change, update only the fields that changed in the same RenditionInfo object. Leave the unchanged fields as-is, and report the updated object to the SDK.

```javascript
var renditionInfo = new RenditionInfo();
rendition.bitrate = <birate>;            //Integr Value in bps
rendition.width = <width>;               //Integr Value
rendition.height = <height>;             //Integer Value
rendition.frameRate = <frame_rate>;      //Integr Value in fps
rendition.aCodec = "AUDIO_CODEC";
rendition.vCodec = "VIDEO_CODEC";

mmJSPlugin.reportRendition(renditionInfo);
```

#### Step 4.6: Update DRM Type:

```javascript
mmJSPlugin.updateDRMType("NEW_DRM_TYPE");
```

#### Step 4.7: Report Network Information:

```javascript
var networkInfo = {
    "cdn": "CDN",
    "asn": asn,                     //Integer Value
    "hostName": "SOURCE_HOST_NAME",
    "networkType": "NETWORK_TYPE",  // Network Connection Type
    "networkOperator": "NETWORK_OPERATOR"
}
mmJSPlugin.reportNetworkInfo(networkInfo);
```

{% hint style="info" %}
Use the `reportNetworkInfo` API to report the CDN along with other network information.\
If additional network information is not available, use `reportCDN` instead.
{% endhint %}

#### Step 4.8: Report CDN Information:

```javascript
mmJSPlugin.reportCDN("CDN");
```

#### Step 4.9: Report Encoding Service:

```javascript
mmJSPlugin.reportEncodingService("ENCODING_SERVICE");
```

### Step 5: Chunk/Segment Information

#### Step 5.1: Report Download Rate:

Report the latest chunk download rate using this method. Trigger this method for every chunk.

```javascript
mmJSPlugin.reportDownloadRate(downloadRate);    //Integer Value in bps (bits per second
```

### Step 6: Player Events

#### Step 6.1: Report Player State:

```javascript
mmJSPlugin.reportPlayerState(MMPlayerState.PLAYING);

Enum: MMPlayerState
- PLAYING
- PAUSED
- STOPPED
```

#### Step 6.2: Report Buffering:

```javascript
mmJSPlugin.reportBufferingStarted();
mmJSPlugin.reportBufferingCompleted();
```

#### Step 6.3: Report Seek:

```javascript
mmJSPlugin.reportPlayerSeekStarted(); 
mmJSPlugin.reportPlayerSeekCompleted(seekEndPositionInMS); //Integer Value in Milli Seconds
```

#### Step 6.4: Report Error:

```javascript
mmJSPlugin.reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DETAILS");
```

#### Step 6.5: Report Warning:

```javascript
mmJSPlugin.reportWarning("WARNING_CODE", "WARNING_MESSAGE", "WARNING_DETAILS");
```

#### Step 6.6: Report Playback Position:

Call this every 0.5 sec or 1 sec to report the playback position from the player

```javascript
mmJSPlugin.reportPlaybackPosition(playback_position); //Integer Value in Milli Seconds
```

#### Step 6.7: Report Player Resolution:

```javascript
mmJSPlugin.reportPlayerResolution(width, height);
```

### Step 7: Fallback & Request Status

#### Step 7.1: Report Fallback Event:

```javascript
mmJSPlugin.reportFallbackEvent("FALLBACK_MANIFEST_URL", "DESCRIPTION");
```

#### Step 7.2: Report Request Status:

```javascript
var requestInfo = {
    id: "ID",
    error: "ERROR",
    text: "TEXT",
    hostname: "HOSTNAME",
    url: "URL",
    ...
}

mmJSPlugin.reportRequestStatus(RequestStatus.FAILED, "REQUEST_TYPE", requestInfo);

Enum: RequestStatus
- FAILED
- CANCELLED
```

### Step 8: Ad Data & Ad Events

#### Step 8.1: Report Ad Break Start & End:

```javascript
mmJSPlugin.reportAdBreakStart();
mmJSPlugin.reportAdBreakEnd();
```

#### Step 8.2: Report Ad Data, Ad Start & End:

```javascript
var adInfo = {
    "adTitle": "AD_TITLE",
    "adId": "AD_ID",
    "adCreativeId": "AD_CREATIVE_ID",
    "adCreativeType": "AD_CREATIVE_TYPE",
    "adClient": "AD_CLIENT",
    "adPosition": "AD_POSITION",               //pre, mid, post
    "adServer": "AD_SERVER",
    "adResolution": "AD_RESOLUTION",
    "adUrl": "AD_URL",
    "adDuration": ad_duration,              //Double Value
    "adPodIndex": pod_index,                //Integer Value
    "adPositionInPod": ad_position_in_pod,  //Integer Value
    "isBumper": is_bumper                   //Boolean Value
}

mmJSPlugin.reportAdStart(adInfo);
mmJSPlugin.reportAdEnd();
```

<details>

<summary>AdInfo Object description</summary>

<table data-header-hidden><thead><tr><th width="198.04296875">Field</th><th width="116.59375">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>adInfo.adTitle</td><td>String</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adInfo.adId</td><td>String</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adInfo.adCreativeId</td><td>String</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adInfo.adCreativeType</td><td>String</td><td>The format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>adInfo.adClient</td><td>String</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adInfo.adPosition</td><td>String</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adInfo.adServer</td><td>String</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adInfo.adResolution</td><td>String</td><td>The resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>adInfo.adUrl</td><td>String</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adInfo.adDuration</td><td>Integer</td><td>The total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>adInfo.adPodIndex</td><td>Integer</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adInfo.adPositionInPod</td><td>Integer</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>adInfo.adPodLendth</td><td>Integer</td><td>The total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr><tr><td>adInfo.isBumper</td><td>Boolean</td><td>A boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr></tbody></table>

</details>

#### Step 8.3: Report Ad Buffering:

Use Ad Buffering APIs to report any buffering that occurs during ad playback. For any buffering event, either content buffering or ad buffering should be reported, but not both.

```javascript
mmJSPlugin.reportAdBufferingStrated();
mmJSPlugin.reportAdBufferingCompleted();
```

### Step 9: Custom Events

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```javascript
mmJSPlugin.reportCustomEvent("EVENT_NAME", "EVENT_VALUE");
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 30 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

#### Release Notes

<details>

<summary>Current Release</summary>

#### v1.4.5[^1]  <sup><sub>`Mar 30, 2026`<sub></sup>

* Added support for reporting a new field encoding service via `reportEncodingService`.
* Introduced custom event reporting through `reportCustomEvent`.
* Added support for ad buffering events:
  * `reportAdBufferingStarted`
  * `reportAdBufferingCompleted`
* Improved event handling to restrict event reporting after playback has ended.<https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/web/javascript-custom-sdk-performance-metrics>

</details>

***

<details>

<summary>Previous Releases</summary>

#### v1.4.4[^1]  <sup><sub>`Feb 06, 2026`<sub></sup>

* Added an additional API to report CDN alone.
* Added `CDN_CHANGE` event.
* Added Seek Duration calculation internally.

#### v1.4.3[^1]  <sup><sub>`Dec 20, 2025`<sub></sup>

* Improved bitrate reporting for weighted average bitrate calculation
* Updated internal SDK version format

#### v1.4.2  <sup><sub>`Dec 12, 2025`<sub></sup>

* Preload field addition
* App Session ID field addition
* Fix to consider Exit in Buffering
* Added rendition metrics for upscale and downscale percentage calculations

</details>

[^1]: **Performance Report:** [here](https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/web/javascript-custom-sdk-performance-metrics)


# MediaMelon JS Custom Multi-Player SDK Integration Document

This guide is for integrating the MediaMelon Custom Multi-Player SDK for the JavaScript-based Web Players

**Step 1:** [Add MediaMelon Player SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Instantiate and Register SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Initialize Playback Session](#step-3-initialize-playback-session)

**Step 4:** [Custom Metadata](#step-4-custom-metadata)

**Step 5:** [Stream and Network Information](#step-5-stream-and-network-information)

**Step 6:** [Chunk/Segment Information](#step-6-chunk-segment-information)

**Step 7:** [Player Events](#step-7-player-events)

**Step 8:** [Fallback & Request Status](#step-8-fallback-and-request-status)

**Step 9:** [Ad Data & Ad Events](#step-9-a-d-data-and-ad-events)

**Step 10:** [Custom Events](#step-10-custom-events)

[Release Notes](#release-notes)

### **Step 1: Add** MediaMelon SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

* **NPM (2.2.1):**

```bash
npm i mediamelon-js-custom-sdk
```

```javascript
import { mmJSCustomAdapter, MMPlayerState, RenditionInfo, RequestStatus, MMAdEvent} from 'mediamelon-js-custom-sdk'
```

### **Step 2:** Instantiate and Register SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

#### Step 2.1: Instantiate and Report Registration Information:

```javascript
var mmJSPlugin = new mmJSCustomAdapter();
mmJSPlugin.registerMMSmartStreaming("PLAYER_NAME", 
    "CUSTOMER_ID", 
    "SUBSCRIBER_ID", 
    "DOMAIN_NAME", 
    "SUBSCRIBER_TYPE", 
    "SUBSCRIBER_TAG", 
    hashSubscriberId      //Boolean Value
);
```

{% hint style="info" %}
`hashSubscriberId`: Set it to `true` to hash the subscriber ID, and to `false` to process the subscriber ID without hashing.
{% endhint %}

#### Step 2.2: Report Player Information:

```javascript
mmJSPlugin.reportPlayerId("PLAYER_ID");
mmJSPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");            
mmJSPlugin.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.3: Report Application Information:

```javascript
mmJSPlugin.reportAppInfo("APPLICATION_NAME","APPLICATION_VERSION");
mmJSPlugin.reportAppSessionId("APP_SESSION_ID");
```

#### Step 2.4: Report Device Information:

```javascript
var deviceInfo = {
    "deviceName": "DEVICE_NAME",
    "deviceBrand": "DEVICE_BRAND",      // Device Brand or Manufacturer
    "deviceModel": "DEVICE_MODEL",
    "deviceId": "DEVICE_ID",
    "deviceOS": "DEVICE_OS",
    "deviceOSVersion": "DEVICE_OS_VERSION",            
    "screenWidth": screen_width,        //Integer Value
    "screenHeight": screen_height,       //Integer Value
    "deviceCapabilities": "DEVICE_CAPABILITIES"
};
mmJSPlugin.reportDeviceInfo(deviceInfo);
```

#### Step 2.5: Report Sub Property ID:

```javascript
mmJSPlugin.reportSubPropertyId("SUB_PROPERTY_ID");
```

### Step 3: Initialize Playback Session

#### Step 3.1: Initialize Session with Content Metadata:

```javascript
var contentMetaData = {
    "assetName": "ASSET_NAME",
    "assetId": "ASSET_ID",
    "videoId": "VIDEO_ID",
    "contentType": "CONTENT_TYPE",
    "genre": "GENRE",
    "drmProtection": "DRM_PROTECTION",
    "drmLevel": "DRM_LEVEL",
    "episodeNumber": "EPISODE_NUMBER",
    "season": "SEASON",
    "seriesTitle": "SERIES_TITLE"
};

mmJSPlugin.initializeSession(contentMetaData, "STREAM_URL");
```

{% hint style="warning" %}
All metadata fields set from **Step 3** will be reset when `initializeSession` is called. Therefore, ensure that all session-specific metadata, such as `view session ID`, `preload`, and similar fields, are reported after `initializeSession` is called for every playback session.
{% endhint %}

#### Step 3.2: Report View Session ID:

```javascript
mmJSPlugin.reportViewSessionId("VIEW_SESSION_ID");
```

#### Step 3.3: Report Experiment Name:

```javascript
mmJSPlugin.reportExperimentName("EXPERIMENT_NAME");
```

#### Step 3.4: Report Preload:

```javascript
mmJSPlugin.reportPreload(<boolean>);
```

#### Step 3.5: Report Player Resolution:

```javascript
mmJSPlugin.reportPlayerResolution(width, height);
```

#### Step 3.6: Report User-Initiated Playback:

{% hint style="info" %}
This function indicates the intent for playback and must be invoked after `initializeSession`. Any metadata fields reported before this API call will be included in the first payload sent to the dashboard. To avoid `Null` values in metadata fields, it is recommended to report all available metadata before calling this API.
{% endhint %}

```javascript
mmJSPlugin.reportUserInitiatedPlayback();
```

### Step 4: Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```javascript
mmJSPlugin.reportCustomMetadata("custom_1", "value1");
mmJSPlugin.reportCustomMetadata("custom_2", "value2");
```

### Step 5: Stream and Network Information

#### Step 5.1: Report Stream Information:

```javascript
mmJSPlugin.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE");
```

#### Step 5.2: Update Stream URL:

```javascript
mmJSPlugin.updateStreamURL("STREAM_URL");
```

#### Step 5.3: Report Presentation Info:

```javascript
mmJSPlugin.reportPresentationInfo(<is_live>, <video_duration>);
```

{% hint style="info" %}

* `is_live`: Set to `true` for live video stream and to `false` for the VOD stream.
* `video_duration`: Integer value in milliseconds.
  {% endhint %}

#### Step 5.4: Report Track Information

Call this API with initial values, and every time there is a change in the track info. Call this API when the user enables/disables subtitles or when the user changes the audio track.

```javascript
mmJSPlugin.reportTrackinfo(<is_subtitle_active>, "SUBTITLE_TRACK", "AUDIO_TRACK", <is_vds_active>);
```

{% hint style="info" %}
`is_subtitle_active`: Set it to `true` if the subtitles are active; otherwise, set it to `false`.

`is_vds_active`: Set it to `true` if the type of audio is Virtual Dialogue Sound, otherwise, set it to `false`.
{% endhint %}

#### Step 5.5: Report Rendition:

At the start of the video, create a ReditionInfo object, assign initial rendition values to the object, and report it to the SDK. For any subsequent rendition change, update only the fields that changed in the same RenditionInfo object. Leave the unchanged fields as-is, and report the updated object to the SDK.

```javascript
var renditionInfo = new RenditionInfo();
rendition.bitrate = <birate>;            //Integr Value in bps
rendition.width = <width>;               //Integr Value
rendition.height = <height>;             //Integer Value
rendition.frameRate = <frame_rate>;      //Integr Value in fps
rendition.aCodec = "AUDIO_CODEC";
rendition.vCodec = "VIDEO_CODEC";

mmJSPlugin.reportRendition(renditionInfo);
```

#### Step 5.6: Update DRM Type:

{% hint style="danger" %}
`updateDrmType(drmType:)` is **deprecated**. A new API called `updateDRM(drmProtection:, drmLevel:)` is introduced.
{% endhint %}

```javascript
mmJSPlugin.updateDRM("DRM_PROTECTION", "DRM_LEVEL");
```

#### Step 5.7: Report Network Information:

```javascript
var networkInfo = {
    "cdn": "CDN",
    "asn": asn,                     //Integer Value
    "hostName": "SOURCE_HOST_NAME",
    "networkType": "NETWORK_TYPE",  // Network Connection Type
    "networkOperator": "NETWORK_OPERATOR"
}
mmJSPlugin.reportNetworkInfo(networkInfo);
```

{% hint style="info" %}
Use the `reportNetworkInfo` API to report the CDN along with other network information.\
If additional network information is not available, use `reportCDN` instead.
{% endhint %}

#### Step 5.8: Report CDN Information:

```javascript
mmJSPlugin.reportCDN("CDN");
```

#### Step 5.9: Report Encoding Service:

```javascript
mmJSPlugin.reportEncodingService("ENCODING_SERVICE");
```

### Step 6: Chunk/Segment Information

#### Step 6.1: Report Download Rate:

Report the latest chunk download rate using this method. Trigger this method for every chunk.

```javascript
mmJSPlugin.reportDownloadRate(downloadRate);    //Integer Value in bps (bits per second
```

### Step 7: Player Events

#### Step 7.1: Report Player State:

```javascript
mmJSPlugin.reportPlayerState(MMPlayerState.PLAYING);

Enum: MMPlayerState
- PLAYING
- PAUSED
- STOPPED
```

#### Step 7.2: Report Buffering:

```javascript
mmJSPlugin.reportBufferingStarted();
mmJSPlugin.reportBufferingCompleted();
```

#### Step 7.3: Report Seek:

```javascript
mmJSPlugin.reportPlayerSeekStarted(); 
mmJSPlugin.reportPlayerSeekCompleted(seekEndPositionInMS); //Integer Value in Milli Seconds
```

#### Step 7.4: Report Error:

```javascript
mmJSPlugin.reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DETAILS");
```

#### Step 7.5: Report Warning:

```javascript
mmJSPlugin.reportWarning("WARNING_CODE", "WARNING_MESSAGE", "WARNING_DETAILS");
```

#### Step 7.6: Report Playback Position:

Call this every 0.5 sec or 1 sec to report the playback position from the player

```javascript
mmJSPlugin.reportPlaybackPosition(playback_position); //Integer Value in Milli Seconds
```

#### Step 7.7: Report Player Resolution:

```javascript
```

### Step 8: Fallback & Request Status

#### Step 8.1: Report Fallback Event:

```javascript
mmJSPlugin.reportFallbackEvent("FALLBACK_MANIFEST_URL", "DESCRIPTION");
```

#### Step 8.2: Report Request Status:

```javascript
var requestInfo = {
    id: "ID",
    error: "ERROR",
    text: "TEXT",
    hostname: "HOSTNAME",
    url: "URL",
    ...
}

mmJSPlugin.reportRequestStatus(RequestStatus.FAILED, "REQUEST_TYPE", requestInfo);

Enum: RequestStatus
- FAILED
- CANCELLED
```

### Step 9: Ad Data & Ad Events

#### Step 9.1: Report Ad Break Start & End:

{% hint style="info" %}
`reportAdBreakStart` and `reportAdBreakEnd` APIs now can be reported with an optional JSON parameter.
{% endhint %}

```javascript
var adBreakInfo = {  } // ad break information
mmJSPlugin.reportAdBreakStart(adBreakInfo);
mmJSPlugin.reportAdBreakEnd();
```

#### Step 9.2: Report Ad Data, Ad Start & End:

```javascript
var adInfo = {
    "adTitle": "AD_TITLE",
    "adId": "AD_ID",
    "adUniversalId": "AD_UNIVERSAL_ID",
    "adCreativeId": "AD_CREATIVE_ID",
    "adCreativeType": "AD_CREATIVE_TYPE",
    "adClient": "AD_CLIENT",
    "adPosition": "AD_POSITION",               //pre, mid, post
    "adServer": "AD_SERVER",
    "adResolution": "AD_RESOLUTION",
    "adUrl": "AD_URL",
    "adDuration": ad_duration,              //Double Value
    "adPodIndex": pod_index,                //Integer Value
    "adPositionInPod": ad_position_in_pod,  //Integer Value
    "isBumper": is_bumper                   //Boolean Value
}

mmJSPlugin.reportAdStart(adInfo);
mmJSPlugin.reportAdEnd();
```

<details>

<summary>AdInfo Object description</summary>

<table data-header-hidden><thead><tr><th width="198.04296875">Field</th><th width="116.59375">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>adInfo.adTitle</td><td>String</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adInfo.adId</td><td>String</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adInfo.adCreativeId</td><td>String</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adInfo.adCreativeType</td><td>String</td><td>The format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>adInfo.adClient</td><td>String</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adInfo.adPosition</td><td>String</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adInfo.adServer</td><td>String</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adInfo.adResolution</td><td>String</td><td>The resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>adInfo.adUrl</td><td>String</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adInfo.adDuration</td><td>Integer</td><td>The total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>adInfo.adPodIndex</td><td>Integer</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adInfo.adPositionInPod</td><td>Integer</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>adInfo.adPodLendth</td><td>Integer</td><td>The total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr><tr><td>adInfo.isBumper</td><td>Boolean</td><td>A boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr></tbody></table>

</details>

#### Step 9.3: Report Ad Buffering:

Use Ad Buffering APIs to report any buffering that occurs during ad playback. For any buffering event, either content buffering or ad buffering should be reported, but not both.

```javascript
mmJSPlugin.reportAdBufferingStrated();
mmJSPlugin.reportAdBufferingCompleted();
```

#### Step 9.3: Report Ad Events:

Use the `reportAdEvent` function to report all Ad events.

{% hint style="info" %}
`reportAdStart` and `reportAdEnd` are kept as it is for backward compatibility, but going forward, all the new Integrations should use the  `reportAdEvent` API for all ad states. `MMAdEvent` need to be imported by the client from the SDK.
{% endhint %}

```javascript
mmJSPlugin.reportAdEvent(MMAdEvent, adInfo);
```

<details>

<summary>MMAdEvent (Enum)</summary>

| Ad Event            | Description                                           |
| ------------------- | ----------------------------------------------------- |
| AD\_START           | Report on ad start.                                   |
| AD\_FIRST\_QUARTILE | Report on ad reached first quartile.                  |
| AD\_MID\_POINT      | Report on ad reached midpoint.                        |
| AD\_THIRD\_QUARTILE | Report on ad reached third quartile.                  |
| AD\_SKIP            | Report on ad skipped.                                 |
| AD\_END             | Report on ad ended.                                   |
| AD\_COMPLETE        | Report on ad ended and ad play time greater than 95%. |
| AD\_CLICK           | Report on ad clicked.                                 |

</details>

#### Step 9.4: Report Ad Errors and Warnings

Report Ad Error :

```javascript
mmJSPlugin.reportError("AD_ERROR_CODE", "AD_ERROR_MESSAGE", "AD_ERROR_DETAILS");
```

Report Ad Warning:

```javascript
mmJSPlugin.reportWarning("AD_WARNING_CODE", "AD_WARNING_MESSAGE", "AD_WARNING_DETAILS");
```

### Step 10: Custom Events

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```javascript
mmJSPlugin.reportCustomEvent("EVENT_NAME", "EVENT_VALUE");
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 30 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

#### Release Notes

<details>

<summary>Current Release</summary>

#### v2.2.1[^1]  <sup><sub>`July 13, 2026`<sub></sup>&#x20;

* Fixed an internal mapping issue for payload ID.

</details>

***

<details>

<summary>Previous Releases</summary>

#### v2.2.0[^1]  <sup><sub>`July 6, 2026`<sub></sup>&#x20;

* Enhanced Internal SDK data reporting
  * Added batch-based data reporting with configurable reporting intervals.
  * Improved reliability with exponential backoff retries, jitter, request timeouts, and Dead Letter Queue (DLQ) support.
  * Enabled remote configuration for batch size, reporting interval, retry settings, and the batching feature flag.
* Added new APIs for reporting ad events, including quartiles, request/response, errors, warnings, skip, and click events.
* Added support for reporting device capabilities through DeviceInfo.

#### v2.1.1[^2]  <sup><sub>`June 10, 2026`<sub></sup>

* Handled event reporting failure exception

#### v2.1.0[^2]  <sup><sub>`April 30, 2026`<sub></sup>

* Added support for multiple player instances within a single application.
* Added the following new metadata fields:
  * **Player ID** - report it using `reportPlayerId`.
  * **DRM Level** - report it as part of Content Metadata.
  * **Ad Universal ID** - report it as part of Ad Info.
* `updateDRMType(drmType)` → **Deprecated**
  * Use `updateDRM(drmProtection, drmLevel)` (refer to [Step 5.6](#step-5.6-update-drm-type))
* Buffering events exceeding the stats interval are now included in the stats payload.
* Updated **metadata lifecycle handling**:
  * [Step 2](#step-2-register-and-initialize-mediamelon-sdk) metadata fields persist across the SDK instance lifecycle.
  * All Metadata fields from [Step 3](#step-3-initialize-playback-session) are reset for every playback session.

#### [Non-Multiplayer Releases](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/web/mediamelon-js-custom-sdk-integration-document#release-notes)

</details>

[^1]: Performance Report: [here](https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/web/javascript-custom-sdk-performance-metrics)

[^2]: **Performance Report:** [here](https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/web/javascript-custom-sdk-performance-metrics)


# MediaMelon Shaka Player SDK Integration Document

This guide is for integrating the MediaMelon Player SDK for the javascript based Shaka Player

**Step 1:** [Add the MediaMelonPlayer SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Register and Initialize the MediaMelon Player SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Errors and Warnings](#step-3-errors-and-warnings-important)

**Step 4:** [Report Additional Metadata Fields](#step-4-report-additional-metadata-fields)

**Step 5:** [Update Asset Information](#step-5-update-asset-information)

[Release Notes](#release-notes)

### **Step 1: Add** the MediaMelonPlayer SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

**CDN URL:**

```javascript
<script type="text/javascript" src="https://sdks.mediamelon.com/web/shaka/2.5.2/mmsmartstreaming_shakaplayer.min.js"></script>
```

**NPM:**

```bash
npm i mediamelon-js-shaka-sdk@2.5.2

import {SHAKAPlayerMMSSIntgr} from 'mediamelon-js-shaka-sdk'
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

#### Step 2.1: Instantiate and Register SDK:

```javascript
var mmShakaPlugin = new SHAKAPlayerMMSSIntgr();
mmShakaPlugin.registerMMSmartStreaming("PLAYER_NAME", 
    "CUSTOMER_ID", 
    "SUBSCRIBER_ID", 
    "DOMAIN_NAME", 
    "SUBSCRIBER_TYPE", 
    "SUBSCRIBER_TAG", 
    hashSubscriberId      //Boolean
);
```

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon-assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at [support@mediamelon.com](https://emailto:support@mediamelon.com/).&#x20;
{% endhint %}

#### Step 2.2: Report Player Information:

```javascript
mmShakaPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");            
mmShakaPlugin.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.3: Report Application Information:

```javascript
mmShakaPlugin.reportAppInfo("APPLICATION_NAME","APPLICATION_VERSION");
mmShakaPlugin.reportAppSessionId("APP_SESSION_ID");
```

#### Step 2.4: Report Experiment Name & Sub Property ID:

```javascript
mmShakaPlugin.reportExperimentName("EXPERIMENT_NAME");
mmShakaPlugin.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.5: Report Device Information:

```javascript
mmShakaPlugin.setDeviceInfo("DEVICE_MARKETING_NAME");
mmShakaPlugin.reportDeviceId("DEVICE_ID");
```

#### Step 2.6: Initialize Session with Content Metadata:

```javascript
const video = document.getElementById('video');
const player = new shaka.Player(video);

var contentMetadata = {
    "assetName": "ASSET_NAME",
    "assetId": "ASSET_ID",
    "videoId": "VIDEO_ID",
    "contentType": "CONTENT_TYPE",
    "genre": "GENRE",
    "drmProtection": "DRM_PROTECTION",
    "episodeNumber": "EPISODE_NUMBER",
    "season": "SEASON",
    "seriesTitle": "SERIES_TITLE",
    "customTags": {
      "KEY1": "VALUE_STRING1",
      "KEY2": "VALUE_STRING2"
    }
};

mmShakaPlugin.reportViewSessionId("VIEW_SESSION_ID");
mmShakaPlugin.initializeSession(player, video, "STREAM_URL", contentMetadata, isLive);

player.load("STREAM_URL");
```

{% hint style="info" %}
For Custom Metadata, first map the values in the [SmartSight](https://smartsight.mediamelon.com/) dashboard under Settings, then send them to the SDK accordingly. Refer to [Custom Metadata Configuration Guide](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/custom-metadata-configuration-guide).
{% endhint %}

### Step 3: Errors and Warnings (Important)

The SDK provides two ways to report errors: automatic error capture and manual error reporting via API.

⚙️ **Default Behavior (Auto Error Capture):**

By default, the SDK automatically listens to and captures player errors that occur *after the stream has loaded*. SDK will classify the errors based on severity.

{% hint style="info" %}

> ⚠️ Note: Errors that occur **before or during stream loading** are not captured automatically by the SDK, as they fall outside the player’s event lifecycle. Use the error and warning APIs below to manually report such issues.
> {% endhint %}

🚫 **Disabling Auto Error Capture:**

If you prefer to handle error reporting manually, you can disable this automatic behavior by calling:

```javascript
mmShakaPlugin.disableAutoErrorCapture();
```

{% hint style="info" %}

> ⚠️ When disabled, the SDK will not listen for any player-generated errors. You will be responsible for reporting all errors & warnings manually using the APIs described below.
> {% endhint %}

**🛠️ Manual Error Reporting APIs:**

Use these APIs to custom report errors and warnings to the SDK—especially for errors that occur **before or during stream loading**, or when auto-capture is disabled.

🔴 **Report Fatal Error:**

All errors reported via reportError are treated as **fatal**.

```javascript
mmShakaPlugin.reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DETAILS");
```

🟠 **Report Warning (Non-Fatal):**

All warnings reported via reportWarning are treated as non-fatal and will be tracked accordingly.

```javascript
mmShakaPlugin.reportWarning("WARNING_CODE", "WARNING_MESSAGE", "WARNING_DETAILS");
```

### Step 4: Report Additional Metadata Fields

#### Step 4.1: CDN:

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```javascript
mmShakaPlugin.reportCDN("CDN");
```

#### Step 4.2: Custom Metadata:

Check the custom metadata configuration in the [SmartSight](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure them and use them as needed.&#x20;

Use this method to report any additional metadata that doesn’t fall under predefined metadata fields. This provides flexibility to send custom, business, or platform-specific information to the SDK. This is the same as `customTags` in the `contentMetadata` object.

```javascript
mmShakaPlugin.reportCustomMetadata("KEY", "VALUE");
```

#### Step 4.3: Stream Information:

Report key stream attributes that describe the encoding and delivery method.

```javascript
mmShakaPlugin.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE");
```

#### Step 4.4: Player resolution:

Report the width and height of the player window (in pixels). This is useful to understand playback size and user experience across different screen sizes or platforms.

```javascript
mmShakaPlugin.reportPlayerResolution(<player_width>, <player_height>);
```

#### Step 4.5: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```java
mmShakaPlugin.reportFallbackEvent("FALLBACK_URL", "DESCRIPTION");
```

#### Step 4.6: Report Video Duration

Report video duration for LIVE content. Video Duration should be reported after every session initialization and asset update.

```javascript
mmShakaPlugin.reportVideoDuration(durationInMs);
```

### Step 5: Update Asset Information

If Asset Information needs to be updated dynamically during the live session without re-initiating the player, then the `updateAssetInfo` API can be used to update the new AssetInfo

{% hint style="info" %}
**Note**

* This API must be called for updating asset info for the live streams only&#x20;
* This API must be called after the Player has started the playback of the live stream&#x20;
* New Asset Info Object will override the previous values. Hence, set all the fields that are required every time calling this API, including all **Custom Tags.**
* Optionally report `isLive` (boolean) for the new asset.
  {% endhint %}

```javascript
// Create a new assetInfo object with the values need to be updated
var newAssetInfo =  { 
     "assetName": "ASSET_NAME",
     "assetId": "ASSET_ID",
     "videoId": "VIDEO_ID",
     "contentType": "CONTENT_TYPE",
     "drmProtection": "DRM_PROTECTION",
     "episodeNumber": "EPISODE_NUMBER",
     "season": "SEASON",
     "seriesTitle": "SERIES_TITLE",
     "customTags":{
         "key1": "VALUE1",
         "key2": "VALUE2"
     }          
}

// Update the new assetInfo
mmShakaPlugin.updateAssetInfo(newAssetInfo, isLive);
```

### Release Notes

<details>

<summary>Current Release</summary>

#### v2.5.2  <sup><sub>`Oct 9, 2026`<sub></sup>

* Bugfix - `isLive` intermittently reported as false for LIVE content.
* Added `isLive` as an optional param for `updateAssetInfo`.
* Added `reportVideoDuration` to report video duration for LIVE content.

</details>

***

<details>

<summary>Previous Releases</summary>

#### v2.5.1  <sup><sub>`Mar 9, 2026`<sub></sup>

* Added App Session ID metadata field.
* Fixed the buffering and seek complete events order issue.
* Added Seek duration.
* Updated the rendition reporting to enable rendition metrics in the dashboard.
* Improved bitrate reporting.
* Added `CDN_CHANGE` event.

#### v2.4.0  <sup><sub>`Sep 12, 2025`<sub></sup>

* Added Shaka 2.x support

#### v2.3.2  <sup><sub>`Sep 3, 2025`<sub></sup>

* Fixed buffering and seek-related issues.
* Fixed heartbeat missing in case of registration response delayed.

</details>


# MediaMelon VideoJS Player SDK Integration Document

This guide is for integrating the MediaMelon Player SDK for the javascript based VideoJS Player

**Step 1:** [Add the MediaMelonPlayer SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Register and Initialize the MediaMelon Player SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Errors and Warnings (Important)](#step-3-errors-and-warnings-important)

**Step 4:** [Report Additional Metadata Fields](#step-4-report-additional-metadata-fields)

[Release Notes](#release-notes)

### **Step 1: Add** the MediaMelonPlayer SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

**CDN URL:**

```javascript
<script type="text/javascript" src="https://sdks.mediamelon.com/web/videojs/1.3.0/mmsmartstreaming_videojsplayer.min.js"></script>
```

**NPM:**

```bash
npm i mediamelon-js-videojs-sdk@1.3.0

import {VideoJSMMSSIntgr} from 'mediamelon-js-videojs-sdk'
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

#### Step 2.1: Instantiate and Register SDK:

```javascript
var mmVideoJSPlugin = new VideoJSMMSSIntgr();
mmVideoJSPlugin.registerMMSmartStreaming("PLAYER_NAME", 
    "CUSTOMER_ID", 
    "SUBSCRIBER_ID", 
    "DOMAIN_NAME", 
    "SUBSCRIBER_TYPE", 
    "SUBSCRIBER_TAG", 
    hashSubscriberId      //Boolean
);
```

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon-assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at [support@mediamelon.com](https://emailto:support@mediamelon.com/).&#x20;
{% endhint %}

#### Step 2.2: Report Player Information:

```javascript
mmVideoJSPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");            
mmVideoJSPlugin.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.3: Report Application Information:

```javascript
mmVideoJSPlugin.reportAppInfo("APPLICATION_NAME","APPLICATION_VERSION");
mmVideoJSPlugin.reportAppSessionId("APP_SESSION_ID");
```

#### Step 2.4: Report Experiment Name & Sub Property ID:

```javascript
mmVideoJSPlugin.reportExperimentName("EXPERIMENT_NAME");
mmVideoJSPlugin.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.5: Report Device Information:

```javascript
mmVideoJSPlugin.setDeviceInfo("DEVICE_MARKETING_NAME");
mmVideoJSPlugin.reportDeviceId("DEVICE_ID");
```

#### Step 2.6: Initialize Session with Content Metadata:

```javascript
<video id="video-js" class="vjs-default-skin" preload="auto"></video>
..
var player = videojs('video-js');

var contentMetadata = {
    "assetName": "ASSET_NAME",
    "assetId": "ASSET_ID",
    "videoId": "VIDEO_ID",
    "contentType": "CONTENT_TYPE",
    "genre": "GENRE",
    "drmProtection": "DRM_PROTECTION",
    "episodeNumber": "EPISODE_NUMBER",
    "season": "SEASON",
    "seriesTitle": "SERIES_TITLE",
    "customTags": {
      "KEY1": "VALUE_STRING1",
      "KEY2": "VALUE_STRING2"
    }
};

mmVideoJSPlugin.reportViewSessionId("VIEW_SESSION_ID");
mmVideoJSPlugin.initialize(player, "STREAM_URL", contentMetadata, isLive);

player.src({
      src: "STREAM_URL"
});
player.play();
```

{% hint style="info" %}
For Custom Metadata, first map the values in the [SmartSight](https://smartsight.mediamelon.com/) dashboard under Settings, then send them to the SDK accordingly. Refer to [Custom Metadata Configuration Guide](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/custom-metadata-configuration-guide).
{% endhint %}

### Step 3: Errors and Warnings (Important)

The SDK provides two ways to report errors: automatic error capture and manual error reporting via API.

⚙️ **Default Behavior (Auto Error Capture):**

By default, the SDK automatically listens to and captures player errors that occur *after the stream has loaded*. SDK will classify the errors based on severity.

{% hint style="info" %}

> ⚠️ Note: Errors that occur **before or during stream loading** are not captured automatically by the SDK, as they fall outside the player’s event lifecycle. Use the error and warning APIs below to manually report such issues.
> {% endhint %}

🚫 **Disabling Auto Error Capture:**

If you prefer to handle error reporting manually, you can disable this automatic behavior by calling:

```javascript
mmVideoJSPlugin.disableAutoErrorCapture();
```

{% hint style="info" %}

> ⚠️ When disabled, the SDK will not listen for any player-generated errors. You will be responsible for reporting all errors & warnings manually using the APIs described below.
> {% endhint %}

**🛠️ Manual Error Reporting APIs:**

Use these APIs to custom report errors and warnings to the SDK—especially for errors that occur **before or during stream loading**, or when auto-capture is disabled.

🔴 **Report Fatal Error:**

All errors reported via reportError are treated as **fatal**.

```javascript
mmVideoJSPlugin.reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DETAILS");
```

🟠 **Report Warning (Non-Fatal):**

All warnings reported via reportWarning are treated as non-fatal and will be tracked accordingly.

```javascript
mmVideoJSPlugin.reportWarning("WARNING_CODE", "WARNING_MESSAGE", "WARNING_DETAILS");
```

### Step 4: Report Additional Metadata Fields

#### Step 4.1: CDN:

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```javascript
mmVideoJSPlugin.reportCDN("CDN");
```

#### Step 4.2: Custom Metadata:

Check the custom metadata configuration in the [SmartSight](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure them and use them as needed.&#x20;

Use this method to report any additional metadata that doesn’t fall under predefined metadata fields. This provides flexibility to send custom, business, or platform-specific information to the SDK. This is the same as `customTags` in the `contentMetadata` object.

```javascript
mmVideoJSPlugin.reportCustomMetadata("KEY", "VALUE");
```

#### Step 4.3: Stream Information:

Report key stream attributes that describe the encoding and delivery method.

```javascript
mmVideoJSPlugin.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE");
```

#### Step 4.4: Player resolution:

Report the width and height of the player window (in pixels). This is useful to understand playback size and user experience across different screen sizes or platforms.

```javascript
mmVideoJSPlugin.reportPlayerResolution(<player_width>, <player_height>);
```

#### Step 4.5: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```java
mmVideoJSPlugin.reportFallbackEvent("FALLBACK_URL", "DESCRIPTION");
```

### Release Notes

<details>

<summary>Current Release</summary>

#### v1.3.0  <sup><sub>`Mar 9, 2026`<sub></sup>

* Added App Session ID metadata field.
* Added Seek duration.
* Updated the rendition reporting to enable rendition metrics in the dashboard.
* Improved bitrate reporting.
* Added `CDN_CHANGE` event.

</details>

***

<details>

<summary>Previous Releases</summary>

</details>


# MediaMelon Bitmovin Web SDK Integration Guide

This guide is for integrating the MediaMelon Player SDK for the javascript based Bitmovin Player

**Step 1:** [Add the MediaMelonPlayer SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Register and Initialize the MediaMelon Player SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Errors and Warnings (Important)](#step-3-errors-and-warnings-important)

**Step 4:** [Report Additional Metadata Fields](#step-4-report-additional-metadata-fields)

**Step 5:** [Update Asset Information](#step-5-update-asset-information)

[Release Notes](#release-notes)

### **Step 1: Add** the MediaMelonPlayer SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

**CDN URL:**

```javascript
<script type="text/javascript" src="https://sdks.mediamelon.com/web/bitmovin/2.7.0/mmsmartstreaming_bitmovinplayer.min.js"></script>
```

**NPM:**

```bash
npm i mediamelon-js-bitmovin-sdk@2.7.0

import {MMBitmovinSDKIntgr} from 'mediamelon-js-bitmovin-sdk'
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

#### Step 2.1: Instantiate and Register SDK:

```javascript
var mmBitmovinPlugin = new MMBitmovinSDKIntgr();
mmBitmovinPlugin.registerMMSmartStreaming("PLAYER_NAME", 
    "CUSTOMER_ID", 
    "SUBSCRIBER_ID", 
    "DOMAIN_NAME", 
    "SUBSCRIBER_TYPE", 
    "SUBSCRIBER_TAG", 
    hashSubscriberId      //Boolean
);
```

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon-assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at [support@mediamelon.com](https://emailto:support@mediamelon.com/).&#x20;
{% endhint %}

#### Step 2.2: Report Player Information:

```javascript
mmBitmovinPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");            
mmBitmovinPlugin.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.3: Report Application Information:

```javascript
mmBitmovinPlugin.reportAppInfo("APPLICATION_NAME","APPLICATION_VERSION");
mmBitmovinPlugin.reportAppSessionId("APP_SESSION_ID");
```

#### Step 2.4: Report Experiment Name & Sub Property ID:

```javascript
mmBitmovinPlugin.reportExperimentName("EXPERIMENT_NAME");
mmBitmovinPlugin.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.5: Report Device Information:

```javascript
mmBitmovinPlugin.setDeviceInfo("DEVICE_MARKETING_NAME");
mmBitmovinPlugin.reportDeviceId("DEVICE_ID");
```

#### Step 2.6: Initialize Session with Content Metadata:

```javascript
const player = new bitmovin.player.Player(document.getElementById('video'), config);
const playerEvent = bitmovin.player.playerEvent;

var contentMetadata = {
    "assetName": "ASSET_NAME",
    "assetId": "ASSET_ID",
    "videoId": "VIDEO_ID",
    "contentType": "CONTENT_TYPE",
    "genre": "GENRE",
    "drmProtection": "DRM_PROTECTION",
    "episodeNumber": "EPISODE_NUMBER",
    "season": "SEASON",
    "seriesTitle": "SERIES_TITLE",
    "customTags": {
      "KEY1": "VALUE_STRING1",
      "KEY2": "VALUE_STRING2"
    }
};

mmBitmovinPlugin.reportViewSessionId("VIEW_SESSION_ID");
mmBitmovinPlugin.initialize(player, "STREAM_URL", contentMetadata, isLive, playerEvent);
```

{% hint style="info" %}
For Custom Metadata, first map the values in the [SmartSight](https://smartsight.mediamelon.com/) dashboard under Settings, then send them to the SDK accordingly. Refer to [Custom Metadata Configuration Guide](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/custom-metadata-configuration-guide).
{% endhint %}

### Step 3: Errors and Warnings (Important):

The SDK provides two ways to report errors: automatic error capture and manual error reporting via API.

⚙️ **Default Behavior (Auto Error Capture):**

By default, the SDK automatically listens to and captures player errors that occur *after the stream has started loading*. SDK will classify the errors based on severity.

{% hint style="info" %}

> ⚠️ Note: Errors that occur **before stream loading** are not captured automatically by the SDK, as they fall outside the player’s event lifecycle. Use the error and warning APIs below to manually report such issues.
> {% endhint %}

🚫 **Disabling Auto Error Capture:**

If you prefer to handle error reporting manually, you can disable this automatic behavior by calling:

```javascript
mmBitmovinPlugin.disableAutoErrorCapture();
```

{% hint style="info" %}

> ⚠️ When disabled, the SDK will not listen for any player-generated errors. You will be responsible for reporting all errors & warnings manually using the APIs described below.
> {% endhint %}

**🛠️ Manual Error Reporting APIs:**

Use these APIs to custom report errors and warnings to the SDK—especially for errors that occur **before stream loading**, or when auto-capture is disabled.

🔴 **Report Fatal Error:**

All errors reported via reportError are treated as **fatal**.

```javascript
mmBitmovinPlugin.reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DETAILS");
```

🟠 **Report Warning (Non-Fatal):**

All warnings reported via reportWarning are treated as non-fatal and will be tracked accordingly.

```javascript
mmBitmovinPlugin.reportWarning("WARNING_CODE", "WARNING_MESSAGE", "WARNING_DETAILS");
```

### Step 4: Report Additional Metadata Fields

#### Step 4.1: CDN:

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```javascript
mmBitmovinPlugin.reportCDN("CDN");
```

#### Step 4.2: Custom Metadata:

Check the custom metadata configuration in the [SmartSight](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure them and use them as needed.&#x20;

Use this method to report any additional metadata that doesn’t fall under predefined metadata fields. This provides flexibility to send custom, business, or platform-specific information to the SDK. This is the same as `customTags` in the `contentMetadata` object.

```javascript
mmBitmovinPlugin.reportCustomMetadata("KEY", "VALUE");
```

#### Step 4.3: Stream Information:

Report key stream attributes that describe the encoding and delivery method.

```javascript
mmBitmovinPlugin.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE");
```

#### Step 4.4: Player resolution:

Report the width and height of the player window (in pixels). This is useful to understand playback size and user experience across different screen sizes or platforms.

```javascript
mmBitmovinPlugin.reportPlayerResolution(<player_width>, <player_height>);
```

#### Step 4.5: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```java
mmBitmovinPlugin.reportFallbackEvent("FALLBACK_URL", "DESCRIPTION");
```

### Step 5: Update Asset Information

If Asset Information needs to be updated dynamically during the live session without re-initiating the player, then the `updateAssetInfo` API can be used to update the new AssetInfo

{% hint style="info" %}
**Note**

* This API must be called for updating asset info for the live streams only&#x20;
* This API must be called after the Player has started the playback of the live stream&#x20;
* New Asset Info Object will override the previous values. Hence, set all the fields that are required every time calling this API, including all **Custom Tags.**
  {% endhint %}

```javascript
// Create a new assetInfo object with the values need to be updated
var newAssetInfo =  { 
     "assetName": "ASSET_NAME",
     "assetId": "ASSET_ID",
     "videoId": "VIDEO_ID",
     "contentType": "CONTENT_TYPE",
     "drmProtection": "DRM_PROTECTION",
     "episodeNumber": "EPISODE_NUMBER",
     "season":"SEASON",
     "seriesTitle": "SERIES_TITLE",
     "customTags":{
         "key1": "VALUE1",
         "key2": "VALUE2"
     }          
}

// Update the new assetInfo
mmBitmovinPlugin.updateAssetInfo(newAssetInfo);
```

### Release Notes

<details>

<summary>Current Release</summary>

#### v2.7.0  <sup><sub>`Mar 9, 2026`<sub></sup>

* Added App Session ID metadata field.
* Added Seek duration.
* Updated the rendition reporting to enable rendition metrics in the dashboard.
* Improved bitrate reporting.
* Added `CDN_CHANGE` event.

</details>

***

<details>

<summary>Previous Releases</summary>

#### v2.6.5  <sup><sub>`Sep 12, 2025`<sub></sup>

* &#x20;Fixed buffering reporting.
* Handled streaminfo in case of update asset info.

</details>


# MediaMelon Theo Player SDK Integration Document

This guide is for integrating the MediaMelon Player SDK for the javascript based Theo Player

**Step 1:** [Add the MediaMelonPlayer SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Register and Initialize the MediaMelon Player SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Errors and Warnings (Important)](#step-3-errors-and-warnings-important)

**Step 4:** [Report Additional Metadata Fields](#step-4-report-additional-metadata-fields)

[Release Notes](#release-notes)

### **Step 1: Add** the MediaMelonPlayer SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

**CDN URL:**

```javascript
<script type="text/javascript" src="https://sdks.mediamelon.com/web/theo/1.4.1/mmsmartstreaming_theoplayer.min.js"></script>
```

**NPM:**

```bash
npm i mediamelon-js-theo-sdk@1.4.1

import {mmTheoJSAdapter} from 'mediamelon-js-theo-sdk'
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

#### Step 2.1: Instantiate and Register SDK:

```javascript
var mmTheoPlugin = new mmTheoJSAdapter();
mmTheoPlugin.registerMMSmartStreaming("PLAYER_NAME", 
    "CUSTOMER_ID", 
    "SUBSCRIBER_ID", 
    "DOMAIN_NAME", 
    "SUBSCRIBER_TYPE", 
    "SUBSCRIBER_TAG", 
    hashSubscriberId      //Boolean
);
```

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon-assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at [support@mediamelon.com](https://emailto:support@mediamelon.com/).&#x20;
{% endhint %}

#### Step 2.2: Report Player Information:

```javascript
mmTheoPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");            
mmTheoPlugin.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.3: Report Application Information:

```javascript
mmTheoPlugin.reportAppInfo("APPLICATION_NAME","APPLICATION_VERSION");
mmTheoPlugin.reportAppSessionId("APP_SESSION_ID");
```

#### Step 2.4: Report Experiment Name & Sub Property ID:

```javascript
mmTheoPlugin.reportExperimentName("EXPERIMENT_NAME");
mmTheoPlugin.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.5: Report Device Information:

```javascript
mmTheoPlugin.setDeviceInfo("DEVICE_MARKETING_NAME");
mmTheoPlugin.reportDeviceId("DEVICE_ID");
```

#### Step 2.6: Initialize Session with Content Metadata:

```javascript
var player = new THEOplayer.Player(element, {
     libraryLocation: 'THEO_LIBRARY_LOCATION',
     license: 'LICENSE'
})

var contentMetadata = {
    "assetName": "ASSET_NAME",
    "assetId": "ASSET_ID",
    "videoId": "VIDEO_ID",
    "contentType": "CONTENT_TYPE",
    "genre": "GENRE",
    "drmProtection": "DRM_PROTECTION",
    "episodeNumber": "EPISODE_NUMBER",
    "season": "SEASON",
    "seriesTitle": "SERIES_TITLE",
    "customTags": {
      "KEY1": "VALUE_STRING1",
      "KEY2": "VALUE_STRING2"
    }
};

mmTheoPlugin.reportViewSessionId("VIEW_SESSION_ID");
mmTheoPlugin.initialize(player, "STREAM_URL", contentMetadata, isLive);
```

{% hint style="info" %}
For Custom Metadata, first map the values in the [SmartSight](https://smartsight.mediamelon.com/) dashboard under Settings, then send them to the SDK accordingly. Refer to [Custom Metadata Configuration Guide](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/custom-metadata-configuration-guide).
{% endhint %}

### Step 3: Errors and Warnings (Important)

The SDK provides two ways to report errors: automatic error capture and manual error reporting via API.

⚙️ **Default Behavior (Auto Error Capture):**

By default, the SDK automatically listens to and captures player errors that occur *after the stream has loaded*. SDK will classify the errors based on severity.

{% hint style="info" %}

> ⚠️ Note: Errors that occur **before or during stream loading** are not captured automatically by the SDK, as they fall outside the player’s event lifecycle. Use the error and warning APIs below to manually report such issues.
> {% endhint %}

🚫 **Disabling Auto Error Capture:**

If you prefer to handle error reporting manually, you can disable this automatic behavior by calling:

```javascript
mmTheoPlugin.disableAutoErrorCapture();
```

{% hint style="info" %}

> ⚠️ When disabled, the SDK will not listen for any player-generated errors. You will be responsible for reporting all errors & warnings manually using the APIs described below.
> {% endhint %}

**🛠️ Manual Error Reporting APIs:**

Use these APIs to custom report errors and warnings to the SDK—especially for errors that occur **before or during stream loading**, or when auto-capture is disabled.

🔴 **Report Fatal Error:**

All errors reported via reportError are treated as **fatal**.

```javascript
mmTheoPlugin.reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DETAILS");
```

🟠 **Report Warning (Non-Fatal):**

All warnings reported via reportWarning are treated as non-fatal and will be tracked accordingly.

```javascript
mmTheoPlugin.reportWarning("WARNING_CODE", "WARNING_MESSAGE", "WARNING_DETAILS");
```

### Step 4: Report Additional Metadata Fields

#### Step 4.1: CDN:

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```javascript
mmTheoPlugin.reportCDN("CDN");
```

#### Step 4.2: Custom Metadata:

Check the custom metadata configuration in the [SmartSight](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure them and use them as needed.&#x20;

Use this method to report any additional metadata that doesn’t fall under predefined metadata fields. This provides flexibility to send custom, business, or platform-specific information to the SDK. This is the same as `customTags` in the `contentMetadata` object.

```javascript
mmTheoPlugin.reportCustomMetadata("KEY", "VALUE");
```

#### Step 4.3: Stream Information:

Report key stream attributes that describe the encoding and delivery method.

```javascript
mmTheoPlugin.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE");
```

#### Step 4.4: Player resolution:

Report the width and height of the player window (in pixels). This is useful to understand playback size and user experience across different screen sizes or platforms.

```javascript
mmTheoPlugin.reportPlayerResolution(<player_width>, <player_height>);
```

#### Step 4.5: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```java
mmTheoPlugin.reportFallbackEvent("FALLBACK_URL", "DESCRIPTION");
```

### Release Notes

<details>

<summary>Current Release</summary>

#### v1.4.1  <sup><sub>`Mar 9, 2026`<sub></sup>

* Added App Session ID metadata field.
* Added Seek duration.
* Updated the rendition reporting to enable rendition metrics in the dashboard.
* Improved bitrate reporting.
* Added `CDN_CHANGE` event.
* Added ad buffering tracking for IMA and DAI ads.

</details>

***

<details>

<summary>Previous Releases</summary>

#### v1.3.1

* Fixed an initialisation crash issue.

</details>


# MediaMelon HTML5 Player SDK Integration Document

This guide is for integrating the MediaMelon Player SDK for the javascript based HTML5 Player

**Step 1:** [Add the MediaMelonPlayer SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Register and Initialize the MediaMelon Player SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Errors and Warnings](#step-3-errors-and-warnings-important)

**Step 4:** [Report Additional Metadata Fields](#step-4-report-additional-metadata-fields)

[Release Notes](#release-notes)

### **Step 1: Add** the MediaMelonPlayer SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

**CDN URL:**

```javascript
<script type="text/javascript" src="https://sdks.mediamelon.com/web/html5/1.3.0/mmsmartstreaming_htmlplayer.min.js"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

#### Step 2.1: Instantiate and Register SDK:

```javascript
var mmHtmlPlugin = new Html5MMSSIntgr();
mmHtmlPlugin.registerMMSmartStreaming("PLAYER_NAME", 
    "CUSTOMER_ID", 
    "SUBSCRIBER_ID", 
    "DOMAIN_NAME", 
    "SUBSCRIBER_TYPE", 
    "SUBSCRIBER_TAG", 
    hashSubscriberId      //Boolean
);
```

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon-assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at [support@mediamelon.com](https://emailto:support@mediamelon.com/).&#x20;
{% endhint %}

#### Step 2.2: Report Player Information:

```javascript
mmHtmlPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");            
mmHtmlPlugin.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.3: Report Application Information:

```javascript
mmHtmlPlugin.reportAppInfo("APPLICATION_NAME","APPLICATION_VERSION");
mmHtmlPlugin.reportAppSessionId("APP_SESSION_ID");
```

#### Step 2.4: Report Experiment Name & Sub Property ID:

```javascript
mmHtmlPlugin.reportExperimentName("EXPERIMENT_NAME");
mmHtmlPlugin.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.5: Report Device Information:

```javascript
mmHtmlPlugin.setDeviceInfo("DEVICE_MARKETING_NAME");
mmHtmlPlugin.reportDeviceId("DEVICE_ID");
```

#### Step 2.6: Initialize Session with Content Metadata:

```javascript
const video = document.getElementById('video');

var contentMetadata = {
    "assetName": "ASSET_NAME",
    "assetId": "ASSET_ID",
    "videoId": "VIDEO_ID",
    "contentType": "CONTENT_TYPE",
    "genre": "GENRE",
    "drmProtection": "DRM_PROTECTION",
    "episodeNumber": "EPISODE_NUMBER",
    "season": "SEASON",
    "seriesTitle": "SERIES_TITLE",
    "customTags": {
      "KEY1": "VALUE_STRING1",
      "KEY2": "VALUE_STRING2"
    }
};

mmHtmlPlugin.reportViewSessionId("VIEW_SESSION_ID");
mmHtmlPlugin.initialize(video, "STREAM_URL", contentMetadata, isLive);
```

{% hint style="info" %}
For Custom Metadata, first map the values in the [SmartSight](https://smartsight.mediamelon.com/) dashboard under Settings, then send them to the SDK accordingly. Refer to [Custom Metadata Configuration Guide](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/custom-metadata-configuration-guide).
{% endhint %}

### Step 3: Errors and Warnings (Important)

The SDK provides two ways to report errors: automatic error capture and manual error reporting via API.

⚙️ **Default Behavior (Auto Error Capture):**

By default, the SDK automatically listens to and captures player errors that occur *after the stream has loaded*. SDK will classify the errors based on severity.

{% hint style="info" %}

> ⚠️ Note: Errors that occur **before or during stream loading** are not captured automatically by the SDK, as they fall outside the player’s event lifecycle. Use the error and warning APIs below to manually report such issues.
> {% endhint %}

🚫 **Disabling Auto Error Capture:**

If you prefer to handle error reporting manually, you can disable this automatic behavior by calling:

```javascript
mmHtmlPlugin.disableAutoErrorCapture();
```

{% hint style="info" %}

> ⚠️ When disabled, the SDK will not listen for any player-generated errors. You will be responsible for reporting all errors & warnings manually using the APIs described below.
> {% endhint %}

**🛠️ Manual Error Reporting APIs:**

Use these APIs to custom report errors and warnings to the SDK—especially for errors that occur **before or during stream loading**, or when auto-capture is disabled.

🔴 **Report Fatal Error:**

All errors reported via reportError are treated as **fatal**.

```javascript
mmHtmlPlugin.reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DETAILS");
```

🟠 **Report Warning (Non-Fatal):**

All warnings reported via reportWarning are treated as non-fatal and will be tracked accordingly.

```javascript
mmHtmlPlugin.reportWarning("WARNING_CODE", "WARNING_MESSAGE", "WARNING_DETAILS");
```

### Step 4: Report Additional Metadata Fields

#### Step 4.1: CDN:

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```javascript
mmHtmlPlugin.reportCDN("CDN");
```

#### Step 4.2: Custom Metadata:

Check the custom metadata configuration in the [SmartSight](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure them and use them as needed.&#x20;

Use this method to report any additional metadata that doesn’t fall under predefined metadata fields. This provides flexibility to send custom, business, or platform-specific information to the SDK. This is the same as `customTags` in the `contentMetadata` object.

```javascript
mmHtmlPlugin.reportCustomMetadata("KEY", "VALUE");
```

#### Step 4.3: Stream Information:

Report key stream attributes that describe the encoding and delivery method.

```javascript
mmHtmlPlugin.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE");
```

#### Step 4.4: Player resolution:

Report the width and height of the player window (in pixels). This is useful to understand playback size and user experience across different screen sizes or platforms.

```javascript
mmHtmlPlugin.reportPlayerResolution(<player_width>, <player_height>);
```

#### Step 4.5: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```java
mmHtmlPlugin.reportFallbackEvent("FALLBACK_URL", "DESCRIPTION");
```

### Release Notes

<details>

<summary>Current Release</summary>

#### **​v1.3.0**

* Added App Session ID and Device ID metadata fields.
* Fixed the buffering and seek complete events order issue.
* Added Seek duration.
* Added `CDN_CHANGE` event.

</details>

***


# MediaMelon HLSJS SDK Integration Document

This guide is for integrating the MediaMelon Player SDK  for the javascript based  HLSJS Player Web

**Step 1:** [Add the MediaMelonPlayer SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Register and Initialize the MediaMelon Player SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Errors and Warnings](#step-3-errors-and-warnings-important)

**Step 4:** [Report Additional Metadata Fields](#step-4-report-additional-metadata-fields)

[Release Notes](#release-notes)

### **Step 1: Add** the MediaMelonPlayer SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

**CDN URL:**

```javascript
<script type="text/javascript" src="https://sdks.mediamelon.com/web/hlsjs/1.3.0/mmsmartstreaming_hlsjsplayer.min.js"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

#### Step 2.1: Instantiate and Register SDK:

```javascript
var mmHlsjsPlugin = new HLSJSMMSSIntgr();
mmHlsjsPlugin.registerMMSmartStreaming("PLAYER_NAME", 
    "CUSTOMER_ID", 
    "SUBSCRIBER_ID", 
    "DOMAIN_NAME", 
    "SUBSCRIBER_TYPE", 
    "SUBSCRIBER_TAG", 
    hashSubscriberId      //Boolean
);
```

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon-assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at [support@mediamelon.com](https://emailto:support@mediamelon.com/).&#x20;
{% endhint %}

#### Step 2.2: Report Player Information:

```javascript
mmHlsjsPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");            
mmHlsjsPlugin.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.3: Report Application Information:

```javascript
mmHlsjsPlugin.reportAppInfo("APPLICATION_NAME","APPLICATION_VERSION");
mmHlsjsPlugin.reportAppSessionId("APP_SESSION_ID");
```

#### Step 2.4: Report Experiment Name & Sub Property ID:

```javascript
mmHlsjsPlugin.reportExperimentName("EXPERIMENT_NAME");
mmHlsjsPlugin.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.5: Report Device Information:

```javascript
mmHlsjsPlugin.setDeviceInfo("DEVICE_MARKETING_NAME");
mmHlsjsPlugin.reportDeviceId("DEVICE_ID");
```

#### Step 2.6: Initialize Session with Content Metadata:

```javascript
var video = document.getElementById('videoPlayer');
var hls = new Hls();                      
hls.attachMedia(video);

var contentMetadata = {
    "assetName": "ASSET_NAME",
    "assetId": "ASSET_ID",
    "videoId": "VIDEO_ID",
    "contentType": "CONTENT_TYPE",
    "genre": "GENRE",
    "drmProtection": "DRM_PROTECTION",
    "episodeNumber": "EPISODE_NUMBER",
    "season": "SEASON",
    "seriesTitle": "SERIES_TITLE",
    "customTags": {
      "KEY1": "VALUE_STRING1",
      "KEY2": "VALUE_STRING2"
    }
};

mmHlsjsPlugin.reportViewSessionId("VIEW_SESSION_ID");
mmHlsjsPlugin.initialize(hls, "STREAM_URL", contentMetadata, isLive);
```

{% hint style="info" %}
For Custom Metadata, first map the values in the [SmartSight](https://smartsight.mediamelon.com/) dashboard under Settings, then send them to the SDK accordingly. Refer to [Custom Metadata Configuration Guide](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/custom-metadata-configuration-guide).
{% endhint %}

### Step 3: Errors and Warnings (Important)

The SDK provides two ways to report errors: automatic error capture and manual error reporting via API.

⚙️ **Default Behavior (Auto Error Capture):**

By default, the SDK automatically listens to and captures player errors that occur *after the stream has loaded*. SDK will classify the errors based on severity.

{% hint style="info" %}

> ⚠️ Note: Errors that occur **before or during stream loading** are not captured automatically by the SDK, as they fall outside the player’s event lifecycle. Use the error and warning APIs below to manually report such issues.
> {% endhint %}

🚫 **Disabling Auto Error Capture:**

If you prefer to handle error reporting manually, you can disable this automatic behavior by calling:

```javascript
mmHlsjsPlugin.disableAutoErrorCapture();
```

{% hint style="info" %}

> ⚠️ When disabled, the SDK will not listen for any player-generated errors. You will be responsible for reporting all errors & warnings manually using the APIs described below.
> {% endhint %}

**🛠️ Manual Error Reporting APIs:**

Use these APIs to custom report errors and warnings to the SDK—especially for errors that occur **before or during stream loading**, or when auto-capture is disabled.

🔴 **Report Fatal Error:**

All errors reported via reportError are treated as **fatal**.

```javascript
mmHlsjsPlugin.reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DETAILS");
```

🟠 **Report Warning (Non-Fatal):**

All warnings reported via reportWarning are treated as non-fatal and will be tracked accordingly.

```javascript
mmHlsjsPlugin.reportWarning("WARNING_CODE", "WARNING_MESSAGE", "WARNING_DETAILS");
```

### Step 4: Report Additional Metadata Fields

#### Step 4.1: CDN:

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```javascript
mmHlsjsPlugin.reportCDN("CDN");
```

#### Step 4.2: Custom Metadata:

Check the custom metadata configuration in the [SmartSight](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure them and use them as needed.&#x20;

Use this method to report any additional metadata that doesn’t fall under predefined metadata fields. This provides flexibility to send custom, business, or platform-specific information to the SDK. This is the same as `customTags` in the `contentMetadata` object.

```javascript
mmHlsjsPlugin.reportCustomMetadata("KEY", "VALUE");
```

#### Step 4.3: Stream Information:

Report key stream attributes that describe the encoding and delivery method.

```javascript
mmHlsjsPlugin.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE");
```

#### Step 4.4: Player resolution:

Report the width and height of the player window (in pixels). This is useful to understand playback size and user experience across different screen sizes or platforms.

```javascript
mmHlsjsPlugin.reportPlayerResolution(<player_width>, <player_height>);
```

#### Step 4.5: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```java
mmHlsjsPlugin.reportFallbackEvent("FALLBACK_URL", "DESCRIPTION");
```

### Release Notes

<details>

<summary>Current Release</summary>

#### **​v1.3.0**

* Added App Session ID and Device ID metadata fields.
* Provided an API to report CDN data.
* Fixed the buffering and seek complete events order issue.
* Added Seek duration.
* Added `CDN_CHANGE` event.

</details>

***


# MediaMelon DashJS SDK Integration Document

This guide is for integrating the MediaMelon Player SDK for the javascript based DASHJS Player Web

### **Step 1: Add** the MediaMelon Player SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Include the following line in the web page at the start

```javascript
<script type="text/javascript" src="https://sdk.mediamelon.com/SDK_RELEASES/Javascript/dashjs/v1.3.0/mmsmartstreaming_dashjsplayer.min.js"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](emailto:support@mediamelon.com)
{% endhint %}

After the player instance has been created, create a new Plugin object, register, report player Info and then initialize the plugin as shown below:

```html
<script>
    var player = dashjs.MediaPlayer().create();
    var mmdashjsPlugin = new DASHPlayerMMSSIntgr();

    var mmVideoAssetInfo = {
      "assetName": "ASSET_NAME",
      "assetId": "ASSET_ID",
      "videoId": "VIDEO_ID",
      "contentType": "CONTENT_TYPE",
      "genre": "GENRE",
      "drmProtection": "DRM_PROTECTION",
      "episodeNumber": "EPISODE_NUMBER",
      "season": "SEASON",
      "seriesTitle": "SERIES_TITLE",
      "customTags": {
        "key1": "VALUE_STRING1",
        "key2": "VALUE_STRING2"
      }
    };

    let mediaURL = "https://livesim.dashif.org/livesim/chunkdur_1/ato_7/testpic4_8s/Manifest.mpd";
    let isLive = true;

      if (mmdashjsPlugin.getRegistrationStatus() === false) {
        mmdashjsPlugin.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID",
          "SUBSCRIBER_ID",
          "DOMAIN_NAME",
          "SUBSCRIBER_TYPE",
          "SUBSCRIBER_TAG");
        mmdashjsPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", 'PLAYER_VERSION');        
      }
      
      mmdashjsPlugin.reportAppInfo("APP_NAME", "APP_VERSION");
      mmdashjsPlugin.setDeviceInfo("DEVICE_MARKETING_NAME");
      mmdashjsPlugin.reportExperimentName("EXPERIMENT_NAME");
      mmdashjsPlugin.reportSubPropertyId("SUB_PROPERTY_ID");         
      mmdashjsPlugin.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");

    mmdashjsPlugin.reportViewSessionId("VIEW_SESSION_ID");
    mmdashjsPlugin.initialize(player, mediaURL, mmVideoAssetInfo, isLive);
    player.initialize(document.querySelector("#videoPlayer"), mediaURL, true);    
  </script>
```


# MediaMelon React Player SDK with IMA

This guide provides detailed instructions on integrating the MediaMelon IMA SDK with the React Player

**Step 1:** [Prerequisites](#step-1-prerequisites)

**Step 2:** [Set up the build environment](#step-2-set-up-the-build-environment)

**Step 3:** [Import Packages](#step-3-import-packages)

**Step 4:** [Register and Initialise SDK](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 5:** [Report Ad Information](#step-5-report-a-d-information)

**Step 6:** [Report Ad Events](#step-6-report-a-d-events)

**Step 7:** [MMAdState](#step-7-mmadstate)

**Step 8:** [Variables and Description](#step-8-variables-and-description)

### Step 1: Prerequisites

* React Player Application.
* MediaMelon SmartSight SDK `mmsmartstreaming_reactplayer.min.js`   file is necessary.

### Step 2: Set up the build environment

**Using NPM:**

```bash
npm i mediamelon-react-sdk
```

### Step 3: Import Packages

**Using NPM:**

```javascript
import {MMReactPlayerSDK, MMIMAAdapter, MMAdState, MMAdInfo} from 'mediamelon-react-sdk';
```

**Using JS file:**&#x20;

```javascript
import {MMReactPlayerSDK, MMIMAAdapter, MMAdState, MMAdInfo} from './mmsmartstreaming_reactplayer.min.js'
```

### Step 4: Register and Initialise SDK <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The SDK must be initialised at the start of each video session. Initialisation includes setting the application context, initialising the playback session, and indicating the intent for playback with the SDK.

{% hint style="info" %}
The `enableLogTrace` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production.
{% endhint %}

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

Wrap your `Video` component with the `MMReactPlayerSDK`.

```javascript
const MMReactPlayerSDK = MMReactPlayerSDK(ReactPlayer);

<MMReactPlayerSDK
  ref={this.ref}
  playerRef={this.player}
  className='react-player'
  width='100%'
  height='100%'
  url={url}
  ...
  mmOptions={{
    register: {
      customerId: 'CUSTOMER_ID',      
      subscriberId: 'SUBSCRIBER_ID',   
      subscriberType: 'SUBSCRIBER_TYPE',
      subscriberTag:'SUBSCRIBER_TAG',  
      playerName: 'PLAYER_NAME',
      playerBrand:"PLAYER_BRAND",
      playerModel:"PLAYER_MODEL",
      playerVersion:'PLAYER_VERSION',
      basePlayerName: "BASE_PLAYER_NAME",
      basePlayerVersion: "BASE_PLAYER_VERSION",
      experimentName: "EXPERIMENT_NAME",
      subPropertyId: "SUB_PROPERTY_ID",
      viewSessionId: "VIEW_SESSION_ID",
      domainName: 'DOMAIN_NAME',
      applicationName: 'APP_NAME',            
      applicationVersion: 'APP_VERSION',      
      deviceMarketingName:'DEVICE_MARKETING_NAME'
    },
    contentMetadata: {
      assetName:'ASSET_NAME',
      assetId:"ASSET_ID",
      videoId:"VIDEO_ID",
      contentType:'CONTENT_TYPE',
      genre:'GENRE',
      drmProtection:'DRM_PROTECTION',
      episodeNumber:'EPISODE_NUMBER',
      season:'SEASON',
      seriesTitle:'SERIES_TITLE',                  
      isLive: false,
    },
    customTags:{
      "KEY1": "VALUE_STRING1",
      "KEY2": "VALUE_STRING2"
    },
    enableLogTrace:false
  }}
/>
```

### Step 5: Report Ad Information

```javascript
const mmAdAdapter = MMIMAAdapter();

const sdkAdInfo = MMAdInfo();
sdkAdInfo.adClient = "AD_CLIENT";
sdkAdInfo.adId = "AD_ID";
sdkAdInfo.adCreativeId = "CREATIVE_ID";
sdkAdInfo.adUrl = "AD_URL";
sdkAdInfo.adTitle = "AD_TITLE";
sdkAdInfo.adServer = "AD_SERVER";
sdkAdInfo.adCreativeType = "AD_CREATIVE_TYPE";
sdkAdInfo.adDuration = <ad_duration_in_seconds>;
sdkAdInfo.adPodLength = <ad_pod_length>;
sdkAdInfo.adIsLinear = <is_ad_linear_boolean>;

mmAdAdapter.reportAdInfo(sdkAdInfo);
```

### Step 6: Report Ad Events

```javascript
mmAdAdapter.reportAdEvent(<MMAdState>);
```

### Step 7: MMAdState

MMAdState Enum has the following fields:

* AD\_REQUEST
* AD\_IMPRESSION
* AD\_PLAY
* AD\_PLAYING
* AD\_MIDPOINT
* AD\_FIRST\_QUARTILE
* AD\_THIRD\_QUARTILE
* AD\_CLICKED
* AD\_PAUSED
* AD\_RESUMED
* AD\_SKIPPED
* AD\_ENDED
* AD\_COMPLETED
* AD\_ERROR
* AD\_BLOCKED
* AD\_BUFFERING


# MediaMelon JWPlayer SDK Integration Document

This guide is for integrating the MediaMelon Player SDK  for the javascript based  JWPlayer Web v8

### **Step 1: Add** the MediaMelonPlayer SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Add the following lines to the web page before JWPlayer js files are loaded.&#x20;

```javascript
  <script type="text/javascript" src="https://PATH_TO_MEDIAMELON_PLAYER_SDK/mmsmartstreaming_jwplayer.min.js"></script>

  <script type='text/javascript' src='https://cdn.jwplayer.com/libraries/YQo8ItYG.js'></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](http://40mediamelon.com/)
{% endhint %}

After the player instance has been created, create a new Plugin object, register, report player Info and then initialize the plugin as shown below:

```javascript
<!DOCTYPE html>
<html>
<head>
    <title>JWPlayer HTML5</title>

    <script type="text/javascript" src="./mmsmartstreaming_jwplayer.min.js"></script>
    <script type="text/javascript" src="https://cdn.jwplayer.com/libraries/YQo8ItYG.js"></script>
</head>

<body>
    <div id="player">Loading the player...</div>
    <script>

        // Setup the player
        var player = jwplayer('player').setup({
            "playlist": [
                {
                    "file": "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8",
                    "title": "TITLE",
                    "mmVideoAssetInfo": {
                        "assetName": "ASSET_NAME",
                        "assetId": "ASSET_ID",
                        "videoId": "VIDEO_ID",
                        "contentType": "CONTENT_TYPE",
                        "genre": "GENRE",
                        "drmProtection": "DRM_PROTECTION",
                        "episodeNumber": "EPISODE_NUMBER",
                        "season": "SEASON",
                        "seriesTitle": "SERIES_TITLE",
                        "videoType": "VIDEO_TYPE",
                        "customTags": {
                            "key1": "VALUE_STRING1",
                            "key2": "VALUE_STRING2"
                        }
                    }
                }]

        });

        //mmintegration
        var MMsdkAdapter = new JWPlayerMMSSIntgr();
        MMsdkAdapter.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG");
        MMsdkAdapter.reportPlayerInfo("BRAND", "MODEL", "VERSION");
        
        var isLive = false;    //Set this to true for a live stream or false for a VOD stream
        // If isLive is not set here, it will be handled internally by the SDK.
        MMsdkAdapter.init(player, isLive);
    </script>
</body>
</html>
```


# Kaltura Player Web with Mediamelon Analytics

This guide is for integrating the MediaMelon Player SDK   for the javascript based  Kaltura Web player.

### **Step 1: Add** the MediaMelon Player SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Include the following line to the web page at the start

```javascript
<script type="text/javascript" src="https://PATH_TO_SMARTSTREAMING_SDK"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>
{% endhint %}

After the player instance has been created, create a new Plugin object, register, report player Info and then initialize the plugin as shown below:

```html
<script>
  var mmVideoAssetInfo = {
    "assetName": "Lucifer",
    "assetId": "AssetId",
    "videoId": "videoId",
    "contentType": "contentType",
    "genre": "genre",
    "title": "title",
    "drmProtection": "none",
    "episodeNumber": "episodeNumber",
    "season": "season",
    "seriesTitle": "seriesTitle-On-Earth",      
    "customTags": {
      "Key1": "Value1",
      "Key2": "Value2"
    }
  };

  var config = {
    targetId: 'player-placeholder',
    "provider": {
      "partnerId": "1091",
      "uiConfId": "15215933"
    },
    sources: {
         hls: [
           {
             mimetype: 'application/x-mpegurl',
             url: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8',
             "mmVideoAssetInfo":mmVideoAssetInfo
           }
         ]
    }
  };

  try {
    var kalturaPlayer = KalturaPlayer.setup(config);
    // MediaMelon integration
    var kalturaPlugin = new KALTURAPlayerMMSSIntgr();
    if (kalturaPlugin.getRegistrationStatus() === false) {
      kalturaPlugin.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE11", "SUBSCRIBER_TAG");
      kalturaPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
    }

    var mediaUrl = "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8";
    var isLive = false;
    kalturaPlugin.initialize(kalturaPlayer, mediaUrl, mmVideoAssetInfo, isLive);

  } catch (e) {
    console.error(e.message);
  }
</script>
```


# Radiant Player Web

This guide is for integrating the MediaMelon Player SDK  for the javascript based  RadiantPlayer Web v7

### **Step 1: Add** the MediaMelonPlayer SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Add the following lines to the web page before RadiantPlayer js files are loaded.&#x20;

```javascript
  <script type="text/javascript" src="https://PATH_TO_MEDIAMELON_PLAYER_SDK/mmsmartstreaming_radiantplayer.min.js"></script>

 // Include Radiant Media Player - here we use the optimised build for Shaka player
  <script src="https://cdn.radiantmediatechs.com/rmp/7.10.0/js/rmp-shaka.min.js"></script>

 // Include Radiant Media Player - here we use the optimised build for hls.js
 // <script src="https://cdn.radiantmediatechs.com/rmp/7.10.0/js/rmp-hlsjs.min.js"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](http://40mediamelon.com/)
{% endhint %}

After the player instance has been created, create a new Plugin object, register, report player Info and then initialize the plugin as shown below:

```html
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
  <title>Radiant Media Player - Example</title>
</head>

<body>
  <script type='text/javascript' src='./mmsmartstreaming_radiantplayer.min.js'></script>

  <!-- Include Radiant Media Player - here we use the optimised build for Shaka player -->
  <script src="https://cdn.radiantmediatechs.com/rmp/7.10.0/js/rmp-shaka.min.js"></script>

  <!-- Include Radiant Media Player - here we use the optimised build for hls.js -->
  <!-- <script src="https://cdn.radiantmediatechs.com/rmp/5.3.5/js/rmp-hlsjs.min.js"></script> -->

  <!-- Player container -->
  <div id="rmpPlayer"></div>
  <script>
    var playlistData = [{
      src: {
        hls: "https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8"
      },
      poster: "https://www.radiantmediaplayer.com/media/playlist/poster/item-1.jpg",
      thumbnail: "https://www.radiantmediaplayer.com/media/playlist/poster/item-1-thumbnail.jpg",
      adTagUrl: "https://www.radiantmediaplayer.com/vast/tags/inline-linear.xml",
      contentTitle: "Playlist Item 1",
      contentDescription: "Description for playlist item 1",
      "mmVideoAssetInfo": {
        "assetName": "ASSET_NAME",
        "assetId": "ASSET_ID",
        "videoId": "VIDEO_ID",
        "contentType": "CONTENT_TYPE",
        "genre": "GENRE",
        "drmProtection": "DRM_PROTECTION",
        "episodeNumber": "EPISODE_NUMBER",
        "season": "SEASON",
        "seriesTitle": "SERIES_TITLE",
        "videoType": "VIDEO_TYPE",
        "customTags": {
          "key1": "VALUE_STRING1",
          "key2": "VALUE_STRING2"
        }
      }
    }];


    var settings = {
      licenseKey: 'ENTER_THE_LICENSE_KEY',
      skin: 's1',
      width: 640,
      height: 360,
      pathToRmpFiles: '../',
      playlistUpNextAutoplay: true,
      playlistEndedLoop: false,
      playlistData: playlistData
    };

    // init player
    var elementID = 'rmpPlayer';
    var rmp = new RadiantMP(elementID);
    rmp.init(settings);


    // MediaMelon integration
    var rmpPlugin = new mmRadiantJSAdapter();
    if (rmpPlugin.getRegistrationStatus() === false) {
      rmpPlugin.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG");
      rmpPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
    }
    
    var isLive = false;    //Set this to true for a live stream or false for a VOD stream
    // If isLive is not set here, it will be handled internally by the SDK.
    rmpPlugin.initialize(rmp, isLive);

  </script>
</body>

</html>
```


# Flow Player Web

This guide is for integrating the MediaMelon Player SDK  for the javascript based  Flow Player Web

### **Step 1: Add** the MediaMelonPlayer SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Add the following lines to the web page at the starting.&#x20;

```javascript
  <script type="text/javascript" src="https://PATH_TO_MEDIAMELON_PLAYER_SDK/mmsmartstreaming_flowjsplayer.min.js"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](http://40mediamelon.com/)
{% endhint %}

After the player instance has been created, create a new Plugin object, register, report player Info and then initialize the plugin as shown below:

```javascript
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FlowJS Player</title>

    <link rel="stylesheet" href="//cdn.flowplayer.com/releases/native/3/stable/style/flowplayer.css" />

    <script src="//cdn.flowplayer.com/releases/native/3/stable/default/flowplayer.min.js"></script>
    <script src="//cdn.flowplayer.com/releases/native/3/stable/plugins/hls.min.js"></script>
    <script src="./mmsmartstreaming_flowjsplayer.min.js"></script>
</head>

<body>
    <div id="player"></div>

    <script>
        var player = flowplayer("#player", {
            token: "eyJraWQiOiJxaEZ6dWR4dmJuTDMiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJjIjoie1wiYWNsXCI6NixcImlkXCI6XCJxaEZ6dWR4dmJuTDNcIixcImRvbWFpblwiOltcImZsb3dwbGF5ZXIuY29tXCJdfSIsImlzcyI6IkZsb3dwbGF5ZXIifQ.pdpIEfbRN_6P-ayyNsEazPPPjr0RSmd8SjJyqp8w8BYXTYsg11FjCODutzLZ6jkSm5hHTqfg05cCVuHcFIfI1w"
            , src: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8"
        })

        var mmVideoAssetInfo = {
            "assetName": "ASSET_NAME",
            "assetId": "ASSET_ID",
            "videoId": "VIDEO_ID",
            "contentType": "CONTENT_TYPE",
            "genre": "GENRE",
            "drmProtection": "DRM_PROTECTION",
            "episodeNumber": "EPISODE_NUMBER",
            "season": "SEASON",
            "seriesTitle": "SERIES_TITLE",
            "videoType": "VIDEO_TYPE",
            "customTags": {
                "key1": "VALUE_STRING1",
                "key2": "VALUE_STRING2"
            }
        };

        //registering to the MediaMelon plugin
        var mmFlowPlugin = new FlowJSMMSSIntgr();
        if (mmFlowPlugin.getRegistrationStatus() === false) {
            mmFlowPlugin.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID",
                "SUBSCRIBER_ID",
                "DOMAIN_NAME",
                "SUBSCRIBER_TYPE",
                "SUBSCRIBER_TAG");
            mmFlowPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", 'PLAYER_VERSION');
        }

        let mediaURL = "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8";
        let isLive = false;    //Set this to true for a live stream or false for a VOD stream
        // If isLive is not set here, it will be handled internally by the SDK.
        
        mmFlowPlugin.initialize(player, mediaURL, mmVideoAssetInfo, isLive);        
    </script>

</body>

</html>
```


# HbbTV SDK

This guide is for integrating the MediaMelon Player SDK  for the javascript based HbbTV Applications

### **Step 1: Add** the MediaMelonPlayer SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Import the MediaMelon SDK file in start of the resources.php file.

```php

$resources = array(
    "mmsmartstreaming_hbbtvplayer.min.js"
    .
    .
    .
);
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](http://40mediamelon.com/)
{% endhint %}

After the player instance has been created, create a new MediaMelon Plugin object, register, report player Info and then initialize the plugin as shown below:

```javascript
var mmVideoAssetInfo = {
		"assetName": "ASSET_NAME",
		"assetId": "ASSET_ID",
		"videoId": "VIDEO_ID",
		"contentType": "CONTENT_TYPE",
		"genre": "GENRE",
		"drmProtection": "DRM_PROTECTION",
		"episodeNumber": "EPISODE_NUMBER",
		"season": "SEASON",
		"seriesTitle": "SERIES_TITLE",
		"videoType": "VIDEO_TYPE",
		"customTags": {
			"key1": "VALUE_STRING1",
			"key2": "VALUE_STRING2"
		}
	};


// SDK integration for HTML5 video player component (src/videoplayer/videoplayer_html5.js)
var mmhtmljsPlugin = new Html5MMSSIntgr();
if (mmhtmljsPlugin.getRegistrationStatus() === false) {
	mmhtmljsPlugin.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID",
		"SUBSCRIBER_ID",
		"DOMAIN_NAME",
		"SUBSCRIBER_TYPE",
		"SUBSCRIBER_TAG");
	mmhtmljsPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", 'PLAYER_VERSION');
	mmhtmljsPlugin.reportAppInfo("APP_NAME", "APP_VERSION"); // optinal
	mmhtmljsPlugin.setDeviceInfo("DEVICE_MARKETING_NAME"); 	// optinal
	mmhtmljsPlugin.reportVideoQuality("VIDEO_QUALITY");	// optinal
}

mmhtmljsPlugin.initialize(player, "MEDIA_URL", mmVideoAssetInfo); // player -> Video Player Object


// SDK integration for OIPF AV object video player component (src/videoplayer/videoplayer_oipf.js)
var mmoipfjsPlugin = new OipfMMSSIntgr();
if (mmoipfjsPlugin.getRegistrationStatus() === false) {
	mmoipfjsPlugin.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID",
		"SUBSCRIBER_ID",
		"DOMAIN_NAME",
		"SUBSCRIBER_TYPE",
		"SUBSCRIBER_TAG");
	mmoipfjsPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", 'PLAYER_VERSION');
	mmoipfjsPlugin.reportAppInfo("APP_NAME", "APP_VERSION"); // optinal
	mmoipfjsPlugin.setDeviceInfo("DEVICE_MARKETING_NAME"); 	// optinal
	mmoipfjsPlugin.reportVideoQuality("VIDEO_QUALITY");	// optinal
}

mmoipfjsPlugin.initialize(self.video, "MEDIA_URL", mmVideoAssetInfo); // self.video -> Video Player Object


// SDK integration for MSE-EME video player component (src/videoplayer/videoplayer_mse-eme.js)
var mmdashjsPlugin = new DASHPlayerMMSSIntgr();
if (mmdashjsPlugin.getRegistrationStatus() === false) {
	mmdashjsPlugin.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID",
		"SUBSCRIBER_ID",
		"DOMAIN_NAME",
		"SUBSCRIBER_TYPE",
		"SUBSCRIBER_TAG");
	mmdashjsPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", 'PLAYER_VERSION');
	mmdashjsPlugin.reportAppInfo("APP_NAME", "APP_VERSION"); // optinal
	mmdashjsPlugin.setDeviceInfo("DEVICE_MARKETING_NAME"); 	// optinal
	mmdashjsPlugin.reportVideoQuality("VIDEO_QUALITY");	// optinal
}

mmdashjsPlugin.initialize(self.player, "MEDIA_URL", mmVideoAssetInfo); // self.player -> Video Player Object

```


# Castlabs Player Web

This guide is for integrating the MediaMelon Player SDK  for the javascript based  Castlabs Player Web

### **Step 1: Add** the MediaMelon Player SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Include the following line to the web page in the start

```javascript
<script type="text/javascript" src="https://PATH_TO_SMARTSTREAMING_SDK"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>
{% endhint %}

After the player instance has been created, create a new Plugin object, register, report player Info and then initialize the plugin as shown below:

```javascript
<script>
    const player = new clpp.Player('video', {
      license: '....',
      viewerId: '....'
    });


    let mmCastlabsPlugin = CastlabsMMSSJSIntgr();
    
    if (mmCastlabsPlugin.getRegistrationStatus() === false) {
      mmCastlabsPlugin.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID",
        "SUBSCRIBER_ID",
        "DOMAIN_NAME",
        "SUBSCRIBER_TYPE",
        "SUBSCRIBER_TAG");
      mmCastlabsPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", 'PLAYER_VERSION');
      mmCastlabsPlugin.enableLogTrace(false);
    }
    
    var mmVideoAssetInfo = {
      "assetName": "ASSET_NAME",
      "assetId": "ASSET_ID",
      "videoId": "VIDEO_ID",
      "contentType": "CONTENT_TYPE",
      "genre": "GENRE",
      "drmProtection": "DRM_PROTECTION",
      "episodeNumber": "EPISODE_NUMBER",
      "season": "SEASON",
      "seriesTitle": "SERIES_TITLE",
      "videoType": "VIDEO_TYPE",
      "customTags": {
        "key1": "VALUE_STRING1",
        "key2": "VALUE_STRING2"
      }
    };

    let mediaURL = "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8";

    mmCastlabsPlugin.initialize(player, mediaURL, mmVideoAssetInfo);
    player.load(mediaURL);
</script>
```


# Cordova Plugin Toast (Smart TV)

This guide is for integrating the MediaMelon Player SDK  for the javascript based  Cordova Plugin Toast (Tizen, WebOS, Orsay)

### **Step 1: Add** the MediaMelon Player SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Include the following line to the web page in the start

```javascript
<script type="text/javascript" src="https://PATH_TO_SMARTSTREAMING_SDK"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>
{% endhint %}

→**js/media.js:**

After the player instance has been created, create a new Plugin object, register, and report player information as shown below:

```javascript
function playMedia() {
    .....
    .....
    document.body.appendChild(bgContainer);

    // MediaMelon Start
    toastMMPlugin = new ToastJsMMSSIntgr();
    if(toastMMPlugin.getRegistrationStatus() === false){
        toastMMPlugin.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE" , "SUBSCRIBER_TAG");
        toastMMPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
    }
    var mediaSourceURL = 'http://media.w3.org/2010/05/sintel/trailer.mp4'';
    // MediaMelon End
    
    media = toast.Media.getInstance();
    media.open(mediaSourceURL);
```

You can also provide the Content Metadata like assetID, assetName, videoID, and custom tags as shown below while setting source information. Please use the mmVideoAssetInfo structure to provide this information.

And then initialize as shown below:

```javascript
.....
 addControlBar();
    
    // MediaMelon Start (Content Metadata)
      var mmVideoAssetInfo = {
            "assetName": "ASSET_NAME",
            "assetId": "ASSET_ID",
            "videoId": "VIDEO_ID",
            "contentType": "CONTENT_TYPE",
            "genre": "GENRE",
            "drmProtection": "DRM_PROTECTION",
            "episodeNumber": "EPISODE_NUMBER",
            "season": "SEASON",
            "seriesTitle": "SERIES_TITLE",
            "videoType": "VIDEO_TYPE",
            "customTags": {
              "key1": "VALUE_STRING1",
              "key2": "VALUE_STRING2"
            }
          };

    toastMMPlugin.initialize(mediaSourceURL, mmVideoAssetInfo);
    // MediaMelon End
    
    media.setListener({
        onevent: function(evt) {
        
        // MediaMelon Start
        toastMMPlugin.onToastEvent(evt);
        // MediaMelon End
         
            switch(evt.type) {
                case 'STATE':
.....
```

Add the call for reporting error to the Toast Plugin and just before media.play(), call the `reportUserInitiatedPlayback()`api.

```javascript
.....
        },
        onerror: function (err) {
            console.error('MediaError is occured: ' + JSON.stringify(err));
            document.getElementById('log').innerHTML = 'MediaError is occured';
            // MediaMelon Start
            toastMMPlugin.onToastError(err);
            // MediaMelon End
        }
    });
    
    // MediaMelon Start
    toastMMPlugin.reportUserInitiatedPlayback();
    // MediaMelon End
    media.play();
    //You don't have to call setScreenSaver Method. It is configurated by toast.avplay.
}
.....
```

### **Step 3: Toast Level Changes for Bitrate Support** <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

→ **toast.js:**

Please make the following changes toast.js for supporting bitrate change notifications. (**Applicable for sectv-tizen platform only.)**

Add the Media Events:

```javascript
.....
Media.EVENT_SUBTITLE = 'SUBTITLE';
Media.EVENT_ENDED = 'ENDED';

// MediaMelon Start
Media.EVENT_BITRATE_CHANGE = 'BITRATE_CHANGE';
Media.EVENT_RESOLUTION_CHANGE = 'RESOLUTION_CHANGE';
Media.EVENT_TRACKINFO_CHANGE = 'TRACKINFO_CHANGE';
// MediaMelon End
//Media.MEDIA_SUBTITLE = 5;

.....
```

Add the respective Media Event handling in Media.mediaEvent() function:

```javascript
.....
       case Media.EVENT_SUBTITLE :
            media._mediaEventCallBack.onevent && media._mediaEventCallBack.onevent(value);
            break;
            
        // MediaMelon Start
        case Media.EVENT_BITRATE_CHANGE :
            media._mediaEventCallBack.onevent && media._mediaEventCallBack.onevent(value);
            break;
        case Media.EVENT_RESOLUTION_CHANGE :
            media._mediaEventCallBack.onevent && media._mediaEventCallBack.onevent(value);
            break;
        case Media.EVENT_TRACKINFO_CHANGE :
            media._mediaEventCallBack.onevent && media._mediaEventCallBack.onevent(value);
            break;
        // MediaMelon End
        
        case Media.EVENT_ENDED :
            media.stop();
.....
```

Add the following code in the getMediaEventValue() function:

```javascript
.....
    case Media._MEDIA_ERROR :
        reval = {
            'type': type,
            'data': data
        };
        break;
        
    // MediaMelon Start
    case Media.EVENT_BITRATE_CHANGE :
        reval = {
            'type': type,
            'data': {
                'currentBitrate': data
            }
        };
        break;
    case Media.EVENT_RESOLUTION_CHANGE :
        reval = {
            'type': type,
            'data': {
                'currentResolution': data
            }
        };
        break;
    case Media.EVENT_TRACKINFO_CHANGE :
        reval = {
            'type': type,
            'data': {
                'trackInfos': data
            }
        };
        break;
    // MediaMelon End
    
    }
    return reval;
}
.....
```

Add the following code in the open: function(successCallback, errorCallback, args) function:

```javascript
.....
  oncurrentplaytime: function(currentTime) {
                    if(currentMediaState !== Media.STATE_PLAYING && currentTime > 0) {
                        Media.mediaEvent(id,getMediaEventValue(Media.EVENT_STATE,Media.STATE_PLAYING));
                    }
                    console.log('media::Current playtime: ' + currentTime);
                    Media.mediaEvent(id,getMediaEventValue(Media.EVENT_POSITION,currentTime));
                },
                onevent: function(eventType, eventData) {
                    console.log('media::Event type error: ' + eventType + ', eventData: ' + eventData);
                    
                    // MediaMelon Start
                    if (eventType === 'PLAYER_MSG_BITRATE_CHANGE') {
                        let currentBitrate = eventData.split(':')[1];
            		    console.log("MMSS Bitrate: " + currentBitrate);
                        Media.mediaEvent(id,getMediaEventValue(Media.EVENT_BITRATE_CHANGE,currentBitrate));
                    } else if (eventType === 'PLAYER_MSG_RESOLUTION_CHANGED') {
                        //Media.mediaEvent(id,getMediaEventValue(Media.EVENT_RESOLUTION_CHANGE,currentTime));
                    }
                    // MediaMelon End
                    
                },
                onerror: function(errorData) {
                    console.log('media::Event type error: ' + errorData);
                    Media.mediaEvent(id,getMediaEventValue(Media._MEDIA_ERROR,errorData));
                },
              .....
              .....
              .....
       function playMedia() {
            webapis.avplay.prepareAsync(function() {
              .....
              .....
                        }
                        /*jshint camelcase: true */
                        /*jscs:enable requireCamelCaseOrUpperCaseIdentifiers*/
                    }
                }
                
                // MediaMelon Start
                var totalTracks = webapis.avplay.getStreamingProperty("AVAILABLE_BITRATE");
                var bitrate_arr = totalTracks.split(":");
                var trackInfo = [];
                for(var i=0 ; i < bitrate_arr.length; i++){
                    trackInfo.push({'bitrate': bitrate_arr[i]});
                }                
                Media.mediaEvent(id,getMediaEventValue(Media.EVENT_TRACKINFO_CHANGE, trackInfo));
                // MediaMelon End
                
                Media.mediaEvent(id, getMediaEventValue(Media.EVENT_STATE, Media.STATE_PLAYING));
                var duration = webapis.avplay.getDuration();
                .....
                .....
```

This concludes the changes needed to integrate MediaMelon’s SDK into Samsung and LG SmartTVs using the Cordova Toast plugin.


# Plyr Player Web with MediaMelon Analytics

This guide is for integrating the MediaMelon Player SDK for the javascript based  Plyr Web player.

### **Step 1: Add** the MediaMelon Player SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Include the following line to the web page at the start

```javascript
<script type="text/javascript" src="https://PATH_TO_SMARTSTREAMING_SDK"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>
{% endhint %}

After the player instance has been created, create a new Plugin object, register, report player Info, and then initialize the plugin as shown below:

```html
<!DOCTYPE html>
<html lang="en">
  <body>
    <script src="https://cdn.plyr.io/3.7.8/plyr.js"></script>      
    <link rel="stylesheet" href="https://cdn.plyr.io/3.7.8/demo.css">
    <script src="./mmsmartstreaming_plyrjsplayer.min.js"></script>
    <div class="grid">
      <main>
        <div id="container">
          <video controls crossorigin playsinline id="player">            
            <source
              src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4"
              type="video/mp4"
              size="720"
            />
          </video>
        </div>
      </main>
    </div>

    <script>
      var mmPlyrPlugin = new PlyrJSMMSSIntgr();

      const player = new Plyr('#player');
      
      var mmVideoAssetInfo = {
          "assetName": "ASSET_NAME11",
          "assetId": "ASSET_ID",
          "videoId": "VIDEO_ID",
          "contentType": "CONTENT_TYPE",
          "genre": "GENRE",
          "drmProtection": "DRM_PROTECTION",
          "episodeNumber": "EPISODE_NUMBER",
          "season": "SEASON",
          "seriesTitle": "SERIES_TITLE",
          "videoType": "VIDEO_TYPE",
          "customTags": {
            "key1": "VALUE_STRING1",
            "key2": "VALUE_STRING2"
          }
      };

      let isLive = false;
      let streamURL = "https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4";
      if (mmPlyrPlugin.getRegistrationStatus() === false) {
        mmPlyrPlugin.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE11", "SUBSCRIBER_TAG1234");
        mmPlyrPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", 'PLAYER_VERSION');
        mmPlyrPlugin.reportAppInfo("APP_NAME", "APP_VERSION");
        mmPlyrPlugin.setDeviceInfo("DEVICE_MARKETING_NAME");
        mmPlyrPlugin.reportVideoQuality("VIDEO_QUALITY");
        mmPlyrPlugin.reportDeviceId("DEVICE_ID");

        mmPlyrPlugin.initialize(player, streamURL, mmVideoAssetInfo, isLive);        
      }
    </script>    
  </body>
</html>
```


# VideoJS Web with Google DAI

### **Step 1: Add** the MediaMelon Player SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Include the following lines to the web page after  all video js player and Google IMA SDK files are loaded.&#x20;

```javascript
<script type="text/javascript" src="https://PATH_TO_SMARTSTREAMING_SDK"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](http://40mediamelon.com/)
{% endhint %}

We integrate the Media Melon SDK in 5 easy steps

Step 2.1 Specify asset information for MM SDK

Step 2.2 Create Video JS Plugin  Object

Step 2.3 Register SDK with Mediamelon data platform&#x20;

Step 2.4 Provide additional player information

Step 2.5 initialize Video JS IMA Plugin

These steps have been annotated in the code below

```javascript
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>VIDEO JS IMA</title>

<link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
</head>
<body>
  <h1>Video.js IMA Example Embed</h1>

 <video id="my_video_1" muted="muted" class="vjs-default-skin" controls preload="auto" width="640" height="268"></video>
 <script src="https://unpkg.com/video.js/dist/video.js"></script>
 <script src="https://cdn.jsdelivr.net/npm/videojs-contrib-hls.js@3.2.0/dist/videojs-contrib-hlsjs.min.js"></script> 
 <script type="text/javascript" src="//imasdk.googleapis.com/js/sdkloader/ima3_dai.js"></script>
 
 <script src="https://unpkg.com/@videojs/http-streaming/dist/videojs-http-streaming.js"></script>
 <script src="mmsmartstreamingsdk_videojs_ima.min.js"></script>
  
 <script>
    var player = videojs('my_video_1');
    var BACKUP_STREAM =
    'https://storage.googleapis.com/interactive-media-ads/media/bbb.m3u8'

    // Live stream asset key.
    var TEST_ASSET_KEY = "c-rArva4ShKVIAkNfy6HUQ";

    // VOD content source and video IDs.
    var TEST_CONTENT_SOURCE_ID = "2528370";
    var TEST_VIDEO_ID = "tears-of-steel";
    var videoElement;
    var adUiElement;
    var isAdBreak;
    var streamManager;

    function initPlayer() 
    { 
        videoElement = document.querySelector('video');
        streamManager = new google.ima.dai.api.StreamManager(videoElement);
        streamManager.addEventListener(
                [google.ima.dai.api.StreamEvent.Type.LOADED,
                google.ima.dai.api.StreamEvent.Type.ERROR,
                google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED,
                google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED],
                onStreamEvent,
                false);

 
            // Use requestLiveStream(TEST_ASSET_KEY, null) for Live Stream
            requestVODStream(TEST_CONTENT_SOURCE_ID, TEST_VIDEO_ID, null);
    }

    function requestVODStream(cmsId, videoId, apiKey) {
      var streamRequest = new google.ima.dai.api.VODStreamRequest();
      streamRequest.contentSourceId = cmsId;
      streamRequest.videoId = videoId;
      streamRequest.apiKey = apiKey;
      streamManager.requestStream(streamRequest);
    }

    function requestLiveStream(assetKey, apiKey) {
      var streamRequest = new google.ima.dai.api.LiveStreamRequest();
      streamRequest.assetKey = assetKey;
      streamRequest.apiKey = apiKey;
      streamManager.requestStream(streamRequest);
    }
    function onStreamEvent(e) {
        switch (e.type) {
          case google.ima.dai.api.StreamEvent.Type.LOADED:
            console.log('Stream loaded');
            player.textTracks().on('addtrack', function (e) {
            // find out if the new track is metadata
            var track = e.track;
            if (track.kind === 'metadata') {

              // a cuechange event fires when the player crosses over an ID3 tag
              track.on('cuechange', function () {
                let elemTrack = track.activeCues[0];

                if (elemTrack && elemTrack.value.data) {

                  var metadata = {};

                  metadata[elemTrack.value.key] = elemTrack.value.data;
                  metadata["duration"] = Infinity;
                  streamManager.onTimedMetadata(metadata);
                }

              });
            }
            });
            loadUrl(e.getStreamData().url);
            break;

          case google.ima.dai.api.StreamEvent.Type.ERROR:
            console.log('Error loading stream, playing backup stream.' + e);
            loadUrl(BACKUP_STREAM);
            break;

          case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:
            console.log('Ad Break Started FROM Customer');
            isAdBreak = true;
            break;

          case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:
            console.log('Ad Break Ended FROM Customer');
            isAdBreak = false;
            break;

          default:
            break;
        }
      }
  
    
    var options = {};
    
    //Step 2.1 Specify asset information for MM SDK
    var mmVideoAssetInfo = {
      "assetName":"Lucifer",
                    "assetId": "Lucifer-Netflix",
                    "videoId": "Lucifer-Netflix_India",
                    "contentType": "Comedy/Horror",
                    "genre" : "Comedy",
                    "title" : "Lucifer-Series",
                    "drmProtection": "none",
                    "episodeNumber": "799",
                    "season":"2",
                    "seriesTitle": "Lucifer-On-Earth",
                    "videoType" : "LIVE",
                    "customTags":{
                        "Key1": "Value1",
                        "Key2": "Value2"
                    }
             };
             
    // Initialize Player for Google DAI         
     initPlayer();
    //Step 2.2 Create MM Video JS Plugin  Object
    var mmvjs7Plugin = new VideoJSMMSSIntgr();
    //Step 2.3 Register SDK with Mediamelon data platform 
    if (mmvjs7Plugin.getRegistrationStatus() === false) {
        mmvjs7Plugin.registerMMSmartStreaming("Video JS IMA Player", "CUSTOMER_ID",
                                                "SAMPLE_SUBSCRIBER_ID",
                                                "SAMPLE_DOMAIN_NAME", 
                                                "SAMPLE_SUBSCRIBER_TYPE",
                                                "SAMPLE_SUBSCRIBER_TAG");
        //Step 2.4 Provide additional player information                                        
        mmvjs7Plugin.reportPlayerInfo("videojs-vhs", "vhs", '7');
    }
    function loadUrl(url) { 
      console.log('Loading:' + url);

        player.src({
        src : url,
        type: 'application/x-mpegURL',
        mmVideoAssetInfo: mmVideoAssetInfo
      });
      
       //Step 2.5 initialize Video JS IMA Plugin
        mmvjs7Plugin.initialize(player,url, mmVideoAssetInfo,streamManager);     
        player.play();
    }

  </script>
  
</body>
</html>


```


# MediaMelon Web Kaltura Player Plugin Integration Document

This guide provides detailed instructions on integrating the MediaMelon Plugin into a Kaltura player based Web Media Player Application

[**Step 1:** Import Frameworks](#step-1-install-the-npm-package)

[**Step 2:** Register MediaMelon Plugin](#step-2-register-mediamelon-plugin)

[**Step 3:** Configure and Initialise MediaMelon SDK](#step-3-configure-and-initialise-mediamelon-sdk)

### Step 1: Install the NPM Package

**package link:** <https://www.npmjs.com/package/mm-kaltura-sdk>

```javascript
npm install mm-kaltura-sdk
```

### Step 2: Register MediaMelon Plugin

Register the MediaMelon Plugin in the start file

```typescript
import { registerPlugin } from '@playkit-js/kaltura-player-js';
import { pluginName, MediaMelonKPPlugin } from './mediamelon-plugin';

registerPlugin(pluginName, MediaMelonKPPlugin);
```

### Step 3: Configure and Initialise MediaMelon SDK

```javascript
const config = {
    logLevel: 'DEBUG',
    targetId: 'player-placeholder',
    provider: {},
    playback: {
      autoplay: true
    },
    ui: {
      translations: {
        en: {
          'plugin-example': {
            greeting: 'Welcome'
          }
        }
      }
    },
    plugins: {
      mediaMelonKPPlugin: {            
        customerId: 'CUSTOMER_ID',
        domainName: 'DOMAIN_NAME',
        subscriberTag: 'SUBSCRIBER_TAG',
        subscriberId: 'SUBSCRIBER_ID',
        subscriberType: 'SUBSCRIBER_TYPE',
        playerName: 'PLAYER_NAME',
        playerVersion: 'PLAYER_VERSION',
        playerBrand: 'PLAYER_BRAND',
        playerModel: 'PLAYER_MODEL',
        videoAssetInfo: {
          assetId: 'ASSET_ID',
          assetName: 'ASSET_NAME',
          videoId: 'VIDEO_ID',
          seriesTitle: 'SERIES_TITLE',
          episodeNumber: 'EPISODE_NUMBER',
          season: 'SEASON',
          contentType: 'CONTENT_TYPE',
          drmProtection: 'DRM_PROTECTION',
          genre: 'GENRE',
        },
        appName: 'APP_NAME',
        appVersion: 'APP_VERSION',
        deviceMarketingName: 'DEVICE_MARKETING_NAME',
        videoQuality: 'VIDEO_QUALITY',
        deviceId: 'DEVICE_ID',
        videoQuality: "VIDEO_QUALITY",
        customTags: {
          'KEY1' : "VALUE1",
          'KEY2' : "VALUE2"
        }
      }
    }
  };

  const player = KalturaPlayer.setup(config);
```

<table data-header-hidden><thead><tr><th width="296">Variable</th><th>Description</th></tr></thead><tbody><tr><td>Variable</td><td>Description</td></tr><tr><td>PLAYER_NAME</td><td>String containing the Player Name.</td></tr><tr><td>CUSTOMER_ID</td><td>String containing your MediaMelon-assigned Customer ID.</td></tr><tr><td>SUBSCRIBER_ID</td><td>String containing your Subscriber’s ID. If you do not use subscriber IDs, enter null</td></tr><tr><td>DOMAIN_NAME</td><td>String containing your section of your subscriber or assets.</td></tr><tr><td>SUBSCRIBER_TYPE</td><td>String containing the Subscriber Type (e.g. “Free”, “Paid”). If you do not use subscriber types, enter null</td></tr><tr><td>SUBSCRIBER_TAG</td><td>String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field.</td></tr><tr><td>ASSET_ID</td><td>String containing Asset Id.</td></tr><tr><td>ASSET_NAME</td><td>String containing Asset Name.</td></tr><tr><td>VIDEO_ID</td><td>String containing your video’s ID. If you do not use videos IDs, enter null.</td></tr><tr><td>CONTENT_TYPE</td><td>String containing type of the Content. For example - "Movie", "Special", "Clip", "Scene Epis Lifts".</td></tr><tr><td>GENRE</td><td>String containing Genre of the content. For example - "Comedy", "Horror".</td></tr><tr><td>DRM_PROTECTION</td><td>Widevine, Fairplay, Playready etc. Unknown means content is protected, but protection type is unknown. For clear contents, do not set this field</td></tr><tr><td>EPISODE_NUMBER</td><td>String containing sequence number of the Episode.</td></tr><tr><td>SEASON</td><td>String containing the Season. For example - "Season1".</td></tr><tr><td>SERIES_TITLE</td><td>String containing Title of the Series.</td></tr><tr><td>CUSTOM_TAGS</td><td>Extra custom metadata can be added here if required.</td></tr><tr><td>PLAYER_BRAND</td><td>String containing Player Brand.</td></tr><tr><td>PLAYER_MODEL</td><td>String containing Player Model. For example - This could be a variant of player. Say name of third party player used by organisation. Or any human readable name of the player.</td></tr><tr><td>PLAYER_VERSION</td><td>String containing Player Version.</td></tr></tbody></table>


# NexPlayer Web v4

This guide is for integrating the MediaMelon Player SDK   for the javascript based  NexPlayer Web v4

### **Step 1: Add** the MediaMelon Player SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Include the following lines to the web page before nexplayer js files are loaded

```javascript
<script type="text/javascript" src="https://PATH_TO_SMARTSTREAMING_SDK/mmsmartstreaming-nexplayer-sdk.js"></script>
<script src="https://nexplayer.nexplayersdk.com/4.2/nexplayer.js"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](http://40mediamelon.com/)
{% endhint %}

After the player instance has been created, create a new Plugin object, register, report player Info and then initialize the plugin as shown below:

```javascript
<!DOCTYPE html>
<html>
<head>
    ...
    ...
    ...
</head>

<body>
    <h1>NexPlayer HTML5</h1>
    ...
    ...
    <script src="path to your Mediamelon SDK file"></script>
    <script src="https://nexplayer.nexplayersdk.com/latest/nexplayer.js"></script>
    
    <script type="text/javascript">
    let nexPlayer_wrapper = new NEXPlayerJSMMSSIntgr();

        if(nexPlayer_wrapper.getRegistrationStatus() === false){
            nexPlayer_wrapper.registerMMSmartStreaming(<player_name>,<customer_id>, <subscriber_id>,<domain_name>, <subscriber_type>, <subscriber_tag>);
            nexPlayer_wrapper.reportPlayerInfo(<player_brand>,<player_model>,<player_version>);
        };
      var   mmVideoAssetInfo= {
                    "assetName":"$AssetName / $EpisodeName / $ContentTitle",
                    "assetId": "$AssetID",
                    "videoId": "$VideoID",
                    "contentType": "$Genre",
                    "drmProtection": "$DrmType",
                    "episodeNumber": "$EpisodeNumber",
                    "season":"$SeasonNumber",
                    "seriesTitle": "$Series Title",
                    "customTags":{
                        "Key1": "Value1",
                        "Key2": "Value2"
                    }
                  };
                  
        let mmAssetData = {
         "mmVideoAssetInfo" : mmVideoAssetInfo
      };

  let callBackWithPlayers = function (nexplayerInstance, videoElement) {
      nexPlayer_wrapper.initialize(nexplayerInstance,videoElement,mmAssetData.mmVideoAssetInfo);
  }
        nexplayer.Setup({
            key: <Enter your key here>,
            div: document.getElementById('player'),
            src: <Enter link to your video/stream/mediaSource>,
            callbacksForPlayer: callBackWithPlayers,
        });

    </script>
</body>
</html>
```


# ChromeCast Player

This guide is for integrating the MediaMelon Player SDK  for the javascript based  CastPlayer Web

### **Step 1: Add** the MediaMelonPlayer SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Add the MediaMelon SDK in the receivers application html file as shown in the below code snippet.&#x20;

```javascript
<script src="//www.gstatic.com/cast/sdk/libs/devtools/debug_layer/caf_receiver_logger.js"></script>

//MediaMelon SDK Integration Start
<script src="https://PATH_TO_MEDIAMELON_PLAYER_SDK/mmsmartstreaming_chromecastplayer.min.js"></script>
//MediaMelon SDK Integration Stop

<script src="js/receiver.js" type="module"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](http://40mediamelon.com/)
{% endhint %}

After the player instance has been created, create a new Plugin object, register, report player Info and then initialize the plugin as shown below:

```javascript
//MediaMelon SDK Integration Start
import { CastRecvAdapter } from './mmsmartstreaming_chromecastplayer.min.js';
//MediaMelon SDK Integration Stop
.
.
const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();

//MediaMelon SDK Integration Start
var castMM = new CastRecvAdapter();
if (castMM.getRegistrationStatus() === false) {
  castMM.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE");
  castMM.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
}
castMM.initialize(playerManager);
//MediaMelon SDK Integration Stop
```

### Step 3: Adding Asset Information or Custom MetaData

Sender application has to set the a extra "mmVideoAssetInfo" object in the chrome.cast.media.MediaInfo while sending chrome.cast.media.LoadRequest() as shown in below code snippet.

```javascript
    let mediaInfo = new chrome.cast.media.MediaInfo(MEDIA_SOURCE_ROOT + this.mediaContents[mediaIndex]['contentUrl'], this.mediaContents[mediaIndex]['contentType']);
    mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED;
    mediaInfo.metadata = new chrome.cast.media.TvShowMediaMetadata();
    mediaInfo.metadata.title = this.mediaContents[mediaIndex]['title'];
    mediaInfo.metadata.subtitle = this.mediaContents[mediaIndex]['subtitle'];
    mediaInfo.metadata.images = [{
      'url': MEDIA_SOURCE_ROOT + this.mediaContents[mediaIndex]['thumb']
    }];

    //MediaMelon SDK Integration Start
    mediaInfo.mmVideoAssetInfo = {
        "assetName": "ASSET_NAME",
        "assetId": "ASSET_ID",
        "videoId": "VIDEO_ID",
        "contentType": "CONTENT_TYPE",
        "genre": "GENRE",
        "drmProtection": "DRM_PROTECTION",
        "episodeNumber": "EPISODE_NUMBER",
        "season": "SEASON",
        "seriesTitle": "SERIES_TITLE",
        "videoType": "VIDEO_TYPE",
        "customTags": {
          "key1": "VALUE_STRING1",
          "key2": "VALUE_STRING2"
        }
    };
    //MediaMelon SDK Integration Stop

    let request = new chrome.cast.media.LoadRequest(mediaInfo);
```

| Variable         | Description                                                                                                                                                                          |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| PLAYER\_NAME     | String containing the Player Name                                                                                                                                                    |
| CUSTOMER\_ID     | String containing your MediaMelon-assigned Customer ID.                                                                                                                              |
| SUBSCRIBER\_ID   | String containing your Subscriber’s ID. If you do not use subscriber IDs, enter null                                                                                                 |
| DOMAIN\_NAME     | String containing your section of your subscriber or assets. (Optional)                                                                                                              |
| SUBSCRIBER\_TYPE | String containing the Subscriber Type (e.g. “Free”, “Paid”). If you do not use subscriber types, enter null                                                                          |
| SUBSCRIBER\_TAG  | String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field. |
| ASSET\_ID        | String containing Asset Id.                                                                                                                                                          |
| ASSET\_NAME      | String containing Asset Name.                                                                                                                                                        |
| VIDEO\_ID        | String containing your video’s ID. If you do not use videos IDs, enter null.                                                                                                         |
| CONTENT\_TYPE    | String containing type of the Content. For example - "Movie", "Special", "Clip", "Scene Epis Lifts".                                                                                 |
| GENRE            | String containing Genre of the content. For example - "Comedy", "Horror".                                                                                                            |
| DRM\_PROTECTION  | Widevine, Fairplay, Playready etc. Unknown means content is protected, but protection type is unknown. For clear contents, do not set this field                                     |
| EPISODE\_NUMBER  | String containing sequence number of the Episode.                                                                                                                                    |
| SEASON           | String containing the Season. For example - "Season1".                                                                                                                               |
| SERIES\_TITLE    | String containing Title of the Series.                                                                                                                                               |
| VIDEO\_TYPE      | String containing Video Type. For example - "LIVE", "VOD".                                                                                                                           |
| CUSTOM\_TAGS     | Extra custom metadata can be added here if required. If extra metadata is not required, enter null.                                                                                  |
| PLAYER\_BRAND    | String containing Player Brand                                                                                                                                                       |
| PLAYER\_MODEL    | String containing Player Model. For example - This could be a variant of player. Say name of third party player used by organisation. Or any human readable name of the player.      |
| PLAYER\_VERSION  | String containing Player Version                                                                                                                                                     |


# Comcast PDK 6

This guide is for integrating the MediaMelon Player SDK  for the javascript based  Comcast PDK Web Version 6.4.5

### **Register and Initialize** the MediaMelon Player SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](http://40mediamelon.com/)
{% endhint %}

Add the MediaMelon SDK Path, Customer ID, Subscriber Information and Video Asset Information in the HTML file as shown below:

```html
<div id="player" class="tpPlayer" tp:fp.bgcolor="0x131313" tp:wmode="direct" tp:logLevel="debug"
        tp:plugin_mmpdk="priority=1|
        URL=PATH_TO_MEDIAMELON_SDK|
        CUSTID=CUTOMER_ID|
        SUBSCRIBER_ID=SUBSCRIBER_ID|
        SUBSCRIBER_TYPE=SUBSCRIBER_TYPE|
        SUBSCRIBER_TAG=SUBSCRIBER_TAG|
        DOMAIN_NAME=DOMAIN_NAME|
        PLAYER_NAME=PLAYER_NAME|
        deferred=false|
        VIDEO_ID=VIDEO_ID|
        CONTENT_TYPE=CONTENT_TYPE|
        DRM_PROTECTION=DRM_PROTECTION|
        EPISODE_NUMBER=EPISODE_NUMBER|
        GENRE=GENRE|
        SEASON=SEASON|
        ASSET_NAME=ASSET_NAME|
        ASSET_ID=ASSET_ID|
        SERIES_TITLE=SERIES_TITLE|
        TRACE=true">
</div>
```

| Variable                  | Description                                                                                                                                                                          |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| PATH\_TO\_MEDIAMELON\_SDK | String containing AWS S3 url provided by MediaMelon.                                                                                                                                 |
| PLAYER\_NAME              | String containing the Player Name.                                                                                                                                                   |
| CUSTOMER\_ID              | String containing your MediaMelon-assigned Customer ID.                                                                                                                              |
| SUBSCRIBER\_ID            | String containing your Subscriber’s ID. If you do not use subscriber IDs, enter null                                                                                                 |
| DOMAIN\_NAME              | String containing your section of your subscriber or assets. (Optional)                                                                                                              |
| SUBSCRIBER\_TYPE          | String containing the Subscriber Type (e.g. “Free”, “Paid”). If you do not use subscriber types, enter null                                                                          |
| SUBSCRIBER\_TAG           | String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field. |
| ASSET\_ID                 | String containing Asset Id.                                                                                                                                                          |
| ASSET\_NAME               | String containing Asset Name.                                                                                                                                                        |
| VIDEO\_ID                 | String containing your video’s ID. If you do not use videos IDs, enter null.                                                                                                         |
| CONTENT\_TYPE             | String containing type of the Content. For example - "Movie", "Special", "Clip", "Scene Epis Lifts".                                                                                 |
| GENRE                     | String containing Genre of the content. For example - "Comedy", "Horror".                                                                                                            |
| DRM\_PROTECTION           | Widevine, Fairplay, Playready etc. Unknown means content is protected, but protection type is unknown. For clear contents, do not set this field                                     |
| EPISODE\_NUMBER           | String containing sequence number of the Episode.                                                                                                                                    |
| SEASON                    | String containing the Season. For example - "Season1".                                                                                                                               |
| SERIES\_TITLE             | String containing Title of the Series.                                                                                                                                               |
| VIDEO\_TYPE               | String containing Video Type. For example - "LIVE", "VOD".                                                                                                                           |


# Custom Player Web SDK

This guide is for integrating the JavaScript-based MediaMelon Custom Player Web SDK

### **Step 1: Add** the MediaMelon SDK Files <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Add the following lines to the web page before player files are loaded.&#x20;

```javascript
  <script type="text/javascript" src="https://PATH_TO_MEDIAMELON_SDK/mmsmartstreamingsdk.min.js"></script>
```

### **Step 2: Register and Initialize** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> as your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](http://40mediamelon.com/)
{% endhint %}

After the player instance has been created, create a new Plugin object, register, report player Info, and then initialize the plugin as shown below:

```javascript
var customPlugin = new mmCustomJSAdapter();

var mmVideoAssetInfo = {
   "assetName": "ASSET_NAME",
   "assetId": "ASSET_ID",
   "videoId": "VIDEO_ID",
   "contentType": "CONTENT_TYPE",
   "genre": "GENRE",
   "drmProtection": "DRM_PROTECTION",
   "episodeNumber": "EPISODE_NUMBER",
   "season": "SEASON",
   "seriesTitle": "SERIES_TITLE",
   "videoType": "VIDEO_TYPE",
   "customTags": {
       "key1": "VALUE_STRING1",
       "key2": "VALUE_STRING2"
}

if(customPlugin.getRegistrationStatus() === false){
 customPlugin.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE" , "SUBSCRIBER_TAG");
 customPlugin.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
}
 
customPlugin.reportAppInfo("APP_NAME", "APP_VERSION");
customPlugin.setDeviceInfo("DEVICE_ID", "DEVICE_MARKETING_NAME");
customPlugin.reportVideoQuality("VIDEO_QUALITY");

customPlugin.reportPresentationInfo(presentationType, presentationArray);

var isLive = false;    //Set this to true for a live stream or false for a VOD stream
customPlugin.initialize(mmVideoAssetInfo, streamURL, totalDuration, isLive);
```

> **Note:** **Presentation Info API**
>
> This API should send all the available video and audio qualities and it requires two parameters: `presentationType` and `presentationArray`. Variable `presentationType` is a Enum which describes whether the data is of Video or Audio.
>
> **Presentation Array Structure:**
>
> ```javascript
> [
>     {
>         "codec": "avc1.42001e",
>         "bandwidth": 493000,
>         "width": 224,
>         "height": 100 
>     },
>     {
>         "codec": "avc1.640028",
>         "bandwidth": 2468000,
>         "width": 1680,
>         "height": 750 
>     }
> ]
> ```

Enum values and their descriptions for the `presentationType` variable are as below;

<table><thead><tr><th width="326">Enum value</th><th>Description</th></tr></thead><tbody><tr><td>PRESENTATIONTYPE.VIDEO</td><td>If the presentation data is about video track then send this enum value in the API</td></tr><tr><td>PRESENTATIONTYPE.AUDIO</td><td>If the presentation data is about audio track then send this enum value in the API</td></tr></tbody></table>

### **Step 3: API to Report Video Progress**  <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

This API should be triggered every 1 second. It requires an object as a parameter that contains information like playback position, current bitrate, and resolution in the form of width & height. The same API should be used for content progress reporting and Ad progress reporting.

```javascript
var progressObject = {
    "playbackPosition": 10, //playback position should be in milliseconds
    "bitrate": 12000,
    "width": 208,
    "height": 100
}
customPlugin.reportTimeUpdate(progressObject);
```

### **Step 4: APIs that can be Triggered when Required** <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

#### Report State:&#x20;

Trigger this API when a state change occurs in the player. This API requires an Enum value as a parameter that represents the current state of the player or the action that happened to the player.

```javascript
var state = PLAYERSTATE.PLAYING;
customPlugin.reportStateChange(state);
```

Enum values that can be sent as a parameter in the reportStateChange API as described below;

<table><thead><tr><th width="406">Enum Value</th><th>Description</th></tr></thead><tbody><tr><td>PLAYERSTATE.MANIFEST_LOAD_START</td><td>When the manifest load started. Not required if the video doesn't support manifest.</td></tr><tr><td>PLAYERSTATE.MANIFEST_LOAD_COMPLETE</td><td>When the manifest load is completed successfully. </td></tr><tr><td>PLAYERSTATE.PLAYING</td><td>When the video starts playing. It might be the first play or play after a pause.</td></tr><tr><td>PLAYERSTATE.PAUSE</td><td>When the video is paused.</td></tr><tr><td>PLAYERSTATE.SEEK_START</td><td>When the video seek starts.</td></tr><tr><td>PLAYERSTATE.SEEK_COMPLETE</td><td>When the video seek completes.</td></tr><tr><td>PLAYERSTATE.BUFFER_START</td><td>When the video buffering starts.</td></tr><tr><td>PLAYERSTATE.BUFFER_COMPLETE</td><td>When the video buffering completes.</td></tr><tr><td>PLAYERSTATE.ENDED</td><td>When the video is ended.</td></tr><tr><td>PLAYERSTATE.AD_BREAK_STARTED</td><td>When the Ad break started.</td></tr><tr><td>PLAYERSTATE.AD_IMPRESSION</td><td>When the Ad impression occurs.</td></tr><tr><td>PLAYERSTATE.AD_STARTED</td><td>When the Ad started.</td></tr><tr><td>PLAYERSTATE.AD_FIRST_QUARTILE</td><td>When Ad reached 25% of its duration.</td></tr><tr><td>PLAYERSTATE.AD_MIDPOINT</td><td>When Ad reached 50% of its duration.</td></tr><tr><td>PLAYERSTATE.AD_THIRD_QUARTILE</td><td>When Ad reached 75% of its duration.</td></tr><tr><td>PLAYERSTATE.AD_SKIPPED</td><td>When Ad skipped.</td></tr><tr><td>PLAYERSTATE.AD_CLICKED</td><td>When Ad clicked.</td></tr><tr><td>PLAYERSTATE.AD_COMPLETED</td><td>When Ad completed.</td></tr><tr><td>PLAYERSTATE.AD_STOPPED</td><td>When the Ad stopped in between without completion.</td></tr><tr><td>PLAYERSTATE.AD_BREAK_STOPPED</td><td>When the Ad break ended.</td></tr></tbody></table>

#### Report Ad Data:

Trigger this API to report the Ad data before an Ad break. This API requires a `adTimelineArray` parameter that should contain all the Ad details of the upcoming Ad break.&#x20;

If the upcoming Ad break contains 4 Ads then the adTimelineArray should contain all 4 ad details.

```javascript
var adTimelineArray = [
    {
        "adClient": "mmAds-Nowtilus",
        "adId": "11023407",
        "adDuration": 15000,    // Ad duration should be in milliseconds
        "adPosition": ADPOSITION.MID,
        "adLinear": "linear",
        "adCreativeType": "hls",
        "adSystem": "SMART AdServer",
        "isBumper": false,
        "adTitle": "Washing Machine Ad",
        "adUrl": "adurl.com",
        "adCreativeId": "14738"
    }
];

customPlugin.reportAdTimelineData(adTimelineArray);
```

Enum values and descriptions for ADPOSITION are mentioned below;

| Enum            | Description              |
| --------------- | ------------------------ |
| ADPOSITION.PRE  | Represents pre Ad break  |
| ADPOSITION.MID  | Represents mid Ad break  |
| ADPOSITION.POST | Represents post Ad break |

#### Report Error:

Trigger this API when an error occurs in the player, content, Ad, or application. This API requires three parameters that are error message, error code, and error type.

```javascript
var errorType = ERRTYPE.FATAL;
customPlugin.reportError("ERROR_MESSAGE", "ERROR_CODE", errorType);
```

Enum values and their descriptions for the error type variable are as below;

<table><thead><tr><th width="326">Enum value</th><th>Description</th></tr></thead><tbody><tr><td>ERRTYPE.FATAL</td><td>If the error type is fatal</td></tr><tr><td>ERRTYPE.WARNING</td><td>If the error type is warning</td></tr></tbody></table>

**Report Track:**

Trigger this API when a track change occurs in Audio, Video, or Subsitle tracks. This API requires two parameters: track type and current track.

Also, trigger this API when the video starts playing to report initial Audio, Video, and Subtitle tracks.

```javascript
var trackType = TRACK.AUDIO;
customPlugin.reportTrackChange(trackType, "CURRENT_TRACK");
```

Enum values and their descriptions for the track type variable are as below;

| Enum Value     | Description                                                              |
| -------------- | ------------------------------------------------------------------------ |
| TRACK.SUBTITLE | If reporting the subtitle track information, send this as the trackType. |
| TRACK.AUDIO    | If reporting the audio track information, send this as the trackType.    |
| TRACK.VIDEO    | If reporting the video track information, send this as the trackType.    |

#### Report Volume:

Trigger this API when a volume change occurs in the player. Send the volume value in percentage as shown below;

```javascript
customPlugin.reportVolumeChange(76);
```


# Android SDK


# MediaMelon Android Custom SDK Integration Document

This guide provides detailed instructions on integrating the Android MediaMelon Custom SDK .

**Step 1:** [Set Up Build Environment](#step-1-set-up-the-build-environment)

**Step 2:** [Register and Initialize the SDK](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 3:** [Report Custom Metadata](#step-3-report-custom-metadata)

**Step 4:** [Report Playback Events](#step-4-report-playback-events)

**Step 5:** [Report Stream and Network Related Information](#step-5-report-stream-and-network-related-information)

**Step 6:** [Report Request Status and Fallback Events](#step-3-initialize-session-and-report-user-intent-to-playback-8)

**Step 7:** [Report Ad Events](#step-7-report-a-d-events)

**Step 8:** [Report Custom Events](#step-8-report-custom-events)

[Release Notes](#release-notes)

### Step 1: Set up the build environment&#x20;

#### **Step 1.1: Add Gradle Dependency:**

1. Add MediaMelon SDK gradle dependency to `app/build.gradle`

```gradle
dependencies {
   ...
  implementation 'com.github.MediamelonSDK:mm-java-custom-sdk:1.2.11'
}
```

#### Step 1.2 Provide Permissions

Add network permissions to `AndroidManifest.xml`

```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

#### Step 1.3: Import Packages

```java
import com.mediamelon.core.qubit.ChunkStatus;
import com.mediamelon.core.qubit.ChunkType;
import com.mediamelon.core.qubit.DeviceInfo;
import com.mediamelon.core.qubit.ManifestStatus;
import com.mediamelon.core.qubit.Rendition;
import com.mediamelon.core.qubit.ep.AdInfo;
import com.mediamelon.core.qubit.ep.ContentMetadata;
import com.mediamelon.core.qubit.RequestStatus;
import com.mediamelon.wrapper.smartstreaming.MMPlayerState;
import com.mediamelon.wrapper.smartstreaming.custom_sdk.MMSmartStreamingMedia3;
```

### Step 2: Register and Initialise SDK <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The player application must register the SDK and provide player information once the player is initialized. Please note that values provided in this integration step persist across video sessions.

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production.

`MMSmartStreamingMedia3.enableLogTrace(false);`
{% endhint %}

#### Step 2.1:  Set Context

Set the application context

```java
MMSmartStreamingMedia3.setContext(applicationContext)
```

#### Step 2.2: Register SDK

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```java
MMSmartStreamingMedia3.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG", true);
```

#### Step 2.3: Report Player Information

```java
MMSmartStreamingMedia3.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
```

#### Step 2.4: Report Base Player Information

```java
MMSmartStreamingMedia3.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.5: Report Application Information

```java
MMSmartStreamingMedia3.reportAppInfo("APP_NAME","APP_VERSION");
```

#### Step 2.6: Report Device Information

```java
MMSmartStreamingMedia3.reportDeviceInfo(deviceInfo);
```

<details>

<summary>Device Info Object Description</summary>

<table><thead><tr><th width="161.60546875">Parameter</th><th width="116.296875">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>brand</td><td>String</td><td>Company or Brand to which the device belongs. Ex:  Samsung</td></tr><tr><td>deviceModel</td><td>String</td><td>Model Identifier of the device. Ex: SM-1921</td></tr><tr><td>deviceType</td><td>String</td><td>The type of device. Ex: Smart TV</td></tr><tr><td>os</td><td>String</td><td>Operatin system name. Ex: Android, iOS, etc</td></tr><tr><td>osVersion</td><td>String</td><td>Operating system verion. Ex: 14, 18.2.0</td></tr><tr><td>telecomOperator</td><td>String</td><td>Telecom operator currently used.</td></tr><tr><td>screenWidth</td><td>String</td><td>Screen width of the device</td></tr><tr><td>screenHeight</td><td>String</td><td>Screen height of the device</td></tr></tbody></table>

</details>

#### Step 2.7: Initialize session with Content Metadata

```java
ContentMetadata contentMetadata  = new ContentMetadata();
    contentMetadata.assetName="ASSET_NAME";
    contentMetadata.assetId="ASSET_ID";
    contentMetadata.videoId="VIDEO_ID";
    contentMetadata.seriesTitle="SERIES_TITLE";
    contentMetadata.season="SEASON";
    contentMetadata.genre="GENRE";
    contentMetadata.episodeNumber="EPISODE_NUMBER";
    contentMetadata.drmProtection="DRM_PROTECTION";
    contentMetadata.contentType="CONTENT_TYPE";
    
    MMSmartStreamingMedia3.initializeSession(cm);
    MMSmartStreamingMedia3.reportUserInitiatedPlayback();
```

<details>

<summary>Content Metadata Object Description</summary>

<table><thead><tr><th width="148.34765625">Parameter</th><th width="117.17578125">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>assetId</td><td>String</td><td>Unique identifier for the video asset.</td></tr><tr><td>assetName</td><td>String</td><td>Human-readable name or title of the video asset.</td></tr><tr><td>videoId</td><td>String</td><td>Unique identifier for the video content. It can be the same as <strong>Asset ID</strong> or a different logical ID used in your system.</td></tr><tr><td>seriesTitle</td><td>String</td><td>Title of the series to which the episode belongs.</td></tr><tr><td>season</td><td>String</td><td>Name or number of the season (e.g., "Season 1", "S2").</td></tr><tr><td>genre</td><td>String</td><td>Genre of the content, such as "Drama", "Comedy", "Documentary", etc.</td></tr><tr><td>episodeNumber</td><td>String</td><td>Episode number within a season. Useful for TV series or episodic content.</td></tr><tr><td>contentType</td><td>String</td><td>The category or type of content, e.g., "Movie", "Episode", "Clip", "LiveStream".</td></tr><tr><td>drmProtection</td><td>String</td><td>DRM technology used (e.g., “Widevine”, “FairPlay”, “PlayReady”). Use “Unknown” if the content is protected, but the DRM type is unknown. Leave blank for clear (non-DRM) content.</td></tr></tbody></table>

</details>

#### Step 2.8: Report Experiment Name

```java
MMSmartStreamingMedia3.reportExperimentName("EXPERIMENT_NAME");
```

#### Step 2.9: Report View Session Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

{% hint style="info" %}
Report the View Session Id attribute after `initializeSession` and before `reportUserInitiatedPlayback`.&#x20;
{% endhint %}

```java
MMSmartStreamingMedia3.reportViewSessionId("VIEW_SESSION_ID");
```

#### Step 2.10: Report Sub Property Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

{% hint style="info" %}
Report the Sub Property ID attribute after `initializeSession` and before `reportUserInitiatedPlayback`.&#x20;
{% endhint %}

```java
MMSmartStreamingMedia3.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.11: Report Preload

{% hint style="info" %}
Report the preload attribute after `initializeSession` and before `reportUserInitiatedPlayback`. The preload value is reset inside `initializeSession`, so reporting it before this method will be ignored. If you report it after `reportUserInitiatedPlayback`, the first event will not contain the preload field.
{% endhint %}

```java
MMSmartStreamingMedia3.reportPreload(preload);// preload -> boolean
```

#### Step 2.12: Report App Session ID

Report Application Session ID

```java
MMSmartStreamingMedia3.reportAppSessionId("APP_SESSION_ID");
```

#### Step 2.13: Report Device ID

```java
MMSmartStreamingMedia3.reportDeviceId("DEVICE_ID");
```

#### Step 2.14 Report Device Marketing Name

```java
MMSmartStreamingMedia3.reportDeviceMarketingName("DEVICE_MARKETING_NAME");
```

### Step 3: Report Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```java
MMSmartStreamingMedia3.reportCustomMetadata("custom_1","VALUE_1");
MMSmartStreamingMedia3.reportCustomMetadata("custom_2","VALUE_2");
```

### Step 4: Report Playback Events

#### Step 4.1: Report Player State <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

Report the player state using the following function.

```java
MMSmartStreamingMedia3.reportPlayerState(MMPlayerState.PLAYING);
```

<details>

<summary>MMPlayerState</summary>

<table><thead><tr><th width="210.51953125">MMPlayerState</th><th>Description</th></tr></thead><tbody><tr><td>PLAYING</td><td>Report when video starts playing froma paused state or on first frame rendered</td></tr><tr><td>PAUSED</td><td>Report when video paused</td></tr><tr><td>STOPPED</td><td>Report when user exits the video playback</td></tr></tbody></table>

</details>

#### Step 4.2: Report Buffering Events

```java
//buffering start
MMSmartStreamingMedia3.reportBufferingStarted();

//buffering complete
MMSmartStreamingMedia3.reportBufferingCompleted();
```

#### Step 4.3: Report Seek Events

```java
//seek started
MMSmartStreamingMedia3.reportSeekStarted();
      
//seek completed
MMSmartStreamingMedia3.reportSeekCompleted();
```

#### Step 4.4: Report Errors

```java
MMSmartStreamingMedia3.reportError(ERROR_CODE_INT, "ERROR_MESSAGE", "ERROR_DETAILS");
```

#### Step 4.5: Report Warnings

```java
MMSmartStreamingMedia3.reportWarning(WARNING_INT, "WARNING_MESSAGE", "WARNING_DETAILS");
```

#### Step 4.6: Report Playback Position

```java
MMSmartStreamingMedia3.reportPlaybackPosition(playbackPositionInMs)
```

### Step 5: Report Stream and Network Related Information

#### Step 5.1: Report Stream URL  <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

Report stream URL that is currently being used.

```java
MMSmartStreamingMedia3.setStreamURL("STREAM_URL");
```

#### Step 5.2: Report Video Duration <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
MMSmartStreamingMedia3.reportVideoDuration(inMilliSeconds);
```

#### Step 5.3: Report Stream Information

Report Information related to the stream

```java
MMSmartStreamingMedia3.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE", isLive);
```

#### Step 5.4:  Report Network Information <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
MMSmartStreamingMedia3.reportNetworkInfo("CDN", "ASN", "HOST_NAME", "NETWORK_TYPE", "NETWORK_OPERATOR"); 
```

{% hint style="info" %}
Use the **`reportNetworkInfo`** API to report the CDN along with other network information.\
If additional network information is not available, use **`reportCDN`** instead.
{% endhint %}

#### Step 5.5: Report CDN

```java
MMSmartStreamingMedia3.reportCDN("CDN");
```

#### Step 5.6:  Report Track Information <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
MMSmartStreamingMedia3.reportTrackInfo("AUDIO_TRACK", "SUBTITLE_TRACK", isSubtitleActive, isVDSActive, "VIDEO_TRACK");
```

#### Step 5.7: Report Rendition

Report changes in the rendition of the current stream  wrapped in the `Rendition` object.

```java
MMSmartStreamingMedia3.reportRendition(renditionObject);
```

<details>

<summary>Rendition Object</summary>

<table><thead><tr><th width="144.796875">Parameter</th><th width="168.09765625">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>bitrate</td><td>int</td><td>Current bitrate at which the video is playing</td></tr><tr><td>width</td><td>int</td><td>current width of the video</td></tr><tr><td>height</td><td>int</td><td>current height of the video</td></tr><tr><td>frameRate</td><td>double</td><td>current frame rate of the video</td></tr><tr><td>aCodec</td><td>String</td><td>current Audio Codec of video</td></tr><tr><td>vCodec</td><td>String</td><td>current Video Codec of video</td></tr></tbody></table>

</details>

#### Step 5.7: Update DRM Type

```java
MMSmartStreamingMedia3.updateDRMType("DRM_TYPE");
```

#### Step 5.8: Report Player Download Rate

Report Player download rate in bps

```java
MMSmartStreamingMedia3.reportPlayerDownloadRate(bps) //  bps -> Long 
```

#### Step 5.9: Report Frame Loss

```java
MMSmartStreamingMedia3.reportFrameloss(frameloss) // frameloss -> Int
```

#### Step 5.10: Report Encoding Service

```java
MMSmartStreamingMedia3.reportEncodingService("ENCODING_SERVICE");
```

### Step 6: Report Request Status and Fallback Events <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

#### Step 6.1: Report Request Status

```java
MMSmartStreamingMedia3.reportRequestStatus(RequestStatus, "REQUEST_TYPE", map); // map -> Map<String, String>
```

<details>

<summary>RequestStatus (Enum)</summary>

| Request Status | Description                   |
| -------------- | ----------------------------- |
| FAILED         | Report on a failed request    |
| CANCELLED      | Report on a cancelled request |

</details>

#### Step 6.2: Report Fallback event

Report fallback events in case a fallback strategy is applied.

```java
MMSmartStreamingMedia3.reportFallbackEvent("STREAM_URL", "DESCRIPTION");
```

#### Step 6.3: Update Content Metadata

```java
MMSmartStreamingMedia3.updateContentMetadata(cm);
```

#### Step 6.4: Update Subscriber Info

```java
MMSmartStreamingMedia3.updateSubscriberInfo("SUB_ID_NEW", "SUB_TYPE_NEW", "SUB_TAG_NEW");
```

### Step 7: Report Ad Events

#### Step 7.1: Report Ad Start and End

```java
MMSmartStreamingMedia3.reportAdBreakStarted();
MMSmartStreamingMedia3.reportAdBreakEnded();
MMSmartStreamingMedia3.reportAdStarted(adInfoObject);
MMSmartStreamingMedia3.reportAdEnd();
```

<details>

<summary>AdInfo Object</summary>

<table><thead><tr><th width="160.1796875">Parameter</th><th width="117.765625">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>adClient</td><td>String</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adId</td><td>String</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adDuration</td><td>Double</td><td>The total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>adPosition</td><td>String</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adCreativeType</td><td>String</td><td>The format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>adServer</td><td>String</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adResolution</td><td>String</td><td>The resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>adPodIndex</td><td>int</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adPositionInPod</td><td>int</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>isBumper</td><td>Boolean</td><td>A boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr><tr><td>adCreativeId</td><td>String</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adUrl</td><td>String</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adTitle</td><td>String</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adBitRate</td><td>int</td><td>Bitrate at which the ad is playing</td></tr><tr><td>adTimeStamp</td><td>Long</td><td>Timestamp of ad as received</td></tr></tbody></table>

</details>

#### Step 7.2: Report Ad Buffering:

Use Ad Buffering APIs to report any buffering that occurs during ad playback. For any buffering event, either content buffering or ad buffering should be reported, but not both.

```java
MMSmartStreamingMedia3.reportAdBufferingStarted();
MMSmartStreamingMedia3.reportAdBufferingCompleted();
```

### Step 8: Report Custom Events

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```javascript
MMSmartStreamingMedia3.reportCustomEvent("EVENT_NAME", "EVENT_VALUE");
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 30 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

### Release Notes

<details>

<summary>Current Release</summary>

#### v1.2.11[^1]  <sup><sub>`Mar 27, 2026`<sub></sup>

* Added support for reporting a new field encoding service via `reportEncodingService`.
* Introduced custom event reporting through `reportCustomEvent`.
* Added support for ad buffering events:
  * `reportAdBufferingStarted`
  * `reportAdBufferingCompleted`
* Improved event handling to restrict event reporting after playback has ended.

</details>

***

<details>

<summary>Previous Releases</summary>

#### v1.2.10

* **Skip Release**

#### v1.2.[^1]9  <sup><sub>`Feb 6, 2026`<sub></sup>

* Added an additional API to report CDN alone.
* Added `CDN_CHANGE` event.
* Added Internal functionality to report seek duration.

#### [**v1.2.8**](#user-content-fn-2)[^2]  <sup><sub>`Dec 20, 2025`<sub></sup>

* Added Api to report frame loss
* Added Api to report Device ID
* Added Api to report Device Marketing Name
* Internal Improvements for Device Info and Network Info
* Improved bitrate reporting for weighted average bitrate calculation
* Updated internal SDK version format

#### v**1.2.7**  <sup><sub>`Dec 3, 2025`<sub></sup>

* Preload field addition
* App Session Id field addition
* Fix to consider Exit in Buffering
* New metrics to enable upscale and downscale %s for bitrate and resolution
* Improved failed and offline payloads queueing

#### v**1.2.6**  <sup><sub>`Oct 31, 2025`<sub></sup>

* CPU optimisation
* fix: ENDED event in case of EBVS

</details>

[^1]: **Performance Report:** [here](https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/android/android-custom-sdk-performance-metrics)

[^2]: **Performance Report:** [here](https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/android/android-custom-sdk-performance-metrics)


# MediaMelon Android Multiplayer Custom SDK Integration Document

This guide provides detailed instructions on integrating the Android MediaMelon Custom SDK .

**Step 1:** [Prerequisites and Setup](#step-1-prerequisites-and-setup)

**Step 2:** [Instantiate and Register SDK](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 3:** [Initialize Playback Session](#step-3-initialize-playback-session)

**Step 4:** [Report Custom Metadata](#step-4-report-custom-metadata)

**Step 5:** [Report Playback Events](#step-3-initialize-session-and-report-user-intent-to-playback-3)

**Step 6:** [Report Stream and Track Related Events](#step-3-initialize-session-and-report-user-intent-to-playback-4)

**Step 7:** [Report Request Status and Fallback Events](#step-3-initialize-session-and-report-user-intent-to-playback-8)

**Step 8:** [Report Ad Events](#step-8-report-a-d-events)

**Step 9:** [Report Custom Events](#step-9-report-custom-events)

**Step 10:** [Destroy SDK](#step-10-destroy-sdk)

[Release Notes](#release-notes)

### Step 1: Prerequisites and Setup

#### **Step 1.1: Add Gradle Dependency:**

1. Add MediaMelon SDK Gradle dependency to `app/build.gradle`

{% tabs %}
{% tab title="Maven" %}

```java
dependencies {
   ...
  implementation 'com.github.MediamelonSDK:mm-java-custom-sdk:2.2.5'
}
```

{% endtab %}
{% endtabs %}

#### Step 1.2: Provide Manifest Permissions

Add network permissions.

```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

#### Step 1.3: Import Packages

```java
import com.mediamelon.core.qubit.DeviceInfo;
import com.mediamelon.core.qubit.Rendition;
import com.mediamelon.core.qubit.ep.AdInfo;
import com.mediamelon.core.qubit.ep.ContentMetadata;
import com.mediamelon.wrapper.smartstreaming.MMIntegrationWrapper;
import com.mediamelon.wrapper.smartstreaming.MMPlayerState;
import com.mediamelon.wrapper.smartstreaming.custom_sdk.MMSmartStreamingMedia3;
```

### Step 2: Instantiate and Register SDK <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The player application must register the SDK and provide Player Information once the player is initialized. Please note that the values configured during this integration step persist across all subsequent video sessions for that SDK instance.

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production.

`MMSmartStreamingMedia3.enableLogTrace(false);`
{% endhint %}

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

#### Step 2.1: Create SDK instance&#x20;

For every Player Instance create a new SDK Instance.

```java
MMIntegrationWrapper sdkInstance = MMSmartStreamingMedia3.getInstance(); 
```

#### Step 2.2:  Set Context

Set the application context

```java
sdkInstance.setContext(applicationContext)
```

#### Step 2.3: Register SDK

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```java
sdkInstance.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG", true);
```

#### Step 2.4: Report Player ID

```java
sdkInstance.reportPlayerId("PLAYER_ID");
```

#### Step 2.5: Report Player Information

```java
sdkInstance.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
```

#### Step 2.6: Report Base Player Information

```java
sdkInstance.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.7: Report Application Information

```java
sdkInstance.reportAppInfo("APP_NAME","APP_VERSION");
```

#### Step 2.8: Report Device Information

```java
sdkInstance.reportDeviceInfo(deviceInfo);
```

<details>

<summary>Device Info Object Description</summary>

| Parameter           | Data Type |
| ------------------- | --------- |
| deviceMarketingName | String    |
| brand               | String    |
| deviceModel         | String    |
| deviceId            | String    |
| os                  | String    |
| osVersion           | String    |
| telecomOperator     | String    |
| screenWidth         | String    |
| screenHeight        | String    |
| deviceCapabilities  | String    |

</details>

#### Step 2.9: Report Sub Property Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
sdkInstance.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.10: Report App Session Id

Report Application Session ID

```java
sdkInstance.reportAppSessionId("APP_SESSION_ID");
```

### Step 3: Initialize Playback Session

The SDK must be initialized at the start of each video session. Initialization includes reporting Content Metadata and indicating the intent for playback with the SDK.

#### Step 3.1: Initialize Session with Content Metadata

Initialize the session with Content Metadata.

```java
ContentMetadata contentMetadata  = new ContentMetadata();
contentMetadata.assetName="ASSET_NAME";
contentMetadata.assetId="ASSET_ID";
contentMetadata.videoId="VIDEO_ID";
contentMetadata.seriesTitle="SERIES_TITLE";
contentMetadata.season="SEASON";
contentMetadata.genre="GENRE";
contentMetadata.episodeNumber="EPISODE_NUMBER";
contentMetadata.drmProtection="DRM_PROTECTION";
contentMetadata.drmLevel = "DRM_LEVEL"
contentMetadata.contentType="CONTENT_TYPE";
    
sdkInstance.initializeSession(contentMetadata);
```

<details>

<summary>Content Metadata Object Description</summary>

<table><thead><tr><th width="148.34765625">Parameter</th><th width="117.17578125">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>assetId</td><td>String</td><td>Unique identifier for the video asset.</td></tr><tr><td>assetName</td><td>String</td><td>Human-readable name or title of the video asset.</td></tr><tr><td>videoId</td><td>String</td><td>Unique identifier for the video content. It can be the same as <strong>Asset ID</strong> or a different logical ID used in your system.</td></tr><tr><td>seriesTitle</td><td>String</td><td>Title of the series to which the episode belongs.</td></tr><tr><td>season</td><td>String</td><td>Name or number of the season (e.g., "Season 1", "S2").</td></tr><tr><td>genre</td><td>String</td><td>Genre of the content, such as "Drama", "Comedy", "Documentary", etc.</td></tr><tr><td>episodeNumber</td><td>String</td><td>Episode number within a season. Useful for TV series or episodic content.</td></tr><tr><td>contentType</td><td>String</td><td>The category or type of content, e.g., "Movie", "Episode", "Clip", "LiveStream".</td></tr><tr><td>drmProtection</td><td>String</td><td>DRM technology used (e.g., “Widevine”, “FairPlay”, “PlayReady”). Use “Unknown” if the content is protected, but the DRM type is unknown. Leave blank for clear (non-DRM) content.</td></tr></tbody></table>

</details>

#### Step 3.2: Report Experiment Name

Report the experiment name as a String.

```java
sdkInstance.reportExperimentName("Experiment Name");
```

#### Step 3.3: Report View Session Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

{% hint style="info" %}
Report the View Session Id attribute after `initializeSession` and before `reportUserInitiatedPlayback`.&#x20;
{% endhint %}

```java
sdkInstance.reportViewSessionId("VIEW_SESSION_ID");
```

#### Step 3.4: Report Preload

{% hint style="info" %}
Report the preload attribute after `initializeSession` and before `reportUserInitiatedPlayback`. The preload value is reset inside `initializeSession`, so reporting it before this method will be ignored. If you report it after `reportUserInitiatedPlayback`, the first event will not contain the preload field.
{% endhint %}

```java
sdkInstance.reportPreload(preload);// preload -> boolean
```

#### Step 3.5: Report Player Resolution

```java
sdkInstance.reportPlayerResolution(playerWidth, playerHeight);
```

#### Step 3.6 Report User Initiated Playback

{% hint style="info" %}
This function indicates the intent for playback and must be reported after `initializeSession` .
{% endhint %}

```java
sdkInstance.reportUserInitiatedPlayback();
```

### Step 4: Report Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```java
sdkInstance.reportCustomMetadata("custom_1","VALUE_1");
sdkInstance.reportCustomMetadata("custom_2","VALUE_2");
```

### Step 5: Report Playback Events <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

#### Step 5.1: Report Player State

{% hint style="info" %}
Make sure to report ***MMPlayerState.STOPPED*** at the end of playback completion to mark session as ended.
{% endhint %}

```java
// Report Player State --> Playing, Paused, Stopped
sdkInstance.reportPlayerState(MMPlayerState.PLAYING);
```

<details>

<summary>MMPlayerState</summary>

| MMPlayerState |
| ------------- |
| PLAYING       |
| PAUSED        |
| STOPPED       |

</details>

#### Step 5.2: Report Buffering Events

```java
//buffering start
sdkInstance.reportBufferingStarted();

//buffering complete
sdkInstance.reportBufferingCompleted();
```

#### Step 5.3 Report Seek Events

```java
//seek started
sdkInstance.reportSeekStarted();
      
//seek completed
sdkInstance.reportSeekCompleted();
```

#### Step 5.4: Report Errors

```java
sdkInstance.reportError(ERROR_CODE_INT, "ERROR_MESSAGE", "ERROR_DETAILS");
```

#### Step 5.5: Report Warnings

```java
sdkInstance.reportWarning(WARNING_INT, "WARNING_MESSAGE", "WARNING_DETAILS");
```

#### Step 5.6: Report Playback Position

Report Playback position in ms.

```java
sdkInstance.reportPlaybackPosition(playbackpos);
```

### Step 6: Report Stream and Track Related Information <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

#### &#x20;Step 6.1: Report Stream URL <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

Report stream url that is currently being used.

```java
sdkInstance.setStreamURL("STREAM_URL");
```

#### Step 6.2: Report Stream  Information

Report Information related to stream

```java
sdkInstance.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE", isLive);
```

#### Step 6.3: Report Video Duration <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
sdkInstance.reportVideoDuration(inMilliSeconds);
```

#### Step 6.4 Report Network Info

```java
sdkInstance.reportNetworkInfo("CDN", "ASN", "HOST_NAME", "NETWORK_TYPE", "NETWORK_OPERATOR"); 
```

{% hint style="info" %}
Use the **`reportNetworkInfo`** API to report the CDN along with other network information.\
If additional network information is not available, use **`reportCDN`** instead.
{% endhint %}

#### Step 6.5: Report CDN

```java
MMSmartStreamingMedia3.reportCDN("CDN");
```

#### Step 6.6:  Report Track Related Information <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
sdkInstance.reportTrackInfo("AUDIO_TRACK", "SUBTITLE_TRACK", isSubtitleActive, isVDSActive, "VIDEO_TRACK");
```

#### Step 6.7: Report Rendition Changes

Report changes in the rendition of current stream wrapped in the `Rendition` object.

```java
sdkInstance.reportRendition(renditionObject);
```

<details>

<summary>Rendition Object</summary>

| Parameter | Data Type |
| --------- | --------- |
| bitrate   | int       |
| width     | int       |
| height    | int       |
| frameRate | double    |
| aCodec    | String    |
| vCodec    | String    |

</details>

#### Step 6.8: Update DRM Type

{% hint style="warning" %}
This API has been deprecated. Please refer [Step 7.3](#step-7.3-update-drm) for updated API.
{% endhint %}

```java
sdkInstance.updateDRMType("DRM_TYPE");
```

#### Step 6.9: Report Player Download Rate

Report Player download rate in bps

```java
sdkInstance.reportPlayerDownloadRate(bps) //  bps -> Long 
```

#### Step 6.10: Report Frame Loss

```java
sdkInstance.reportFrameloss(frameloss) // frameloss -> Int
```

#### Step 6.11: Report Encoding Service

```java
sdkInstance.reportEncodingService("ENCODING_SERVICE");
```

### Step 7:  Report Request Status and Fallback Events <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

#### Step 7.1: Report Request Status

```java
sdkInstance.reportRequestStatus(RequestStatus, "REQUEST_TYPE", map); // map -> Map<String, String>
```

<details>

<summary>Request Status (Enum)</summary>

| Request Status | Description                   |
| -------------- | ----------------------------- |
| FAILED         | Report on a failed request    |
| CANCELLED      | Report on a cancelled request |

</details>

#### Step 7.2: Report Stream Fallback event

Report fallback events in case a fallback strategy is applied.&#x20;

```java
sdkInstance.reportFallbackEvent("FALLBACK_STREAM_URL", "DESCRIPTION");
```

#### Step 7.3: Update DRM

```java
sdkInstance.updateDRM("DRM_TYPE", "DRM_LEVEL");
```

#### Step 7.4: Update Content Metadata

```java
sdkInstance.updateContentMetadata(cm);
```

#### Step 7.5: Update Subscriber Information

```java
sdkInstance.updateSubscriberInfo("SUBSCRIBER_ID", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG");
```

### Step 8: Report Ad Events

#### Step 8.1: Report Ad Start and End

{% hint style="info" %}
`reportAdBreakStarted` and `reportAdBreakEnded` APIs now can be reported with an optional Map\<String, Object> as param.
{% endhint %}

```java
sdkInstance.reportAdBreakStarted(map);
sdkInstance.reportAdBreakEnded();
sdkInstance.reportAdStarted(adInfoObject);
sdkInstance.reportAdEnd();
```

<details>

<summary>AdInfo Object</summary>

<table data-header-hidden><thead><tr><th width="238.8984375">Field</th><th>Description</th></tr></thead><tbody><tr><td>adInfo.adTitle</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adInfo.adId</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adInfo.adCreativeId</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adInfo.adCreativeType</td><td>The format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>adInfo.adClient</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adInfo.adPosition</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adInfo.adServer</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adInfo.adResolution</td><td>The resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>adInfo.adUrl</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adInfo.adDuration</td><td>The total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>adInfo.adPodIndex</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adInfo.adPositionInPod</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>adInfo.adPodLendth</td><td>The total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr><tr><td>adInfo.isBumper</td><td>A boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr><tr><td>adInfo.adUniversalId</td><td>A String value to report Ad Universal ID.</td></tr></tbody></table>

</details>

#### Step 8.2: Report Ad Buffering:

Use Ad Buffering APIs to report any buffering that occurs during ad playback. For any buffering event, either content buffering or ad buffering should be reported, but not both.

```java
sdkInstance.reportAdBufferingStarted();
sdkInstance.reportAdBufferingCompleted();
```

#### Step 8.3: Report Ad Events:

Use the `reportAdEvent` function to report all Ad events.

{% hint style="info" %}
`reportAdStarted` and `reportAdEnd` are kept as it is for backward compatibility, but going forward, all the new Integrations should use the  `reportAdEvent` API for all ad states.
{% endhint %}

```java
sdkInstance.reportAdEvent(MMAdEvent, adInfoObject);
```

<details>

<summary><strong>MMAdEvent (Enum)</strong></summary>

| Ad Event            | Description                                           |
| ------------------- | ----------------------------------------------------- |
| AD\_START           | Report on ad start.                                   |
| AD\_FIRST\_QUARTILE | Report on ad reached first quartile.                  |
| AD\_MID\_POINT      | Report on ad reached midpoint.                        |
| AD\_THIRD\_QUARTILE | Report on ad reached third quartile.                  |
| AD\_SKIP            | Report on ad skipped.                                 |
| AD\_END             | Report on ad ended.                                   |
| AD\_COMPLETE        | Report on ad ended and ad play time greater than 95%. |
| AD\_CLICK           | Report on ad clicked.                                 |

</details>

#### Step 8.4: Report Ad Request and Response

Report Ad Request and Ad Response using the following API:

{% hint style="info" %}
Both of these APIs requires Map\<String, Object> as parameter to report ad data.&#x20;
{% endhint %}

```java
sdkInstance.reportAdRequest(requestMap); 
sdkInstance.reportAdResponse(responseMap);
```

#### Step 8.5: Report Ad Errors and Warnings

Report Ad Error :

```java
sdkInstance.reportAdError(AD_ERROR_CODE_INT, "AD_ERROR_MESSAGE", "AD_ERROR_DESCRIPTION");
```

Report Ad Warnings :

```java
sdkInstance.reportAdWarning(AD_WARNING_CODE_INT, "AD_WARNING_MESSAGE", "AD_WARNING_DESCRIPTION");
```

### Step 9: Report Custom Events

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```javascript
sdkInstance.reportCustomEvent("EVENT_NAME", "EVENT_VALUE");
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 30 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

### Step 10: Destroy SDK

Release the SDK resource by destroying the SDK Instance using the following method:&#x20;

{% hint style="info" %}
Use this only when the player object is destroyed.
{% endhint %}

```java
sdkInstance.destroy()
```

#### Release Notes

<details>

<summary>Current Release</summary>

#### v2.2.[^1]5  <sup><sub>`Jul 28, 2026`<sub></sup>

* Crash fix added for NPE in case of unstable network on sim carrier

</details>

***

<details>

<summary>Previous Releases</summary>

#### v2.2.4[^1]  <sup><sub>`Jul 20, 2026`<sub></sup>

* Added `destroy()`  method to release the sdk resources.

#### v2.2.3[^2]  <sup><sub>`Jul 13, 2026`<sub></sup>

* Added queue size limit for event queue and dead letter queue.
* Added additional exception handling for corner cases.

#### v2.2.2[^2]  <sup><sub>`Jul 7, 2026`<sub></sup>

* Internal optimisation for event queueing.

#### v2.2.1[^2]  <sup><sub>`Jul 1, 2026`<sub></sup>

* Added retry handling for socket timeout exceptions.

#### v2.2.0[^2]  <sup><sub>`Jun 29, 2026`<sub></sup>

* Enhanced Internal SDK data reporting
  * Added batch-based data reporting with configurable reporting intervals.
  * Improved reliability with exponential backoff retries, jitter, request timeouts, and Dead Letter Queue (DLQ) support.
  * Enabled remote configuration for batch size, reporting interval, retry settings, and the batching feature flag.
* Added new APIs for reporting ad events, including quartiles, request/response, errors, warnings, skip, and click events.
* Added support for reporting device capabilities through DeviceInfo.

#### v2.1.4[^3]  <sup><sub>`Jun 19, 2026`<sub></sup>

* Updated proguard rules as fix for build pipeline failure.

#### v2.1.3[^4]  <sup><sub>`Apr 30, 2026`<sub></sup>

* Added missing methods in the wrapper `updateSubscriberInfo` and `updateContentMetadata` .

#### v2.1.2[^4]  <sup><sub>`Apr 14, 2026`<sub></sup>

* Initial release with Multi-Player support.
* New Field `playerID` addition and API to report it via `reportPlayerId` .
* New Field `drmLevel` addition in `contentMetadata`.
* Deprecated `updateDrmType` API. Added new API called `updateDRM` to update DRM Protection and DRM Level.
* New Field `adUniversalId` addition in `AdInfo` Object.
* Added `deviceMarketingName` and  `deviceId` in the `DeviceInfo` object.
* Buffering events exceeding the stats interval are now included in the stats payload.<br>

</details>

[^1]: Performance Report: [here](https://docs.mediamelon.com/mediamelon-sdk-performance-metrics/android/android-multiplayer-custom-sdk-performance-metrics)​

[^2]: Performance Report: [here](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/android/pages/ixxiubK0IMhscBqIxMAG#v2.2.0)

[^3]: Performance Report: [here](https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/android/android-multiplayer-custom-sdk-performance-metrics)

[^4]: **Performance Report:** [here](https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/android/android-multiplayer-custom-sdk-performance-metrics)


# MediaMelon Android Media3 SDK Integration Document

This guide provides detailed instructions on integrating the Android MediaMelon SDK with the Media3 player

**Step 1:** [Set up the build environment](#step-1-set-up-the-build-environment)

**Step 2:** [Register and Initialise SDK](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 3:** [Report Custom Metadata](#step-3-report-custom-metadata)

**Step 4:** [Report Ended State](#step-5-report-ended-state-when-the-player-instance-is-released)

**Step 5:** [Report Errors and Warnings](#step-5-report-errors-and-warnings)

**Step 6:** [Report Stream Level Information](#step-6-report-stream-level-information)

**Step 7:** [Update Asset Information](#step-7-update-asset-information)

[Release Notes](#release-notes)

### Step 1: Set up the build environment&#x20;

> `$MEDIA3PROJECT = {Media3 - v1.x.x}`

The SDK files should be added to the build environment, and the required network permissions should be enabled.

#### **Step 1.1: Add Gradle Dependency:**

**Using Maven:**

1. Add MediaMelon Media3 Maven dependency to `main/build.gradle`

{% tabs %}
{% tab title="1.7.1" %}

```java
dependencies {
   ...
  implementation 'com.github.MediamelonSDK:mm-android-sdk-media3:v1.7.1-2.4.0'
}
```

{% endtab %}

{% tab title="1.4.1" %}

```java
dependencies {
   ...
  implementation 'com.github.MediamelonSDK:mm-android-sdk-media3:v1.4.1-2.4.0'
}
```

{% endtab %}

{% tab title="1.3.1" %}

```gradle
dependencies {
   ...
  implementation 'com.github.MediamelonSDK:mm-android-sdk-media3:1.2.1'
}
```

{% endtab %}
{% endtabs %}

**Using AAR:**&#x20;

1. Copy `mmsmartstreaming.aar` provided in the release package for the Media3 project. Example  `$MEDIA3PROJECT/demos/main/mmsmartstreaming.aar` .
2. Add the following library to `$MEDIA3PROJECT/demos/main/build.gradle` :-

```gradle
dependencies {
  ...
  api files ('mmsmartstreaming.aar')
}
```

#### Step 1.2: Add Permissions

Add network permissions to `$MEDIA3PROJECT/demos/main/src/main/AndroidManifest.xml`

```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

#### Step 1.3: Import Packages

`$MEDIA3PROJECT/demos/main/src/main/java/androidx/media3/demo/main/PlayerActivity.java`

```java
import com.mediamelon.qubit.ep.ContentMetadata;
import com.mediamelon.smartstreaming.media3.MMSmartStreamingMedia3;
```

### Step 2: Register and Initialise SDK <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The player application must register the SDK and provide player information once the player is initialized. Please note that values provided in this integration step persist across video sessions.

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production.

```java
MMSmartStreamingMedia3.enableLogTrace(true);
```

{% endhint %}

#### Step 2.1:  Set Context

Set the application context

```java
MMSmartStreamingMedia3.setContext(applicationContext)
```

#### Step 2.2: Register SDK

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```java
MMSmartStreamingMedia3.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG", true);
```

#### Step 2.3: Report Player Information

```java
MMSmartStreamingMedia3.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
```

#### Step 2.4: Report Base Player Information

```java
MMSmartStreamingMedia3.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.5: Report Application Information

```java
MMSmartStreamingMedia3.reportAppInfo("APP_NAME","APP_VERSION");
```

#### Step 2.6: Initialize session with Content Metadata

```java
ContentMetadata contentMetadata  = new ContentMetadata();
contentMetadata.assetName="ASSET_NAME";
contentMetadata.assetId="ASSET_ID";
contentMetadata.videoId="VIDEO_ID";
contentMetadata.seriesTitle="SERIES_TITLE";
contentMetadata.season="SEASON";
contentMetadata.genre="GENRE";
contentMetadata.episodeNumber="EPISODE_NUMBER";
contentMetadata.drmProtection="DRM_PROTECTION";
contentMetadata.contentType="CONTENT_TYPE";
    
MMSmartStreamingMedia3.initializeSession(player, "STREAM_URL", contentMetadata, isLive);
MMSmartStreamingMedia3.reportUserInitiatedPlayback();
```

#### Step 2.8: Report Experiment Name

```java
MMSmartStreamingMedia3.reportExperimentName("EXPERIMENT_NAME");
```

#### Step 2.9: Report View Session Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

{% hint style="info" %}
Report the View Session Id attribute after `initializeSession` and before `reportUserInitiatedPlayback`.&#x20;
{% endhint %}

```java
MMSmartStreamingMedia3.reportViewSessionId("VIEW_SESSION_ID");
```

#### Step 2.10: Report Sub Property Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

{% hint style="info" %}
Report the Sub Property ID attribute after `initializeSession` and before `reportUserInitiatedPlayback`.&#x20;
{% endhint %}

```java
MMSmartStreamingMedia3.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.12: Report App Session ID

Report Application Session ID

```java
MMSmartStreamingMedia3.setAppSessionID("APP_SESSION_ID");
```

#### Step 2.13: Report Player Resolution

Report the width and height of the player  (in pixels). This is useful to understand playback size and user experience across different screen sizes or platforms.

```java
MMSmartStreamingMedia3.reportPlayerResolution(playerWidth, playerHeight);
```

### Step 3: Report Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```java
MMSmartStreamingMedia3.reportCustomMetadata("custom_1","VALUE_1");
```

### Step 4: Report Ended State <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

In `$MEDIA3PROJECT/demos/main/src/main/java/androidx/media3/demo/main/PlayerActivity.java`&#x20;

```java
private void releasePlayer() {
    if (player != null) {
      player.release();
      player = null;
      
      MMSmartStreamingMedia3.reportPlayerState(false, Player.STATE_ENDED);
    }
  }
```

### Step 5: Report Errors and Warnings

The SDK provides two ways to report errors: automatic error capture and manual error reporting via API.

⚙️ **Default Behavior (Auto Error Capture):**

By default, the SDK automatically listens to and captures player errors that occur during a playback session.

{% hint style="info" %}
⚠️ Note: Errors that occur **before** are not captured automatically by the SDK, as they fall outside the player’s event lifecycle. Use the error and warning APIs below to manually report such issues.
{% endhint %}

🚫 **Disabling Auto Error Capture:**

If you prefer to handle error reporting manually, you can disable this automatic behavior by calling:

```java
MMSmartStreamingMedia3.disableAutoErrorCapture(true);
```

{% hint style="info" %}
⚠️ When disabled, the SDK will not listen for any player-generated errors. You will be responsible for reporting all errors & warnings manually using the APIs described below.
{% endhint %}

**🛠️ Manual Error Reporting APIs:**

Use these APIs to custom report errors and warnings to the SDK—especially for errors that occur **before**, or when auto-capture is disabled.

🔴 **Report Fatal Error:**

All errors reported via reportError are treated as **fatal**.

```java
MMSmartStreamingMedia3.reportError((int) errorCode, "ERROR_MESSAGE", "ERROR_DESCRIPTION");
```

🟠 **Report Warning (Non-Fatal):**

All warnings reported via reportWarning are treated as non-fatal and will be tracked accordingly.

```java
MMSmartStreamingMedia3.reportWarning((int) errorCode, "ERROR_MESSAGE", "ERROR_DESCRIPTION");
```

### Step 6: Report Stream Level Information

#### Step 6.1: Report Stream Info

Report key stream attributes that describe the encoding and delivery method.

```java
MMSmartStreamingMedia3.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE", isLive)
```

#### Step 6.2: Report CDN

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```java
MMSmartStreamingMedia3.reportCDN("CDN");
```

#### Step 6.3: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```java
MMSmartStreamingMedia3.reportFallbackEvent("FALLBACK_URL", "DESCRIPTION");
```

#### Step 6.4: Report Video Duration

Report Video duration in case of live content. Video Duration should be reported after every session initialization and asset update.

```java
MMSmartStreamingMedia3.reportVideoDuration(durationInMs);
```

### Step 7: Update Asset Information

If Asset Information needs to be updated dynamically during the live session without re-initializing the player, then the `updateAssetInfo` API can be used to update the new AssetInfo.

{% hint style="info" %}
**Note**

* This API must be called for updating asset info for the live streams only&#x20;
* This API must be called after the Player has started the playback of the live stream&#x20;
* Optionally report isLive(boolean) in the updateAssetInfo.
  {% endhint %}

```java
MMSmartStreamingMedia3.updateAssetInfo(contentMetaData, isLive);
```

### Release Notes

<details>

<summary>Current Release</summary>

#### **v2.4.2 &#x20;**<sup><sub>**`Oct 9, 2026`**<sub></sup>

* Bugfix - `isLive` reported false intermittently for LIVE content.
* Added `isLive` as an optional param for `updateAssetInfo`.
* Added new API `reportVideoDuration` to report video duration in case of live content.

</details>

***

<details>

<summary>Previous Release</summary>

#### **v2.4.1 &#x20;**<sup><sub>**`Aug 4, 2026`**<sub></sup>

* Intermittent crash fix added for v1.7.1

#### **v2.4.0 &#x20;**<sup><sub>**`Mar 11, 2026`**<sub></sup>

* Added API to report CDN.
* Added events for AD-BUFFERING.
* Added support for Seek Duration

</details>


# MediaMelon Android ExoPlayer SDK Integration Document

This guide provides detailed instructions on integrating the Android MediaMelon SDK with the ExoPlayer.

**Step 1:** [Set up the build environment](#step-2-set-up-the-build-environment)

**Step 2:** [Register and Initialise SDK](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 3:** [Report Custom Metadata](#step-3-report-custom-metadata)

**Step 4:** [Report Ended State](#step-5-report-ended-state-when-the-player-instance-is-released)

**Step 5:** [Report Errors and Warnings](#step-5-report-errors-and-warnings)

**Step 6:** [Report Stream Level Information](#step-6-report-stream-level-information)

**Step 7:** [Update Asset Information](#step-7-update-asset-information)

[Release Notes](#release-notes)

### Step 1: Set up the build environment&#x20;

The SDK files should be added to the build environment and the required network permissions should be enabled.

#### **Step 1.1: Add Gradle Dependency:**

**Using Maven:**

1. Add MediaMelon ExoPlayer Maven dependency to `/build.gradle`

{% tabs %}
{% tab title="2.19.1" %}

```gradle
dependencies {
   ...
   implementation 'com.github.MediamelonSDK:mm-android-sdk-exoplayer:v2.19.1-2.3.5'
}
```

{% endtab %}

{% tab title="2.18.6" %}

```
dependencies {
   ...
   implementation 'com.github.MediamelonSDK:mm-android-sdk-exoplayer:v2.18.6:2.3.0'
}
```

{% endtab %}

{% tab title="2.17.1" %}

```gradle
dependencies {
   ...
   implementation 'com.github.MediamelonSDK:mm-android-sdk-exoplayer-2.17.1:2.3.0'
}
```

{% endtab %}
{% endtabs %}

**Using AAR:**&#x20;

1. Copy `mmsmartstreaming.aar` provided in the release package. Example `$project/main/mmsmartstreaming.aar` .

{% tabs %}
{% tab title="2.19.1" %}
[`mmsmartstreaming.aar`](https://mediamelon-builds.s3.us-east-1.amazonaws.com/MM-RELEASE-BUILDS/SDK_RELEASES/Android/2025-11-4/mmsmartstreaming.aar)
{% endtab %}

{% tab title="2.18.6" %}
[`mmsmartstreaming.aar`](https://mediamelon-builds.s3.us-east-1.amazonaws.com/MM-RELEASE-BUILDS/SDK_RELEASES/Android/2025-05-06/mmsmartstreaming.aar)&#x20;
{% endtab %}

{% tab title="2.17.1" %}
[`mmsmartstreaming.aar`](https://mediamelon-builds.s3.us-east-1.amazonaws.com/MM-RELEASE-BUILDS/SDK_RELEASES/Android/2025-04-24/mmsmartstreaming.aar)&#x20;
{% endtab %}
{% endtabs %}

2. Add the following library to `build.gradle` :-

```gradle
dependencies {
  ...
  api files ('mmsmartstreaming.aar')
}
```

#### Step 1.2 Provide Permissions

Add network permissions to `AndroidManifest.xml`

```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

#### Step 1.3: Import Packages

Import dependencies in `PlayerActivity.java`

```java
import com.mediamelon.qubit.ep.ContentMetadata
import com.mediamelon.smartstreaming.exoplayer.MMSmartStreamingAdapter
import com.mediamelon.smartstreaming.exoplayer.MMSmartStreamingFactory
```

### Step 2: Register and Initialise SDK <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The player application must register the SDK and provide player information once the player is initialized. Please note that values provided in this integration step persist across video sessions.

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

#### Step 2.1 Get Adapter Instance

```java
MMSmartStreamingAdapter mmSmartStreamingAdapter = MMSmartStreamingFactory.getInstance();
```

#### Step 2.2:  Set Context

Set the application context

```java
mmSmartStreamingAdapter.setContext(applicationContext)
```

#### Step 2.3: Register SDK

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```java
mmSmartStreamingAdapter.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG", true);
```

#### Step 2.4: Report Player Information

```java
mmSmartStreamingAdapter.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
```

#### Step 2.5: Report Base Player Information

```java
mmSmartStreamingAdapter.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.6: Report Application Information

```java
mmSmartStreamingAdapter.reportAppInfo("APP_NAME","APP_VERSION");
```

#### Step 2.7: Initialize Session&#x20;

```java
ContentMetadata contentMetadata  = new ContentMetadata();
contentMetadata.assetName="ASSET_NAME";
contentMetadata.assetId="ASSET_ID";
contentMetadata.videoId="VIDEO_ID";
contentMetadata.seriesTitle="SERIES_TITLE";
contentMetadata.season="SEASON";
contentMetadata.genre="GENRE";
contentMetadata.episodeNumber="EPISODE_NUMBER";
contentMetadata.drmProtection="DRM_PROTECTION";
contentMetadata.contentType="CONTENT_TYPE";
    
mmSmartStreamingAdapter.initializeSession(Companion.getPlayer(), "STREAM_URL",contentMetaData, isLive);
mmSmartStreamingAdapter.reportUserInitiatedPlayback();
```

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production.

```java
mmSmartStreamingAdapter.enableLogTrace(true)
```

{% endhint %}

#### Step 2.8: Report Experiment Name

```java
mmSmartStreamingAdapter.reportExperimentName("EXPERIMENT_NAME");
```

#### Step 2.9: Report View Session Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

{% hint style="info" %}
Report the View Session Id attribute after `initializeSession` and before `reportUserInitiatedPlayback`.&#x20;
{% endhint %}

```java
mmSmartStreamingAdapter.reportViewSessionId("VIEW_SESSION_ID");
```

#### Step 2.10: Report Sub Property Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

{% hint style="info" %}
Report the Sub Property ID attribute after `initializeSession` and before `reportUserInitiatedPlayback`.&#x20;
{% endhint %}

```java
mmSmartStreamingAdapter.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.11: Report Player Resolution

Report the width and height of the player  (in pixels). This is useful to understand playback size and user experience across different screen sizes or platforms.

```java
mmSmartStreamingAdapter.reportPlayerResolution(playerWidth, playerHeight);
```

#### Step 2.12: Report App Session ID

```java
mmSmartStreamingAdapter.reportAppSessionId("APP_SESSION_ID);
```

### Step 3: Report Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```java
mmSmartStreamingAdapter.reportCustomMetadata("custom_1","VALUE1");
```

### Step 4: Report Ended State <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

Report ENDED state in  `PlayerActivity` when playback ends.

{% hint style="info" %}
If not reported at the end of the playback, it may reflect a longer playtime.
{% endhint %}

```java
private void releasePlayer() {
    if (player != null) {
      player.release();
      player = null;
      
      mmSmartStreamingAdapter.reportPlayerState(false, Player.STATE_ENDED);
    }
  }
```

### Step 5: Report Errors and Warnings

The SDK provides two ways to report errors: automatic error capture and manual error reporting via API.

⚙️ **Default Behavior (Auto Error Capture):**

By default, the SDK automatically listens to and captures player errors that occur during a playback session.

{% hint style="info" %}
⚠️ Note: Errors that occur **before** are not captured automatically by the SDK, as they fall outside the player’s event lifecycle. Use the error and warning APIs below to manually report such issues.
{% endhint %}

🚫 **Disabling Auto Error Capture:**

If you prefer to handle error reporting manually, you can disable this automatic behavior by calling:

```java
mmSmartStreamingAdapter.disableAutoErrorCapture(true);
```

{% hint style="info" %}
⚠️ When disabled, the SDK will not listen for any player-generated errors. You will be responsible for reporting all errors & warnings manually using the APIs described below.
{% endhint %}

**🛠️ Manual Error Reporting APIs:**

Use these APIs to custom report errors and warnings to the SDK—especially for errors that occur **before**, or when auto-capture is disabled.

🔴 **Report Fatal Error:**

All errors reported via reportError are treated as **fatal**.

```java
mmSmartStreamingAdapter.reportError((int) errorCode, "ERROR_MESSAGE", "ERROR_DESCRIPTION");
```

🟠 **Report Warning (Non-Fatal):**

All warnings reported via reportWarning are treated as non-fatal and will be tracked accordingly.

```java
mmSmartStreamingAdapter.reportWarning((int) errorCode, "ERROR_MESSAGE", "ERROR_DESCRIPTION");
```

### Step 6: Report Stream Level Information

#### Step 6.1: Report Stream Info

Report key stream attributes that describe the encoding and delivery method.

```java
mmSmartStreamingAdapter.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE", isLive)
```

#### Step 6.2: Report CDN

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```java
mmSmartStreamingAdapter.reportCDN("CDN");
```

#### Step 6.3: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```java
mmSmartStreamingAdapter.reportFallbackEvent("FALLBACK_URL", "DESCRIPTION");
```

### Step 7: Update Asset Information

If Asset Information needs to be updated dynamically during the live session without re-initializing the player, then the `updateAssetInfo` API can be used to update the new AssetInfo.

{% hint style="info" %}
**Note**

* This API must be called for updating asset info for the live streams only&#x20;
* This API must be called after the Player has started the playback of the live stream&#x20;
  {% endhint %}

```java
mmSmartStreamingAdapter.updateAssetInfo(contentMetaData);
```

#### Release Notes

<details>

<summary><strong>Current Release</strong></summary>

#### v2.3.5  <sup><sub>**`Mar 11, 2026`**<sub></sup>

* Added API to report App Session ID.
* Added API to report CDN.
* Added events for AD-BUFFERING.
* Added support for Seek Duration

</details>

***

<details>

<summary>Previous Releases</summary>

</details>


# MediaMelon Android IMA Media3 SDK Integration Document

This guide provides detailed instructions on integrating the Android MediaMelon IMA SDK with the Media3 player

**Step 1:** [Set up the build environment](#step-1-set-up-the-build-environment)

**Step 2:** [Register and Initialise SDK](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 3:** [Report Custom Metadata](#step-3-report-custom-metadata)

**Step 4:** [Report Custom Errors](#step-4-report-custom-errors)

**Step 5:** [Report Ended State](#step-5-report-ended-state-when-the-player-instance-is-released)

Step 6: [Report Stream Info](#step-6-report-stream-information)

**Step 7:** [Enable IMA/DAI Ad tracking](#step-7-enable-ima-dai-a-d-tracking)

[Release Notes](#releases-notes)

### Step 1: Set up the build environment&#x20;

> `$MEDIA3PROJECT = {Media3 - v1.4.0}`

The SDK files should be added to the build environment and the required network permissions should be enabled.

#### **Step 1.1: Add Gradle Dependency:**

**Using Maven:**

1. Add MediaMelon Media3 Maven dependency to `$MEDIA3PROJECT/demos/main/build.gradle`

{% tabs %}
{% tab title="1.4.0" %}

```java
dependencies {
   ...
  implementation 'com.github.MediamelonSDK:mm-android-sdk-media3-ima:2.2.5'
}
```

{% endtab %}
{% endtabs %}

**Using AAR:**&#x20;

1. Copy [`mmsmartstreaming.aar`](https://sdks.mediamelon.com/android/media3/IMA/2.2.5/mmsmartstreaming.aar) provided in the release package for the Media3 project. Example  `$MEDIA3PROJECT/demos/main/mmsmartstreaming.aar` .
2. Add the following library to `$MEDIA3PROJECT/demos/main/build.gradle` :-

```gradle
dependencies {
  ...
  api files ('mmsmartstreaming.aar')
}
```

#### Step 1.2 Provide Permissions

Add network permissions to `$MEDIA3PROJECT/demos/main/src/main/AndroidManifest.xml`

```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

#### Step 1.3: Import Packages

`$MEDIA3PROJECT/demos/main/src/main/java/androidx/media3/demo/main/PlayerActivity.java`

```java
import com.mediamelon.qubit.ep.ContentMetadata;
import com.mediamelon.smartstreaming.media3_ima.MMAnalyticsBridge;
import com.mediamelon.smartstreaming.media3_ima.MMSmartStreamingExo2;
```

### Step 2: Register and Initialise SDK <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The player application must register the SDK and provide player information once the player is initialized. Please note that values provided in this integration step persist across video sessions.

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production.
{% endhint %}

#### Step 2.1:  Set Context

Set the application context

```java
MMSmartStreamingExo2.getInstance().setContext(applicationContext)
```

#### Step 2.2: Register SDK

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```java
MMSmartStreamingExo2.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG", true);
```

#### Step 2.3: Report Player Information

```java
MMSmartStreamingExo2.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
```

#### Step 2.4: Report Base Player Information

```java
MMSmartStreamingExo2.getInstance().reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.5: Report Application Information

```java
MMSmartStreamingExo2.reportAppInfo("APP_NAME","APP_VERSION");
```

#### Step 2.6: Initialize session with Content Metadata

```java
ContentMetadata contentMetadata  = new ContentMetadata();
contentMetadata.assetName="ASSET_NAME";
contentMetadata.assetId="ASSET_ID";
contentMetadata.videoId="VIDEO_ID";
contentMetadata.seriesTitle="SERIES_TITLE";
contentMetadata.season="SEASON";
contentMetadata.genre="GENRE";
contentMetadata.episodeNumber="EPISODE_NUMBER";
contentMetadata.drmProtection="DRM_PROTECTION";
contentMetadata.contentType="CONTENT_TYPE";
    
MMSmartStreamingExo2.getInstance().initializeSession(player, streamURL, contentMetadata, isLive);
MMSmartStreamingExo2.getInstance().reportUserInitiatedPlayback();
```

#### Step 2.7: Report Experiment Name

```java
MMSmartStreamingExo2.getInstance().reportExperimentName("EXPERIMENT_NAME");
```

#### Step 2.8: Report View Session Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

{% hint style="info" %}
Report the View Session Id attribute after `initializeSession` and before `reportUserInitiatedPlayback`.&#x20;
{% endhint %}

```java
MMSmartStreamingExo2.getInstance().reportViewSessionId("VIEW_SESSION_ID");
```

#### Step 2.9: Report Sub Property Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

{% hint style="info" %}
Report the Sub Property ID attribute after `initializeSession` and before `reportUserInitiatedPlayback`.&#x20;
{% endhint %}

```java
MMSmartStreamingExo2.getInstance().reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.10: Report App Session ID

Report Application Session ID

```java
MMSmartStreamingExo2.getInstance().reportAppSessionId("APP_SESSION_ID");
```

#### Step 2.11: Report Player Resolution

```java
MMSmartStreamingExo2.getInstance().reportPlayerResolution(playerWidth, playerHeight);
```

### Step 3: Report Custom Metadata

```java
MMSmartStreamingExo2.getInstance().reportCustomMetadata("CUSTOM_KEY_1","VALUE1");
```

### Step 4: Report Custom Errors

{% hint style="info" %}
Make sure that `enableCustomErrorReporting` is set to `true` for this to be able to report errors&#x20;
{% endhint %}

```java
MMSmartStreamingExo2.getInstance().reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DESCRIPTION");
```

### Step 5: Report Ended State <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

Report ENDED state in  `PlayerActivity` when playback ends.

{% hint style="info" %}
If not reported at the end of the playback, it may reflect a longer playtime.
{% endhint %}

```java
private void releasePlayer() {
    if (player != null) {
      player.release();
      player = null;
      
      MMSmartStreamingExo2.getInstance().reportPlayerState(false, Player.STATE_ENDED);
    }
  }
```

### Step 6: Report Stream Information

#### Step 6.1: Report Stream Info

Report key stream attributes that describe the encoding and delivery method.

```java
MMSmartStreamingExo2.getInstance().reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE", isLive)
```

#### Step 6.2: Report CDN

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```java
MMSmartStreamingExo2.getInstance().reportCDN("CDN");
```

#### Step 6.3: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```java
MMSmartStreamingExo2.getInstance().reportFallbackEvent("FALLBACK_URL", "DESCRIPTION");
```

### Step 7: Enable IMA/DAI Ad tracking

Add the following steps to enable IMA/DAI Ad tracking

#### 7.a: IMA Ad Tracking

```java
private final ImaSdkFactory sdkFactory;
private AdsLoader adsLoader;
private StreamDisplayContainer displayContainer;

MMAnalyticsBridge analyticsBridgeObject;
```

```java
//Get the Analytics Bridge Object, this should be done wherever in your application the adsLoader is created
analyticsBridgeObject = MMSmartStreamingExo2.getInstance().getAnalyticsBridge(); 

//Initialising ads loader
ImaSdkSettings settings = sdkFactory.createImaSdkSettings();
adsLoader = sdkFactory.createAdsLoader(context, settings, displayContainer);
```

```java
// For IMA Ad Tracking
public void requestAndPlayAds() {  
  adsLoader.addAdErrorListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ads error listeners
  adsLoader.addAdsLoadedListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ads loaded listeners
}
```

{% hint style="info" %}
Alternate method for IMA ad tracking
{% endhint %}

```java
adsLoader = new ImaAdsLoader.Builder(/* context= */ this)
                .setAdEventListener(analyticsBridgeObject)
                .setAdErrorListener(analyticsBridgeObject)
                .build();
```

#### 7.b: DAI Ad Tracking

The function `onAdsManagerLoaded` is part of `AdsLoader.AdsLoadedListener`&#x20;

```java
private StreamManager streamManager;
MMAnalyticsBridge analyticsBridgeObject;
```

```java
@Override
public void onAdsManagerLoaded(AdsManagerLoadedEvent event) {
 //Get the Analytics Bridge Object ,this should be done wherever in your application the adsManager is loaded
analyticsBridgeObject = MMSmartStreamingExo2.getInstance().getAnalyticsBridge();
  
  if(event.getStreamManager()!=null) {
      streamManager = event.getStreamManager();
      
      streamManager.addAdErrorListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ad error listeners
      streamManager.addAdEventListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ad event listeners
      streamManager.init();
    }
}
```

#### Releases Notes

<details>

<summary>Current Release</summary>

#### v2.2.5  <sup><sub>**`Mar 11, 2026`**<sub></sup>

* Added API to report App Session ID.
* Added API to report CDN.
* Added events for AD-BUFFERING.
* Added API to Report Stream Information
* Added API to Report Fallback Event.
* Added support for Seek Duration

</details>

***

<details>

<summary>Previous Releases</summary>

</details>


# MediaMelon Android Bitmovin SDK Integration Document

This page describes the integration of the MediaMelon Player SDK with Bitmovin Player on the Android platform

**Step 1:** [Set up the build environment](#step-1-set-up-the-build-environment)

**Step 2:** [Register and Initialise SDK](#step-2-register-and-initialise-sdk)

**Step 3:** [Report Custom Metadata](#step-3-report-custom-metadata)

**Step 4:** [Report Stream Level Info](#step-4-report-stream-level-information)

**Step 5:** [Report Ended State](#step-5-report-ended-state)

**Step 6:** [Setup SSAI Ad Manager for Ad Callbacks](#step-6-setup-ssai-a-d-manager-for-ad-callbacks)

**Step 7:** [Initialize Harmonic SSAI Ad Manager](#step-7-initialize-harmonic-ssai-a-d-manager)

**Step 8:** [Update Asset Info dynamically](#step-8-update-asset-info-dynamically)

[Release Notes](#release-notes)

### Step 1: Set up the build environment

The SDK files are added to the build environment and the required network permissions are enabled.

1. Copy [`bitmovin-lib-release.aar`](https://sdks.mediamelon.com/android/bitmovin/qoe/1.3.5/bitmovin-lib-release.aar) provided with the release notes.

#### **Step 1.1: Add Gradle Dependency:**

**Using AAR:**

1. ```
   dependencies {
     ...
     api files ('bitmovin-lib-release.aar')
   }
   ```

**Using Maven:**

1. Add the following library to `app/build.gradle` :-<br>

   ```java
   dependencies {
       ...
       implementation("com.github.MediamelonSDK:mediamelon_bitmovin_sdk:1.3.5")
       ...
   }
   ```

#### Step 1.2 Provide Permissions

Add network permissions to `$MEDIA3PROJECT/demos/main/src/main/AndroidManifest.xml`

```xml
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

#### Step 1.3: Import Packages

```java
import com.mediamelon.qubit.ep.ContentMetadata;
import com.mediamelon.smartstreaming.MMAVAssetInformation;
import com.mediamelon.smartstreaming.MMPlayerState;
import com.mediamelon.smartstreaming.MMRegistrationInformation;
import com.mediamelon.smartstreaming.MMSmartStreaming;
import com.mediamelon.smartstreaming.ssai.harmonic.MMHarmonicSSAIAdInfo;
import com.mediamelon.smartstreaming.ssai.harmonic.MMHarmonicSSAIEventListeners;
import com.mediamelon.smartstreaming.bitmovin_harmonic_ssai.MMSmartStreamingBitmovinAdaptor;
```

### Step 2: Register and Initialise SDK

The player application must register the MediaMelon Player SDK and provide player information once when the application launches. Please note that values provided in this integration step persist across video sessions. This is typically done when the player itself is initialised.

#### Step 2.1: Set Asset Information

```java
MMAVAssetInformation assetInformation = new MMAVAssetInformation("ASSET_ID", "ASSET_NAME", "VIDEO_ID");
String jsonAssetInfo = assetInformation.toJSON();
MMSmartStreamingBitmovinAdaptor.JsonFromClient = jsonAssetInfo;
```

#### Step 2.2: Create Adaptor Instance

```java
MMSmartStreamingBitmovinAdaptor mmSmartStreamingBitmovinAdaptor  = new MMSmartStreamingBitmovinAdaptor(getApplicationContext()) ;
```

#### Step 2.3: Set Registration and Player Information

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

{% hint style="info" %}
Please provide the `hashSubscriberId` value in `setSubscriberInformation()`, `hashSubscriberId` boolean variable indicates whether the `SUBSCRIBER_ID` to be hashed or not.
{% endhint %}

<pre class="language-java"><code class="lang-java">MMRegistrationInformation registrationInformation = new MMRegistrationInformation("CUSTOMER_ID", "PLAYER_NAME");
registrationInformation.setPlayerInformation("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
registrationInformation.setDomain("DOMAIN_NAME");
boolean hashSubscriberId = true; 
registrationInformation.setSubscriberInformation("SUBSCRIBER_ID", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG", hashSubscriberId);
MMSmartStreamingBitmovinAdaptor.setPlayerRegistrationInformation(registrationInformation, <a data-footnote-ref href="#user-content-fn-1">player</a>, getApplicationContext());
</code></pre>

#### Step 2.4: Set Stream URL

```java
mmSmartStreamingBitmovinAdaptor.setURL(url);
```

#### Step 2.5: Report Base Player Information

```java
MMSmartStreamingBitmovinAdaptor.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

#### Step 2.6: Report Application Information

```java
mmSmartStreamingBitmovinAdaptor.reportAppInfo("APP_NAME", "APP_VERSION");
```

#### Step 2.7: Report Content Metadata

```java
ContentMetadata cm  = new ContentMetadata();

cm.videoId="VIDEO_ID";
cm.seriesTitle="SERIES_TITLE";
cm.season="SEASON";
cm.genre="GENRE";
cm.episodeNumber="EPISODE_NUMBER";
cm.drmProtection="DRM_PROTECTION";
cm.contentType="CONTENT_TYPE";
cm.assetName="ASSET_NAME";
cm.assetId="ASSET_ID";

JSONObject jsonObj = cm.getJSONObject();
MMSmartStreamingBitmovinAdaptor.contentMetadataFromUser = jsonObj;
```

#### Step 2.8: Report Experiment Name

```java
mmSmartStreamingBitmovinAdaptor.reportExperimentName("EXPERIMENT_NAME");
```

#### Step 2.9: Report View Session Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
mmSmartStreamingBitmovinAdaptor.reportViewSessionId("VIEW_SESSION_ID");
```

#### Step 2.10: Report Sub Property Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
mmSmartStreamingBitmovinAdaptor.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 2.11: Report Player Resolution

```java
mmSmartStreamingBitmovinAdaptor.reportPlayerResolution(playerWidth, playerHeight);
```

### Step 3: Report Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```java
mmSmartStreamingBitmovinAdaptor.reportCustomMetadata("custom_1", "VALUE_1");
```

### Step 4: Report Stream Level Information

#### Step 4.1: Report Stream Info

Report key stream attributes that describe the encoding and delivery method.

```java
mmSmartStreamingBitmovinAdaptor.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE", isLive)
```

#### Step 4.2: Report CDN

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```java
mmSmartStreamingBitmovinAdaptor.reportCDN("CDN");
```

### Step 5: Report Ended State

```java
@Override
protected void onDestroy() {
    playerView.onDestroy();
    super.onDestroy();
    MMSmartStreaming.getInstance().reportPlayerState(MMPlayerState.STOPPED);
}
```

### Step 6: Setup SSAI Ad Manager for Ad Callbacks

To handle Harmonic SSAI events, create an object of `MMHarmonicSSAIEventListeners` in the required class and implement the methods you need. Once implemented, add the listener to `mmSmartStreamingBitmovinAdaptor` as shown below:

```swift
 MMHarmonicSSAIEventListeners mmHarmonicSSAIEventListeners = new MMHarmonicSSAIEventListeners() {
    @Override
    public void onAdImpression(MMHarmonicSSAIAdInfo ssaiAdInfo) {}
    
    @Override
    public void onAdStarted(MMHarmonicSSAIAdInfo ssaiAdInfo) {}
    
    @Override
    public void onAdFirstQuartile(MMHarmonicSSAIAdInfo ssaiAdInfo) {}
    
    @Override
    public void onAdMidpoint(MMHarmonicSSAIAdInfo ssaiAdInfo) {}
    
    @Override
    public void onAdThirdQuartile(MMHarmonicSSAIAdInfo ssaiAdInfo) {}
    
    @Override
    public void onAdComplete(MMHarmonicSSAIAdInfo ssaiAdInfo) { }
 };
 mmSmartStreamingBitmovinAdaptor.addSSAIListener(mmHarmonicSSAIEventListeners);
```

#### **6.1  MMHarmonicSSAIEventListners  callbacks:**

The following callbacks are available within the `MMHarmonicSSAIEventListeners` interface:

* `onAdImpression`
* `onAdStarted`
* `onAdFirstQuartile`
* `onAdMidpoint`
* `onAdThirdQuartile`
* `onAdComplete`

#### **6.2  AdInfo Accessible Methods:**

The `AdInfo` object provides several methods to access ad-related information:

* `getAdClient()`
* `getAdCurrentPlaybackTime()`
* `getAdDuration()`
* `getAdStartTime()`
* `getAdEndTime()`
* `getAdId()`
* `getAdServer()`

### Step 7: Initialize Harmonic SSAI Ad Manager

* **DASH** `PMM_URL`: Send the final redirected URL with the pmm ID.
* **HLS** `PMM_URL`: Send the variant URL with the pmm ID.

{% hint style="info" %}
Note: Call `initializeHarmonicSSAIAdManager` only once at the stream start.
{% endhint %}

```java
mmSmartStreamingBitmovinAdaptor.initializeHarmonicSSAIAdManager("PMM_URL");
```

### Step 8: Update Asset Info dynamically

If Asset Information needs to be updated dynamically during the live session without re-initiating the player, then the "updateAssetInfo” API can be used to update the new AssetInfo.

**Note:**

1. This API must be called for updating asset info for the live streams only
2. This API must be called after the Player has started the live-stream playback.
3. The new Asset Info Object will override the previous values, hence set all the required fields every time before calling this API.

```java
MMAVAssetInformation newAssetInformation = new MMAVAssetInformation("ASSET_ID", "ASSET_NAME", "VIDEO_ID");
MMSmartStreamingBitmovinAdaptor.updateAssetInfo(newAssetInformation, player, "SEASON","GENRE","EPISODE_NUMBER","CONTENT_TYPE","VIDEO_TYPE","DRM_PROTECTION","SERIES_TITLE");
```

#### Release Notes

<details>

<summary>Current Release</summary>

#### v1.3.5  <sup><sub>**`Mar 11, 2026`**<sub></sup>

* Added API to report App Session ID.
* Added API to report CDN.
* Added events for AD-BUFFERING.
* Fix for Ad playtime for session with no ads.
* Updated folder structure

</details>

***

<details>

<summary>Previous Releases</summary>

#### v1.3.4

* Added API to report Application Information
* Added API to report Stream Information

#### v1.3.3

* Number field in streaming\_progress removed

</details>

[^1]: Player Instance


# Theoplayer SDK Integration Document

**Step 1:** [Prerequisites](#step-1-prerequisites)

**Step 2:** [Set up the build environment](#step-2-set-up-the-build-environment)

**Step 3:**[ Register SDK](#step-3-register-sdk)

**Step 5:** [Initialize Session](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 10:** [Report Ended State](#step-5-report-ended-state-when-the-player-instance-is-released)

### Step 1: Prerequisites

* MediaMelon SmartSight SDK `smartstreaming_release.aar`

### Step 2: Set up the build environment&#x20;

The SDK files are added to the build environment and the required network permissions are enabled.&#x20;

1. Copy smartstreaming-release.aar provided with the release package to the theoplayer project, Example `app/libs/smartstreaming-release.aar`&#x20;
2. Add the following library to `app/build.gradle` :-

```gradle
dependencies {
  .
  .
  .
   //<!-- <MMSmartStreaming 1a> -->
    api files ('smartstreaming-release.aar')
  //<!-- </MMSmartStreaming 1a> -->
}
```

Add network permissions to&#x20;

`app/src/main/AndroidManifest.xml`

```java
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

### Step 3: Register SDK

The player application must register the SDK and provide player information once when the application launches. Please note that values provided in this integration step persist across video sessions. This is typically done when the player itself is initialized.&#x20;

\
Step 3a: Import packages

`app/src/main/java/com/theoplayer/theoplayerexample/MainActivity.java`

```java
// <MMSmartStreaming 2a>
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMSmartStreaming;
import com.mediamelon.smartstreaming.MMSmartStreamingTheo;
import com.mediamelon.smartstreaming.MMSmartStreamingInitializationStatus;
import com.mediamelon.smartstreaming.MMSmartStreamingObserver;
import java.util.ArrayList;
import android.util.Log;
// </MMSmartStreaming 2a>
```

#### Step 3b: Registration

&#x20;Perform registration tasks by modifying the `onCreate()` method in `app/src/main/java/com/theoplayer/theoplayerexample/MainActivity.java`

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production
{% endhint %}

```java
public void onCreate(Bundle savedInstanceState) {
  ...
   @Override
            public void onClick(View v) {
                if (theoPlayerView.getPlayer().isPaused()) {
                    theoPlayerView.getPlayer().play();
                } else {
                    theoPlayerView.getPlayer().pause();
                }
            }
        });
        //<MMSmartStreaming 2b>
        MMSmartStreamingTheo.enableLogTrace(<boolean>); //set to "false" before releasing player to production
        if (MMSmartStreamingTheo.getRegistrationStatus() == false){ //Check if it is the first time Registration process is done
            MMSmartStreamingExo2.setDeviceInfo($DEVICE_MARKETING_NAME);
            MMSmartStreamingExo2.registerMMSmartStreaming($PLAYERNAME, $CUSTOMERID, $SUBSCRIBERID, $DOMAINNAME, $SUBSCRIBERTYPE, $SUBSCRIBERTAG,$hashSubscriberId);
            MMSmartStreamingExo2.reportPlayerInfo("CustomPlayerName","Player_Version", "1.0");
            MMSmartStreamingExo2.getInstance().setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
            MMSmartStreamingExo2.getInstance().reportAppInfo($APP_NAME,$APP_VERSION);
            MMSmartStreamingExo2.getInstance().reportVideoQuality($VIDEO_QUALITY);
            }
        // </MMSmartStreaming 2b>
  }
```

* **`hashSubscriberID`**: To hash the subscriber ID, set it to <mark style="color:orange;">`true`</mark>. To leave the subscriber ID un-hashed, set it to <mark style="color:orange;">`false`</mark>.This is optional

### Step 4: Initialize Session  <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

`app/src/main/java/com/theoplayer/theoplayerexample/MainActivity.java`

```java
// after player is initialised and not null anymore
    String mediaUrl = "get the mediaURL from your application"
    String assetId  = "assetID"; //enter you assetId here
    String assetName = "assetNAME"; // enter your assetname here
    String videoId = "videoID"; // enter your videoId here
    ContentMetadata cm  = new ContentMetadata();
    String episodeNumber = "EpisodeNumber";
    String season = "Season";
    String genre = "Genre";
    String drmProtection = "drmProtection";
    String contentType = "contentType";
    String title = "Title";
    cm.videoId=videoId;
    cm.seriesTitle=title;
    cm.season=season;
    cm.genre=genre;
    cm.episodeNumber=episodeNumber;
    cm.drmProtection=drmProtection;
    cm.contentType=contentType;
    cm.assetName=assetName;
    cm.assetId=assetId;
    JSONObject contentMetadata = cm.getJSONObject();
    //optional content metadata
    MMSmartStreamingTheo.getInstance().initializeSession(player, MMQBRMode.QBRModeDisabled, mediaUrl, null,contentMetadata,isLive);
```

{% hint style="info" %}

* **`isLive`**: Set it to <mark style="color:orange;">`true`</mark> for a live video and <mark style="color:orange;">`false`</mark> for a VOD video. This is optional.
  {% endhint %}

### &#x20;Step 5: Report Ended State <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

```java
@Override
protected void onDestroy() {
    super.onDestroy();
    //MM
    MMSmartStreaming.getInstance().reportPlayerState(MMPlayerState.STOPPED);
    //MM
    theoPlayerView.onDestroy();
}
```


# Kaltura SDK Integration Document

This document provides a step by step guide to integrate the Mediamelon SDK with the Kaltura Player 4.2.59

**Step 1:** [Prerequisites](#step-1-prerequisites)

**Step 2:** [Set up the build environment](#step-2-set-up-the-build-environment)

**Step 3:** [Include and Configure the MediaMelon Plugin](#step-3-include-and-configure-the-mediamelon-plugin)

### Step 1: Prerequisites

* Kaltura Player Playtkit  <https://github.com/kaltura/playkit-android>
* MediaMelon Kaltura Player Plugin  (com.github.MediamelonSDK:mm-KalturaPlayer:1.1.1)
* IMADAISample  from [https://github.com/kaltura/playkit-android-samples/tree/develop/](https://github.com/kaltura/playkit-android-samples/tree/develop/BasicPluginsSetup)
* Allsamples folder from <https://github.com/kaltura/playkit-android-samples/tree/develop/AllSamples> ( AllSamples folder and BasicPluginSetup need to be at the same level )

### Step 2: Set up the build environment&#x20;

The SDK files are added to the build environment and the required network permissions are enabled.&#x20;

1. Copy mediamelonplugin-release.aar provided with the release package to the libs folder ( create one if its not already there ) in the  BasicPluginsSetup project
2. Add the following library to `IMADAISample/app/build.gradle` :-

```java
dependencies {
  .
  .
  .
  //<!-- <MMSmartStreaming 1b> -->
   implementation 'com.github.MediamelonSDK:mm-KalturaPlayer:1.1.1'
  //<!-- </MMSmartStreaming 1b> -->
  
}
```

Add network permissions to `IMADAISample/app/manifests/AndroidManifest.xml`

```java
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

### Step 3: Include and Configure the MediaMelon Plugin

The MediaMelon plugin needs to be configured . The following steps need to be executed.&#x20;

Step 3a: Import packages

The MediaMelon plugin package needs to be imported in the following file

`IMADAISample/app/com/kaltura/playkit/samples/imadaisample/MainActivity.java`

{% tabs %}
{% tab title="JAVA" %}

```java
import com.kaltura.playkit.plugins.mediamelon.*;
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
import com.kaltura.playkit.plugins.mediamelon.*
```

{% endtab %}
{% endtabs %}

#### Step 3b: Configure the Plugin

Add the following function createPluginConfigs in the file `IMADAISample/app/com/kaltura/playkit/samples/imadaisample/MainActivity.java`

{% tabs %}
{% tab title="JAVA" %}

```java
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Initialize media config object.
        createMediaConfig();

        //Create plugin configurations.
        PKPluginConfigs pluginConfigs = createIMADAIPlugin();
        pluginConfigs = createMMPluginConfigs(pluginConfigs);

        //Create instance of the player with plugin configurations.
        player = PlayKitManager.loadPlayer(this, pluginConfigs);
.....
}

private PKPluginConfigs createMMPluginConfigs(PKPluginConfigs pkPluginConfigs) {
        //First register your SamplePlugin.
        PlayKitManager.registerPlugins(this, MediamelonPlugin.factory);

        //Initialize plugin configuration object.

        if(pkPluginConfigs == null) {
            //Initialize plugin configuration object.
            pkPluginConfigs = new PKPluginConfigs();
        }

        //Set jsonObject to the main pluginConfigs object.
        pkPluginConfigs.setPluginConfig(MediamelonPlugin.factory.getName(),  createJson() );

        //Return created and populated object.
        return pkPluginConfigs;
    }

// Json parameters for configuring plugin
private JsonObject createJson() {
        JsonObject optJson = new JsonObject();

        // Main config goes here.
        optJson.addProperty("customerId", "18410666590");
        optJson.addProperty("domainName", "EladDomain");
        optJson.addProperty("subscriberId", "SubscriberId");
        optJson.addProperty("subscriberType", "SubscriberType");
        optJson.addProperty("subscriberTag", "SubscriberTag");
        optJson.addProperty("doHash", false);
        optJson.addProperty("playerName", "KALTURA PLAYER");

        optJson.addProperty("playerVersion", PlayKitManager.VERSION_STRING);

        // Set ContentMetadata for every asset played.
        optJson.addProperty("assetId", "1234");
        optJson.addProperty("assetName", "My IMA Asset");
        optJson.addProperty("videoId", "5678");
        optJson.addProperty("seriesTitle", "Test Series");
        optJson.addProperty("episodeNumber", "1");
        optJson.addProperty("season", "2");
        optJson.addProperty("contentType", "Episode");
        optJson.addProperty("drmProtection", "WideVine");
        optJson.addProperty("genre", "Romance,Horror");

        // Set Application data.
        optJson.addProperty("appName", "KalturaApp");
        optJson.addProperty("appVersion", "v1.0.0");

        // Set metadata for device.
        optJson.addProperty("deviceMarketingName", "Oneplus6");
        optJson.addProperty("videoQuality", "4K-HDR");
        optJson.addProperty("deviceId", "abcd-efgh-ijkl-mnop");
        optJson.addProperty("isDisableManifestFetch", false);

        // Set CustomTags.
        JsonObject optCustomJson = new JsonObject();

        optCustomJson.addProperty("param1", "12345");
        optCustomJson.addProperty("param2", "Sandbox Watch");
        optCustomJson.addProperty("param3", "12345");
        optCustomJson.addProperty("param4", "54321");
        optCustomJson.addProperty("param5", "1_nd547djd");
        optCustomJson.addProperty("householdId", "12345");
        optCustomJson.addProperty("properties", "{'key':'value'}");
        optCustomJson.addProperty("playerStartupTime", "12345");
        optCustomJson.addProperty("username", "123456789");
        optCustomJson.addProperty("seriesId", "123454321");
        
        optJson.addProperty("customTags", optCustomJson.toString() );
        

        return optJson;
    }


```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
    private fun createJson(): JsonObject? {
        val optJson = JsonObject()

        // Main config goes here.
        optJson.addProperty("customerId", "18410666590")
        optJson.addProperty("domainName", "EladDomain")
        optJson.addProperty("subscriberId", "SubscriberId")
        optJson.addProperty("subscriberType", "SubscriberType")
        optJson.addProperty("subscriberTag", "SubscriberTag")
        optJson.addProperty("doHash", false)
        optJson.addProperty("playerName", "KALTURA PLAYER")
        optJson.addProperty("playerVersion", PlayKitManager.VERSION_STRING)

        // Set ContentMetadata for every asset played.
        optJson.addProperty("assetId", "1234")
        optJson.addProperty("assetName", "My IMA Asset")
        optJson.addProperty("videoId", "5678")
        optJson.addProperty("seriesTitle", "Test Series")
        optJson.addProperty("episodeNumber", "1")
        optJson.addProperty("season", "2")
        optJson.addProperty("contentType", "Episode")
        optJson.addProperty("drmProtection", "WideVine")
        optJson.addProperty("genre", "Romance,Horror")

        // Set Application data.
        optJson.addProperty("appName", "KalturaApp")
        optJson.addProperty("appVersion", "v1.0.0")

        // Set metadata for device.
        optJson.addProperty("deviceMarketingName", "Oneplus6")
        optJson.addProperty("videoQuality", "4K-HDR")
        optJson.addProperty("deviceId", "abcd-efgh-ijkl-mnop")
        optJson.addProperty("isDisableManifestFetch", false)

        // Set CustomTags.
        val optCustomJson =  JsonObject()

        optCustomJson.addProperty("param1", "12345")
        optCustomJson.addProperty("param2", "Sandbox Watch")
        optCustomJson.addProperty("param3", "12345")
        optCustomJson.addProperty("param4", "54321")
        optCustomJson.addProperty("param5", "1_nd547djd")
        optCustomJson.addProperty("householdId", "12345")
        optCustomJson.addProperty("properties", "{'key':'value'}")
        optCustomJson.addProperty("playerStartupTime", "12345")
        optCustomJson.addProperty("username", "123456789")
        optCustomJson.addProperty("seriesId", "123454321")
        
        optJson.addProperty("customTags", optCustomJson.toString() )
        
        return optJson
    }
    
    
    private fun createIMADAIPlugin(): PKPluginConfigs {


        //First register your SamplePlugin.
        PlayKitManager.registerPlugins(this, MediamelonPlugin.factory)

        //Initialize plugin configuration object.
        val pluginConfigs = PKPluginConfigs()
    .....
        //Initialize + Configure  IMADAIConfig object
        pluginConfigs.setPluginConfig(IMADAIPlugin.factory.name, daiConfigVodHls2)

        //Set jsonObject to the main pluginConfigs object.
        pluginConfigs.setPluginConfig(MediamelonPlugin.factory.getName(), createJson())

    .....
    }
    
```

{% endtab %}
{% endtabs %}


# App Analytics SDK

This page describes the integration of the MediaMelon App Analytics SDK

## Prerequisites

1. Android Sample App&#x20;
2. MediaMelon SmartSight SDK  `appanalytics-release.aar`
3. MediaMelon-assigned Customer ID

{% hint style="info" %}
If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](mailto:support%40mediamelon.com)
{% endhint %}

## Step 1: Set up the build environment

1. Copy `appanalytics-release.aar` provided with the release package to `SampleApp/appanalytics-release.aar`
2. Add network permissions to

   `app/src/main/AndroidManifest.xml`

   ```
   <uses-permission android:name="android.permission.INTERNET"/>
   <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
   ```

## Step 2: Integrate MediaMelon SDK Code to SampleApp

The application must register the MediaMelon SDK and provide app information once when the application launches. Please note that values provided in this integration step persist across app sessions.

you need to create Application class `MyApplication.java`

```java
import android.app.Application;
import java.util.HashMap;
import com.mediamelon.appanalytics.MMIntegrationWrapper;

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ....
        MMIntegrationWrapper.getInstance(this).initialize("CUTOMER_ID" , "APP_NAME" , "APP_VERSION");
        HashMap<String , Object> userInfoCustomData = new HashMap<String , Object>();
        userInfoCustomData.put("KEY" , "VALUE");
        MMIntegrationWrapper.reportSubscriberInfo("SUBSCRIBER_ID","SUBSCRIBER_TYPE","SUBSCRIBER_TAG","PROFILE_ID",userInfoCustomData);
        ...
    }
    @Override
    public void onTerminate() {
        super.onTerminate();
        MMIntegrationWrapper.release(true);
    }
}
```

{% hint style="info" %}
**Note:**\
you can rename `MyApplication.java` according to your application
{% endhint %}

Now you need to mention in your `MyApplication.java`  AndroidManifest.xml

```java
 <application
        ...
           android:name=".MyApplication"
        ...
   </application>
```

## Step 3: Custom Data & Referral Data

```java
//Report Referral data
HashMap<String,Object> referralCustomData = new HashMap<String,Object>()
referralCustomData.put("REFERAl_KEY", "R_VALUE");
MMIntegrationWrapper.reportReferralInfo("REFERRAL_ID",referralCustomData);

// Report custom data
HashMap<String,Object> customData = new HashMap<String,Object>()
customData.put("KEY","VALUE")
MMIntegrationWrapper.reportCustomData("EVENT_NAME",customData)
```

## Step 4 : User Actions

* #### Screen View

```java
HashMap<String,Object> screenData = new HashMap<String,Object>()
screenData.put("KEY","VALUE")
MMIntegrationWrapper.reportScreenView("EVENT_NAME",screenData)
```

* #### Event

```java
HashMap<String,Object> eventData = new HashMap<String,Object>()
eventData.put("KEY","VALUE")
MMIntegrationWrapper.reportEvent("EVENT_NAME",eventData)
```

* #### App State

```java
MMIntegrationWrapper.reportAppState("APP_STATE")
```

* #### App Error

<pre class="language-java"><code class="lang-java">HashMap&#x3C;String,Object> errorData = new HashMap&#x3C;String,Object>()
errorData.put("KEY","VALUE")
<strong>MMIntegrationWrapper.reportAppError("APP_ERROR" , errorData)
</strong></code></pre>

* #### Video State

```java
HashMap<String,Object> videoData = new HashMap<String,Object>()
videoData.put("KEY","VALUE")
MMIntegrationWrapper.reportVideoState("VIDEO_STATE" , videoData)
```

* #### Interruption

```java
HashMap<String,Object> interruptionData = new HashMap<String,Object>()
interruptionData.put("KEY","VALUE")
MMIntegrationWrapper.reportInterruption("INTERRUTION_TYPE" , interruptionData)
```

* #### Purchase

```java
HashMap<String,Object> purchaseData = new HashMap<String,Object>()
purchaseData.put("KEY","VALUE")
MMIntegrationWrapper.reportPurchase("PURCHASE_TYPE" , purchaseData)
```

* #### Subscription

<pre class="language-java"><code class="lang-java"><strong>HashMap&#x3C;String,Object> subscriptionData = new HashMap&#x3C;String,Object>()
</strong>subscriptionData.put("KEY","VALUE")
MMIntegrationWrapper.reportSubcription("SUBSCRIPTION_TYPE" , subscriptionData)
</code></pre>

## Step 4: Report Ended State to the SDK

```java
 MMIntegrationWrapper.release(true);
```

| Variable         | Description                                                                                                                                                                          |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| CUSTOMER\_ID     | String containing your MediaMelon-assigned Customer ID.                                                                                                                              |
| SUBSCRIBER\_ID   | String containing your subscriber’s ID. If you do not use subscriber IDs, enter null                                                                                                 |
| SUBSCRIBER\_TYPE | String containing the subscriber type (e.g. “Free”, “Paid”). If you do not use subscriber types, enter null                                                                          |
| SUBSCRIBER\_TAG  | String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field. |
| PROFILE\_ID      | ...                                                                                                                                                                                  |
| REFERRAL\_ID     | A unique referral id                                                                                                                                                                 |


# Custom Multi Player SDK Integration Document

This guide provides detailed instructions on integrating the Android MediaMelon Multi Player Custom SDK .

**Step 1:** [Prerequisites and Setup](#step-1-prerequisites-and-setup)

**Step 2:** [Register and Initialize SDK](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 3:** [Report Session Level Details](#step-3-initialize-session-and-report-user-intent-to-playback-1)

**Step 4:** [Report Player Events](#step-3-initialize-session-and-report-user-intent-to-playback-4)

**Step 5:** [Report Stream and Track Related Events](#step-3-initialize-session-and-report-user-intent-to-playback-5)

**Step 6:** [Report Network Related Information](#step-3-initialize-session-and-report-user-intent-to-playback-9)

Step 7: [Report Errors and Fallback](#step-3-initialize-session-and-report-user-intent-to-playback-10)[s](#step-3-initialize-session-and-report-user-intent-to-playback-10)

Step 8: [Report Ad Events](#step-8-report-a-d-events)

### Step 1: Prerequisites and Setup

* MediaMelon Media3 SDK Maven dependencies or the provided AAR file is necessary.

#### Step 1.1: Set up the build environment&#x20;

> `$MEDIA3PROJECT = {Media3 - v1.x.x}`

The SDK files should be added to the build environment and the required network permissions should be enabled.

1. Add MediaMelon Media3 Maven dependency to `$MEDIA3PROJECT/demos/main/build.gradle`
2. Copy `mmsmartstreaming.aar` provided in the release package for the Media3 project. Example  `$MEDIA3PROJECT/demos/main/mmsmartstreaming.aar` .

{% tabs %}
{% tab title="Maven" %}

```gradle
dependencies {
   ...
  implementation 'com.github.MediamelonSDK:mm-java-custom-sdk:2.0.1'
}
```

{% endtab %}

{% tab title="AAR file" %}

```gradle
dependencies {
  ...
  api files ('mmsmartstreaming.aar')
}
```

{% endtab %}
{% endtabs %}

#### Step 1.2: Provide Manifest Permissions

Add network permissions to `$MEDIA3PROJECT/demos/main/src/main/AndroidManifest.xml`

```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

#### Step 1.3: Import Packages

`$MEDIA3PROJECT/demos/main/src/main/java/androidx/media3/demo/main/PlayerActivity.java`

```java
import com.mediamelon.core.qubit.ChunkStatus;
import com.mediamelon.core.qubit.ChunkType;
import com.mediamelon.core.qubit.DeviceInfo;
import com.mediamelon.core.qubit.ManifestStatus;
import com.mediamelon.core.qubit.Rendition;
import com.mediamelon.core.qubit.ep.AdInfo;
import com.mediamelon.core.qubit.ep.ContentMetadata;
import com.mediamelon.wrapper.smartstreaming.MMIntegrationWrapper;
import com.mediamelon.wrapper.smartstreaming.MMPlayerState;
import com.mediamelon.wrapper.smartstreaming.custom_sdk.MMSmartStreamingMedia3;
```

### Step 2: Register and Initialise SDK <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The player application must register the SDK and provide player information once the player is initialized. Please note that values provided in this integration step persist across video sessions.

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production.

`MMSmartStreamingMedia3.enableLogTrace(false);`
{% endhint %}

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

#### Step 2.1: Get SDK instance&#x20;

For every new player instance create a new sdk instance.

```java
protected boolean initializePlayer() { 
    if (player == null) { 
    Intent intent = getIntent(); ...
    //get the instance of SDK 
    MMIntegrationWrapper sdkInstance = new MMSmartStreamingMedia3(); 
    
    initializeMediaMelon(sdkInstance); 
    ... 
}
```

#### Step 2.2: Initialize session with SDK instance

```java
void initializeMediaMelon(MMIntegrationWrapper sdkInstance){
    sdkInstance.setContext(applicationContext)
    sdkInstance.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG", false);
    sdkInstance.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
    sdkInstance.reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
    sdkInstance.reportAppInfo("APP_NAME","APP_VERSION");
    sdkInstance.reportDeviceInfo(deviceInfo);
    sdkInstance.reportDeviceID("DEVICE_ID");
    
    ContentMetadata cm  = new ContentMetadata();
    cm.assetName="ASSET_NAME";
    cm.assetId="ASSET_ID";
    cm.videoId="VIDEO_ID";
    cm.seriesTitle="SERIES_TITLE";
    cm.season="SEASON";
    cm.genre="GENRE";
    cm.episodeNumber="EPISODE_NUMBER";
    cm.drmProtection="DRM_PROTECTION";
    cm.contentType="CONTENT_TYPE";
    cm.drmLevel = "DRM_LEVEL"
    
    sdkInstance.initializeSession(cm, "PLAYER_INSTANCE_ID");
    sdkInstance.reportUserInitiatedPlayback();
}
```

#### Device Info

| Parameter       | Data Type |
| --------------- | --------- |
| brand           | String    |
| deviceModel     | String    |
| os              | String    |
| osVersion       | String    |
| telecomOperator | String    |
| screenWidth     | String    |
| screenHeight    | String    |

### Step 3: Report Session level details <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

#### Step 3.1 Report Experiment Name

Report the experiment names as a list of String.

```java
sdkInstance.reportExperimentNames(List<String>);
```

#### Step 3.2: Report View Session Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
sdkInstance.reportViewSessionId("VIEW_SESSION_ID");
```

#### Step 3.3: Report Sub Property Id <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
sdkInstance.reportSubPropertyId("SUB_PROPERTY_ID");
```

#### Step 3.4: Report Time Shift Enabled / DVR enabled

```java
sdkInstance.reportTimeShiftEnabled(isTimeShiftEnabled); // isTimeShiftEnabled -> boolean
```

#### Step 3.5: Report Page Type

```java
sdkInstance.reportPageType("PAGE_TYPE");
```

#### Step 3.6: Report PiP Mode

Report the PiP status of the player. If the player goes into PiP mode throughout the session report *true*.

```java
sdkInstance.reportPipEnabled(isPipEnabled); // isPipEnabled -> boolean
```

#### Step 3.7: Report Device Orientation

Report current orientation of device as string.&#x20;

```java
sdkInstance.reportDeviceOrientation("ORIENTATION");
```

#### Step 3.8: Report Custom Metadata

Report additional custom metadata

```java
sdkInstance.reportCustomMetadata("custom_1", "VALUE_1");
```

### Step 4: Report Player Events <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

#### Step 4.1: Report Player State

{% hint style="info" %}
Make sure to report ***MMPlayerState.STOPPED*** at the end of playback completion to mark session as ended.
{% endhint %}

```java
// Report Player State --> Playing, Paused, Stopped
sdkInstance.reportPlayerState(MMPlayerState.PLAYING);
```

| MMPlayerState |
| ------------- |
| PLAYING       |
| PAUSED        |
| STOPPED       |

#### Step 4.2: Report Buffering Events

```java
//buffering start
sdkInstance.reportBufferingStarted();

//buffering complete
sdkInstance.reportBufferingCompleted();
```

#### Step 4.3 Report Seek Events

```java
//seek started
sdkInstance.reportSeekStarted();
      
//seek completed
sdkInstance.reportSeekCompleted();
```

#### Step 4.4: Report Playback Position

Report Playback position in ms.

```java
sdkInstance.reportPlaybackPosition(playbackpos);
```

### Step 5: Report Stream and Track Related Information <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

#### &#x20;Step 5.1: Report Stream URL <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

Report stream url that is currently being used.

```java
sdkInstance.setStreamURL("STREAM_URL");
```

#### Step 5.2: Report Stream  Information

Report Information related to stream

```java
sdkInstance.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SOURCE_TYPE", isLive);
```

#### Step 5.3: Report Video Duration <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
sdkInstance.reportVideoDuration(inMilliSeconds);
```

#### Step 5.4:  Report Track Related Information <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

```java
sdkInstance.reportTrackInfo("AUDIO_TRACK", "SUBTITLE_TRACK", isSubtitleActive, isVDSActive, "VIDEO_TRACK");
```

#### Step 5.5: Report Rendition Changes

Report changes in the rendition of current stream  wrapped in the `Rendition` object.

```java
sdkInstance.reportRendition(renditionObject);
```

#### Rendition Object

| Parameter | Data Type |
| --------- | --------- |
| bitrate   | int       |
| width     | int       |
| height    | int       |
| frameRate | double    |
| aCodec    | String    |
| vCodec    | String    |

### Step 6:  Report Network Related Information <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

#### Step 6.1 Report Network Info

```java
sdkInstance.reportNetworkInfo("CDN", "ASN", "HOST_NAME", "NETWORK_TYPE", "NETWORK_OPERATOR"); 
```

#### Step 6.2: Report Request Status

```java
sdkInstance.reportRequestStatus(RequestStatus, "REQUEST_TYPE", map); // map -> Map<String, String>
```

| RequestStatus |
| ------------- |
| FAILED        |
| CANCELLED     |

#### Step 6.3: Report Player Download rate

```java
sdkInstance.reportPlayerDownloadRate(bps) //  bps -> Long 
```

### Step 7: Report Errors & Fallbacks <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

#### Step 7.1: Report Fatal Errors

```java
//Custom Errors 
sdkInstance.reportError(ERROR_CODE_INT, "ERROR_MESSAGE", "ERROR_DETAILS");
```

#### Step 7.2: Report Warnings

```java
sdkInstance.reportWarning(ERROR_CODE_INT, "ERROR_MESSAGE", "ERROR_DETAILS");
```

#### Step 7.3: Report Stream Fallback event

Report fallback events in case a fallback strategy is applied.&#x20;

```java
sdkInstance.reportFallbackEvent("FALLBACK_STREAM_URL", "DESCRIPTION");
```

#### Step 7.4: Update DRM Type

```java
sdkInstance.updateDRMType("DRM_TYPE", "DRM_LEVEL");
```

#### Step 7.5: Update Content Metadata

```java
sdkInstance.updateContentMetadata(cm);
```

### Step 8: Report Ad Events

#### Step 8.1: Report Ad Breaks

```java
sdkInstance.reportAdBreakStarted();
sdkInstance.reportAdBreakEnded();
```

#### Step 8.2: Report Ad Start and End

```java
sdkInstance.reportAdStarted(adInfoObject);
sdkInstance.reportAdEnd();
```

#### Step 8.3 Report Ad Quartile Events

```java
sdkInstance.reportAdFirstQuartile();
sdkInstance.reportAdMidpoint();
sdkInstance.reportAdThirdQuartile();
```

#### Step 8.4 Report Ad Request/Response (Optional)

```java
sdkInstance.reportAdRequest(map) // map -> Map<String, String>
sdkInstance.reportAdResponse(map)
```

#### AdInfo Object

<table data-header-hidden><thead><tr><th width="238.8984375">Field</th><th>Description</th></tr></thead><tbody><tr><td>adInfo.adTitle</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adInfo.adId</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adInfo.adCreativeId</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adInfo.adCreativeType</td><td>The format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>adInfo.adClient</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adInfo.adPosition</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adInfo.adServer</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adInfo.adResolution</td><td>The resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>adInfo.adUrl</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adInfo.adDuration</td><td>The total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>adInfo.adPodIndex</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adInfo.adPositionInPod</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>adInfo.adPodLendth</td><td>The total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr><tr><td>adInfo.isBumper</td><td>A boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr><tr><td>adInfo.adUniversalId</td><td>A String value to report Ad Universal ID.</td></tr></tbody></table>


# Exoplayer v2.11

This guide is for integrating MediaMelon SDK with Exoplayer v2.11.0 - v2.11.8

{% hint style="info" %}
This guide uses Exoplayer 2.11.4 as a reference. Please replace with the correct version of v2.11 player
{% endhint %}

### Prerequisites&#x20;

1. ExoPlayer-r2.11.4 <https://github.com/google/ExoPlayer>&#x20;
2. MediaMelon SmartSight SDK `smartstreaming.aar`

### Step 1: Set up the build environment&#x20;

Note `$EXOPROJECT = {ExoPlayer-r2.11.4}`&#x20;

The SDK files are added to the build environment and the required network permissions are enabled.&#x20;

1. Copy smartstreaming-release.aar provided with the release package to the exoplayer project, Example `$EXOPROJECT/demos/main/smartstreaming-release.aar`&#x20;
2. Add the following library to `$EXOPROJECT/demos/main/build.gradle` :-

```java
dependencies {
  .
  .
  .
   //<!-- <MMSmartStreaming 1b> -->
    api files ('smartstreaming-release.aar')
  //<!-- </MMSmartStreaming 1b> -->
  
}
```

Add network permissions to `$EXOPROJECT/demos/main/src/main/AndroidManifest.xml`

```java
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- <MMSmartStreaming 1c> -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- </MMSmartStreaming 1c> -->
```

### Step 2: Register SDK

The player application must register the SDK and provide player information once when the application launches. Please note that values provided in this integration step persist across video sessions. This is typically done when the player itself is initialized.&#x20;

{% hint style="info" %}
You can check SDK registration status with `getRegistrationStatus()`. If the registration is not complete, use the `registerMMSmartStreaming()` to complete the registration.
{% endhint %}

#### Step 2a: Import packages

`$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
// <MMSmartStreaming 2a>
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMSmartStreaming;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
import com.mediamelon.smartstreaming.MMSmartStreamingInitializationStatus;
import com.mediamelon.smartstreaming.MMSmartStreamingObserver;
import java.util.ArrayList;
import android.util.Log;
// </MMSmartStreaming 2a>
```

#### Step 2b: Registration

&#x20;Perform registration tasks by modifying the `onCreate()` method in `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production
{% endhint %}

```java
public void onCreate(Bundle savedInstanceState) {
  ...
  }else {
    trackSelectorParameters = new DefaultTrackSelector.ParametersBuilder().build();
    clearStartPosition();
  }

  //<MMSmartStreaming 2b>
  Log.d("SmartStreamingIntgr", MMSmartStreamingExo2.getVersion());
  MMSmartStreamingExo2.enableLogTrace(true); //set to "false" before releasing player to production
  if (MMSmartStreamingExo2.getRegistrationStatus() == false)

{ //Check if it is the first time Registration process is done

    MMSmartStreamingExo2.registerMMSmartStreaming($PLAYERNAME, $CUSTOMERID, $SUBSCRIBERID, $DOMAINNAME, $SUBSCRIBERTYPE, $SUBSCRIBERTAG);
    MMSmartStreamingExo2.reportPlayerInfo("CustomPlayerName", ExoPlayerLibraryInfo.VERSION, "1.0");
    MMSmartStreamingExo2.getInstance().setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
  }
  // </MMSmartStreaming 2b> 
}
```

### Step 3: Initialize Session & Report User Intent to Playback <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

Provide application context to SDK by modifying the `createTopLevelMediaSource()` method in `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
@Nullable
  private MediaSource createTopLevelMediaSource(Intent intent) {
    String action = intent.getAction();
    boolean actionIsListView = ACTION_VIEW_LIST.equals(action);
    if (!actionIsListView && !ACTION_VIEW.equals(action)) {
      showToast(getString(R.string.unexpected_intent_action, action));
      finish();
      return null;
    }

    Sample intentAsSample = Sample.createFromIntent(intent);
    UriSample[] samples =
        intentAsSample instanceof Sample.PlaylistSample
            ? ((Sample.PlaylistSample) intentAsSample).children
            : new UriSample[] {(UriSample) intentAsSample};

    boolean seenAdsTagUri = false;
    for (UriSample sample : samples) {
      seenAdsTagUri |= sample.adTagUri != null;
      if (!Util.checkCleartextTrafficPermitted(sample.uri)) {
        showToast(R.string.error_cleartext_not_permitted);
        return null;
      }
      if (Util.maybeRequestReadExternalStoragePermission(/* activity= */ this, sample.uri)) {
        // The player will be reinitialized if the permission is granted.
        return null;
      }
    }

    MediaSource[] mediaSources = new MediaSource[samples.length];
    for (int i = 0; i < samples.length; i++) {
      mediaSources[i] = createLeafMediaSource(samples[i]);
      Sample.SubtitleInfo subtitleInfo = samples[i].subtitleInfo;
      if (subtitleInfo != null) {
        if (Util.maybeRequestReadExternalStoragePermission(
            /* activity= */ this, subtitleInfo.uri)) {
          // The player will be reinitialized if the permission is granted.
          return null;
        }
        Format subtitleFormat =
            Format.createTextSampleFormat(
                /* id= */ null,
                subtitleInfo.mimeType,
                C.SELECTION_FLAG_DEFAULT,
                subtitleInfo.language);
        MediaSource subtitleMediaSource =
            new SingleSampleMediaSource.Factory(dataSourceFactory)
                .createMediaSource(subtitleInfo.uri, subtitleFormat, C.TIME_UNSET);
        mediaSources[i] = new MergingMediaSource(mediaSources[i], subtitleMediaSource);
      }
    }
    MediaSource mediaSource =
        mediaSources.length == 1 ? mediaSources[0] : new ConcatenatingMediaSource(mediaSources);
        
    // //<MMSmartStreaming 3> Integration start ------
    if(mediaSources.length > 0 ){
      String mediaUrl = samples[0].uri.toString();
      MMSmartStreamingExo2.getInstance().initializeSession(player, $QBRREQUESTEDMODE, mediaUrl, $ASSETMETAURL, "ASSETID", "ASSETNAME", "VIDEOID", null);
    }
    // //</MMSmartStreaming 3> Integration end -------

    if (seenAdsTagUri) {
      Uri adTagUri = samples[0].adTagUri;
      if (actionIsListView) {
        showToast(R.string.unsupported_ads_in_concatenation);
      } else {
        if (!adTagUri.equals(loadedAdTagUri)) {
          releaseAdsLoader();
          loadedAdTagUri = adTagUri;
        }
        MediaSource adsMediaSource = createAdsMediaSource(mediaSource, adTagUri);
        if (adsMediaSource != null) {
          mediaSource = adsMediaSource;
        } else {
          showToast(R.string.ima_not_loaded);
        }
      }
    } else {
      releaseAdsLoader();
    }

    return mediaSource;
  }
```

{% hint style="info" %}
Please note line number 55-60 is where MediaMelon code is added
{% endhint %}

### Step 4: Report User Intent to Playback <a href="#step-4-report-user-intent-to-playback" id="step-4-report-user-intent-to-playback"></a>

When the user presses the play button for the first time to start the playback, or in autoplay mode when a player is fed with a content URL to load the session, `reportUserInitiatedPlayback()` should be called. In the demo application, autoplay is “on”, so let's call this API just before `player.prepare()`

In `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
// Internal methods

  private void initializePlayer() {
    if (player == null) {
      Intent intent = getIntent();
      // <MMSmartStreaming 4> Integration start Comment below lines 
      //mediaSource = createTopLevelMediaSource(intent);
      //if (mediaSource == null) {
      //  return;
      //}
      // </MMSmartStreaming 4> Integration end
      
      TrackSelection.Factory trackSelectionFactory;
      String abrAlgorithm = intent.getStringExtra(ABR_ALGORITHM_EXTRA);
      if (abrAlgorithm == null || ABR_ALGORITHM_DEFAULT.equals(abrAlgorithm)) {
        trackSelectionFactory = new AdaptiveTrackSelection.Factory();
      } else if (ABR_ALGORITHM_RANDOM.equals(abrAlgorithm)) {
        trackSelectionFactory = new RandomTrackSelection.Factory();
      } else {
        showToast(R.string.error_unrecognized_abr_algorithm);
        finish();
        return;
      }

      boolean preferExtensionDecoders =
          intent.getBooleanExtra(PREFER_EXTENSION_DECODERS_EXTRA, false);
      RenderersFactory renderersFactory =
          ((DemoApplication) getApplication()).buildRenderersFactory(preferExtensionDecoders);

      trackSelector = new DefaultTrackSelector(/* context= */ this, trackSelectionFactory);
      trackSelector.setParameters(trackSelectorParameters);
      lastSeenTrackGroupArray = null;

      player =
          new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory)
              .setTrackSelector(trackSelector)
              .build();
      player.addListener(new PlayerEventListener());
      player.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true);
      player.setPlayWhenReady(startAutoPlay);
      player.addAnalyticsListener(new EventLogger(trackSelector));
      playerView.setPlayer(player);
      playerView.setPlaybackPreparer(this);
      debugViewHelper = new DebugTextViewHelper(player, debugTextView);
      debugViewHelper.start();
      if (adsLoader != null) {
        adsLoader.setPlayer(player);
      }
      // <MMSmartStreaming 4> Integration start Add below lines
      mediaSource = createTopLevelMediaSource(intent);
      if (mediaSource == null) {
        return;
      }
      // </MMSmartStreaming 4> Integration end
    }
    boolean haveStartPosition = startWindow != C.INDEX_UNSET;
    if (haveStartPosition) {
      player.seekTo(startWindow, startPosition);
    }
    // <MMSmartStreaming 4> Integration Start (User playback Loaded)
    MMSmartStreamingExo2.getInstance().reportUserInitiatedPlayback();
    // </MMSmartStreaming 4> Integration end
    player.prepare(mediaSource, !haveStartPosition, false);
    updateButtonVisibility();
  }
```

### Step 5: Report ended state when the player instance is released <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

In `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
private void releasePlayer() {
    if (player != null) {
      updateTrackSelectorParameters();
      updateStartPosition();
      debugViewHelper.stop();
      debugViewHelper = null;
      player.release();
      player = null;
      mediaSource = null;
      trackSelector = null;
       // <MMSmartStreaming 5> Start
	  MMSmartStreamingExo2.getInstance().reportPlayerState(false, Player.STATE_ENDED);
	  // </MMSmartStreaming 5> End
    }
    if (adsLoader != null) {
      adsLoader.setPlayer(null);
    }
  }
```


# Exoplayer v2.12.2 integration with MediaMelon SDK

This guide is for integrating MediaMelon SDK with Exoplayer v2.12.2

### Prerequisites&#x20;

1. ExoPlayer-r2.12.2 <https://github.com/google/ExoPlayer>&#x20;
2. MediaMelon SmartSight SDK `smartstreaming.aar`

### Step 1: Set up the build environment&#x20;

Note `$EXOPROJECT = {ExoPlayer-r2.12.2}`&#x20;

The SDK files are added to the build environment and the required network permissions are enabled.&#x20;

1. Copy smartstreaming-release.aar provided with the release package to the exoplayer project, Example `$EXOPROJECT/demos/main/smartstreaming-release.aar`&#x20;
2. Add the following library to `$EXOPROJECT/demos/main/build.gradle` :-

```java
dependencies {
  .
  .
  .
   //<!-- <MMSmartStreaming 1b> -->
    api files ('smartstreaming-release.aar')
  //<!-- </MMSmartStreaming 1b> -->
  
}
```

Add network permissions to `$EXOPROJECT/demos/main/src/main/AndroidManifest.xml`

```java
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- <MMSmartStreaming 1c> -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- </MMSmartStreaming 1c> -->
```

### Step 2: Register SDK

The player application must register the SDK and provide player information once when the application launches. Please note that values provided in this integration step persist across video sessions. This is typically done when the player itself is initialized.&#x20;

{% hint style="info" %}
You can check SDK registration status with `getRegistrationStatus()`. If the registration is not complete, use the `registerMMSmartStreaming()` to complete the registration.
{% endhint %}

#### Step 2a: Import packages

`$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
// <MMSmartStreaming 2a>
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMSmartStreaming;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
import com.mediamelon.smartstreaming.MMSmartStreamingInitializationStatus;
import com.mediamelon.smartstreaming.MMSmartStreamingObserver;
import java.util.ArrayList;
import android.util.Log;
// </MMSmartStreaming 2a>
```

#### Step 2b: Registration

&#x20;Perform registration tasks by modifying the `onCreate()` method in `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production
{% endhint %}

```java
public void onCreate(Bundle savedInstanceState) {
  ...
  }else {
    trackSelectorParameters = new DefaultTrackSelector.ParametersBuilder().build();
    clearStartPosition();
  }

  //<MMSmartStreaming 2b>
  Log.d("SmartStreamingIntgr", MMSmartStreamingExo2.getVersion());
  MMSmartStreamingExo2.enableLogTrace(true); //set to "false" before releasing player to production
  if (MMSmartStreamingExo2.getRegistrationStatus() == false)

{ //Check if it is the first time Registration process is done

    MMSmartStreamingExo2.registerMMSmartStreaming($PLAYERNAME, $CUSTOMERID, $SUBSCRIBERID, $DOMAINNAME, $SUBSCRIBERTYPE, $SUBSCRIBERTAG);
    MMSmartStreamingExo2.reportPlayerInfo("CustomPlayerName", ExoPlayerLibraryInfo.VERSION, "1.0");
    MMSmartStreamingExo2.getInstance().setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
  }
  // </MMSmartStreaming 2b> 
}
```

### Step 3: Initialize Session & Report User Intent to Playback <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

Provide application context to SDK by modifying the `createTopLevelMediaSource()` method in `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
protected boolean initializePlayer() {
if (player == null) {
Intent intent = getIntent();
...
...
...

// after player is initialised and not null anymore
    String mediaUrl = "get the mediaURL from your application"
    String assetId  = "assetID"; //enter you assetId here
    String assetName = "assetNAME"; // enter your assetname here
    String videoId = "videoID"; // enter your videoId here
    ContentMetadata cm  = new ContentMetadata();
    String episodeNumber = "EpisodeNumber";
    String season = "Season";
    String genre = "Genre";
    String drmProtection = "drmProtection";
    String contentType = "contentType";
    String title = "Title";
    cm.videoId=videoId;
    cm.seriesTitle=title;
    cm.season=season;
    cm.genre=genre;
    cm.episodeNumber=episodeNumber;
    cm.drmProtection=drmProtection;
    cm.contentType=contentType;
    cm.assetName=assetName;
    cm.assetId=assetId;
    JSONObject contentMetadata = cm.getJSONObject();
    //optional content metadata
    MMSmartStreamingExo2.getInstance().initializeSession(player, MMQBRMode.QBRModeDisabled, mediaUrl, null, assetId, assetName, videoId,null,contentMetadata);
    MMSmartStreamingExo2.getInstance().reportUserInitiatedPlayback();
 ...
 ...
}
```

### Step 4: Report User Intent to Playback <a href="#step-4-report-user-intent-to-playback" id="step-4-report-user-intent-to-playback"></a>

When the user presses the play button for the first time to start the playback, or in autoplay mode when a player is fed with a content URL to load the session, `reportUserInitiatedPlayback()` should be called. In the demo application, autoplay is “on”, so let's call this API just before `player.prepare()`

In `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
// Internal methods

  private void initializePlayer() {
    if (player == null) {
      Intent intent = getIntent();
      MMSmartStreamingExo2.getInstance().reportUserInitiatedPlayback();
      player.prepare(mediaSource, !haveStartPosition, false);
      updateButtonVisibility();
  }
```

### Step 5: Report ended state when the player instance is released <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

In `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
private void releasePlayer() {
    if (player != null) {
      updateTrackSelectorParameters();
      updateStartPosition();
      debugViewHelper.stop();
      debugViewHelper = null;
      player.release();
      player = null;
      mediaSource = null;
      trackSelector = null;
       // <MMSmartStreaming 5> Start
	  MMSmartStreamingExo2.getInstance().reportPlayerState(false, Player.STATE_ENDED);
	  // </MMSmartStreaming 5> End
    }
    if (adsLoader != null) {
      adsLoader.setPlayer(null);
    }
  }
```


# Exoplayer v2.13.2 integration with MediaMelon SDK

### Prerequisites

* ExoPlayer-r2.13.2 <https://github.com/google/ExoPlayer>&#x20;
* MediaMelon SmartSight SDK `smartstreaming.aar`

### Step 1: Set up the build environment&#x20;

Note `$EXOPROJECT = {ExoPlayer-r2.13.2}`&#x20;

The SDK files are added to the build environment and the required network permissions are enabled.&#x20;

1. Copy smartstreaming-release.aar provided with the release package to the exoplayer project, Example `$EXOPROJECT/demos/main/smartstreaming-release.aar`&#x20;
2. Add the following library to `$EXOPROJECT/demos/main/build.gradle` :-

```java
dependencies {
  .
  .
  .
   //<!-- <MMSmartStreaming 1b> -->
    api files ('smartstreaming-release.aar')
  //<!-- </MMSmartStreaming 1b> -->
  
}
```

Add network permissions to `$EXOPROJECT/demos/main/src/main/AndroidManifest.xml`

```java
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- <MMSmartStreaming 1c> -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- </MMSmartStreaming 1c> -->
```

### Step 2: Register SDK

The player application must register the SDK and provide player information once when the application launches. Please note that values provided in this integration step persist across video sessions. This is typically done when the player itself is initialized.&#x20;

#### &#x20;Step 2a: Import packages

`$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
// <MMSmartStreaming 2a>
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMSmartStreaming;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
import com.mediamelon.smartstreaming.MMSmartStreamingInitializationStatus;
import com.mediamelon.smartstreaming.MMSmartStreamingObserver;
import com.mediamelon.qubit.ep.ContentMetadata;
import java.util.ArrayList;
import android.util.Log;
// </MMSmartStreaming 2a>
```

#### Step 2b: Registration

&#x20;Perform registration tasks by modifying the `onCreate()` method in `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production
{% endhint %}

```java
public void onCreate(Bundle savedInstanceState) {
  ...
  }else {
    trackSelectorParameters = new DefaultTrackSelector.ParametersBuilder().build();
    clearStartPosition();
  }

  //<MMSmartStreaming 2b>
  Log.d("SmartStreamingIntgr", MMSmartStreamingExo2.getVersion());
  MMSmartStreamingExo2.enableLogTrace(true); //set to "false" before releasing player to production
  if (MMSmartStreamingExo2.getRegistrationStatus() == false)

{ //Check if it is the first time Registration process is done

    MMSmartStreamingExo2.registerMMSmartStreaming($PLAYERNAME, $CUSTOMERID, $SUBSCRIBERID, $DOMAINNAME, $SUBSCRIBERTYPE, $SUBSCRIBERTAG);
    MMSmartStreamingExo2.reportPlayerInfo("CustomPlayerName", ExoPlayerLibraryInfo.VERSION, "1.0");
    MMSmartStreamingExo2.getInstance().setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
  }
 MMSmartStreamingExo2.disableManifestsFetch(true); // pass true if you want to disable Manifests Fetch 
  // </MMSmartStreaming 2b> 
}
```

### Step 3: Initialize Session & Report User Intent to Playback <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

```java
protected boolean initializePlayer() {
if (player == null) {
Intent intent = getIntent();
...
...
...

// after player is initialised and not null anymore
    String mediaUrl = "get the mediaURL from your application"
    String assetId  = "assetID"; //enter you assetId here
    String assetName = "assetNAME"; // enter your assetname here
    String videoId = "videoID"; // enter your videoId here
    ContentMetadata cm  = new ContentMetadata();
    String episodeNumber = "EpisodeNumber";
    String season = "Season";
    String genre = "Genre";
    String drmProtection = "drmProtection";
    String contentType = "contentType";
    String title = "Title";
    cm.videoId=videoId;
    cm.seriesTitle=title;
    cm.season=season;
    cm.genre=genre;
    cm.episodeNumber=episodeNumber;
    cm.drmProtection=drmProtection;
    cm.contentType=contentType;
    cm.assetName=assetName;
    cm.assetId=assetId;
    JSONObject contentMetadata = cm.getJSONObject();
    //optional content metadata
    //(optional) add custom tags
    MMSmartStreamingExo2.getInstance().reportCustomMetadata("key","value");
    MMSmartStreamingExo2.getInstance().initializeSession(player, MMQBRMode.QBRModeDisabled, mediaUrl, null, assetId, assetName, videoId,null,contentMetadata);
    MMSmartStreamingExo2.getInstance().reportUserInitiatedPlayback();
 ...
 ...
}
```

### Step 4: Report ended state when the player instance is released <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

In `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
private void releasePlayer() {
    if (player != null) {
      updateTrackSelectorParameters();
      updateStartPosition();
      debugViewHelper.stop();
      debugViewHelper = null;
      player.release();
      player = null;
      mediaSource = null;
      trackSelector = null;
       // <MMSmartStreaming 5> Start
	  MMSmartStreamingExo2.getInstance().reportPlayerState(false, Player.STATE_ENDED);
	  // </MMSmartStreaming 5> End
    }
    if (adsLoader != null) {
      adsLoader.setPlayer(null);
    }
  }
```


# Exoplayer v2.13.3 integration with MediaMelon SDK

### Prerequisites

* ExoPlayer-r2.13.3 <https://github.com/google/ExoPlayer>&#x20;
* MediaMelon SmartSight SDK `smartstreaming.aar`

### Step 1: Set up the build environment&#x20;

Note `$EXOPROJECT = {ExoPlayer-r2.13.3}`&#x20;

The SDK files are added to the build environment and the required network permissions are enabled.&#x20;

1. Copy smartstreaming-release.aar provided with the release package to the exoplayer project, Example `$EXOPROJECT/demos/main/smartstreaming-release.aar`&#x20;
2. Add the following library to `$EXOPROJECT/demos/main/build.gradle` :-

```java
dependencies {
  .
  .
  .
   //<!-- <MMSmartStreaming 1b> -->
    api files ('smartstreaming-release.aar')
  //<!-- </MMSmartStreaming 1b> -->
  
}
```

Add network permissions to `$EXOPROJECT/demos/main/src/main/AndroidManifest.xml`

```java
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- <MMSmartStreaming 1c> -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- </MMSmartStreaming 1c> -->
```

### Step 2: Register SDK

The player application must register the SDK and provide player information once when the application launches. Please note that values provided in this integration step persist across video sessions. This is typically done when the player itself is initialized.&#x20;

#### &#x20;Step 2a: Import packages

`$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
// <MMSmartStreaming 2a>
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMSmartStreaming;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
import com.mediamelon.smartstreaming.MMSmartStreamingInitializationStatus;
import com.mediamelon.smartstreaming.MMSmartStreamingObserver;
import com.mediamelon.qubit.ep.ContentMetadata;
import java.util.ArrayList;
import android.util.Log;
// </MMSmartStreaming 2a>
```

#### Step 2b: Registration

&#x20;Perform registration tasks by modifying the `onCreate()` method in `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production
{% endhint %}

```java
public void onCreate(Bundle savedInstanceState) {
  ...
  }else {
    trackSelectorParameters = new DefaultTrackSelector.ParametersBuilder().build();
    clearStartPosition();
  }

  //<MMSmartStreaming 2b>
  Log.d("SmartStreamingIntgr", MMSmartStreamingExo2.getVersion());
  MMSmartStreamingExo2.enableLogTrace(true); //set to "false" before releasing player to production
  if (MMSmartStreamingExo2.getRegistrationStatus() == false)

{ //Check if it is the first time Registration process is done

    MMSmartStreamingExo2.registerMMSmartStreaming($PLAYERNAME, $CUSTOMERID, $SUBSCRIBERID, $DOMAINNAME, $SUBSCRIBERTYPE, $SUBSCRIBERTAG);
    MMSmartStreamingExo2.reportPlayerInfo("CustomPlayerName", ExoPlayerLibraryInfo.VERSION, "1.0");
    MMSmartStreamingExo2.getInstance().setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
  }
 MMSmartStreamingExo2.disableManifestsFetch(true); // pass true if you want to disable Manifests Fetch 
  // </MMSmartStreaming 2b> 
}
```

### Step 3: Initialize Session & Report User Intent to Playback <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

```java
protected boolean initializePlayer() {
if (player == null) {
Intent intent = getIntent();
...
...
...

// after player is initialised and not null anymore
    String mediaUrl = "get the mediaURL from your application"
    String assetId  = "assetID"; //enter you assetId here
    String assetName = "assetNAME"; // enter your assetname here
    String videoId = "videoID"; // enter your videoId here
    ContentMetadata cm  = new ContentMetadata();
    String episodeNumber = "EpisodeNumber";
    String season = "Season";
    String genre = "Genre";
    String drmProtection = "drmProtection";
    String contentType = "contentType";
    String title = "Title";
    cm.videoId=videoId;
    cm.seriesTitle=title;
    cm.season=season;
    cm.genre=genre;
    cm.episodeNumber=episodeNumber;
    cm.drmProtection=drmProtection;
    cm.contentType=contentType;
    cm.assetName=assetName;
    cm.assetId=assetId;
    JSONObject contentMetadata = cm.getJSONObject();
    //optional content metadata
    //(optional) add custom tags
    MMSmartStreamingExo2.getInstance().reportCustomMetadata("key","value");
    MMSmartStreamingExo2.getInstance().initializeSession(player, MMQBRMode.QBRModeDisabled, mediaUrl, null, assetId, assetName, videoId,null,contentMetadata);
    MMSmartStreamingExo2.getInstance().reportUserInitiatedPlayback();
 ...
 ...
}
```

### Step 4: Report ended state when the player instance is released <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

In `$EXOPROJECT/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java`

```java
private void releasePlayer() {
    if (player != null) {
      updateTrackSelectorParameters();
      updateStartPosition();
      debugViewHelper.stop();
      debugViewHelper = null;
      player.release();
      player = null;
      mediaSource = null;
      trackSelector = null;
       // <MMSmartStreaming 5> Start
	  MMSmartStreamingExo2.getInstance().reportPlayerState(false, Player.STATE_ENDED);
	  // </MMSmartStreaming 5> End
    }
    if (adsLoader != null) {
      adsLoader.setPlayer(null);
    }
  }
```


# ExoPlayer v2.14.2 MediaMelon SDK with Google IMA DAI

This procedure describes the MediaMelon SDK(with  Google  IMA DAI) Integration with a ExoPlayer Android . This is a sample integration done with the sample application from the Google IMA DAI.

## Prerequisites:

1. Google IMA DAI Sample app (link for the sample app - <https://github.com/googleads/googleads-ima-android-dai>)\
   Documentation of the sample app -<https://developers.google.com/interactive-media-ads/docs/sdks/android/dai>
2. MediaMelon SmartSight SDK`exoplayer-smartstreaming-release.aar`
3. MediaMelon-assigned Customer ID

**Note:** If you do not know your Customer ID contact mediamelon at [support@mediamelon.com](mailto:support%40mediamelon.com)

## **Step 1: Set up the build environment**

The SDK files are added to the build environment and the required network permissions are enabled.

1. Copy `exoplayer-smartstreaming-release.aar` provided with the release package to `BasicExample/app/`
2. Add the following library to `BasicExample/app/build.gradle` :-<br>

   ```
   dependencies {
       .
       .
       implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.24.0'
       implementation 'com.google.android.exoplayer:exoplayer:2.14.2'
       api files ('exoplayer-smartstreaming-release.aar')
       .
       .
   }
   ```

## Step 2: Add MediaMelon library to  Sample App.

\
**Step 2.1 :** \
Add the below imports to:\
*BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\videoplayerapp/MyActivity.java*

```java
import com.mediamelon.smartstreaming.MMAVAssetInformation;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMRegistrationInformation;
import com.mediamelon.smartstreaming.MMSmartStreaming;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
```

\
**Step 2.2 :** \
Add the below imports to: *BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\samplevideoplayer/SampleVideoPlayer.java*

```java
import com.mediamelon.qubit.ep.ContentMetadata;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
```

**Step 2.3 :** \
Add the below imports to: \
*BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\videoplayerapp/SampleAdsWrapper.java*

```java
import com.mediamelon.smartstreaming.MMAnalyticsBridge;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
```

### &#x20;Step 3 : Integrate MediaMelon code to the Sample App

The below steps shows the procedure to integrate the MediaMelon library to the sample app.\
**Note -**  Only the code written inside the *\<MediaMelon Integration>* tag is to be added for MediaMelon specific integration , the rest of the code above and below the *\<MediaMelon Integration>* tag is shown just to give a context ,as shown below :-

```java
<MediaMelon Integration>
Code for MediaMelon specific integration
<//MediaMelon Integration>
```

\
\
**Step 3.1:**\
Add the following code to:\
*BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\samplevideoplayer/SampleVideoPlayer.java*

```java
private void initPlayer() { // this is the function that creates/initialises the EXO player
  release();
  simpleExoPlayer = new SimpleExoPlayer.Builder(context).build();
  playerView.setPlayer(simpleExoPlayer);
  .
  .
  .
  .
  <MediaMelon Integration>
  String assetId  = "assetID"; //enter you assetId here
  String assetName = "assetNAME"; // enter your assetname here
  String videoId = "videoID"; // enter your videoId here

  //optional content metadata
  ContentMetadata cm  = new ContentMetadata();
  String episodeNumber ="$episodeNumber ";
  String season = "$season";
  String genre = "$genre";
  String drmProtection = "$drmProtection";
  String contentType = "$contentType";
  String title = "$title";
  String videoType  = "$videoType";
  cm.videoId=videoId;
  cm.seriesTitle=title;
  cm.season=season;
  cm.genre=genre;
  cm.episodeNumber=episodeNumber;
  cm.drmProtection=drmProtection;
  cm.contentType=contentType;
  cm.assetName=assetName;
  cm.assetId=assetId;
  cm.videoType = videoType;
  JSONObject ContentMetadataAsJSON = cm.getJSONObject();
  //the below initializeSession() call is to be made only after the EXO player instance has been created
  MMSmartStreamingExo2.getInstance().initializeSession(simpleExoPlayer,MMQBRMode.QBRModeDisabled,"$streamUrl",null,assetId,assetName,videoId,null,ContentMetadataAsJSON);
  //(optional) add custom tags
  MMSmartStreamingExo2.getInstance().reportCustomMetadata("key","value");
  MMSmartStreamingExo2.getInstance().reportUserInitiatedPlayback();
  <//MediaMelon Integration>
};
```

```java
private void release() {
  if (simpleExoPlayer != null) {
    simpleExoPlayer.release();
    simpleExoPlayer = null;
    streamRequested = false;
    <MediaMelon Integration>
    MMSmartStreamingExo2.getInstance().reportPlayerState(false, Player.STATE_ENDED);
    <//MediaMelon Integration>
  }
}
```

\
**Step 3.2:**\
Add the following code to:\
*BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\videoplayerapp/MyActivity.java*

```java
@Override
  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);
    .
    .
    .
    .
    <MediaMelon Integration>
    Log.d("SmartStreamingIntgr", MMSmartStreamingExo2.getVersion());
    MMSmartStreamingExo2.enableLogTrace(true); //set to "false" before releasing player to production
    if (MMSmartStreamingExo2.getRegistrationStatus() == false){ //Check if it is the first time Registration process is done
      MMSmartStreamingExo2.registerMMSmartStreaming("$PLAYERNAME", "$CustomerId", "$SUBSCRIBERID", "$DOMAINNAME", "$SUBSCRIBERTYPE", "$SUBSCRIBERTAG");
      MMSmartStreamingExo2.reportPlayerInfo("$Brand", "$Model", "$Version");
      MMSmartStreamingExo2.getInstance().setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
    }
    <//MediaMelon Integration>
    .
    .
    .
    .

  }

```

| Variable         | Description                                                                                                                                                                          |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| $PLAYERNAME      | String containing the player version (e.g. “Bitmovin\_Android\_Player\_2.28.0”).                                                                                                     |
| $CUSTOMERID      | String containing your MediaMelon-assigned Customer ID.                                                                                                                              |
| $SUBSCRIBERID    | String containing your subscriber’s ID. If you do not use subscriber IDs, enter null                                                                                                 |
| $DOMAINNAME      | String containing your section of your subscriber or assets. (Optional)                                                                                                              |
| $SUBSCRIBERTYPE  | String containing the subscriber type (e.g. “Free”, “Paid”). If you do not use subscriber types, enter null                                                                          |
| $SUBSCRIBERTAG   | String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field. |
| $ASSETID         | String containing Asset Id.                                                                                                                                                          |
| $ASSETNAME       | String containing Asset Name.                                                                                                                                                        |
| $VIDEOID         | String containing your video’s ID. If you do not use videos IDs, enter null.                                                                                                         |
| $PLAYER\_BRAND   | String containing the player brand (e.g. “bitmovin”).                                                                                                                                |
| $PLAYER\_MODEL   | String containing the player model. For example - This could be a variant of player. Say name of third party player used by organisation. Or any human readable name of the player.  |
| $PLAYER\_VERSION | String containing the player version.                                                                                                                                                |

\
**Step 3.3 :** \
Add the following code to: \
*BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\videoplayerapp/SampleAdsWrapper.java*

```java
private final ImaSdkFactory sdkFactory;
private AdsLoader adsLoader;
private StreamDisplayContainer displayContainer;
private StreamManager streamManager;
private final List<VideoStreamPlayer.VideoStreamPlayerCallback> playerCallbacks;
.
.
<MediaMelon Integration>
MMAnalyticsBridge analyticsBridgeObject; // Declaration of Analytics Bridge object , wherever the IMA AdsLoader and IMA StreamManager are declared in your application
<//MediaMelon Integration>
```

```java
private void createAdsLoader() { // this functions creates the Google IMA DAI ads loader (which is preferably a singleton - only one ads loader for the entire lifecyle)
  ImaSdkSettings settings = sdkFactory.createImaSdkSettings();
  <MediaMelon Integration>
  analyticsBridgeObject = MMSmartStreamingExo2.getInstance().getAnalyticsBridge(); // get the Analytics Bridge Object ,this should be done wherever in your application the Google IMA adsLoader is created
  <//MediaMelon Integration>
  .
  .
  .
  adsLoader = sdkFactory.createAdsLoader(context, settings, displayContainer);
}
```

```java
public void requestAndPlayAds() {  
  .
  .
  <MediaMelon Integration>
  adsLoader.addAdErrorListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ads error listeners
  adsLoader.addAdsLoadedListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ads loaded listeners
  <//MediaMelon Integration>
  .
  .
  adsLoader.addAdErrorListener(this);
  adsLoader.addAdsLoadedListener(this); 
  adsLoader.requestStream(buildStreamRequest());
  .
  . 
}
```

```java
 @Override
  public void onAdsManagerLoaded(AdsManagerLoadedEvent event) {
    .
    .
    <MediaMelon Integration>
    streamManager.addAdErrorListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ad error listeners
    streamManager.addAdEventListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ad event listeners
    <//MediaMelon Integration>
    .
    .
    streamManager.addAdErrorListener(this);
    streamManager.addAdEventListener(this);
    streamManager.init();
    .
    .
  }
```

\
**Step 4**:\
Access the various ad events. You can implement your own business logic on  one or more AD events .Please make sure all custom logic for each AD event is implemented here ONLY. List of all Google IMA DAI AD events can be found here  :-<https://developers.google.com/interactive-media-ads/docs/sdks/android/dai/api/reference/com/google/ads/interactivemedia/v3/api/AdEvent.AdEventType>

```java
  @Override
  public void onAdEvent(AdEvent event) { // this is a callback which gets called whenever a AD event occurs
    switch (event.getType()) {
     // Access all ad events here , this method will be automatically called whenever an ad event occurs
      case AD_PROGRESS:
      // write your own logic inside each case
        break;
      case FIRST_QUARTILE:
        // write your own logic inside each case
        break;
      case MIDPOINT:
        // write your own logic inside each case
        break;
      case THIRD_QUARTILE:
        // write your own logic inside each case
        break;
      case COMPLETED:
        // write your own logic inside each case
        break;
      default:
        log(String.format("Event: %s\n", event.getType()));
        break;
    }
  }
```

## <br>


# ExoPlayer v2.17.1 MediaMelon SDK with Google IMA DAI

This procedure describes the MediaMelon SDK(with  Google  IMA DAI) Integration with a ExoPlayer Android . This is a sample integration done with the sample application from the Google IMA DAI.

## Prerequisites:

1. Google IMA DAI Sample app (link for the sample app - <https://github.com/googleads/googleads-ima-android-dai>)\
   Documentation of the sample app -<https://developers.google.com/interactive-media-ads/docs/sdks/android/dai>
2. MediaMelon SmartSight SDK`exoplayer-smartstreaming-release.aar`
3. MediaMelon-assigned Customer ID

**Note:** If you do not know your Customer ID contact mediamelon at [support@mediamelon.com](mailto:support%40mediamelon.com)

## **Step 1: Set up the build environment**

The SDK files are added to the build environment and the required network permissions are enabled.

1. Copy `exoplayer-smartstreaming-release.aar` provided with the release package to `BasicExample/app/`
2. Add the following library to `BasicExample/app/build.gradle` :-<br>

   ```
   dependencies {
       .
       .
       implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.24.0'
       implementation 'com.google.android.exoplayer:exoplayer:2.17.1'
       api files ('exoplayer-smartstreaming-release.aar')
       .
       .
   }
   ```

## Step 2: Add MediaMelon library to  Sample App.

\
**Step 2.1 :** \
Add the below imports to:\
*BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\videoplayerapp/MyActivity.java*

```java
import com.mediamelon.smartstreaming.MMAVAssetInformation;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMRegistrationInformation;
import com.mediamelon.smartstreaming.MMSmartStreaming;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
```

\
**Step 2.2 :** \
Add the below imports to: *BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\samplevideoplayer/SampleVideoPlayer.java*

```java
import com.mediamelon.qubit.ep.ContentMetadata;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
```

**Step 2.3 :** \
Add the below imports to: \
*BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\videoplayerapp/SampleAdsWrapper.java*

```java
import com.mediamelon.smartstreaming.MMAnalyticsBridge;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
```

### &#x20;Step 3 : Integrate MediaMelon code to the Sample App

The below steps shows the procedure to integrate the MediaMelon library to the sample app.\
**Note -**  Only the code written inside the *\<MediaMelon Integration>* tag is to be added for MediaMelon specific integration , the rest of the code above and below the *\<MediaMelon Integration>* tag is shown just to give a context ,as shown below :-

```java
<MediaMelon Integration>
Code for MediaMelon specific integration
<//MediaMelon Integration>
```

\
\
**Step 3.1:**\
Add the following code to:\
*BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\samplevideoplayer/SampleVideoPlayer.java*

```java
private void initPlayer() { // this is the function that creates/initialises the EXO player
  release();
  simpleExoPlayer = new SimpleExoPlayer.Builder(context).build();
  playerView.setPlayer(simpleExoPlayer);
  .
  .
  .
  .
  <MediaMelon Integration>
  String assetId  = "assetID"; //enter you assetId here
  String assetName = "assetNAME"; // enter your assetname here
  String videoId = "videoID"; // enter your videoId here

  //optional content metadata
  ContentMetadata cm  = new ContentMetadata();
  String episodeNumber ="$episodeNumber ";
  String season = "$season";
  String genre = "$genre";
  String drmProtection = "$drmProtection";
  String contentType = "$contentType";
  String title = "$title";
  String videoType  = "$videoType";
  cm.videoId=videoId;
  cm.seriesTitle=title;
  cm.season=season;
  cm.genre=genre;
  cm.episodeNumber=episodeNumber;
  cm.drmProtection=drmProtection;
  cm.contentType=contentType;
  cm.assetName=assetName;
  cm.assetId=assetId;
  cm.videoType = videoType;
  JSONObject ContentMetadataAsJSON = cm.getJSONObject();
  //the below initializeSession() call is to be made only after the EXO player instance has been created
  MMSmartStreamingExo2.getInstance().initializeSession(simpleExoPlayer,MMQBRMode.QBRModeDisabled,"$streamUrl",null,assetId,assetName,videoId,null,ContentMetadataAsJSON);
  //(optional) add custom tags
  MMSmartStreamingExo2.getInstance().reportCustomMetadata("key","value");
  MMSmartStreamingExo2.getInstance().reportUserInitiatedPlayback();
  <//MediaMelon Integration>
};
```

```java
private void release() {
  if (simpleExoPlayer != null) {
    simpleExoPlayer.release();
    simpleExoPlayer = null;
    streamRequested = false;
    <MediaMelon Integration>
    MMSmartStreamingExo2.getInstance().reportPlayerState(false, Player.STATE_ENDED);
    <//MediaMelon Integration>
  }
}
```

\
**Step 3.2:**\
Add the following code to:\
*BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\videoplayerapp/MyActivity.java*

```java
@Override
  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);
    .
    .
    .
    .
    <MediaMelon Integration>
    Log.d("SmartStreamingIntgr", MMSmartStreamingExo2.getVersion());
    MMSmartStreamingExo2.enableLogTrace(true); //set to "false" before releasing player to production
    if (MMSmartStreamingExo2.getRegistrationStatus() == false){ //Check if it is the first time Registration process is done
      MMSmartStreamingExo2.registerMMSmartStreaming("$PLAYERNAME", "$CustomerId", "$SUBSCRIBERID", "$DOMAINNAME", "$SUBSCRIBERTYPE", "$SUBSCRIBERTAG");
      MMSmartStreamingExo2.reportPlayerInfo("$Brand", "$Model", "$Version");
      MMSmartStreamingExo2.getInstance().setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
    }
    <//MediaMelon Integration>
    .
    .
    .
    .

  }

```

| Variable         | Description                                                                                                                                                                          |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| $PLAYERNAME      | String containing the player version (e.g. “Bitmovin\_Android\_Player\_2.28.0”).                                                                                                     |
| $CUSTOMERID      | String containing your MediaMelon-assigned Customer ID.                                                                                                                              |
| $SUBSCRIBERID    | String containing your subscriber’s ID. If you do not use subscriber IDs, enter null                                                                                                 |
| $DOMAINNAME      | String containing your section of your subscriber or assets. (Optional)                                                                                                              |
| $SUBSCRIBERTYPE  | String containing the subscriber type (e.g. “Free”, “Paid”). If you do not use subscriber types, enter null                                                                          |
| $SUBSCRIBERTAG   | String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field. |
| $ASSETID         | String containing Asset Id.                                                                                                                                                          |
| $ASSETNAME       | String containing Asset Name.                                                                                                                                                        |
| $VIDEOID         | String containing your video’s ID. If you do not use videos IDs, enter null.                                                                                                         |
| $PLAYER\_BRAND   | String containing the player brand (e.g. “bitmovin”).                                                                                                                                |
| $PLAYER\_MODEL   | String containing the player model. For example - This could be a variant of player. Say name of third party player used by organisation. Or any human readable name of the player.  |
| $PLAYER\_VERSION | String containing the player version.                                                                                                                                                |

\
**Step 3.3 :** \
Add the following code to: \
*BasicExample\app\src\main\java\com\google\ads\interactivemedia\v3\samples\videoplayerapp/SampleAdsWrapper.java*

```java
private final ImaSdkFactory sdkFactory;
private AdsLoader adsLoader;
private StreamDisplayContainer displayContainer;
private StreamManager streamManager;
private final List<VideoStreamPlayer.VideoStreamPlayerCallback> playerCallbacks;
.
.
<MediaMelon Integration>
MMAnalyticsBridge analyticsBridgeObject; // Declaration of Analytics Bridge object , wherever the IMA AdsLoader and IMA StreamManager are declared in your application
<//MediaMelon Integration>
```

```java
private void createAdsLoader() { // this functions creates the Google IMA DAI ads loader (which is preferably a singleton - only one ads loader for the entire lifecyle)
  ImaSdkSettings settings = sdkFactory.createImaSdkSettings();
  <MediaMelon Integration>
  analyticsBridgeObject = MMSmartStreamingExo2.getInstance().getAnalyticsBridge(); // get the Analytics Bridge Object ,this should be done wherever in your application the Google IMA adsLoader is created
  <//MediaMelon Integration>
  .
  .
  .
  adsLoader = sdkFactory.createAdsLoader(context, settings, displayContainer);
}
```

```java
public void requestAndPlayAds() {  
  .
  .
  <MediaMelon Integration>
  adsLoader.addAdErrorListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ads error listeners
  adsLoader.addAdsLoadedListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ads loaded listeners
  <//MediaMelon Integration>
  .
  .
  adsLoader.addAdErrorListener(this);
  adsLoader.addAdsLoadedListener(this); 
  adsLoader.requestStream(buildStreamRequest());
  .
  . 
}
```

```java
 @Override
  public void onAdsManagerLoaded(AdsManagerLoadedEvent event) {
    .
    .
    <MediaMelon Integration>
    streamManager.addAdErrorListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ad error listeners
    streamManager.addAdEventListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ad event listeners
    <//MediaMelon Integration>
    .
    .
    streamManager.addAdErrorListener(this);
    streamManager.addAdEventListener(this);
    streamManager.init();
    .
    .
  }
```

\
**Step 4**:\
Access the various ad events. You can implement your own business logic on  one or more AD events .Please make sure all custom logic for each AD event is implemented here ONLY. List of all Google IMA DAI AD events can be found here  :-<https://developers.google.com/interactive-media-ads/docs/sdks/android/dai/api/reference/com/google/ads/interactivemedia/v3/api/AdEvent.AdEventType>

```java
  @Override
  public void onAdEvent(AdEvent event) { // this is a callback which gets called whenever a AD event occurs
    switch (event.getType()) {
     // Access all ad events here , this method will be automatically called whenever an ad event occurs
      case AD_PROGRESS:
      // write your own logic inside each case
        break;
      case FIRST_QUARTILE:
        // write your own logic inside each case
        break;
      case MIDPOINT:
        // write your own logic inside each case
        break;
      case THIRD_QUARTILE:
        // write your own logic inside each case
        break;
      case COMPLETED:
        // write your own logic inside each case
        break;
      default:
        log(String.format("Event: %s\n", event.getType()));
        break;
    }
  }
```

**Step 5**:

Exoplayer has a bug where playerState doesnt change sometimes after a preroll AD has finished, so please call this function whenever your application gets the signal that Ad Break has ended or all ADs in the current break are completed. \
The below function call is a sample call made from the onAdBreakEnded() callback (<https://developers.google.com/interactive-media-ads/docs/sdks/android/dai/api/reference/com/google/ads/interactivemedia/v3/api/player/VideoStreamPlayer.html#public-abstract-void-onadbreakended>) fired by Exoplayer when the AD break ends.

```
@Override
public void onAdBreakEnded() // Re-enable player controls.
{
  MMAnalyticsBridge.reportStartAfterAdBreakEnded();
}
```

## <br>


# Theoplayer v4.12.6 with Mediamelon SDK

### Prerequisites

* MediaMelon SmartSight SDK `smartstreaming_release.aar`

### Step 1: Set up the build environment&#x20;

The SDK files are added to the build environment and the required network permissions are enabled.&#x20;

1. Copy smartstreaming-release.aar provided with the release package to the theoplayer project, Example `app/libs/smartstreaming-release.aar`&#x20;
2. Add the following library to `app/build.gradle` :-

```java
dependencies {
  .
  .
  .
   //<!-- <MMSmartStreaming 1a> -->
    api files ('smartstreaming-release.aar')
  //<!-- </MMSmartStreaming 1a> -->
  
}
```

Add network permissions to&#x20;

`app/src/main/AndroidManifest.xml`

```java
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- <MMSmartStreaming 1b> -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- </MMSmartStreaming 1b> -->
```

### Step 2: Register SDK

The player application must register the SDK and provide player information once when the application launches. Please note that values provided in this integration step persist across video sessions. This is typically done when the player itself is initialized.&#x20;

\
Step 2a: Import packages

`app/src/main/java/com/theoplayer/theoplayerexample/MainActivity.java`

```java
// <MMSmartStreaming 2a>
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMSmartStreaming;
import com.mediamelon.smartstreaming.MMSmartStreamingTheo;
import com.mediamelon.smartstreaming.MMSmartStreamingInitializationStatus;
import com.mediamelon.smartstreaming.MMSmartStreamingObserver;
import java.util.ArrayList;
import android.util.Log;
// </MMSmartStreaming 2a>
```

#### Step 2b: Registration

&#x20;Perform registration tasks by modifying the `onCreate()` method in `app/src/main/java/com/theoplayer/theoplayerexample/MainActivity.java`

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production
{% endhint %}

```java
public void onCreate(Bundle savedInstanceState) {
  ...
   @Override
            public void onClick(View v) {
                if (theoPlayerView.getPlayer().isPaused()) {
                    theoPlayerView.getPlayer().play();
                } else {
                    theoPlayerView.getPlayer().pause();
                }
            }
        });
        //<MMSmartStreaming 2b>
        MMSmartStreamingTheo.enableLogTrace(<boolean>); //set to "false" before releasing player to production
        if (MMSmartStreamingTheo.getRegistrationStatus() == false){ //Check if it is the first time Registration process is done
            MMSmartStreamingExo2.setDeviceInfo($DEVICE_MARKETING_NAME);
            MMSmartStreamingExo2.registerMMSmartStreaming($PLAYERNAME, $CUSTOMERID, $SUBSCRIBERID, $DOMAINNAME, $SUBSCRIBERTYPE, $SUBSCRIBERTAG,$hashSubscriberId);
            MMSmartStreamingExo2.reportPlayerInfo("CustomPlayerName","Player_Version", "1.0");
            MMSmartStreamingExo2.getInstance().setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
            MMSmartStreamingExo2.getInstance().reportAppInfo($APP_NAME,$APP_VERSION);
            MMSmartStreamingExo2.getInstance().reportVideoQuality($VIDEO_QUALITY);
            }
        // </MMSmartStreaming 2b>
  }
```

* **`hashSubscriberID`**: To hash the subscriber ID, set it to <mark style="color:orange;">`true`</mark>. To leave the subscriber ID un-hashed, set it to <mark style="color:orange;">`false`</mark>.This is optional

### Parameters passed in Registration call

| Variable        | Description                                                                                                                                                                          |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| $PLAYERNAME     | Player Name as in ExoPlayer, KalturaPlayer etc.                                                                                                                                      |
| $CUSTOMERID     | String containing your MediaMelon-assigned Customer ID.                                                                                                                              |
| $SUBSCRIBERID   | String containing your subscriber’s ID. If you do not use subscriber IDs, leave it as it is.                                                                                         |
| $DOMAINNAME     | String containing your section of your subscriber or assets. (Optional)                                                                                                              |
| $SUBSCRIBERTYPE | String containing the subscriber type (e.g. “Free”, “Paid”). If you do not use subscriber types, leave it as it is.                                                                  |
| $SUBSCRIBERTAG  | String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field. |

### Step 3: Initialize Session  <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

`app/src/main/java/com/theoplayer/theoplayerexample/MainActivity.java`

```java
// after player is initialised and not null anymore
    String mediaUrl = "get the mediaURL from your application"
    String assetId  = "assetID"; //enter you assetId here
    String assetName = "assetNAME"; // enter your assetname here
    String videoId = "videoID"; // enter your videoId here
    ContentMetadata cm  = new ContentMetadata();
    String episodeNumber = "EpisodeNumber";
    String season = "Season";
    String genre = "Genre";
    String drmProtection = "drmProtection";
    String contentType = "contentType";
    String title = "Title";
    cm.videoId=videoId;
    cm.seriesTitle=title;
    cm.season=season;
    cm.genre=genre;
    cm.episodeNumber=episodeNumber;
    cm.drmProtection=drmProtection;
    cm.contentType=contentType;
    cm.assetName=assetName;
    cm.assetId=assetId;
    JSONObject contentMetadata = cm.getJSONObject();
    //optional content metadata
    MMSmartStreamingTheo.getInstance().initializeSession(player, MMQBRMode.QBRModeDisabled, mediaUrl, null, assetId, assetName, videoId,null,contentMetadata,isLive);
```

{% hint style="info" %}

* **`isLive`**: Set it to <mark style="color:orange;">`true`</mark> for a live video and <mark style="color:orange;">`false`</mark> for a VOD video. This is optional.
  {% endhint %}

### &#x20;Step 4: Report ended state when the Activity is destroyed <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

```java
@Override
protected void onDestroy() {
    super.onDestroy();
    //MM
    MMSmartStreaming.getInstance().reportPlayerState(MMPlayerState.STOPPED);
    //MM
    theoPlayerView.onDestroy();
}
```


# Theoplayer v6.0.0 with Mediamelon SDK

### Prerequisites

* MediaMelon SmartSight SDK `smartstreaming_release.aar`

### Step 1: Set up the build environment&#x20;

The SDK files are added to the build environment and the required network permissions are enabled.&#x20;

1. Copy smartstreaming-release.aar provided with the release package to the theoplayer project, Example `app/libs/smartstreaming-release.aar`&#x20;
2. Add the following library to `app/build.gradle` :-

```java
dependencies {
  .
  .
  .
   //<!-- <MMSmartStreaming 1a> -->
    api files ('smartstreaming-release.aar')
  //<!-- </MMSmartStreaming 1a> -->
  
}
```

Add network permissions to&#x20;

`app/src/main/AndroidManifest.xml`

```java
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- <MMSmartStreaming 1b> -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- </MMSmartStreaming 1b> -->
```

### Step 2: Register SDK

The player application must register the SDK and provide player information once when the application launches. Please note that values provided in this integration step persist across video sessions. This is typically done when the player itself is initialized.&#x20;

\
Step 2a: Import packages

`app/src/main/java/com/theoplayer/theoplayerexample/MainActivity.java`

```java
// <MMSmartStreaming 2a>
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMSmartStreaming;
import com.mediamelon.smartstreaming.MMSmartStreamingTheo;
import com.mediamelon.smartstreaming.MMSmartStreamingInitializationStatus;
import com.mediamelon.smartstreaming.MMSmartStreamingObserver;
import java.util.ArrayList;
import android.util.Log;
// </MMSmartStreaming 2a>
```

#### Step 2b: Registration

&#x20;Perform registration tasks by modifying the `onCreate()` method in `app/src/main/java/com/theoplayer/theoplayerexample/MainActivity.java`

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production
{% endhint %}

{% hint style="info" %}

* **`hashSubscriberID`**: To hash the subscriber ID, set it to <mark style="color:orange;">`true`</mark>. To leave the subscriber ID un-hashed, set it to <mark style="color:orange;">`false`</mark>.
  {% endhint %}

```java
public void onCreate(Bundle savedInstanceState) {
  ...
   @Override
            public void onClick(View v) {
                if (theoPlayerView.getPlayer().isPaused()) {
                    theoPlayerView.getPlayer().play();
                } else {
                    theoPlayerView.getPlayer().pause();
                }
            }
        });
        //<MMSmartStreaming 2b>
        MMSmartStreamingTheo.enableLogTrace(<boolean>); //set to "false" before releasing player to production
        if (MMSmartStreamingTheo.getRegistrationStatus() == false){ //Check if it is the first time Registration process is done
            MMSmartStreamingExo2.setDeviceInfo($DEVICE_MARKETING_NAME);
            MMSmartStreamingExo2.registerMMSmartStreaming($PLAYERNAME, $CUSTOMERID, $SUBSCRIBERID, $DOMAINNAME, $SUBSCRIBERTYPE, $SUBSCRIBERTAG,$doHash);
            MMSmartStreamingExo2.reportPlayerInfo("CustomPlayerName","Player_Version", "1.0");
            MMSmartStreamingExo2.getInstance().setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
            MMSmartStreamingExo2.getInstance().reportAppInfo($APP_NAME,$APP_VERSION);
            MMSmartStreamingExo2.getInstance().reportVideoQuality($VIDEO_QUALITY);
            }
        // </MMSmartStreaming 2b>
  }
```

### Parameters passed in Registration call

| Variable        | Description                                                                                                                                                                          |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| $PLAYERNAME     | Player Name as in ExoPlayer, KalturaPlayer etc.                                                                                                                                      |
| $CUSTOMERID     | String containing your MediaMelon-assigned Customer ID.                                                                                                                              |
| $SUBSCRIBERID   | String containing your subscriber’s ID. If you do not use subscriber IDs, leave it as it is.                                                                                         |
| $DOMAINNAME     | String containing your section of your subscriber or assets. (Optional)                                                                                                              |
| $SUBSCRIBERTYPE | String containing the subscriber type (e.g. “Free”, “Paid”). If you do not use subscriber types, leave it as it is.                                                                  |
| $SUBSCRIBERTAG  | String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field. |

### Step 3: Initialize Session  <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

```java
// after player is initialised and not null anymore
    String mediaUrl = "get the mediaURL from your application"
    String assetId  = "assetID"; //enter you assetId here
    String assetName = "assetNAME"; // enter your assetname here
    String videoId = "videoID"; // enter your videoId here
    ContentMetadata cm  = new ContentMetadata();
    String episodeNumber = "EpisodeNumber";
    String season = "Season";
    String genre = "Genre";
    String drmProtection = "drmProtection";
    String contentType = "contentType";
    String title = "Title";
    cm.videoId=videoId;
    cm.seriesTitle=title;
    cm.season=season;
    cm.genre=genre;
    cm.episodeNumber=episodeNumber;
    cm.drmProtection=drmProtection;
    cm.contentType=contentType;
    cm.assetName=assetName;
    cm.assetId=assetId;
    JSONObject contentMetadata = cm.getJSONObject();
    //optional content metadata
    MMSmartStreamingTheo.getInstance().initializeSession(player, MMQBRMode.QBRModeDisabled, mediaUrl, null, assetId, assetName, videoId,null,contentMetadata,isLive);
```

{% hint style="info" %}

* **`isLive`**: Set it to <mark style="color:orange;">`true`</mark> for a live video and <mark style="color:orange;">`false`</mark> for a VOD video. This is optional.
  {% endhint %}


# Media3 v1.3.0 and ExoPlayer 2.19.1 with MediaMelon SDK

This guide is for integrating MediaMelon SDK with Media3 v1.3.0 and Exoplayer v2.19.1

### Prerequisites

* Meida3 - v1.3.0 [sample application](https://mediamelon-builds.s3.amazonaws.com/MM-RELEASE-BUILDS/SDK_RELEASES/Android/2024-03-20/Media3Demo.zip).
* MediaMelon SmartSight SDK Maven dependencies or the provided `smartstreaming_release.aar`  AAR file is necessary.

### Step 1: Set up the build environment&#x20;

> `$MEDIA3PROJETC = {Media3 - v1.3.0}`

The SDK files should be added to the build environment and the required network permissions should be enabled.

**Using Maven:**

1. Add MediaMelon Maven dependency to `$MEDIA3PROJETC/demos/main/build.gradle`<br>

   ```java
   dependencies {
      ...
     //<!-- <MMSmartStreaming 1b> -->
     implementation 'com.github.MediamelonSDK:mm-sdk-media3-android:1.0.0'
     implementation 'com.google.android.exoplayer:exoplayer-core:2.19.1'
     implementation 'androidx.media3:media3-exoplayer:1.3.0'
     //<!-- </MMSmartStreaming 1b> --> 
   }
   ```

**Using AAR:**&#x20;

1. Copy `smartstreaming-release.aar` provided with the release package to the Media3 project. Example  `$MEDIA3PROJETC/demos/main/smartstreaming-release.aar`&#x20;
2. Add the following library to `$MEDIA3PROJETC/demos/main/build.gradle` :-

```java
dependencies {
  ...
  //<!-- <MMSmartStreaming 1b> -->
  api files ('smartstreaming-release.aar')
  implementation 'com.google.android.exoplayer:exoplayer-core:2.19.1'
  implementation 'androidx.media3:media3-exoplayer:1.3.0'
  //<!-- </MMSmartStreaming 1b> --> 
}
```

> To use MediaMelon SDK  you have to implement both media3 and Exoplayer dependencies.

Add network permissions to `$MEDIA3PROJETC/demos/main/src/main/AndroidManifest.xml`

```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- <MMSmartStreaming 1c> -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- </MMSmartStreaming 1c> -->
```

### Step 2: Register SDK

The player application must register the SDK and provide player information once when the application launches. Please note that values provided in this integration step persist across video sessions. This is typically done when the player itself is initialized.&#x20;

#### Step 2a: Import packages

`$MEDIA3PROJETC/demos/main/src/main/java/androidx/media3/demo/main/PlayerActivity.java`

{% tabs %}
{% tab title="JAVA" %}

```java
// <MMSmartStreaming 2a>
import com.mediamelon.qubit.ep.ContentMetadata;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMSmartStreamingAdapter;
import com.mediamelon.smartstreaming.MMSmartStreamingFactory;
// </MMSmartStreaming 2a>
```

{% endtab %}
{% endtabs %}

#### Step 2b: Setup MediaMelon Adapter Object

&#x20;Setup MediaMelon Adapter Object  before `onCreate()` method in `$MEDIA3PROJETC/demos/main/src/main/java/androidx/media3/demo/main/PlayerActivity.java`

{% tabs %}
{% tab title="JAVA" %}

<pre class="language-java"><code class="lang-java">...

//&#x3C;MMSmartStreaming 2b>
MMSmartStreamingAdapter mmSmartStreamingAdapter;
// &#x3C;/MMSmartStreaming 2b> 

<strong>public void onCreate(Bundle savedInstanceState) {
</strong>  ... 
}
</code></pre>

{% endtab %}
{% endtabs %}

### Step 3: Registration, Initialize Session & Report User Intent to Playback <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The player application must register the SDK and provide player information once after player is  initialized. Please note that values provided in this integration step persist across video sessions.

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

* Set the `isLive` variable in initializeSession() call , set true for live stream else false.

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production
{% endhint %}

{% tabs %}
{% tab title="JAVA" %}

```java
protected boolean initializePlayer() {
   if (player == null) {
   Intent intent = getIntent();
   ...
   // after player is initialised and not null anymore
   initializeMediaMelon();
   ...
 }

void initializeMediaMelon(){
    // <MMSmartStreaming 3>
    mmSmartStreamingAdapter = MMSmartStreamingFactory.getInstance(player);
    mmSmartStreamingAdapter.enableLogTrace(true); //set to "false" before releasing player to production
    if (mmSmartStreamingAdapter.getRegistrationStatus() == false)
    { //Check if it is the first time Registration process is done
      mmSmartStreamingAdapter.setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
      mmSmartStreamingAdapter.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG");
      mmSmartStreamingAdapter.reportPlayerInfo("PLAYEER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
      mmSmartStreamingAdapter.reportAppInfo("APP_NAME","APP_VERSION");
      mmSmartStreamingAdapter.reportVideoQuality("VIDEO_QUALITY");
      mmSmartStreamingAdapter.setDeviceInfo("DEVICE_MARKETING_NAME");
    }
    String mediaUrl = String.valueOf(mediaItems.get(0).localConfiguration.uri); //getting the mediaURL from the application

    ContentMetadata cm  = new ContentMetadata();
    cm.assetName="ASSET_NAME";
    cm.assetId="ASSET_ID";
    cm.videoId="VIDEO_ID";
    cm.seriesTitle="SERIES_TITLE";
    cm.season="SEASON";
    cm.genre="GENRE";
    cm.episodeNumber="EPISODE_NUMBER";
    cm.drmProtection="DRM_PROTECTION";
    cm.contentType="CONTENT_TYPE";
    JSONObject contentMetadata = cm.getJSONObject();

    mmSmartStreamingAdapter.reportCustomMetadata("KEY1","VALUE1");
    mmSmartStreamingAdapter.initializeSession(MMQBRMode.QBRModeDisabled, mediaUrl, null, null, contentMetadata, false);
    mmSmartStreamingAdapter.reportUserInitiatedPlayback();
    // <MMSmartStreaming 3>
 }

```

{% endtab %}
{% endtabs %}

### Step 4: Report ended state when the player instance is released <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

In `$MEDIA3PROJETC/demos/main/src/main/java/androidx/media3/demo/main/PlayerActivity.java`&#x20;

{% tabs %}
{% tab title="JAVA" %}

```java
private void releasePlayer() {
    if (player != null) {
      updateTrackSelectorParameters();
      updateStartPosition();
      debugViewHelper.stop();
      debugViewHelper = null;
      player.release();
      player = null;
      mediaSource = null;
      trackSelector = null;
      // <MMSmartStreaming 4> Start
      mmSmartStreamingAdapter.reportPlayerState(false, Player.STATE_ENDED);
      // </MMSmartStreaming 4> End
    }
  }
```

{% endtab %}
{% endtabs %}


# Media3 v1.1.1 SDK Integration Document

This guide provides detailed instructions on integrating the Android MediaMelon SDK with Media3 v1.1.1 player

**Step 1:** [Prerequisites](#prerequisites)

**Step 2:** [Set up the build environment](#step-1-set-up-the-build-environment)

**Step 3:** [Import Packages](#step-2-import-packages)

**Step 4:** [Register and Initialise SDK](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 5:** [Report Ended State](#step-5-report-ended-state-when-the-player-instance-is-released)

**Step 6:** [Variables and Description](#step-6-variables-and-description)

### Step 1: Prerequisites

* Meida3 - v1.1.1 sample application.
* MediaMelon SmartSight SDK Maven dependencies or the provided `smartstreaming_release.aar`  AAR file is necessary.

### Step 2: Set up the build environment&#x20;

> `$MEDIA3PROJECT = {Media3 - v1.1.1}`

The SDK files should be added to the build environment and the required network permissions should be enabled.

**Using Maven:**

1. Add MediaMelon Maven dependency to `$MEDIA3PROJECT/demos/main/build.gradle`<br>

   ```java
   dependencies {
      ...
     implementation 'com.github.MediamelonSDK:mm-sdk-media3-v1.1.1-android:1.0.0'
   }
   ```

**Using AAR:**&#x20;

1. Copy `smartstreaming-release.aar` provided in the release package to the Media3 project. Example  `$MEDIA3PROJECT/demos/main/smartstreaming-release.aar`&#x20;
2. Add the following library to `$MEDIA3PROJECT/demos/main/build.gradle` :-

```java
dependencies {
  ...
  api files ('smartstreaming-release.aar')
}
```

Add network permissions to `$MEDIA3PROJECT/demos/main/src/main/AndroidManifest.xml`

```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

### Step 3: Import Packages

`$MEDIA3PROJECT/demos/main/src/main/java/androidx/media3/demo/main/PlayerActivity.java`

```java
import com.mediamelon.qubit.ep.ContentMetadata;
import com.mediamelon.smartstreaming.media3.MMSmartStreamingMedia3;
```

### Step 4: Register and Initialise SDK <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The player application must register the SDK and provide player information once after player is  initialised. Please note that values provided in this integration step persist across video sessions.

The SDK must be initialised at the start of each video session. Initialisation includes setting the application context, initialising the playback session, and indicating the intent for playback with the SDK.

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production.
{% endhint %}

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```java
protected boolean initializePlayer() {
   if (player == null) {
   Intent intent = getIntent();
   ...
   // after player is initialised and not null anymore
   initializeMediaMelon();
   ...
 }

void initializeMediaMelon(){
     MMSmartStreamingMedia3.enableLogTrace(true);
    if (MMSmartStreamingMedia3.getRegistrationStatus() == false)
    {
      MMSmartStreamingMedia3.setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
      boolean hashSubscriberId = true;
      MMSmartStreamingMedia3.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG", hashSubscriberId);
      MMSmartStreamingMedia3.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
      MMSmartStreamingMedia3.reportAppInfo("APP_NAME","APP_VERSION");
      MMSmartStreamingMedia3.setDeviceInfo("DEVICE_MARKETING_NAME");
    }
    
    String streamURL = String.valueOf(mediaItems.get(0).localConfiguration.uri); //getting the mediaURL from the application

    ContentMetadata cm  = new ContentMetadata();
    cm.assetName="ASSET_NAME";
    cm.assetId="ASSET_ID";
    cm.videoId="VIDEO_ID";
    cm.seriesTitle="SERIES_TITLE";
    cm.season="SEASON";
    cm.genre="GENRE";
    cm.episodeNumber="EPISODE_NUMBER";
    cm.drmProtection="DRM_PROTECTION";
    cm.contentType="CONTENT_TYPE";
    JSONObject contentMetadata = cm.getJSONObject();

    MMSmartStreamingMedia3.reportCustomMetadata("KEY1","VALUE1");
    MMSmartStreamingMedia3.reportCustomMetadata("KEY2","VALUE2");
    
    boolean isLive = false;
    MMSmartStreamingMedia3.initializeSession(player, streamURL, contentMetadata, isLive);
    MMSmartStreamingMedia3.reportUserInitiatedPlayback();
 }
```

### Step 5: Report Ended State <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

In `$MEDIA3PROJECT/demos/main/src/main/java/androidx/media3/demo/main/PlayerActivity.java`&#x20;

```java
private void releasePlayer() {
    if (player != null) {
      player.release();
      player = null;
      
      MMSmartStreamingMedia3.reportPlayerState(false, Player.STATE_ENDED);
    }
  }
```

### Step 6: Variables and Description

<table><thead><tr><th width="243.33333333333331">Variable</th><th width="348">Description</th><th>Requirement</th></tr></thead><tbody><tr><td>PLAYER_NAME</td><td>String containing the Player Name.</td><td>Mandatory</td></tr><tr><td>CUSTOMER_ID</td><td>String containing your MediaMelon-assigned Customer ID.</td><td>Mandatory</td></tr><tr><td>SUBSCRIBER_ID</td><td>String containing your Subscriber’s ID.</td><td>Mandatory</td></tr><tr><td>DOMAIN_NAME</td><td>String containing your section of your subscriber or assets.</td><td>Mandatory</td></tr><tr><td>SUBSCRIBER_TYPE</td><td>String containing the Subscriber Type (e.g. “Free”, “Paid”).</td><td>Optional</td></tr><tr><td>SUBSCRIBER_TAG</td><td>String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field.</td><td>Optional</td></tr><tr><td>ASSET_ID</td><td>String containing Asset Id.</td><td>Mandatory</td></tr><tr><td>ASSET_NAME</td><td>String containing Asset Name.</td><td>Mandatory</td></tr><tr><td>VIDEO_ID</td><td>String containing your video’s ID.</td><td>Mandatory</td></tr><tr><td>CONTENT_TYPE</td><td>String containing type of the Content. For example - "Movie", "Special", "Clip", "Scene" "Episode".</td><td>Mandatory</td></tr><tr><td>GENRE</td><td>String containing Genre of the content. For example - "Comedy", "Horror".</td><td>Optional</td></tr><tr><td>DRM_PROTECTION</td><td>Widevine, Fairplay, Playready etc. Unknown means content is protected, but protection type is unknown. For clear contents, do not set this field</td><td>Optional</td></tr><tr><td>EPISODE_NUMBER</td><td>String containing sequence number of the Episode.</td><td>Optional</td></tr><tr><td>SEASON</td><td>String containing the Season. For example - "Season1".</td><td>Optional</td></tr><tr><td>SERIES_TITLE</td><td>String containing Title of the Series.</td><td>Optional</td></tr><tr><td>VIDEO_TYPE</td><td>String containing Video Type. For example - "LIVE", "VOD".</td><td>Optional</td></tr><tr><td>PLAYER_BRAND</td><td>String containing Player Brand (e.g. “Exo Player”).</td><td>Mandatory</td></tr><tr><td>PLAYER_MODEL</td><td>String containing Player Model. For example - This could be a variant of player. Say name of third party player used by organisation. Or any human readable name of the player.</td><td>Mandatory</td></tr><tr><td>PLAYER_VERSION</td><td>String containing Player Version.</td><td>Mandatory</td></tr><tr><td>CUSTOM_METADATA</td><td>Extra custom metadata can be added here if required.</td><td>Optional</td></tr><tr><td><code>hashSubscriberId</code></td><td>To hash the subscriber Id set this boolean variable to <code>true</code>, else set it to <code>false</code>.</td><td>Optional</td></tr><tr><td><code>player</code></td><td>Player Object.</td><td>Mandatory</td></tr><tr><td><code>streamURL</code></td><td>Current playing content stream URL.</td><td>Mandatory</td></tr><tr><td><code>isLive</code></td><td>Set this boolean variable to <code>true</code> if the content is Live else set it to <code>false</code> for VOD content.</td><td>Optional</td></tr></tbody></table>


# IMA Media3 v1.2.1 SDK Integration Document

This guide provides detailed instructions on integrating the Android MediaMelon IMA SDK with the Media3 v1.2.1 player

**Step 1:** [Prerequisites](#step-1-prerequisites)

**Step 2:** [Set up the build environment](#step-2-set-up-the-build-environment)

**Step 3:** [Import Packages](#step-3-import-packages)

**Step 4:** [Register and Initialise SDK](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 5:** [Report Experiment Name](#step-5-report-experiment-name)

**Step 6:** [Report Sub-Property Id](#step-6-report-sub-property-id)

**Step 7:** [Report View Session](#step-7-report-view-session-id)

**Step 8:** [Report Player Resolution](#step-8-report-player-resolution)

**Step 9:** [Report Custom Errors](#step-9-report-custom-errors-optional)

**Step 10:** [Report Ended State](#step-5-report-ended-state-when-the-player-instance-is-released)

**Step 11:** [Enable IMA/DAI Ad tracking](#step-6-enable-ima-dai-a-d-tracking)

### Step 1: Prerequisites

* Media3 - v1.2.1 sample application.
* MediaMelon Media3 SDK Maven dependencies or the provided AAR file is necessary.

### Step 2: Set up the build environment&#x20;

> `$MEDIA3PROJECT = {Media3 - v1.2.1}`

The SDK files should be added to the build environment and the required network permissions should be enabled.

#### **Using Maven:**

1. Add MediaMelon Media3 Maven dependency to `$MEDIA3PROJECT/demos/main/build.gradle`

```gradle
dependencies {
   ...
  implementation 'com.github.MediamelonSDK:mm-android-sdk-media3-ima:2.2.1'
}
```

#### **Using AAR:**&#x20;

1. Copy [`mmsmartstreaming.aar`](https://mediamelon-builds.s3.us-east-1.amazonaws.com/MM-RELEASE-BUILDS/SDK_RELEASES/Android/2025-02-07/mmsmartstreaming.aar) provided in the release package for the Media3 project. Example  `$MEDIA3PROJECT/demos/main/mmsmartstreaming.aar` .
2. Add the following library to `$MEDIA3PROJECT/demos/main/build.gradle` :-

```gradle
dependencies {
  ...
  api files ('mmsmartstreaming.aar')
}
```

Add network permissions to `$MEDIA3PROJECT/demos/main/src/main/AndroidManifest.xml`

```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

### Step 3: Import Packages

`$MEDIA3PROJECT/demos/main/src/main/java/androidx/media3/demo/main/PlayerActivity.java`

```java
import com.mediamelon.qubit.ep.ContentMetadata;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.media3_ima.MMAnalyticsBridge;
import com.mediamelon.smartstreaming.media3_ima.MMSmartStreamingExo2;
```

### Step 4: Register and Initialise SDK <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The player application must register the SDK and provide player information once the player is initialized. Please note that values provided in this integration step persist across video sessions.

The SDK must be initialized at the start of each video session. Initialization includes setting the application context, initializing the playback session, and indicating the intent for playback with the SDK.

{% hint style="info" %}
The `enableLogTrace()` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production.
{% endhint %}

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```java
protected boolean initializePlayer() {
   
   // after the player is initialized and the player instance is not null
   initializeMediaMelon();
   ...
 }

void initializeMediaMelon(){
     MMSmartStreamingExo2.enableLogTrace(false);
    if (MMSmartStreamingExo2.getRegistrationStatus() == false)
    {
      MMSmartStreamingExo2.getInstance().setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
      boolean hashSubscriberId = true;
      MMSmartStreamingExo2.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG", hashSubscriberId);
      MMSmartStreamingExo2.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
      MMSmartStreamingExo2.getInstance().reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
      
      MMSmartStreamingExo2.reportAppInfo("APP_NAME","APP_VERSION");
      MMSmartStreamingExo2.getInstance().setDeviceInfo("DEVICE_MARKETING_NAME");
      
      //call this function to enable custom error reporting 
      MMSmartStreamingExo2.getInstance().enableCustomErrorReporting(true);
    }
    

    ContentMetadata cm  = new ContentMetadata();
    cm.assetName="ASSET_NAME";
    cm.assetId="ASSET_ID";
    cm.videoId="VIDEO_ID";
    cm.seriesTitle="SERIES_TITLE";
    cm.season="SEASON";
    cm.genre="GENRE";
    cm.episodeNumber="EPISODE_NUMBER";
    cm.drmProtection="DRM_PROTECTION";
    cm.contentType="CONTENT_TYPE";
    JSONObject contentMetadata = cm.getJSONObject();
    
    boolean isLive = false;
    MMSmartStreamingExo2.getInstance().initializeSession(player, MMQBRMode.QBRModeDisabled, streamURL, contentMetadata, isLive);
    MMSmartStreamingExo2.getInstance().reportUserInitiatedPlayback();
    MMSmartStreamingExo2.getInstance().reportCustomMetadata("CUSTOM_KEY_1","VALUE1");
 }
```

### Step 5: Report Experiment Name

```java
MMSmartStreamingExo2.getInstance().reportExperimentName("EXPERIMENT_NAME");
```

### Step 6: Report Sub-Property Id

```java
MMSmartStreamingExo2.getInstance().reportSubPropertyId("SUB_PROPERTY_ID");
```

### Step 7: Report View Session Id

```java
MMSmartStreamingExo2.getInstance().reportViewSessionId("VIEW_SESSION_ID");
```

### Step 8: Report Player Resolution

```java
MMSmartStreamingExo2.getInstance().reportPlayerResolution(playerWidth, playerHeight);
```

### Step 9: Report Custom Errors

{% hint style="info" %}
Make sure that `enableCustomErrorReporting` is set to `true` for this to be able to report errors&#x20;
{% endhint %}

```java
MMSmartStreamingExo2.getInstance().reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DESCRIPTION");
```

### Step 10: Report Ended State <a href="#step-5-report-ended-state-when-the-player-instance-is-released" id="step-5-report-ended-state-when-the-player-instance-is-released"></a>

Report ENDED state in  `PlayerActivity` when playback ends.

{% hint style="info" %}
If not reported at the end of the playback, it may reflect a longer playtime.
{% endhint %}

```java
private void releasePlayer() {
    if (player != null) {
      player.release();
      player = null;
      
      MMSmartStreamingExo2.getInstance().reportPlayerState(false, Player.STATE_ENDED);
    }
  }
```

### Step 11: Enable IMA/DAI Ad tracking

Add the following steps to enable IMA/DAI Ad tracking

#### 11.a: IMA Ad Tracking

```java
private final ImaSdkFactory sdkFactory;
private AdsLoader adsLoader;
private StreamDisplayContainer displayContainer;

MMAnalyticsBridge analyticsBridgeObject;
```

```java
//Get the Analytics Bridge Object, this should be done wherever in your application the adsLoader is created
analyticsBridgeObject = MMSmartStreamingExo2.getInstance().getAnalyticsBridge(); 

//Initialising ads loader
ImaSdkSettings settings = sdkFactory.createImaSdkSettings();
adsLoader = sdkFactory.createAdsLoader(context, settings, displayContainer);
```

```java
// For IMA Ad Tracking
public void requestAndPlayAds() {  
  adsLoader.addAdErrorListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ads error listeners
  adsLoader.addAdsLoadedListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ads loaded listeners
  
}
```

{% hint style="info" %}
Alternate method for IMA ad tracking
{% endhint %}

```java
adsLoader = new ImaAdsLoader.Builder(/* context= */ this)
                .setAdEventListener(analyticsBridgeObject)
                .setAdErrorListener(analyticsBridgeObject)
                .build();
```

#### 11.b: DAI Ad Tracking

The function `onAdsManagerLoaded` is part of `AdsLoader.AdsLoadedListener`&#x20;

```java
private StreamManager streamManager;
MMAnalyticsBridge analyticsBridgeObject;
```

```java
@Override
public void onAdsManagerLoaded(AdsManagerLoadedEvent event) {
 //Get the Analytics Bridge Object ,this should be done wherever in your application the adsManager is loaded
analyticsBridgeObject = MMSmartStreamingExo2.getInstance().getAnalyticsBridge();
  
  if(event.getStreamManager()!=null) {
      streamManager = event.getStreamManager();
      
      streamManager.addAdErrorListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ad error listeners
      streamManager.addAdEventListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ad event listeners
      streamManager.init();
    }
}
```


# IMA Media3 v1.3.0 SDK Integration Document

This procedure describes the MediaMelon SDK(with Google IMA) Integration with a Media3 Android . This is a sample integration done with the sample application from the Google IMA.

### Prerequisites: <a href="#prerequisites" id="prerequisites"></a>

1. Google IMA DAI [Sample app](https://github.com/googleads/googleads-ima-android-dai) and [Documentation](https://developers.google.com/interactive-media-ads/docs/sdks/android/dai).
2. MediaMelon SmartSight SDK  maven dependencies or `smartstreaming-release.aar`.
3. MediaMelon-assigned Customer ID.

{% hint style="info" %}
**Note:** If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](mailto:support%40mediamelon.com)
{% endhint %}

### **Step 1: Set up the build environment** <a href="#step-1-set-up-the-build-environment" id="step-1-set-up-the-build-environment"></a>

The SDK should be added to the build environment and the required network permissions should be enabled.

**Using Maven:**

1. Add the following library to `BasicExample/app/build.gradle` :-

```gradle
dependencies {
    .
    .
    implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.24.0'
    implementation 'androidx.media3:media3-exoplayer:1.3.0'
    implementation 'com.github.MediamelonSDK:mm-sdk-media3-ima-android:1.0.3'
    .
    .
}
```

**Using ARR:**

1. Copy `smartstreaming-release.aar` provided with the release package to `BasicExample/app/`
2. Add the following library to `BasicExample/app/build.gradle` :-

```gradle
dependencies {
    .
    .
    implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.24.0'
    implementation 'androidx.media3:media3-exoplayer:1.3.0'
    api files ('smartstreaming-release.aar')
    .
    .
}
```

### Step 2: Import the required  MediaMelon SDK Classes: <a href="#step-2-add-mediamelon-library-to-sample-app" id="step-2-add-mediamelon-library-to-sample-app"></a>

#### **Step 2.1:** Add the below imports to:

`BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/MyActivity.java`

```java
import com.mediamelon.smartstreaming.MMAVAssetInformation;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMRegistrationInformation;
import com.mediamelon.smartstreaming.MMSmartStreaming;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
```

#### **Step 2.2:** Add the below imports to:&#x20;

`BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/samplevideoplayer/SampleVideoPlayer.java`

```java
import com.mediamelon.qubit.ep.ContentMetadata;
import com.mediamelon.smartstreaming.MMQBRMode;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
```

#### **Step 2.3:** Add the below imports to:&#x20;

`BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/SampleAdsWrapper.java`

```java
import com.mediamelon.smartstreaming.MMAnalyticsBridge;
import com.mediamelon.smartstreaming.MMSmartStreamingExo2;
```

### Step 3: Integrate MediaMelon SDK  <a href="#step-3-integrate-mediamelon-code-to-the-sample-app" id="step-3-integrate-mediamelon-code-to-the-sample-app"></a>

The below steps describe the procedure to integrate the MediaMelon SDK into the application.&#x20;

{% hint style="info" %}
**Note -** Only the code written inside the *\<MediaMelon Integration>* tag is to be added for MediaMelon-specific integration, the rest of the code above and below the *\<MediaMelon Integration>* tag is shown just to give a context, as shown below:-
{% endhint %}

#### **Step 3.1:** Add the following code to:&#x20;

`BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/samplevideoplayer/SampleVideoPlayer.java`

```java
private void initPlayer() { // this is the function that creates/initialises the EXO player
  release();
  simpleExoPlayer = new SimpleExoPlayer.Builder(context).build();
  playerView.setPlayer(simpleExoPlayer);
  .
  .
  //<MediaMelon Integration>
  ContentMetadata cm  = new ContentMetadata();
  cm.videoId="VIDEO_ID";
  cm.seriesTitle="TITLE";
  cm.season="SEASON";
  cm.genre="GENRE";
  cm.episodeNumber="EPISODE_NUMBER";
  cm.drmProtection="DRM_PROTECTION";
  cm.contentType="CONTENT_TYPE";
  cm.assetName="ASSET_NAME";
  cm.assetId="ASSET_ID";
  cm.videoType = "VIDEO_TYPE";
  JSONObject ContentMetadataAsJSON = cm.getJSONObject();
  boolean isLive = false; //Set this to true for a live stream or to false for a VoD stream

  MMSmartStreamingExo2.getInstance().initializeSession(simpleExoPlayer, MMQBRMode.QBRModeDisabled, streamUrl, ContentMetadataAsJSON, isLive); //isLive is an optional field here
  MMSmartStreamingExo2.getInstance().reportCustomMetadata("key","value");   //(optional) add custom tags
  MMSmartStreamingExo2.getInstance().reportUserInitiatedPlayback();
  //<MediaMelon Integration>
};
```

```java
private void release() {
  if (simpleExoPlayer != null) {
    simpleExoPlayer.release();
    simpleExoPlayer = null;
    streamRequested = false;
    
    //<MediaMelon Integration>
    MMSmartStreamingExo2.getInstance().reportPlayerState(false, Player.STATE_ENDED);
    //<MediaMelon Integration>
  }
}
```

#### **Step 3.2:** Add the following code to:&#x20;

`BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/MyActivity.java`

```java
@Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);
    .
    .
    //<MediaMelon Integration>
    Log.d("SmartStreamingIntgr", MMSmartStreamingExo2.getVersion());
    MMSmartStreamingExo2.enableLogTrace(true); //set to "false" before releasing player to production
    if (MMSmartStreamingExo2.getRegistrationStatus() == false){ //Check if it is the first time Registration process is done
      MMSmartStreamingExo2.registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_ID", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG");
      MMSmartStreamingExo2.reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
      MMSmartStreamingExo2.getInstance().setContext(getApplicationContext()); //Please make sure to provide the application's context here, and not the activity's context
    }
    //<MediaMelon Integration>
    .
    .
  }
```

<table><thead><tr><th width="274">Variable</th><th>Description</th></tr></thead><tbody><tr><td>PLAYER_NAME</td><td>String containing the player version (e.g. “Bitmovin_Android_Player_2.28.0”).</td></tr><tr><td>CUSTOMER_ID</td><td>String containing your MediaMelon-assigned Customer ID.</td></tr><tr><td>SUBSCRIBER_ID</td><td>String containing your subscriber’s ID. If you do not use subscriber IDs, enter null</td></tr><tr><td>DOMAIN_NAME</td><td>String containing your section of your subscriber or assets. (Optional)</td></tr><tr><td>SUBSCRIBER_TYPE</td><td>String containing the subscriber type (e.g. “Free”, “Paid”). If you do not use subscriber types, enter null</td></tr><tr><td>SUBSCRIBER_TAG</td><td>String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field.</td></tr><tr><td>ASSET_ID</td><td>String containing Asset Id.</td></tr><tr><td>ASSET_NAME</td><td>String containing Asset Name.</td></tr><tr><td>VIDEO_ID</td><td>String containing your video’s ID. If you do not use videos IDs, enter null.</td></tr><tr><td>PLAYER_BRAND</td><td>String containing the player brand (e.g. “bitmovin”).</td></tr><tr><td>PLAYER_MODEL</td><td>String containing the player model. For example - This could be a variant of player. Say name of third party player used by organisation. Or any human readable name of the player.</td></tr><tr><td>PLAYER_VERSION</td><td>String containing the player version.</td></tr></tbody></table>

#### **Step 3.3:** Add the following code to:&#x20;

`BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/SampleAdsWrapper.java`

```java
private final ImaSdkFactory sdkFactory;
private AdsLoader adsLoader;
private StreamDisplayContainer displayContainer;
private StreamManager streamManager;
private final List<VideoStreamPlayer.VideoStreamPlayerCallback> playerCallbacks;
.
.
//<MediaMelon Integration>
MMAnalyticsBridge analyticsBridgeObject; // Declaration of Analytics Bridge object, wherever the IMA AdsLoader and IMA StreamManager are declared in your application
//<MediaMelon Integration>
```

```java
private void createAdsLoader() { // this functions creates the Google IMA DAI ads loader (which is preferably a singleton - only one ads loader for the entire lifecyle)
  ImaSdkSettings settings = sdkFactory.createImaSdkSettings();
  //<MediaMelon Integration>
  analyticsBridgeObject = MMSmartStreamingExo2.getInstance().getAnalyticsBridge(); // get the Analytics Bridge Object ,this should be done wherever in your application the Google IMA adsLoader is created
  //<MediaMelon Integration>
  .
  .
  adsLoader = sdkFactory.createAdsLoader(context, settings, displayContainer);
}
```

```java
public void requestAndPlayAds() {  
  .
  .
  //<MediaMelon Integration>
  adsLoader.addAdErrorListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ads error listeners
  adsLoader.addAdsLoadedListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ads loaded listeners
  //<MediaMelon Integration>
  .
  .
  adsLoader.addAdErrorListener(this);
  adsLoader.addAdsLoadedListener(this); 
  adsLoader.requestStream(buildStreamRequest());
  .
  . 
}
```

```java
 @Override
  public void onAdsManagerLoaded(AdsManagerLoadedEvent event) {
    .
    .
    //<MediaMelon Integration>
    streamManager.addAdErrorListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ad error listeners
    streamManager.addAdEventListener(analyticsBridgeObject); // pass the Analytics Bridge object to the ad event listeners
    //<MediaMelon Integration>
    .
    .
    streamManager.addAdErrorListener(this);
    streamManager.addAdEventListener(this);
    streamManager.init();
    .
    .
  }
```

#### **Step 4**: AD Event callbacks from the SDK.&#x20;

A list of all Google IMA DAI AD events can be found [here](https://developers.google.com/interactive-media-ads/docs/sdks/android/dai/api/reference/com/google/ads/interactivemedia/v3/api/AdEvent.AdEventType).

```
  @Override
  public void onAdEvent(AdEvent event) { // this is a callback which gets called whenever a AD event occurs
    switch (event.getType()) {
     // Access all ad events here , this method will be automatically called whenever an ad event occurs
      case AD_PROGRESS:
      // write your own logic inside each case
        break;
      case FIRST_QUARTILE:
        // write your own logic inside each case
        break;
      case MIDPOINT:
        // write your own logic inside each case
        break;
      case THIRD_QUARTILE:
        // write your own logic inside each case
        break;
      case COMPLETED:
        // write your own logic inside each case
        break;
      default:
        log(String.format("Event: %s\n", event.getType()));
        break;
    }
  }
```


# Apple SDK


# MediaMelon iOS Custom SDK Integration Document

This guide is for integrating the MediaMelon Custom SDK for the iOS/tvOS-based Players

**Step 1:** [Add MediaMelon SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Register and Initialize MediaMelon SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Additional Custom Metadata](#step-3-additional-custom-metadata)

**Step 4:** [Network and Stream Information](#step-4-network-and-stream-information)

**Step 5:** [Chunk/Segment Information](#step-5-chunk-segment-information)

**Step 6:** [Player Events](#step-6-player-events)

**Step 7:** [Fallback & Request Status](#step-7-fallback-and-request-status)

**Step 8:** [Ad Data & Ad Events](#step-8-a-d-data-and-ad-events)

**Step 9:** [Custom Events](#step-9-custom-events)

[Release Notes](#release-notes)

### **Step 1: Add** MediaMelon SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

* **SPM:**

```swift
.package(
      url: "https://github.com/MediamelonSDK/mm-ios-qoe-sdk",
      .upToNextMajor(from: "2.16.0")
 ),
```

### **Step 2: Register and Initialize** MediaMelon SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

#### Step 2.1: Instantiate and Set SDK Registration Information:

```swift
let mmCustomAdapter = MMCustomAdapter.shared

let registrationInfo = MMRegistrationInformation(customerID: "CUSTOMER_ID", playerName: "PLAYER_NAME")
registrationInfo.setDomain("DOMAIN_NAME")
registrationInfo.setSubscriberInformation(subscriberID: "SUBSCRIBER", subscriberType: "SUBSCRIBER_TYPE", subscriberTag: "SUBSCRIBER_TAG", hashSubscriberID: false)
registrationInfo.setPlayerInformation(brand: "PLAYER_BRAND", model: "PLAYER_MODEL", version: "PLAYER_VERSION")
registrationInfo.setBasePlayerInformation(basePlayerName: "BASE_PLAYER_NAME", basePlayerVersion: "BASE_PLAYER_VERSION")
```

{% hint style="info" %}
`hashSubscriberID`: Set it to `true` to hash the subscriber ID, and to `false` to process the subscriber ID without hashing.
{% endhint %}

#### Step 2.3: Set Device Information:

```swift
let deviceInfo = MMDeviceInformation()
deviceInfo.setDeviceTpe(type: "DEVICE_TYPE")
deviceInfo.setBrandName(brandName: "BRAND_NAME")    // Device Brand or Manufacturer
deviceInfo.setDeviceModel(deviceModel: "DEVICE_MODEL")
deviceInfo.setOSName(osName: "OS_NAME")
deviceInfo.setOSVersion(osVersion: "OS_VERSION")
deviceInfo.setTelecomOperator(telecomOperator: "TELECOM_OPERATOR")
deviceInfo.setScreenResolution(width: <screen_width>, height: <screen_height>)  //Integer Value
```

#### Step 2.4: Report Application Information:

```swift
mmCustomAdapter.reportAppData(appName: "APP_NAME", appVersion: "APP_VERSION")
```

#### Step 2.5: Report Application Session ID:

```swift
mmCustomAdapter.reportAppSessionID(appSessionId: "APP_SESSION_ID")
```

#### Step 2.6: Report Experiment Name & Sub Property ID:

```swift
mmCustomAdapter.reportExperimentName(experimentName: "EXPERIMENT_NAME")
mmCustomAdapter.reportSubPropertyID(subPropertyId: "SUBPROPERTY_ID")
```

#### Step 2.7: Set Content Metadata:

```swift
let assetInfo = MMAssetInformation(assetURL: "STREAM_URL", assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId: "VIDEO_ID")
assetInfo.setEpisodeNumber("EPISODE_NUMBER")
assetInfo.setContentType("CONTENT_TYPE")
assetInfo.setSeriesTitle("SERIES_TITLE")
assetInfo.setGenre("GENRE")
assetInfo.setSeason("SEASON")
assetInfo.setDrmProtection("DRM_PROTECTION")
assetInfo.addCustomKVP("CUSTOM_1", "VALUE_1")
assetInfo.addCustomKVP("CUSTOM_2", "VALUE_2")

mmCustomAdapter.reportViewSessionID(viewSessionId: "VIEW_SESSION_ID")
```

#### Step 2.8: Initialize Session with Content Metadata:

```swift
mmCustomAdapter.initializeAssetForPlayer( assetInfo: assetInfo, 
                                         registrationInfo: registrationInfo, 
                                         deviceInfo: deviceInfo)
mmCustomAdapter.reportPreload(<boolean>)
mmCustomAdapter.reportUserInitiatedPlayback()
```

{% hint style="info" %}
**Preload:** Report the preload attribute after `initializeAssetForPlayer` and before `reportUserInitiatedPlayback`. The preload value is reset inside `initializeAssetForPlayer`, so reporting it before this method will be ignored. If you report it after `reportUserInitiatedPlayback`, the first event will not contain the preload field.
{% endhint %}

### Step 3: Additional Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```swift
mmCustomAdapter.reportCustomMetadata(key: "CUSTOM_3", value: "VALUE_3")
```

### Step 4: Network and Stream Information

#### Step 4.1: Report Network Information:

```swift
mmCustomAdapter.reportNetworkInfo(cdn: "CDN", 
                                  asn: <asn>,                     // Integer Value
                                  hostName: "SOURCE_HOST_NAME", 
                                  networkType: "NETWORK_TYPE",    // Network Connection Type
                                  networkOperator: "NETWORK_OPERATOR")
```

{% hint style="info" %}
Use the `reportNetworkInfo` API to report the CDN along with other network information.\
If additional network information is not available, use `reportCDN` instead.
{% endhint %}

#### Step 4.2: Report CDN Information:

```swift
mmCustomAdapter.reportCDN(cdn: "CDN")
```

#### Step 4.3: Report Stream Information:

```swift
mmCustomAdapter.reportStreamInfo(streamURL: "STREAM_URL", 
                                 streamFormat: "STREAM_FORMAT", 
                                 mediaType: "MEDIA_TYPE", 
                                 sourceType: "SOURCE_TYPE")
```

#### Step 4.4: Report Video Presentation Information:

```swift
mmCustomAdapter.reportPresentationInfo(isLive: <is_live>, videoDurationInMS: <video_duration>)
```

{% hint style="info" %}

* `is_live`: Set to `true` for live video stream and to `false` for the VOD stream.
* `video_duration`: Video duration in milliseconds.
  {% endhint %}

#### Step 4.5: Report Track Information:

Call this API with initial values and every time there is a change in the track info. Call this API when the user enables/disables subtitles or when the user changes the audio track.

```swift
mmCustomAdapter.reportMediaTrackInfo(isSubtitleActive: <is_subtitle_active>, subtitleTrack: "SUBTITLE_TRACK", audioTrack: "AUDIO_TRACK", isVDSActive: <is_vds_active>);
```

{% hint style="info" %}
`is_subtitle_active`: Set it to `true` if the subtitles are active; otherwise, set it to `false`.

`is_vds_active`: Set it to `true` if the type of audio is Virtual Dialogue Sound, otherwise, set it to `false`.
{% endhint %}

#### Step 4.6: Report Rendition:

At the start of the video, create a ReditionInfo object, assign initial rendition values to the object, and report it to the SDK. For any subsequent rendition change, update only the fields that changed in the same RenditionInfo object. Leave the unchanged fields as-is, and report the updated object to the SDK.

```swift
var renditionInfo = MMRenditionInformation()

renditionInfo.bitrate = <bitrate>            //Integr Value in bps
renditionInfo.width = <width>                //Integer Value
renditionInfo.height = <height>              //Integer Value
renditionInfo.frameRate = <frame_rate>       //Double Value in fps
renditionInfo.aCodec = "AUDIO_CODEC"
renditionInfo.vCodec = "VIDEO_CODEC"

mmCustomAdapter.reportRendition(renditionInfo: renditionInfo)
```

#### Step 4.7: Update DRM Type:

```swift
mmCustomAdapter.updateDrmType("NEW_DRM_TYPE");
```

#### Step 4.8: Report Encoding Service:

```swift
mmCustomAdapter.reportEncodingService("ENCODING_SERVICE");
```

### Step 5: Chunk/Segment Information

#### Step 5.1: Report Download Rate:

Report the latest chunk download rate using this method. Trigger this method for every chunk.

```swift
mmCustomAdapter.reportDownloadRate(downloadRate: <downloadRate>)  //Integer Value in bps
```

### Step 6: Player Events

#### Step 6.1: Report Player State:

```swift
mmCustomAdapter.reportPlayerState(playerState: .PLAYING)

Enum: MMPlayerState
- PLAYING
- PAUSED
- STOPPED
```

#### Step 6.2: Report Buffering:

```swift
mmCustomAdapter.reportBufferingStarted()
mmCustomAdapter.reportBufferingCompleted()
```

#### Step 6.3: Report Seek:

```swift
mmCustomAdapter.reportPlayerSeekStarted() 
mmCustomAdapter.reportPlayerSeekCompleted(seekEndPositionInMS: <seek_end_position>) //Integer Value in Milli Seconds
```

#### Step 6.4: Report Error:

```swift
mmCustomAdapter.reportError(errorCode: "ERROR_CODE",
                            errorMessage: "ERROR_MESSAGE",
                            errorDetails: "ERROR_DETAILS")
```

#### Step 6.5: Report Warning:

```swift
mmCustomAdapter.reportWarning(warningCode: "WARNING_CODE",
                              warningMessage: "WARNING_MESSAGE",
                              warningDetails: "WARNING_DETAILS")
```

#### Step 6.5: Report Playback Position:

Call this every 0.5 sec or 1 sec to report the playback position from the player

```swift
mmCustomAdapter.reportPlaybackPosition(currentPlayerPosInMS: <playback_position>) //Integer Value in Milli Seconds
```

#### Step 6.6: Report Player Resolution:

```swift
mmCustomAdapter.reportPlayerResolution(width: <width>, height: <height>)
```

### Step 7: Fallback & Request Status

#### Step 7.1: Report Fallback Event:

```swift
mmCustomAdapter.reportFallbackEvent(fallbackManifestURL: "NEW_STREAM_URL", description: "DESCRIPTION")
```

#### Step 7.2: Report Request Status:

Report `FAILED` or `CANCELLED` requests for the following request types:

* PIR
* MANIFEST
* AUDIO\_CHUNK
* VIDEO\_CHUNK
* DRM
* SUBTITLE

```swift
var requestInfo : [String: Any] = [
    "id": "ID",
    "url": "URL",
    "error": "ERROR",
    "text": "TEXT",
    "hostname": "HOSTNAME",
    "url": "URL",
    ...
]

mmCustomAdapter.reportRequestStatus(status: .CANCELLED, type: "REQUEST_TYPE", requestInfo: requestInfo)

Enum: RequestStatus
- FAILED
- CANCELLED
```

### Step 8: Ad Data & Ad Events

#### Step 8.1: Report Ad Break Start & End:

```swift
mmCustomAdapter.reportAdBreakStart()
mmCustomAdapter.reportAdBreakEnd()
```

#### Step 8.2: Report Ad Data, Ad Start & End:

```swift
let adInfo = MMAdInfo()
adInfo.adTitle = "AD_TITLE"
adInfo.adId = "AD_ID"
adInfo.adCreativeId = "AD_CREATIVE_ID"
adInfo.adCreativeType = "AD_CREATIVE_TYPE"
adInfo.adClient = "AD_CLIENT"
adInfo.adPosition = "AD_POSITION"                    //pre, mid, post
adInfo.adServer = "AD_SERVER"
adInfo.adResolution = "AD_RESOLUTION"
adInfo.adUrl = "AD_URL"
adInfo.adDuration = <ad_duration>                    //Integer Value in Milli Seconds
adInfo.adPodIndex = <pod_index>                      //Integer Value
adInfo.adPositionInPod = <ad_position_in_pod>        //Integer Value
adInfo.adPodLendth = <pod_length>                    //Integer Value
adInfo.isBumper = <is_bumper>                        //Boolean Value

mmCustomAdapter.reportAdStart(adInfo: adInfo)
mmCustomAdapter.reportAdEnd()
```

<details>

<summary>Ad Info Fields &#x26; Description</summary>

<table data-header-hidden data-search="false"><thead><tr><th width="197.25390625">Field</th><th width="114.51953125">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>adInfo.adTitle</td><td>String</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adInfo.adId</td><td>String</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adInfo.adCreativeId</td><td>String</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adInfo.adCreativeType</td><td>String</td><td>The format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>adInfo.adClient</td><td>String</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adInfo.adPosition</td><td>String</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adInfo.adServer</td><td>String</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adInfo.adResolution</td><td>String</td><td>The resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>adInfo.adUrl</td><td>String</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adInfo.adDuration</td><td>Integer</td><td>The total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>adInfo.adPodIndex</td><td>Integer</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adInfo.adPositionInPod</td><td>Integer</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>adInfo.adPodLendth</td><td>Integer</td><td>The total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr><tr><td>adInfo.isBumper</td><td>Boolean</td><td>A boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr></tbody></table>

</details>

#### Step 8.3: Report Ad Buffering:

Use Ad Buffering APIs to report any buffering that occurs during ad playback. For any buffering event, either content buffering or ad buffering should be reported, but not both.

```swift
mmCustomAdapter.reportAdBufferingStrated();
mmCustomAdapter.reportAdBufferingCompleted();
```

### Step 9: Custom Events

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```swift
mmCustomAdapter.reportCustomEvent("EVENT_NAME", "EVENT_VALUE");
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 30 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

#### Release Notes

<details>

<summary>Current Release</summary>

#### v2.16.1 <sup><sub>**`Sep 08, 2026`**<sub></sup>

* Added Device Capabilities API as part of the public Device Information class

#### v2.16.0[^1]  <sup><sub>**`Mar 30, 2026`**<sub></sup>

* Added support for reporting a new field encoding service via `reportEncodingService`.
* Introduced custom event reporting through `reportCustomEvent`.
* Added support for ad buffering events:
  * `reportAdBufferingStarted`
  * `reportAdBufferingCompleted`
* Improved event handling to restrict event reporting after playback has ended.

</details>

***

<details>

<summary>Previous Releases</summary>

#### v2.15.0[^1]  <sup><sub>**`Feb 06, 2026`**<sub></sup>

* Added an additional API to report CDN alone.
* Added `CDN_CHANGE` event.
* Added Seek Duration calculation internally.

#### v2.14.2[^1]  <sup><sub>**`Dec 23, 2025`**<sub></sup>

* Fixed custom tags are not getting overridden issue in the SDK

#### v2.14.1  <sup><sub>**`Dec 22, 2025`**<sub></sup>

* Added full device information support internally (model, brand, marketing name, OS, OS version)
* Added rendition metrics for upscale and downscale percentage calculations
* Improved bitrate reporting for weighted average bitrate calculation
* Updated internal SDK version format

#### v2.13.0  <sup><sub>**`Dec 03, 2025`**<sub></sup>

* Preload field addition
* App Session ID field addition
* Fix to consider Exit in Buffering

#### v2.12.0  <sup><sub>**`Nov 03, 2025`**<sub></sup>

* Crash fix at Ad Start

</details>

[^1]: **Performance Report:** [here](https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/apple/apple-custom-sdk-performance-metrics)


# MediaMelon iOS Custom Multi-Player SDK Integration Document

This guide is for integrating the MediaMelon Custom Multi-Player SDK for the iOS, tvOS & visionOS - based Players

**Step 1:** [Add MediaMelon SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Instantiate and Register SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Initialize Playback Session](#step-3-initialize-playback-session)

**Step 4:** [Additional Custom Metadata](#step-4-additional-custom-metadata)

**Step 5:** [Network and Stream Information](#step-5-network-and-stream-information)

**Step 6:** [Chunk/Segment Information](#step-6-chunk-segment-information)

**Step 7:** [Player Events](#step-7-player-events)

**Step 8:** [Fallback & Request Status](#step-8-fallback-and-request-status)

**Step 9:** [Ad Data & Ad Events](#step-9-a-d-data-and-ad-events)

**Step 10:** [Custom Events](#step-10-custom-events)

[Release Notes](#release-notes)

### **Step 1: Add** MediaMelon SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

* **SPM:**

```swift
.package(
      url: "https://github.com/MediamelonSDK/mm-ios-qoe-sdk",
      .upToNextMajor(from: "3.3.1")
 ),
```

### **Step 2:** Instantiate and Register SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

#### Step 2.1: SDK Instance Creation:

```swift
let mmCustomAdapter = MMCustomAdapter()
```

#### Step 2.2: Report Registration Information:

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```swift
let registrationInfo = MMRegistrationInformation(customerID: "CUSTOMER_ID", playerName: "PLAYER_NAME")
registrationInfo.setDomain("DOMAIN_NAME")
registrationInfo.setSubscriberInformation(subscriberID: "SUBSCRIBER", subscriberType: "SUBSCRIBER_TYPE", subscriberTag: "SUBSCRIBER_TAG", hashSubscriberID: false)
registrationInfo.setPlayerId(playerId: "PLAYER_ID")
registrationInfo.setPlayerInformation(brand: "PLAYER_BRAND", model: "PLAYER_MODEL", version: "PLAYER_VERSION")
registrationInfo.setBasePlayerInformation(basePlayerName: "BASE_PLAYER_NAME", basePlayerVersion: "BASE_PLAYER_VERSION")

mmCustomAdapter.reportRegistrationInformation(registrationInfo)
```

{% hint style="info" %}
`hashSubscriberID`: Set it to `true` to hash the subscriber ID, and to `false` to process the subscriber ID without hashing.
{% endhint %}

#### Step 2.3: Report Device Information:

<pre class="language-swift"><code class="lang-swift">let deviceInfo = MMDeviceInformation()
deviceInfo.setDeviceTpe(type: "DEVICE_TYPE")
deviceInfo.setBrandName(brandName: "BRAND_NAME")    // Device Brand or Manufacturer
deviceInfo.setDeviceModel(deviceModel: "DEVICE_MODEL")
deviceInfo.setOSName(osName: "OS_NAME")
deviceInfo.setOSVersion(osVersion: "OS_VERSION")
deviceInfo.setTelecomOperator(telecomOperator: "TELECOM_OPERATOR")
deviceInfo.setScreenResolution(width: &#x3C;screen_width>, height: &#x3C;screen_height>)  //Integer Value
<a data-footnote-ref href="#user-content-fn-1">deviceInfo.setDeviceCapabilities(deviceCapabilities: "DEVICE_CAPABILITIES")</a>

mmCustomAdapter.reportDeviceInformation(deviceInfo)
</code></pre>

#### Step 2.4: Report Application Information:

```swift
mmCustomAdapter.reportAppData(appName: "APP_NAME", appVersion: "APP_VERSION")
mmCustomAdapter.reportAppSessionID(appSessionId: "APP_SESSION_ID")
```

#### Step 2.5: Report Sub Property ID:

```swift
mmCustomAdapter.reportSubPropertyID(subPropertyId: "SUBPROPERTY_ID")
```

### Step 3: Initialize Playback Session

{% hint style="danger" %}
`initializeAssetForPlayer( assetInfo:, registrationInfo:, deviceInfo:)` is **deprecated**. Use separate APIs to report `registrationInfo` and `deviceInfo` as given in [Step 2.2](#step-2.2-report-registration-information) and [Step 2.3](#step-2.3-report-device-information).
{% endhint %}

#### Step 3.1: Initialize Session with Content Metadata:

```swift
let assetInfo = MMAssetInformation(assetURL: "STREAM_URL", assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId: "VIDEO_ID")
assetInfo.setEpisodeNumber("EPISODE_NUMBER")
assetInfo.setContentType("CONTENT_TYPE")
assetInfo.setSeriesTitle("SERIES_TITLE")
assetInfo.setGenre("GENRE")
assetInfo.setSeason("SEASON")
assetInfo.setDrmProtection("DRM_PROTECTION")
assetInfo.setDrmLevel("DRM_LEVEL")
assetInfo.addCustomKVP("CUSTOM_1", "VALUE_1")
assetInfo.addCustomKVP("CUSTOM_2", "VALUE_2")

mmCustomAdapter.initializeAssetForPlayer(assetInfo: assetInfo)
```

{% hint style="warning" %}
All metadata fields set from **Step 3** will be reset when `initializeAssetForPlayer` is called. Therefore, ensure that all session-specific metadata, such as `view session ID`, `preload`, and similar fields, are reported after `initializeAssetForPlayer` is called for every playback session.
{% endhint %}

#### Step 3.2: Report View Session ID:

```swift
mmCustomAdapter.reportViewSessionID(viewSessionId: "VIEW_SESSION_ID")
```

#### Step 3.3: Report Experiment Name:

```swift
mmCustomAdapter.reportExperimentName(experimentName: "EXPERIMENT_NAME")
```

#### Step 3.4: Report Preload:

```swift
mmCustomAdapter.reportPreload(<boolean>)
```

#### Step 3.5: Report Player Resolution:

```swift
mmCustomAdapter.reportPlayerResolution(width: <width>, height: <height>)
```

#### Step 3.6: Report User-Initiated Playback:

{% hint style="info" %}
This function indicates the intent for playback and must be invoked after `initializeAssetForPlayer`. Any metadata fields reported before this API call will be included in the first payload sent to the dashboard. To avoid `Null` values in metadata fields, it is recommended to report all available metadata before calling this API.
{% endhint %}

```swift
mmCustomAdapter.reportUserInitiatedPlayback()
```

### Step 4: Additional Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```swift
mmCustomAdapter.reportCustomMetadata(key: "CUSTOM_3", value: "VALUE_3")
```

### Step 5: Network and Stream Information

#### Step 5.1: Report Network Information:

```swift
mmCustomAdapter.reportNetworkInfo(cdn: "CDN", 
                                  asn: <asn>,                     // Integer Value
                                  hostName: "SOURCE_HOST_NAME", 
                                  networkType: "NETWORK_TYPE",    // Network Connection Type
                                  networkOperator: "NETWORK_OPERATOR")
```

{% hint style="info" %}
Use the `reportNetworkInfo` API to report the CDN along with other network information.\
If additional network information is not available, use `reportCDN` instead.
{% endhint %}

#### Step 5.2: Report CDN Information:

```swift
mmCustomAdapter.reportCDN(cdn: "CDN")
```

#### Step 5.3: Report Stream Information:

```swift
mmCustomAdapter.reportStreamInfo(streamURL: "STREAM_URL", 
                                 streamFormat: "STREAM_FORMAT", 
                                 mediaType: "MEDIA_TYPE", 
                                 sourceType: "SOURCE_TYPE")
```

#### Step 5.4: Report Encoding Service:

```swift
mmCustomAdapter.reportEncodingService(encodingService: "ENCODING_SERVICE");
```

#### Step 5.5: Report Video Presentation Information:

```swift
mmCustomAdapter.reportPresentationInfo(isLive: <is_live>, videoDurationInMS: <video_duration>)
```

{% hint style="info" %}

* `is_live`: Set to `true` for live video stream and to `false` for the VOD stream.
* `video_duration`: Video duration in milliseconds.
  {% endhint %}

#### Step 5.6: Report Track Information:

Call this API with initial values, and every time there is a change in the track info. Call this API when the user enables or disables subtitles or changes the audio track.

```swift
mmCustomAdapter.reportMediaTrackInfo(isSubtitleActive: <is_subtitle_active>, subtitleTrack: "SUBTITLE_TRACK", audioTrack: "AUDIO_TRACK", isVDSActive: <is_vds_active>);
```

{% hint style="info" %}
`is_subtitle_active`: Set it to `true` if the subtitles are active; otherwise, set it to `false`.

`is_vds_active`: Set it to `true` if the type of audio is Virtual Dialogue Sound, otherwise, set it to `false`.
{% endhint %}

#### Step 5.7: Report Rendition:

At the start of the video, create a ReditionInfo object, assign initial rendition values to the object, and report it to the SDK. For any subsequent rendition change, update only the fields that changed in the same RenditionInfo object. Leave the unchanged fields as-is, and report the updated object to the SDK.

```swift
var renditionInfo = MMRenditionInformation()

renditionInfo.bitrate = <bitrate>            //Integr Value in bps
renditionInfo.width = <width>                //Integer Value
renditionInfo.height = <height>              //Integer Value
renditionInfo.frameRate = <frame_rate>       //Double Value in fps
renditionInfo.aCodec = "AUDIO_CODEC"
renditionInfo.vCodec = "VIDEO_CODEC"

mmCustomAdapter.reportRendition(renditionInfo: renditionInfo)
```

#### Step 5.8: Update DRM:

{% hint style="danger" %}
`updateDrmType(drmType:)` is **deprecated**. A new API called `updateDRM(drmProtection:, drmLevel:)` is introduced.
{% endhint %}

```swift
mmCustomAdapter.updateDRM(drmProtection: "DRM_PROTECTION", drmLevel: "DRM_LEVEL");
```

### Step 6: Chunk/Segment Information

#### Step 6.1: Report Download Rate:

Report the latest chunk download rate using this method. Trigger this method for every chunk.

```swift
mmCustomAdapter.reportDownloadRate(downloadRate: <downloadRate>)  //Integer Value in bps
```

### Step 7: Player Events

#### Step 7.1: Report Player State:

```swift
mmCustomAdapter.reportPlayerState(playerState: .PLAYING)

Enum: MMPlayerState
- PLAYING
- PAUSED
- STOPPED
```

#### Step 7.2: Report Buffering:

```swift
mmCustomAdapter.reportBufferingStarted()
mmCustomAdapter.reportBufferingCompleted()
```

#### Step 7.3: Report Seek:

```swift
mmCustomAdapter.reportPlayerSeekStarted() 
mmCustomAdapter.reportPlayerSeekCompleted(seekEndPositionInMS: <seek_end_position>) //Integer Value in Milli Seconds
```

#### Step 7.4: Report Error:

```swift
mmCustomAdapter.reportError(errorCode: "ERROR_CODE",
                            errorMessage: "ERROR_MESSAGE",
                            errorDetails: "ERROR_DETAILS")
```

#### Step 7.5: Report Warning:

```swift
mmCustomAdapter.reportWarning(warningCode: "WARNING_CODE",
                              warningMessage: "WARNING_MESSAGE",
                              warningDetails: "WARNING_DETAILS")
```

#### Step 7.6: Report Playback Position:

Call this every 0.5 sec or 1 sec to report the playback position from the player

```swift
mmCustomAdapter.reportPlaybackPosition(currentPlayerPosInMS: <playback_position>) //Integer Value in Milli Seconds
```

### Step 8: Fallback & Request Status

#### Step 8.1: Report Fallback Event:

```swift
mmCustomAdapter.reportFallbackEvent(fallbackManifestURL: "NEW_STREAM_URL", description: "DESCRIPTION")
```

#### Step 8.2: Report Request Status:

Report `FAILED` or `CANCELLED` requests for the following request types:

* PIR
* MANIFEST
* AUDIO\_CHUNK
* VIDEO\_CHUNK
* DRM
* SUBTITLE

```swift
var requestInfo : [String: Any] = [
    "id": "ID",
    "url": "URL",
    "error": "ERROR",
    "text": "TEXT",
    "hostname": "HOSTNAME",
    "url": "URL",
    ...
]

mmCustomAdapter.reportRequestStatus(status: .CANCELLED, type: "REQUEST_TYPE", requestInfo: requestInfo)

Enum: RequestStatus
- FAILED
- CANCELLED
```

### Step 9: Ad Data & Ad Events

#### Step 9.1: Report Ad Break Start & End:

```swift
mmCustomAdapter.reportAdBreakStart()
mmCustomAdapter.reportAdBreakEnd()
```

#### Step 9.2: Report Ad Data, Ad Start & End:

```swift
let adInfo = MMAdInformation()

adInfo.setAdTitle("AD_TITLE")
adInfo.setAdId("AD_ID")
adInfo.setAdUniversalId("AD_UNIVERSAL_ID")
adInfo.setAdCreativeId("AD_CREATIVE_ID")
adInfo.setAdCreativeType("AD_CREATIVE_TYPE")
adInfo.setAdClient("AD_CLIENT")
adInfo.setAdPosition("AD_POSITION")
adInfo.setAdServer("AD_SERVER")
adInfo.setAdResolution("AD_RESOLUTION")
adInfo.setAdUrl("AD_URL")
adInfo.setAdDuration(<ad_duration>)                    //Integer Value in Milli Seconds
adInfo.setAdPodIndex(<pod_index>)                      //Integer Value
adInfo.setAdPositionInPod(<ad_position_in_pod>)        //Integer Value
adInfo.setAdPodLendth(<pod_length>)                    //Integer Value
adInfo.setIsBumper(<is_bumper>)                        //Boolean Value

mmCustomAdapter.reportAdStart(adInfo: adInfo)
mmCustomAdapter.reportAdEnd()
```

<details>

<summary>Ad Info Fields &#x26; Description</summary>

<table data-header-hidden><thead><tr><th width="197.25390625">Field</th><th width="114.51953125">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>adTitle</td><td>String</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adId</td><td>String</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adUniversalId</td><td>String</td><td>A globally consistent identifier for an ad creative that remains the same across all platforms and systems, enabling unified tracking and reporting.</td></tr><tr><td>adCreativeId</td><td>String</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adCreativeType</td><td>String</td><td>The format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>adClient</td><td>String</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adPosition</td><td>String</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adServer</td><td>String</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adResolution</td><td>String</td><td>The resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>adUrl</td><td>String</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adDuration</td><td>Integer</td><td>The total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>adPodIndex</td><td>Integer</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adPositionInPod</td><td>Integer</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>adPodLendth</td><td>Integer</td><td>The total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr><tr><td>isBumper</td><td>Boolean</td><td>A boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr></tbody></table>

</details>

#### Step 9.3: Report Ad Buffering:

Use Ad Buffering APIs to report any buffering that occurs during ad playback. For any buffering event, either content buffering or ad buffering should be reported, but not both.

```swift
mmCustomAdapter.reportAdBufferingStrated();
mmCustomAdapter.reportAdBufferingCompleted();
```

#### Step 9.4: Report Ad Events:

Use the `reportAdEvent` function to report all Ad events.

{% hint style="info" %}
`reportAdStart` and `reportAdEnd` are kept as it is for backward compatibility, but going forward, all the new Integrations should use the  `reportAdEvent` API for all ad states.
{% endhint %}

```swift
mmCustomAdapter.reportAdEvent(adEvent: MMAdEvent, adInfo: adInfo);
```

<details>

<summary><strong>MMAdEvent (Enum)</strong></summary>

| Ad Event            | Description                                           |
| ------------------- | ----------------------------------------------------- |
| AD\_START           | Report on ad start.                                   |
| AD\_FIRST\_QUARTILE | Report on ad reached first quartile.                  |
| AD\_MID\_POINT      | Report on ad reached midpoint.                        |
| AD\_THIRD\_QUARTILE | Report on ad reached third quartile.                  |
| AD\_SKIP            | Report on ad skipped.                                 |
| AD\_END             | Report on ad ended.                                   |
| AD\_COMPLETE        | Report on ad ended and ad play time greater than 95%. |
| AD\_CLICK           | Report on ad clicked.                                 |

</details>

#### Step 9.5: Report Ad Request and Response:

Report Ad Request and Ad Response using the following API:

{% hint style="info" %}
Both APIs accept a dictionary of type `[String: Any]` containing the relevant ad request or ad response metadata.
{% endhint %}

```swift
mmCustomAdapter.reportAdRequest(requestInfo: [String: Any]);
mmCustomAdapter.reportAdResponse(responseInfo: [String: Any]);
```

#### Step 9.6: Report Ad Errors and Warnings:

**Ad Errors:**

```swift
mmCustomAdapter.reportAdError(errorCode: "ERROR_CODE", errorMessage: "ERROR_MESSAGE", errorDetails: "ERROR_DETAILS");
```

**Ad Warnings:**

```swift
mmCustomAdapter.reportAdWarning(warningCode: "WARNING_CODE", warningMessage: "MARNING_MESSAGE", warningDetails: "WARNING_DETAILS");
```

### Step 10: Custom Events

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```swift
mmCustomAdapter.reportCustomEvent("EVENT_NAME", "EVENT_VALUE");
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 30 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

#### Release Notes

<details>

<summary>Current Release</summary>

#### v3.4.1 <sup><sub>`July 19, 2026`<sub></sup>

* Added `v3.3.1` crash fix on top `v3.4.0`.
* Added a new public `shutdown()` API to gracefully terminate the SDK. Invoking this API destructs all initialized SDK objects and releases associated resources.

</details>

***

<details>

<summary>Previous Releases</summary>

#### v3.3.1 <sup><sub>`July 17, 2026`<sub></sup>

* Fixed an `EXC_BAD_ACCESS` memory crash on the SDK registration callback.

#### v3.4.0[^2]  <sup><sub>`July 15, 2026`<sub></sup>

* Enhanced Internal SDK data reporting
  * Added batch-based data reporting with configurable reporting intervals.
  * Improved reliability with exponential backoff retries, jitter, request timeouts, and Dead Letter Queue (DLQ) support.
  * Enabled remote configuration for batch size, reporting interval, retry settings, and the batching feature flag.
* Added new APIs for reporting ad events, including quartiles, request/response, errors, warnings, skip, and click events.
* Added support for reporting device capabilities through DeviceInfo.

#### v3.3.0[^3]  <sup><sub>**`Jun 02, 2026`**<sub></sup>

* Added `x86_64` simulator support for the VisionOS platform. (Missed in v3.2.0)

#### v3.2.0[^3]  <sup><sub>**`May 29, 2026`**<sub></sup>

* Added `x86_64` simulator support

#### v3.1.1[^3]  <sup><sub>**`May 04, 2026`**<sub></sup>

* Fixed the `MMPlayerState` missing issue.

#### v3.1.0[^3]  <sup><sub>**`Apr 21, 2026`**<sub></sup>

* Added support for multiple player instances within a single application.
* Added the following new metadata fields:
  * **Player ID** - report it using `setPlayerId` as part of Registration Information.
  * **DRM Level** - report it using `setDrmLevel` as part of the Asset Information.
  * **Ad Universal ID** - report it using `setAduniversalId` as part of the Ad Information.
* Added new APIs to report `Registration Information` and `Device Information` before initialization (refer to [Step 2](#step-2-register-and-initialize-mediamelon-sdk)).
* `MMAdInfo` replaced with `AdInformation` class (refer to [Step 9.2](#step-9.2-report-a-d-data-ad-start-and-end)).
* **Deprecations:**
  * `updateDRMType(drmType)` → **Deprecated**
    * Use `updateDRM(drmProtection, drmLevel)` (refer to [Step 5.8](#step-5.8-update-drm))
  * `initializeAssetForPlayer(assetInfo:, registrationInfo:, deviceInfo:)` → **Deprecated**
    * Use `initializeAssetForPlayer(assetInfo:)` (refer to [Step 3.1](#step-3.1-initialize-session-with-content-metadata))
    * Report `RegistrationInfo` and `DeviceInfo` separately before initialization.
* Buffering events exceeding the stats interval are now included in the stats payload.
* Updated **metadata lifecycle handling**:
  * [Step 2](#step-2-register-and-initialize-mediamelon-sdk) metadata fields persist across the SDK instance lifecycle.
  * All Metadata fields from [Step 3](#step-3-initialize-playback-session) are reset for every playback session.

***

#### [Non-Multiplayer Releases](/mediamelon/smartsight-player-sdk-integration/ios/mediamelon-ios-custom-sdk-integration-document#release-notes)

</details>

[^1]:

[^2]: Performance Report: [here](https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/apple/apple-custom-multi-player-sdk-performance-metrics)

[^3]: **Performance Report:** [here](https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/apple/apple-custom-multi-player-sdk-performance-metrics)


# MediaMelon iOS AVPlayer SDK Integration Document

This guide provides detailed instructions on integrating the MediaMelon AVPlayer SDK into an iOS/tvOS Media Player Application.

**Step 1:** [Setup The SDK](#step-1-set-up-mediamelon-sdk)

**Step 2:** [Import Frameworks](#step-2-import-frameworks)

**Step 3:** [Register and Initialize MediaMelon SDK](#step-3-register-and-initialize-mediamelon-sdk)

**Step 4:** [Additional Custom Metadata](#step-4-additional-custom-metadata)

**Step 5:** [Errors and Warnings](#step-5-errors-and-warnings-important)

**Step 6:** [Report Additional Metadata Fields](#step-6-report-additional-metadata-fields)

**Step 7:** [Cleaning up the SDK Session](#step-7-cleaning-up-the-sdk-session)

**Step 8:** [Update Asset Information](#step-8-update-asset-information)

**Step 9:** [Additional Configurations](#step-9-additional-configurations)

[Release Notes](#release-notes)

### Step 1: Set up MediaMelon SDK

{% tabs %}
{% tab title="SPM" %}

```swift
.package(
      url: "https://github.com/MediamelonSDK/mm-ios-sdk-avplayer",
      .upToNextMajor(from: "2.6.1")
 ),
```

{% endtab %}

{% tab title="Cocoapods" %}

```bash
target 'SwiftDemo' do
  .
  .
  pod 'MediaMelon-AVPlayer-SDK', '~> 2.5.0'
end
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
The `MediaMelon-AVPlayer-SDK` pod includes a dependency on the `MediaMelon-QoE-SDK` framework pod. This dependency framework supports both iOS and tvOS platforms.&#x20;

Check the latest available version of `MediaMelon-QoE-SDK` [here](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/ios/mediamelon-ios-custom-sdk-integration-document#release-notes).
{% endhint %}

### Step 2: Import Frameworks

```swift
import MediaMelonQoE
import MediaMelon_AVPlayer_SDK
```

### Step 3: **Register and Initialize** MediaMelon SDK

#### Step 3.1: Set SDK Registration Information:

```swift
let registrationInfo = MMRegistrationInformation(customerID: "CUSTOMER_ID", playerName: "PLAYER_NAME")
registrationInfo.setPlayerInformation(brand: "PLAYER_BRAND", model: "PLAYER_MODEL", version: "PLAYER_VERSION")
registrationInfo.setBasePlayerInformation(basePlayerName: "BASE_PLAYER_NAME", basePlayerVersion: "BASE_PLAYER_VERSION")
registrationInfo.setSubscriberInformation(subscriberID: "SUBSCRIBER_ID", subscriberType: "SUBSCRIBER_TYPE", subscriberTag: "SUBSCRIBER_TAG", hashSubscriberID: <Bool>)
registrationInfo.setDomain("DOMAIN_NAME")
```

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

#### Step 3.2: Report Application Information:

```swift
AVPlayerIntegrationWrapper.shared.reportAppData(appName: "APP_NAME", appVersion: "APP_VERSION")
AVPlayerIntegrationWrapper.shared.reportAppSessionID(appSessionId: "APP_SESSION_ID")
```

#### Step 3.3: Report Experiment Name & Sub Property ID:

```swift
AVPlayerIntegrationWrapper.shared.reportExperimentName(experimentName: "EXPERIMENT_NAME")
AVPlayerIntegrationWrapper.shared.reportSubPropertyID(subPropertyId: "SUB_PROPERTY_ID") 
```

#### Step 3.4: Set Content Metadata and Initialize Session:

```swift
let assetInfo = MMAssetInformation(assetURL: "STREAM_URL", assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId: "VIDEO_ID")
assetInfo.setEpisodeNumber("EPISODE_NUMBER")
assetInfo.setContentType("CONTENT_TYPE")
assetInfo.setSeriesTitle("SERIES_TITLE")
assetInfo.setGenre("GENRE")
assetInfo.setSeason("SEASON")
assetInfo.setDrmProtection("DRM_PROTECTION")
assetInfo.addCustomKVP("CUSTOM_1", "VALUE_1")
assetInfo.addCustomKVP("CUSTOM_2", "VALUE_2")

AVPlayerIntegrationWrapper.shared.reportViewSessionID(viewSessionId: "VIEW_SESSION_ID")
AVPlayerIntegrationWrapper.initializeAssetForPlayer(assetInfo: assetInfo, registrationInformation: registrationInfo, player: player, isLive: <Bool>)
```

{% hint style="info" %}
For Custom Metadata, first, provide the mapping in the [SmartSight](https://smartsight3.mediamelon.com/settings) dashboard under the settings section and send the values to the SDK accordingly. Refer to [Custom Metadata Configuration Guide](broken://pages/eWhNvkw0ryeL0LrKgj2u).
{% endhint %}

### Step 4: Additional Custom Metadata

Check the custom metadata configuration in the [SmartSight](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.&#x20;

Use this method to report any additional metadata that doesn’t fall under predefined metadata fields. This provides flexibility to send custom, business, or platform-specific information to the SDK.

```swift
AVPlayerIntegrationWrapper.shared.reportCustomMetadata(key: "KEY", value: "VALUE")
```

### Step 5: Errors and Warnings (Important)

The SDK provides two ways to report errors: automatic error capture and manual error reporting via API.

⚙️ **Default Behavior (Auto Error Capture):**

By default, the SDK automatically listens to and captures player errors that occur *after the stream has loaded*. SDK will classify the errors based on severity.

{% hint style="info" %}

> ⚠️ Note: Errors that occur **before or during stream loading** are not captured automatically by the SDK, as they fall outside the player’s event lifecycle. Use the error and warning APIs below to manually report such issues.
> {% endhint %}

🚫 **Disabling Auto Error Capture:**

If you prefer to handle error reporting manually, you can disable this automatic behavior by calling:

```swift
AVPlayerIntegrationWrapper.shared.disableAutoErrorCapture()
```

{% hint style="info" %}

> ⚠️ When disabled, the SDK will not listen for any player-generated errors. You will be responsible for reporting all errors & warnings manually using the APIs described below.
> {% endhint %}

**🛠️ Manual Error Reporting APIs:**

Use these APIs to custom report errors and warnings to the SDK—especially for errors that occur **before or during stream loading**, or when auto-capture is disabled.

🔴 **Report Fatal Error:**

All errors reported via reportError are treated as **fatal**.

```swift
AVPlayerIntegrationWrapper.shared.reportError(errorCode: "ERROR_CODE", errorMessage: "ERROR_MESSAGE", errorDetails: "ERROR_DETAILS")
```

🟠 **Report Warning (Non-Fatal):**

All warnings reported via reportWarning are treated as non-fatal and will be tracked accordingly.

```swift
AVPlayerIntegrationWrapper.shared.reportWarning(warningCode: "WARNING_CODE", warningMessage: "WARNING_MESSAGE", warningDetails: "WARNING_DETAILS")
```

### Step 6: Report Additional Metadata Fields

#### Step 6.1: CDN:

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```swift
AVPlayerIntegrationWrapper.shared.reportCDN(cdn: "CDN")
```

#### Step 6.2: Stream Information:

Report key stream attributes that describe the encoding and delivery method.

```swift
AVPlayerIntegrationWrapper.shared.reportStreamInfo(streamFormat: "STREAM_FORMAT", mediaType: "MEDIA_TYPE", sourceType: "SOURCE_TYPE")
```

#### Step 6.3: Player Resolution:

Report the width and height of the player window (in pixels). This is useful to understand playback size and user experience across different screen sizes or platforms.

```swift
AVPlayerIntegrationWrapper.shared.reportPlayerResolution(width: <player_width>, height: <player_height>)
```

#### Step 6.4: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```swift
AVPlayerIntegrationWrapper.shared.reportFallbackEvent(fallbackManifestURL: "FALLBACK_URL", description: "DESCRIPTION")
```

### Step 7: Cleaning up the SDK Session

{% hint style="info" %}
We need to clean up the SDK session once the playback completes. The SDK internally manages the cleanup for most of the cases. For example - when playback finishes, or some error is notified.

However, in some error cases, like network reachability issues, the error notification is delayed. And before this error notification is available, the user may trigger another session. Therefore, it is advised to clean up the session once the playback finishes.

We recommend cleaning up the SDK session after playback completes or when the player lifecycle is complete. Missing to clean up the SDK session, might playtime, and session end time.
{% endhint %}

```swift
AVPlayerIntegrationWrapper.cleanUp()
```

### Step 8: Update Asset Information

To update the asset information during a content change or a live session, use the `changeAssetForPlayer` method as shown below. Whenever the asset information is updated, a new SDK session will be initialised. Please note either `changeAssetForPlayer` or `initializeAssetForPlayer` should be called not both.

If  Asset Information needs to be updated dynamically during the live session without re-initiating the player, then the `updateAssetInfo` API can be used to update the new AssetInfo

{% hint style="info" %}
The new Asset Info Object will override the previous values. Hence, set all the necessary fields every time this API is called, including all **Custom Tags.**
{% endhint %}

```swift
// Create a new assetInfo object with the values that need to be updated
let newAssetInfo = MMAssetInformation(assetURL: "STREAM_URL", assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId: "VIDEO_ID")
newAssetInfo.setContentType("CONTENT_TYPE")
newAssetInfo.setDrmProtection("DRM_PROTECTION")
newAssetInfo.setEpisodeNumber("EPISODE_NUMBER")
newAssetInfo.setSeriesTitle("SERIES_TITLE")
newAssetInfo.setSeason("SEASON")
newAssetInfo.setGenre("GENRE")

AVPlayerIntegrationWrapper.changeAssetForPlayer(assetInfo: newAssetInfo, player: player)
```

### Step 9: Additional Configurations

#### Step 9.1: Disable manifest fetch by the SDK (Optional)

If your workflow limits access to the manifest from both the player and the MediaMelon Player SDK at the same time, you have the option to prevent manifest fetching by using the `disableManifestsFetch` method calling it before initialization.

```swift
AVPlayerIntegrationWrapper.disableManifestsFetch(disable: true)
```

#### Step 9.2: Enable or Disable SDK Log Trace

To enable the SDK log trace, use the following API call: enableLogTrace.

```swift
AVPlayerIntegrationWrapper.shared.enableLogTrace(logStTrace: true)
```

### Release Notes

<details>

<summary>Current Release</summary>

#### v2.6.1 <sup><sub>**`Sep 08, 2026`**<sub></sup>

* Initial SDK release via SPM

</details>

Dependency Framework Releases: [MediaMelon-QoE-SDK](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/ios/mediamelon-ios-custom-sdk-integration-document#release-notes)

***

<details>

<summary>Previous Releases</summary>

#### v2.5.0  <sup><sub>**`Mar 09, 2026`**<sub></sup>

* Added App Session ID metadata fields.
* Updated Base Player Information reporting.
* Added `CDN_CHANGE` event.

#### v2.4.0  <sup><sub>**`Nov 06, 2025`**<sub></sup>

* Combined iOS and tvOS frameworks into a single xcframework.
* Fixed the DRM protection reset issue.
* Added Stream Information API.

</details>


# MediaMelon iOS AVPlayer IMA SDK Integration Document

This guide provides detailed instructions on integrating the MediaMelon AVPlayer IMA/DAI SDK into an iOS/tvOS Media Player Application.

**Step 1:** [Set up MediaMelon SDK](#step-1-set-up-mediamelon-sdk)

**Step 2:** [Import Frameworks](#step-2-import-frameworks)

**Step 3:** [Register and Initialize MediaMelon SDK](#step-3-register-and-initialize-mediamelon-sdk)

**Step 4:** [Additional Custom Metadata](#step-4-additional-custom-metadata)

**Step 5:** [DAI & IMA Tracking Integration](#step-5-dai-and-ima-tracking-integration)

**Step 6:** [Errors and Warnings](#step-6-errors-and-warnings-important)

**Step 7:** [Report Additional Metadata Fields](#step-7-report-additional-metadata-fields)

**Step 8:** [Cleaning up the SDK Session](#step-8-cleaning-up-the-sdk-session)

**Step 9:** [Update Asset Information](#step-9-update-asset-information)

**Step 10:** [Additional Configurations](#step-10-additional-configurations)

[Release Notes](#release-notes)

### Step 1: Set up MediaMelon SDK

{% tabs %}
{% tab title="SPM" %}

```swift
.package(
      url: "https://github.com/MediamelonSDK/mm-ios-sdk-avplayer-ima",
      .upToNextMajor(from: "2.6.1")
 ),
```

{% endtab %}

{% tab title="Cocoapods" %}

```bash
target 'SwiftDemo' do
  .
  pod 'MediaMelon-AVPlayer-Google-IMA-SDK', '~> 2.5.0'
  pod 'GoogleAds-IMA-iOS-SDK'
end
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
The `MediaMelon-AVPlayer-Google-IMA-SDK` package includes a dependency on the `MediaMelon-IMA-SDK` framework package. This dependency framework supports both iOS and tvOS platforms.&#x20;

Check the latest available version of `MediaMelon-IMA-SDK` [here](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/ios/mediamelon-ios-custom-sdk-integration-document#release-notes).
{% endhint %}

### Step 2: Import Frameworks

```swift
import MediaMelonIMA
import MediaMelon_AVPlayer_Google_IMA_SDK
```

### Step 3: **Register and Initialize** MediaMelon SDK

#### Step 3.1: Set SDK Registration Information:

```swift
let registrationInfo = MMRegistrationInformation(customerID: "CUSTOMER_ID", playerName: "PLAYER_NAME")
registrationInfo.setPlayerInformation(brand: "PLAYER_BRAND", model: "PLAYER_MODEL", version: "PLAYER_VERSION")
registrationInfo.setBasePlayerInformation(basePlayerName: "BASE_PLAYER_NAME", basePlayerVersion: "BASE_PLAYER_VERSION")
registrationInfo.setSubscriberInformation(subscriberID: "SUBSCRIBER_ID", subscriberType: "SUBSCRIBER_TYPE", subscriberTag: "SUBSCRIBER_TAG", hashSubscriberID: <Bool>)
registrationInfo.setDomain("DOMAIN_NAME")
```

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

#### Step 3.2: Report Application Information:

```swift
AVPlayerIntegrationWrapper.shared.reportAppData(appName: "APP_NAME", appVersion: "APP_VERSION")
AVPlayerIntegrationWrapper.shared.reportAppSessionID(appSessionId: "APP_SESSION_ID")
```

#### Step 3.3: Report Experiment Name & Sub Property ID:

```swift
AVPlayerIntegrationWrapper.shared.reportExperimentName(experimentName: "EXPERIMENT_NAME")
AVPlayerIntegrationWrapper.shared.reportSubPropertyID(subPropertyId: "SUB_PROPERTY_ID") 
```

#### Step 3.4: Set Content Metadata and Initialize Session:

```swift
let assetInfo = MMAssetInformation(assetURL: "STREAM_URL", assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId: "VIDEO_ID")
assetInfo.setEpisodeNumber("EPISODE_NUMBER")
assetInfo.setContentType("CONTENT_TYPE")
assetInfo.setSeriesTitle("SERIES_TITLE")
assetInfo.setGenre("GENRE")
assetInfo.setSeason("SEASON")
assetInfo.setDrmProtection("DRM_PROTECTION")
assetInfo.addCustomKVP("CUSTOM_1", "VALUE_1")
assetInfo.addCustomKVP("CUSTOM_2", "VALUE_2")

AVPlayerIntegrationWrapper.shared.reportViewSessionID(viewSessionId: "VIEW_SESSION_ID")
AVPlayerIntegrationWrapper.initializeAssetForPlayer(assetInfo: assetInfo, registrationInformation: registrationInfo, player: player, isLive: <Bool>)

// Create the Ad Manager Delegate that will be used for MediaMelon SDK  
self.mmAdManagerDelegate = MMIMAAdManager.sharedManager
```

{% hint style="info" %}
For Custom Metadata, first, provide the mapping in the [SmartSight](https://smartsight3.mediamelon.com/settings) dashboard under the settings section and send the values to the SDK accordingly. Refer to [Custom Metadata Configuration Guide](broken://pages/eWhNvkw0ryeL0LrKgj2u).
{% endhint %}

<details>

<summary>Example Setup</summary>

In the case of Google DAI, we use `IMALiveStreamRequest` or `IMAVODStreamRequest` to obtain a Live or VOD stream, respectively. The internal URL provided to AV Player needs to be given to the MM SDK during the initialization call. This can be obtained as follows:

```swift
 var mmSDKInitialised: Bool = false
 @objc func handleAVPlayerAccess(notification: Notification) {
        guard let playerItem = notification.object as? AVPlayerItem,
            let lastEvent = playerItem.accessLog()?.events.last else {
            return
        }
        guard let indicatedStream = lastEvent.uri else { return }
        var urlComps = urlString.components(separatedBy: "/")
        urlComps.removeLast()
        var streamComps = indicatedStream.components(separatedBy: "/")
        streamComps.removeLast()
        
        if urlComps != streamComps && !mmSDKInitialised {    
            self.mmSDKInitialised = true
            /**
                Initialize the MediaMelon SDK here. 
                Use indicatedStream for the STREAM_URL variable in MM SDK
            */
        }
    }
```

</details>

### Step 4: Additional Custom Metadata

Check the custom metadata configuration in the [SmartSight](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.&#x20;

Use this method to report any additional metadata that doesn’t fall under predefined metadata fields. This provides flexibility to send custom, business, or platform-specific information to the SDK.

```swift
AVPlayerIntegrationWrapper.shared.reportCustomMetadata(key: "KEY", value: "VALUE")
```

### Step 5: DAI & IMA Tracking Integration

#### Step 5.1: DAI MediaMelon Delegate Integration

```swift
class ViewController: UIViewController, IMAStreamManagerDelegate, IMAAdsLoaderDelegate {
    var mmAdManagerDelegate: MMAdManagerDelegate?
    var streamManager: IMAStreamManager?
  
    func adsLoader(_ loader: IMAAdsLoader!, adsLoadedWith adsLoadedData: IMAAdsLoadedData!) {
        self.streamManager = adsLoadedData.streamManager
        self.streamManager?.delegate = self
        self.streamManager?.initialize(with: nil)
    }
    
    func streamManager(_ streamManager: IMAStreamManager, didReceive error: IMAAdError) {
        print(error.debugDescription)
        mmAdManagerDelegate?.streamManager?(streamManager, didReceive: error)
    }
    
    func streamManager(_ streamManager: IMAStreamManager, didReceive event: IMAAdEvent) {
        mmAdManagerDelegate?.streamManager?(streamManager: streamManager, didReceive: event)
    }
}
```

#### Step 5.2: IMA MediaMelon Delegate Integration&#x20;

```swift
class PlayerContainerViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
    var mmAdManagerDelegate: MMAdManagerDelegate?
    private var adsManager: IMAAdsManager?
    
    // used for getting ads information and for identifying events such as started, first quartile, mid, clicked, skipped, paused, complete etc.
    func adsManager(_ adsManager: IMAAdsManager, didReceive event: IMAAdEvent) {
        mmAdManagerDelegate?.adsManager?(adsManager: adsManager, didReceive: event)
    }
    
    // used for reporting ads error. 
    func adsManager(_ adsManager: IMAAdsManager, didReceive error: IMAAdError) {
        mmAdManagerDelegate?.adsManager?(adsManager, didReceive: error)
    }
    
    // used for reporting ads requested event.
    func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
        mmAdManagerDelegate?.adsLoader?(loader, adsLoadedWith: adsLoadedData)
    }
    
    // used for reporting ads error.
    func adsLoader(_ loader: IMAAdsLoader, failedWith adErrorData: IMAAdLoadingErrorData) {
        mmAdManagerDelegate?.adsLoader?(loader, failedWith: adErrorData)
    }
}
```

### Step 6: Errors and Warnings (Important)

The SDK provides two ways to report errors: automatic error capture and manual error reporting via API.

⚙️ **Default Behavior (Auto Error Capture):**

By default, the SDK automatically listens to and captures player errors that occur *after the stream has loaded*. SDK will classify the errors based on severity.

{% hint style="info" %}

> ⚠️ Note: Errors that occur **before or during stream loading** are not captured automatically by the SDK, as they fall outside the player’s event lifecycle. Use the error and warning APIs below to manually report such issues.
> {% endhint %}

🚫 **Disabling Auto Error Capture:**

If you prefer to handle error reporting manually, you can disable this automatic behavior by calling:

```swift
AVPlayerIntegrationWrapper.shared.disableAutoErrorCapture()
```

{% hint style="info" %}

> ⚠️ When disabled, the SDK will not listen for any player-generated errors. You will be responsible for reporting all errors & warnings manually using the APIs described below.
> {% endhint %}

**🛠️ Manual Error Reporting APIs:**

Use these APIs to custom report errors and warnings to the SDK—especially for errors that occur **before or during stream loading**, or when auto-capture is disabled.

🔴 **Report Fatal Error:**

All errors reported via reportError are treated as **fatal**.

```swift
AVPlayerIntegrationWrapper.shared.reportError(errorCode: "ERROR_CODE", errorMessage: "ERROR_MESSAGE", errorDetails: "ERROR_DETAILS")
```

🟠 **Report Warning (Non-Fatal):**

All warnings reported via reportWarning are treated as non-fatal and will be tracked accordingly.

```swift
AVPlayerIntegrationWrapper.shared.reportWarning(warningCode: "WARNING_CODE", warningMessage: "WARNING_MESSAGE", warningDetails: "WARNING_DETAILS")
```

### Step 7: Report Additional Metadata Fields

#### Step 7.1: CDN:

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

```swift
AVPlayerIntegrationWrapper.shared.reportCDN(cdn: "CDN")
```

#### Step 7.2: Stream Information:

Report key stream attributes that describe the encoding and delivery method.

```swift
AVPlayerIntegrationWrapper.shared.reportStreamInfo(streamFormat: "STREAM_FORMAT", mediaType: "MEDIA_TYPE", sourceType: "SOURCE_TYPE")
```

#### Step 7.3: Player Resolution:

Report the width and height of the player window (in pixels). This is useful to understand playback size and user experience across different screen sizes or platforms.

```swift
AVPlayerIntegrationWrapper.shared.reportPlayerResolution(width: <player_width>, height: <player_height>)
```

#### Step 7.4: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```swift
AVPlayerIntegrationWrapper.shared.reportFallbackEvent(fallbackManifestURL: "FALLBACK_URL", description: "DESCRIPTION")
```

### Step 8: Cleaning up the SDK Session

{% hint style="info" %}
We need to clean up the SDK session once the playback completes. The SDK internally manages the cleanup for most of the cases. For example - when playback finishes, or some error is notified.

However, in some error cases, like network reachability issues, the error notification is delayed. And before this error notification is available, the user may trigger another session. Therefore, it is advised to clean up the session once the playback finishes.

We recommend cleaning up the SDK session after playback completes or when the player lifecycle is complete. Missing to clean up the SDK session, might playtime, and session end time.
{% endhint %}

```swift
AVPlayerIntegrationWrapper.cleanUp()
```

### Step 9: Update Asset Information

To update the asset information during a content change or a live session, use the `changeAssetForPlayer` method as shown below. Whenever the asset information is updated, a new SDK session will be initialised. Please note either `changeAssetForPlayer` or `initializeAssetForPlayer` should be called not both.

If  Asset Information needs to be updated dynamically during the live session without re-initiating the player, then the `updateAssetInfo` API can be used to update the new AssetInfo

{% hint style="info" %}
The new Asset Info Object will override the previous values. Hence, set all the necessary fields every time this API is called, including all **Custom Tags.**
{% endhint %}

```swift
// Create a new assetInfo object with the values that need to be updated
let newAssetInfo = MMAssetInformation(assetURL: "STREAM_URL", assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId: "VIDEO_ID")
newAssetInfo.setContentType("CONTENT_TYPE")
newAssetInfo.setDrmProtection("DRM_PROTECTION")
newAssetInfo.setEpisodeNumber("EPISODE_NUMBER")
newAssetInfo.setSeriesTitle("SERIES_TITLE")
newAssetInfo.setSeason("SEASON")
newAssetInfo.setGenre("GENRE")

AVPlayerIntegrationWrapper.changeAssetForPlayer(assetInfo: newAssetInfo, player: player)
```

### Step 10: Additional Configurations

#### Step 10.1: Disable manifest fetch by the SDK (Optional)

If your workflow limits access to the manifest from both the player and the MediaMelon Player SDK at the same time, you have the option to prevent manifest fetching by using the `disableManifestsFetch` method calling it before initialization.

```swift
AVPlayerIntegrationWrapper.disableManifestsFetch(disable: true)
```

#### Step 10.2: Enable or Disable SDK Log Trace

To enable the SDK log trace, use the following API call: enableLogTrace.

```swift
AVPlayerIntegrationWrapper.shared.enableLogTrace(logStTrace: true)
```

### Release Notes

<details>

<summary>Current Release</summary>

#### v2.6.1 <sup><sub>**`Sep 08, 2026`**<sub></sup>

* Initial SDK release via SPM

</details>

Dependency Framework Releases: [MediaMelon-IMA-SDK](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/ios/mediamelon-ios-custom-sdk-integration-document#release-notes)

***

<details>

<summary>Previous Releases</summary>

#### v2.5.0  <sup><sub>**`Mar 09, 2026`**<sub></sup>

* Combined iOS and tvOS frameworks into a single xcframework.
* Added App Session ID metadata fields.
* Updated Base Player Information reporting.
* Added `CDN_CHANGE` event.
* Added Ad buffering tracking for IMA and DAI.

#### v2.4.0  <sup><sub>**`Nov 06, 2025`**<sub></sup>

* Fixed the DRM protection reset issue.
* Added Stream Information API.

</details>


# MediaMelon iOS Bitmovin Player SDK Integration Document

This guide provides detailed instructions on integrating the MediaMelon BiPlayer IMA/DAI SDK into an iOS/tvOS Media Player Application.

**Step 1:** [Add SDK](#step-1-add-sdk)

**Step 2:** [Register and Initialize MediaMelon SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Additional Custom Metadata](#step-3-additional-custom-metadata)

**Step 4:** [Stream Information](#step-4-stream-information)

**Step 5:** [Set up Harmonic SSAI Ad Tracking](#step-5-set-up-harmonic-ssai-a-d-tracking)

**Step 6:** [Cleaning up the SDK Session](#step-6-cleaning-up-the-sdk-session)

**Step 7:** [Disable SDK Manifest Fetch](#step-7-disable-sdk-manifest-fetch-optional)

**Step 8:** [Update Content Metadata](#step-8-update-content-metadata)

[Release Notes](#release-notes)

### Step 1: Add SDK

Add the Wrapper file and the framework to the application project

* **Wrapper:** <https://sdks.mediamelon.com/iOS/bitmovin/2.6.2/BitmovinPlayerIntegrationWrapper.swift>
* **Framework:** <https://sdks.mediamelon.com/iOS/bitmovin/2.6.2/MediaMelonHarmonic.xcframework.zip>

#### Step 1.1: Import Frameworks:

```swift
import BitmovinPlayer
import MediaMelonHarmonic
```

### Step 2: Register and Initialize MediaMelon SDK

#### Step 2.1: Set SDK Registration Information:

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```swift
let registrationInfo = MMRegistrationInformation(customerID: "CUSTOMER_ID", playerName: "PLAYER_NAME")
registrationInfo.setDomain("DOMAIN_NAME")
registrationInfo.setSubscriberInformation(subscriberID: "SUBSCRIBER", subscriberType: "SUBSCRIBER_TYPE", subscriberTag: "SUBSCRIBER_TAG", hashSubscriberID: false)
registrationInfo.setPlayerInformation(brand: "PLAYER_BRAND", model: "PLAYER_MODEL", version: "PLAYER_VERSION")
registrationInfo.setBasePlayerInformation(basePlayerName: "BASE_PLAYER_NAME", basePlayerVersion: "BASE_PLAYER_VERSION")
```

{% hint style="info" %}
`hashSubscriberID`: Set it to `true` to hash the subscriber ID, and to `false` to process the subscriber ID without hashing.
{% endhint %}

#### Step 2.2: Set Content Metadata:

```swift
let assetInfo = MMAssetInformation(assetURL: "STREAM_URL", assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId: "VIDEO_ID")
assetInfo.setEpisodeNumber("EPISODE_NUMBER")
assetInfo.setContentType("CONTENT_TYPE")
assetInfo.setSeriesTitle("SERIES_TITLE")
assetInfo.setGenre("GENRE")
assetInfo.setSeason("SEASON")
assetInfo.setDrmProtection("DRM_PROTECTION")
assetInfo.addCustomKVP("CUSTOM_1", "VALUE_1")
assetInfo.addCustomKVP("CUSTOM_2", "VALUE_2")
```

#### Step 2.3: Report Application Information:

```swift
  BitmovinPlayerIntegrationWrapper.shared.reportAppData(appName: "APP_NAME", appVersion: "APP_VERSION")
```

#### Step 2.4: Report Application Session ID:

```swift
BitmovinPlayerIntegrationWrapper.shared.reportAppSessionID(appSessionId: "APP_SESSION_ID")
```

#### Step 2.5: Report Experiment Name & Sub Property ID:

```swift
BitmovinPlayerIntegrationWrapper.shared.reportExperimentName(experimentName: "EXPERIMENT_NAME")
BitmovinPlayerIntegrationWrapper.shared.reportSubPropertyID(subPropertyId: "SUBPROPERTY_ID")
```

#### Step 2.6: Initialize Session with Content Metadata:

```swift
BitmovinPlayerIntegrationWrapper.shared.reportViewSessionID(viewSessionId: "VIEW_SESSION_ID")
BitmovinPlayerIntegrationWrapper.initializeAssetForPlayer(assetInfo: assetInfo, registrationInformation: registrationInfo, player: <player_instance>, isLive: <isLive>)
```

{% hint style="info" %}
**isLive:** Set this to true for a live stream or false for a VOD stream. If isLive is not set here, the SDK will handle it internally.
{% endhint %}

### Step 3: Additional Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```swift
BitmovinPlayerIntegrationWrapper.shared.reportCustomMetadata(key: "CUSTOM_3", value: "VALUE_3")
```

### Step 4: Stream Information

#### Step 4.1: Report CDN Information:

```swift
BitmovinPlayerIntegrationWrapper.shared.reportCDN(cdn: "CDN")
```

#### Step 4.2: Report Stream Information:

```swift
BitmovinPlayerIntegrationWrapper.shared.reportStreamInfo(streamURL: "STREAM_URL", 
                                                         streamFormat: "STREAM_FORMAT", 
                                                         mediaType: "MEDIA_TYPE", 
                                                         sourceType: "SOURCE_TYPE")
```

#### Step 4.3: Update DRM Type:

```swift
BitmovinPlayerIntegrationWrapper.shared.updateDrmType("NEW_DRM_TYPE");
```

### Step 5: Set up Harmonic SSAI Ad Tracking

#### Step 5.1: Initialize Harmonic SSAI Ad Manager:

**HLS** `PMM_URL`: Send the variant URL with the pmm ID.

{% hint style="info" %}
Note: Call `initializeHarmonicSSAIAdManager` only once at the stream start.
{% endhint %}

```swift
BitmovinPlayerIntegrationWrapper.shared.initializeHarmonicSSAIAdManager(streamURL: "PMM_URL")
```

#### Step 5.2: Set up Delegate for Ad Callbacks:

Add the `MMSSAIManagerDelegate` protocol to the required class. To confirm with `MMSSAIManagerDelegate` protocol implement the below method in the class.

```swift
BitmovinPlayerIntegrationWrapper.shared.mmssaiManagerDelegate = self
```

```swift
func notifyMMSSAIAdEvent(eventName: MMHarmonicSSAIAdSate, adInfo: MMHarmonicSSAIAdInfo) {
        if(eventName == .adPlaying){
            print("Ad Playback Time = ", adInfo.getAdCurrentPlybackTime());
        } else {
            print("Current Ad State = ", eventName);
        }
}
```

<details>

<summary><strong>MMHarmonicSSAIAdSate</strong></summary>

* `adImpression`
* `adStarted`
* `adFirstQuartile`
* `adMidpoint`
* `adThirdQuartile`
* `adPlaying`
* `adCompleted`

</details>

<details>

<summary><strong>MMHarmonicSSAIAdInfo Methods</strong></summary>

* `getAdClient()`
* `getAdCurrentPlaybackTime()`
* `getAdDuration()`
* `getAdStartTime()`
* `getAdEndTime()`
* `getAdId()`
* `getAdPosition()`
* `getAdServer()`

</details>

### Step 6: Cleaning up the SDK Session

{% hint style="info" %}
We need to clean up the SDK session once the playback is completed. The SDK internally manages the cleanup for most of the cases. For example, when playback finishes or an error is notified.&#x20;

However, in some error cases, like network reachability issues, the error notification is delayed. Before this error notification is available, the user may trigger another session. Therefore, it is advised to clean up the session once the playback finishes.&#x20;

We recommend a cleanup at the following two places.

* When the view controller hosting the post-roll ad terminates
* When the player is restarted
  {% endhint %}

```swift
BitmovinPlayerIntegrationWrapper.cleanUp()
```

### Step 7: Disable SDK Manifest Fetch (Optional)

If your workflow restricts the manifest to be accessible from both the player and the MediaMelon Player SDK simultaneously, then you can disable the fetch of the manifest as shown below. When calling this method, it should be called before the `initializeAssetForPlayer` method.

```swift
BitmovinPlayerIntegrationWrapper.disableManifestsFetch(disable: true)
```

### Step 8: Update Content Metadata

During linear channel playback, if the content changes and a new session needs to be created for each piece of content, please use the updateAssetInfo method. This method can be used to create a new session while updating the asset information.

```swift
func updateContentMetadata() {
    let assetInfo = MMAssetInformation(assetURL: "STREAM_URL", assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId: "VIDEO_ID")
    assetInfo.setEpisodeNumber("EPISODE_NUMBER")
    assetInfo.setContentType("CONTENT_TYPE")
    assetInfo.setSeriesTitle("SERIES_TITLE")
    assetInfo.setGenre("GENRE")
    assetInfo.setSeason("SEASON")
    assetInfo.setDrmProtection("DRM_PROTECTION")
    assetInfo.addCustomKVP("CUSTOM_1", "VALUE_1")
    assetInfo.addCustomKVP("CUSTOM_2", "VALUE_2")
    
    // Create a new session and update the Asset info
    BitmovinPlayerIntegrationWrapper.updateAssetInfo(assetInfo: assetInfo, player: player)
}
```

### Release Notes:

<details>

<summary><strong>Current Release</strong></summary>

#### v2.6.[^1]2  <sup><sub>**`Mar 11, 2026`**<sub></sup>

* Added Ad Buffering tracking.
* Added Seek Duration tracking.

</details>

***

<details>

<summary><strong>Previous Releases</strong></summary>

#### v2.6.1[^2]  <sup><sub>**`Feb 11, 2026`**<sub></sup>

* Added Report **CDN API** for clients to provide CDN information to the SDK.
* Added Report **StreamInfo API** for reporting stream format, media type, and source type.
* Enabled the Report **Player Information API** for clients to pass player details to the SDK.
* Updated the **Base Player Information** reporting API.
* Added **App Session ID** API for client-provided session identification.
* Added the **Update DRM Type** API.
* Fixed an issue that caused duplicate rendition events to be reported by the SDK.

#### v2.5.0[^3]

* Fixed a URL dependency issue in the wrapper file
* Removed the number and value from the Streaming Progress and Playback Error events reported to the toolbox endpoint

</details>

[^1]: **Wrapper:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.6.2/BitmovinPlayerIntegrationWrapper.swift)

    **Framework:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.6.2/MediaMelonHarmonic.xcframework.zip)

[^2]: **Wrapper:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.6.1/BitmovinPlayerIntegrationWrapper.swift)

    **Framework:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.6.1/MediaMelonHarmonic.xcframework.zip)

[^3]: **Wrapper:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.5.0/BitmovinPlayerIntegrationWrapper.swift)

    **Framework:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.5.0/MediaMelonHarmonic.xcframework.zip)


# THEOPlayer XCFramework

This guide provides detailed instructions on integrating the MediaMelon  Player SDK into a Theo player  based iOS Media Player Application

### **Steps Involved in Integrating the MMTheoPlayerFramework**&#x20;

There are four steps involved in integrating the SmartSight Player SDK

1. Importing the framework
2. Providing asset information for the content before starting the player and after creating its instance
3. Cleaning up the SDK integration session
4. Disable manifest-fetching by the SDK

#### **1. Import Frameworks**

```cpp
import THEOplayerSDK
//Integration Step 1
import MMTheoplayerFramework
```

#### 2. Provide asset information

2a) Add the following method to integrate the MediaMelon Player SDK to the class `ViewController`

{% hint style="info" %}
\<customer\_id> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>
{% endhint %}

```cpp
 class ViewController: UIViewController {
    var theoplayer: THEOplayer!
    var assetInfo:MMAssetInformation!
    
    //Integration step 2a
    func integrateMMSDK(){
        TheoPlayerIntegrationWrapper.shared.enableLogTrace(logStTrace: true) //Send false to disable log trace
        
        let regInfo = MMRegistrationInformation(customerID: "CUSTOMER_ID", playerName:"PLAYER_NAME")
        regInfo.setPlayerInformation(brand: "PLAYER_BRAND", model: "PLAYER_MODEL", version: "PLAYER_VERSION")
        regInfo.setSubscriberInformation(subscriberID: "SUBSCRIBER_ID", subscriberType: "SUBSCRIBER_TYPE", subscriberTag: "SUBSCRIBER_TAG")
        TheoPlayerIntegrationWrapper.setPlayerRegistrationInformation(registrationInformation: regInfo, player: theoplayer)
    }
```

{% hint style="info" %}
Call to `setPlayerRegistrationInformation` is mandatory.
{% endhint %}

2b) Call the method integrateMMSDK after setting up the player

```cpp
override func viewDidLoad() {
      super.viewDidLoad()
      setupTheoPlayer()
      //Integration Step 2b
      integrateMMSDK()
      theoplayer.source = sampleSource
}
```

2c) Create and Set the Asset Information

The application may like to set the auxiliary information of the asset so that it can be recorded in Smartsight. This information could be assetId, assetName, videoId (describing the title to which assets belong), custom metadata, etc. Call to `addCustomKVP` is optional. However, when a call is made, setting both the custom key and the value is mandatory

```swift
let assetInfo = MMAssetInformation(assetURL: "ASSET_URL", assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId: "VIDEO_ID")
   assetInfo.setEpisodeNumber("EPISODE_NUMBER")
   assetInfo.setContentType("CONTENT_TYPE")
   assetInfo.setSeriesTitle("SERIES_TITLE")
   assetInfo.setGenre("GENRE")
   assetInfo.setSeason("SEASON")
   assetInfo.setDrmProtection("DRM_PROTECTION")
   assetInfo.addCustomKVP("CUSTOM_KEY_1", "CUSTOM_VALUE_1")
   assetInfo.addCustomKVP("CUSTOM_KEY_2", "CUSTOM_VALUE_2")
        
     let encodedAssetInfo = try? JSONEncoder().encode(assetInfo)
     var jsonAssetInfo = ""
     if let encodedAssetInfo = encodedAssetInfo{
         jsonAssetInfo = String(data: encodedAssetInfo, encoding: .utf8) ?? ""
}
```

2d) Adding Custom parameters.&#x20;

The app can produce this asset information to the SmartSight Player SDK by utilizing the metadata field of the `SourceDescription` used by the Theo player.

```cpp
return SourceDescription(
         source: TypedSource(
             src: "https://cdn.theoplayer.com/video/elephants-dream/playlist.m3u8",
             type: "application/x-mpegurl"
         ),
         //Integration Step 2d
         metadata : MetadataDescription(metadataKeys: [TheoMMIntegration.KAssetInformationKey:jsonAssetInfo])
 )
```

#### 3) Cleanup of session

When the view controller used for playback is removed, call the cleanUp method of the SmartSight Player SDK and add the following method in class `ViewController`

```cpp
 deinit{
     TheoPlayerIntegrationWrapper.cleanUp()
 }
```

#### 4) Disable Manifest

{% hint style="info" %}
&#x20;Disable Manifest Fetch is optional
{% endhint %}

&#x20;If your workflow restricts the manifest to be accessible from both the player and the MediaMelon Player SDK simultaneously, then, you can disable the fetch of the manifest via `disableManifestsFetch` in method `integrateMMSDK()`

```cpp
 func integrateMMSDK(){
     .
     .
     .
     .
     TheoPlayerIntegrationWrapper.setPlayerRegistrationInformation(registrationInformation: regInfo, player: theoplayer)
     TheoPlayerIntegrationWrapper.disableManifestsFetch(disable: true)
 }
```

| **Variable**     | **Description**                                                                                                                                                                      |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| PLAYER\_NAME     | String containing the Player Name.                                                                                                                                                   |
| CUSTOMER\_ID     | String containing your MediaMelon-assigned Customer ID.                                                                                                                              |
| SUBSCRIBER\_ID   | String containing your Subscriber’s ID. If you do not use subscriber IDs, enter null                                                                                                 |
| DOMAIN\_NAME     | String containing your section of your subscriber or assets. (Optional)                                                                                                              |
| SUBSCRIBER\_TYPE | String containing the Subscriber Type (e.g. “Free”, “Paid”). If you do not use subscriber types, enter null                                                                          |
| SUBSCRIBER\_TAG  | String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field. |
| ASSET\_ID        | String containing Asset Id.                                                                                                                                                          |
| ASSET\_NAME      | String containing Asset Name.                                                                                                                                                        |
| VIDEO\_ID        | String containing your video’s ID. If you do not use videos IDs, enter null.                                                                                                         |
| CONTENT\_TYPE    | String containing type of the Content. For example - "Movie", "Special", "Clip", "Scene Epis Lifts".                                                                                 |
| GENRE            | String containing Genre of the content. For example - "Comedy", "Horror".                                                                                                            |
| DRM\_PROTECTION  | Widevine, Fairplay, Playready etc. Unknown means content is protected, but protection type is unknown. For clear contents, do not set this field                                     |
| EPISODE\_NUMBER  | String containing sequence number of the Episode.                                                                                                                                    |
| SEASON           | String containing the Season. For example - "Season1".                                                                                                                               |
| SERIES\_TITLE    | String containing Title of the Series.                                                                                                                                               |
| PLAYER\_BRAND    | String containing Player Brand.                                                                                                                                                      |
| PLAYER\_MODEL    | String containing Player Model. For example - This could be a variant of player. Say name of third party player used by organisation. Or any human readable name of the player.      |
| PLAYER\_VERSION  | String containing Player Version.                                                                                                                                                    |


# THEOPlayer tvOS XCFramework

### **Step 1: Integrating the** MMTHEOPlayerTVOSFramework&#x20;

There are four steps involved for integrating the SmartSight Player SDK

1. Importing the framework
2. Providing asset information for the content before starting the player and after creating its instance
3. Cleaning up the SDK integration session
4. Disable manifest-fetching by the SDK

#### **1. Import Frameworks**

```cpp
import THEOplayerSDK
//Integration Step 1
import MMTHEOPlayerTVOSFramework
```

#### 2. Provide asset information

2a) Add the following method to integrate the MediaMelon Player SDK to the class `ViewController`

```cpp
 class ViewController: UIViewController {
    var theoplayer: THEOplayer!
    var assetInfo:MMAssetInformation!
    var configInfo:IntegrationConfiguration!
    
    //Integration step 2a
    func integrateMMSDK(){
        if configInfo.enableLogs{
            TheoPlayerIntegrationWrapper.shared.enableLogTrace(logStTrace: true)
        }else{
            TheoPlayerIntegrationWrapper.shared.enableLogTrace(logStTrace: false)
        }
        let regInfo = MMRegistrationInformation(customerID: "200417809", playerName:"TheoPlayerApp")
        regInfo.setPlayerInformation(brand: "Theo", model: "VODPlayer", version: ".11")
        regInfo.setSubscriberInformation(subscriberID: "tycho_user1@mm.com", subscriberType: "Basic", subscriberTag: "TestAppUser")
        TheoPlayerIntegrationWrapper.setPlayerRegistrationInformation(registrationInformation: regInfo, player: theoplayer)
    }
```

{% hint style="info" %}
Call to `setPlayerRegistrationInformation` is mandatory.Call to `setPlayerInformation` and `setSubscriberInformation` is optional.
{% endhint %}

2b) Call the method integrateMMSDK after setting up the player

```cpp
override func viewDidLoad() {
      super.viewDidLoad()
      setupTheoPlayer()
      //Integration Step 2b
      integrateMMSDK()
      self.theoplayer.source = sampleSource
}
```

2c) Create and Set the Asset Information

The application may like to set the auxiliary information of the asset so that it can be recorded in the Smartsight. This information could be assetId, assetName, videoId (describing the title to which assets belong), custom metadata etc. The app can produce this information to the SmartSight Player SDK by utilizing the metadata field of the `SourceDescription` used by the Theo player.

```cpp
let assetInfo = MMAssetInformation(assetURL: $ASSETURL, assetID: $ASSETID, assetName: $ASSETNAME, videoId: $VIDEOID)
     assetInfo.addCustomKVP($CUSTOMKEY, $CUSTOMVALUE)
     let encodedAssetInfo = try? JSONEncoder().encode(assetInfo)
     var jsonAssetInfo = ""
     if let encodedAssetInfo = encodedAssetInfo{
         jsonAssetInfo = String(data: encodedAssetInfo, encoding: .utf8) ?? ""
}
```

2d) Adding Custom parameters.&#x20;

Call to `addCustomKVP` is optional. However, when a call is made, setting both custom key and the value is mandatory

```cpp
return SourceDescription(
         source: TypedSource(
             src: "https://cdn.theoplayer.com/video/elephants-dream/playlist.m3u8",
             type: "application/x-mpegurl"
         ),
         //Integration Step 2d
         metadata : MetadataDescription(metadataKeys: [TheoPlayerIntegrationWrapper.KAssetInformationKey:jsonAssetInfo])
 )
```

#### 3) Cleanup of session

When the view controller used for playback is removed, call the cleanUp method of the SmartSight Player SDK and add the following method in class `ViewController`

```cpp
 deinit{
     TheoPlayerIntegrationWrapper.cleanUp()
 }
```

#### 4) Disable Manifest

{% hint style="info" %}
&#x20;Disable Manifest Fetch is optional
{% endhint %}

&#x20;If your workflow restricts the manifest to be accessible from both player and the MediaMelon Player SDK simultaneously, then, you can disable the fetch of manifest via `disableManifestsFetch` in method `integrateMMSDK()`

```cpp
 func integrateMMSDK(){
     .
     .
     .
     .
     TheoPlayerIntegrationWrapper.setPlayerRegistrationInformation(registrationInformation: regInfo, player: theoplayer)
     TheoPlayerIntegrationWrapper.disableManifestsFetch(disable: true)
 }
```


# THEOplayer (Cocoapods)

This guide provides detailed instructions on integrating the MediaMelon  Player SDK into a Theoplayer (2.76.1) based iOS Media Player Application

### **Step 1: Add** the MediaMelon Player SDK using **the MMSmartStreaming Framework**

Navigate to your project folder using the terminal, if you don't have CocoaPods installed, Please install it using the below commands in terminal

```cpp
sudo gem install cocoapods
pod init
touch Podfile
open Podfile
```

Add the MediaMelonSmartStreaming pod using the below lines

```cpp
target '<SamplePorject_name>' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!
  pod 'MediaMelonSmartStreaming-THEO', '~> 1.0.0'
  # Pods for <SamplePorject_name>
end
```

Finally, install the pod `pod install`

### **Step 2: Integrating the MMSmartStreaming Framework**

There are four steps involved for integrating the SmartSight Player SDK

1. Importing the framework
2. Providing asset information for the content before starting the player and after creating its instance
3. Cleaning up the SDK integration session
4. Disable manifest-fetching by the SDK

#### **1. Import Frameworks**

```cpp
import THEOplayerSDK
// MediaMelon Integration #1
import MediaMelonSmartStreaming_THEO
```

#### 2. Provide asset information

2a) Add the following method to integrate the MediaMelon Player SDK to the class `ViewController`

```cpp
 class ViewController: UIViewController {
 var theoplayer: THEOplayer!
 // MediaMelon Integration #2a
 func integrateMMSDK(){
     //TheoMMIntegration.shared.enableLogTrace(logStTrace: true)
     let regInfo = MMRegistrationInformation(customerID: $CUSTOMERID, playerName:$PLAYERNAME)
     regInfo.setPlayerInformation(brand: $PLAYERBRAND, model:$PLAYERMODEL, version: $PLAYERVERSION)
     regInfo.setSubscriberInformation(subscriberID: $SUBSID, subscriberType: $SUBSTYPE, subscriberTag: $SUBSTAG)
     TheoMMIntegration.setPlayerRegistrationInformation(registrationInformation: regInfo, player: theoplayer)
 }
```

{% hint style="info" %}
Call to `setPlayerRegistrationInformation` is mandatory.Call to `setPlayerInformation` and `setSubscriberInformation` is optional.
{% endhint %}

2b) Call the method integrateMMSDK after setting up the player

```cpp
override func viewDidLoad() {
      super.viewDidLoad()
      setupTheoPlayer()
      //Integration Step 2b
      integrateMMSDK()
      self.theoplayer.source = sampleSource
}
```

2c) Create and Set the Asset Information

The application may like to set the auxiliary information of the asset so that it can be recorded in the Smartsight. This information could be assetId, assetName, videoId (describing the title to which assets belong), custom metadata etc. The app can produce this information to the SmartSight Player SDK by utilizing the metadata field of the `SourceDescription` used by the Theo player.

```cpp
let assetInfo = MMAssetInformation(assetURL: $ASSETURL, assetID: $ASSETID, assetName: $ASSETNAME, videoId: $VIDEOID)
     assetInfo.addCustomKVP($CUSTOMKEY, $CUSTOMVALUE)
     let encodedAssetInfo = try? JSONEncoder().encode(assetInfo)
     var jsonAssetInfo = ""
     if let encodedAssetInfo = encodedAssetInfo{
         jsonAssetInfo = String(data: encodedAssetInfo, encoding: .utf8) ?? ""
}
```

2d) Adding Custom parameters.&#x20;

Call to `addCustomKVP` is optional. However, when a call is made, setting both custom key and the value is mandatory

```cpp
return SourceDescription(
         source: TypedSource(
             src: "https://cdn.theoplayer.com/video/elephants-dream/playlist.m3u8",
             type: "application/x-mpegurl"
         ),
         //Integration Step 2d
         metadata : MetadataDescription(metadataKeys: [TheoMMIntegration.KAssetInformationKey:jsonAssetInfo])
 )
```

#### 3) Cleanup of session

When the view controller used for playback is removed, call the cleanUp method of the SmartSight Player SDK and add the following method in class `ViewController`

```cpp
 deinit{
     TheoMMIntegration.cleanUp()
 }
```

#### 4) Disable Manifest

{% hint style="info" %}
&#x20;Disable Manifest Fetch is optional
{% endhint %}

&#x20;If your workflow restricts the manifest to be accessible from both player and the MediaMelon Player SDK simultaneously, then, you can disable the fetch of manifest via `disableManifestsFetch` in method `integrateMMSDK()`

```cpp
 func integrateMMSDK(){
     .
     .
     .
     .
     TheoMMIntegration.setPlayerRegistrationInformation(registrationInformation: regInfo, player: theoplayer)
     TheoMMIntegration.disableManifestsFetch(disable: true)
 }
```


# MediaMelon iOS Kaltura Player Plugin Integration Document

This guide provides detailed instructions on integrating the MediaMelon Plugin into a Kaltura player based iOS Media Player Application

[**Step 1:** Import Frameworks](#step-1-import-frameworks)

[**Step 2:** Register MediaMelon Plugin](#step-2-register-mediamelon-plugin)

[**Step 3:** Configure and Initialise MediaMelon SDK](#step-3-configure-and-initialise-mediamelon-sdk)

### Step 1: Import Frameworks

```swift
import KalturaPlayer
import MediaMelonKPPlugin
```

### Step 2: Register MediaMelon Plugin

Register the MediaMelon Plugin in the App Delegate after the player setup.

```swift
KalturaBasicPlayer.setup()
PlayKitManager.shared.registerPlugin(MediaMelonKPPlugin.self)
```

### Step 3: Configure and Initialise MediaMelon SDK

#### **Swift:**

```swift
func createPluginConfig() ->  MediaMelonKPPluginConfig {
        
    let mediaMelonPluginParams: [String: Any] = [
        "customerId": "CUSTOMER_ID",
        "domainName": "DOMAIN_NAME",
        "subscriberTag": "SUBSCRIBER_TAG",
        "subscriberId": "SUBSCRIBER_ID",
        "subscriberType": "SUBSCRIBER_TYPE",
        "doHash": true,
        "playerName": "PLAYER_NAME",
        "playerVersion": "PLAYER_VERSION",
        "playerBrand": "PLAYER_BRAND",
        "playerModel": "PLAYER_MODEL",
        "assetId": "ASSET_ID",
        "assetName": "ASSET_NAME",
        "videoId": "VIDEO_ID",
        "seriesTitle": "SERIES_TITLE",
        "episodeNumber": "EPISODE_NUMBER",
        "season": "SEASON",
        "contentType": "CONTENT_TYPE",
        "genre": "GENRE",
        "appName": "APP_NAME",
        "appVersion": "APP_VERSION",
        "deviceMarketingName": "DEVICE_MARKETING_NAME",
        "videoQuality": "VIDEO_QUALITY",
        "deviceId": "DEVICE_ID",
        "disableManifestFetch": false,
        "customTags": [
            "KEY1": "VALUE1",
            "KEY2": "VALUE2"
        ]
    ]
    
    var mmPluginConfig = MediaMelonKPPluginConfig(params: mediaMelonPluginParams)
    return mmPluginConfig
  }
```

```swift
func playerOptions(_ videoData: VideoData?) -> PlayerOptions {
    let playerOptions = PlayerOptions()
    
    .....
    
    playerOptions.pluginConfig.config[MediaMelonKPPlugin.pluginName] = createPluginConfig()
    return playerOptions
}
```

{% hint style="info" %}

* **doHash**: To hash the subscriber ID, set it to <mark style="color:orange;">`true`</mark>. To leave the subscriber ID un-hashed, set it to <mark style="color:orange;">`false`</mark>. This is optional.
  {% endhint %}

| Variable         | Description                                                                                                                                                                          |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| PLAYER\_NAME     | String containing the Player Name.                                                                                                                                                   |
| CUSTOMER\_ID     | String containing your MediaMelon-assigned Customer ID.                                                                                                                              |
| SUBSCRIBER\_ID   | String containing your Subscriber’s ID. If you do not use subscriber IDs, enter null                                                                                                 |
| DOMAIN\_NAME     | String containing your section of your subscriber or assets.                                                                                                                         |
| SUBSCRIBER\_TYPE | String containing the Subscriber Type (e.g. “Free”, “Paid”). If you do not use subscriber types, enter null                                                                          |
| SUBSCRIBER\_TAG  | String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field. |
| ASSET\_ID        | String containing Asset Id.                                                                                                                                                          |
| ASSET\_NAME      | String containing Asset Name.                                                                                                                                                        |
| VIDEO\_ID        | String containing your video’s ID. If you do not use videos IDs, enter null.                                                                                                         |
| CONTENT\_TYPE    | String containing type of the Content. For example - "Movie", "Special", "Clip", "Scene Epis Lifts".                                                                                 |
| GENRE            | String containing Genre of the content. For example - "Comedy", "Horror".                                                                                                            |
| DRM\_PROTECTION  | Widevine, Fairplay, Playready etc. Unknown means content is protected, but protection type is unknown. For clear contents, do not set this field                                     |
| EPISODE\_NUMBER  | String containing sequence number of the Episode.                                                                                                                                    |
| SEASON           | String containing the Season. For example - "Season1".                                                                                                                               |
| SERIES\_TITLE    | String containing Title of the Series.                                                                                                                                               |
| CUSTOM\_TAGS     | Extra custom metadata can be added here if required.                                                                                                                                 |
| PLAYER\_BRAND    | String containing Player Brand.                                                                                                                                                      |
| PLAYER\_MODEL    | String containing Player Model. For example - This could be a variant of player. Say name of third party player used by organisation. Or any human readable name of the player.      |
| PLAYER\_VERSION  | String containing Player Version.                                                                                                                                                    |


# Roku SDK


# MediaMelon Roku SDK Integration Document

This document describes the Roku MediaMelon Player SDK Integration with the  Roku media player.

**Step 1:** [Include MediaMelon SmartStreaming SDK](#step-1-include-mediamelon-smartstreaming-sdk)

**Step 2:** [Set up a new MediaMelon Task](#step-2-setup-new-mediamelon-task)

**Step 3:** [MediaMelon Code Integration](#step-3-integrate-mediamelon-code-to-main-application)

**Step 4:** [Request Information](#step-4-request-information)

**Step 5:** [Error Handling](#step-5-error-handling)

**Step 6:** [Ad Data & Ad Events](#step-6-a-d-data-and-ad-events)

**Step 7:** [Custom Events](#step-7-custom-events)

[Release Notes](#release-notes)

### Step 1: Include MediaMelon SmartStreaming SDK <a href="#step-1-include-mediamelon-smartstreaming-sdk" id="step-1-include-mediamelon-smartstreaming-sdk"></a>

To integrate, unzip the MediaMelon Roku library and place the `MMSmartStream` folder in the components directory.

SDK: [MediaMelon Roku SDK](https://sdks.mediamelon.com/roku/qoe/2.11.0/MMSmartStream.zip)

### Step 2: Set up a new MediaMelon Task <a href="#step-2-setup-new-mediamelon-task" id="step-2-setup-new-mediamelon-task"></a>

Create a new XML file `MMTask.xml` inside your components folder. This is used to link MediaMelon’s `brs`files into your application.

The `MMTask.xml`file should contain the following:

```xml
<component name="MMTask" extends="Task">
  <interface>
    <field id="video" type="node" alwaysNotify="true" />
    <field id="config" type="assocarray" alwaysNotify="true" />
    <field id="customConfig" type="assocarray" alwaysNotify="true" />    
    <field id="contentMetadata" type="assocarray" alwaysNotify="true" />
    <field id="customTags" type="assocarray" alwaysNotify="true" />
    <field id="error" type="assocarray" alwaysNotify="true"/>
    <field id="adError" type="assocarray" alwaysNotify="true"/>
    <field id="view" type="String" alwaysNotify="true" />
    <field id="exit" type="Boolean" alwaysNotify="true" />
    <field id="mmRafEvent" type="assocarray" alwaysNotify="true"/>
    <field id="sdk_version" type="String" alwaysNotify="true" />
    <field id="seekThreshold" type="Integer" alwaysNotify="true"/>
    <field id="codecs" type="assocarray" alwaysNotify="true" />
    <field id="isVideoLive" type="Boolean" alwaysNotify="true" />
    <field id="requestInfo" type="assocarray" alwaysNotify="true" />
    <field id="customEvent" type="assocarray" alwaysNotify="true" />
    <field id="deviceInfo" type="assocarray" alwaysNotify="true" />
  </interface>
  <script type="text/brightscript" uri="pkg:/components/MMSmartStream/MMNetworkHandler.brs" />
  <script type="text/brightscript" uri="pkg:/components/MMSmartStream/MMSmartStreamWrapper.brs" />
  <script type="text/brightscript" uri="pkg:/components/MMSmartStream/MMSmartStreamEngine.brs" />
  <script type="text/brightscript" uri="pkg:/components//MMSmartStream/MMSmartStreamRokuPlugin.brs" />
  <script type="text/brightscript" uri="pkg:/components/MMSmartStream/Utilities.brs" />
</component>

```

### Step 3: MediaMelon Code Integration <a href="#step-3-integrate-mediamelon-code-to-main-application" id="step-3-integrate-mediamelon-code-to-main-application"></a>

#### 3.1. Create MM Task Node:

In the main application, after the video instance has been created, create a MediaMelon Task node, and pass the Video node to it.

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```raku
m.MM = createObject("roSGNode", "MMTask")
m.MM.setField("video", m.video)
```

#### 3.2. Set Configuration Details:

```raku
MMConfig = {
  customerID: "CUSTOMER_ID"
  subscriberId: "SUBSCRIBER_ID"
  subscriberType: "SUBSCRIBER_TYPE"
  subscriberTag: "SUBSCRIBER_TAG"
  playerName: "PLAYER_NAME"
  playerId: "PLAYER_ID"
  playerVersion: "PLAYER_VERSION"
  basePlayerName: "BASE_PLAYER_NAME"
  basePlayerVersion: "BASE_PLAYER_VERSION"
  disableManifestFetch: true
  domainName: "DOMAIN_NAME"
  appName: "APP_NAME"
  appSdkVersion: "APP_VERSION"
  viewSessionId: "VIEW_SESSION_ID"
  appSessionId: "APP_SESSION_ID"
  hashSubscriberId: false 'Important
  enableCustomErrorReporting: true 'Important
}
m.MM.setField("config", MMConfig)
```

{% hint style="info" %}

* `disableManifestFetch`: If your workflow restricts the manifest to be accessible from both the player and SDK simultaneously, you can disable manifest fetch. This is an optional step.
* `hashSubscriberId`: Set `true` to hash the subscriberId and to `false` to process the subscriberId without hashing.
* `enableCustomErrorReporting`: If set to `true` SDK will consider only client-reported errors, else if set to `false` SDK will consider errors from the video node. ([Refer Here](#step-4-error-handling))
  {% endhint %}

#### 3.3. Set Content Metadata:

```raku
contentMetadata = {
  "assetName": "ASSET_NAME",
  "assetId": "ASSET_ID",
  "videoId": "VIDEO_ID",
  "genre": "GENRE",
  "drmProtection": "DRM_PROTECTION",
  "drmLevel": "DRM_LEVEL",
  "episodeNumber": "EPISODE_NUMBER",
  "season": "SEASON",
  "seriesTitle": "SERIES_TITLE",
  "contentType": "CONTENT_TYPE"
}
m.MM.setField("contentMetadata", contentMetadata)
```

#### 3.4. Set Custom Configuration Details:

```raku
customConfig = {
  cdn: "CDN"
  experimentName: "EXPERIMENT_NAME"
  subPropertyId: "SUB_PROPERTY_ID"
  streamFormat: "STREAM_FORMAT"
  mediaType: "MEDIA_TYPE"
  drmProtection: "DRM_PROTECTION"
  drmLevel: "DRM_LEVEL"
  preload: <boolean>
  encodingService: "ENCODING_SERVICE"
}
m.MM.setField("customConfig", customConfig)
```

#### 3.5. Set Codecs:

```raku
codecs = {
  video: "VIDEO_CODEC"
  audio: "AUDIO_CODEC"
}
m.MM.setField("codecs", codecs)
```

#### 3.6. Set Custom Metadata:

```raku
customMetadata = {
  "CUSTOM_KEY_1": "VALUE_1",
  "CUSTOM_KEY_2": "VALUE_2"
}
m.MM.setField("customTags", customMetadata)
```

{% hint style="info" %}
For Custom Metadata, first, provide the mapping in the [SmartSight](https://smartsight3.mediamelon.com/settings) dashboard under the settings section, and send the values to the SDK accordingly.
{% endhint %}

#### 3.7. Set Seek Threshold:

By default seek threshold is set to `1.25 seconds` in the SDK.&#x20;

```raku
m.MM.setField("seekThreshold", 2)
```

#### 3.8. Set is Video Live:

Set `isVideoLive` to `true` for live video stream and to `false` for the VOD stream

```raku
m.MM.setField("isVideoLive", true)
```

#### 3.9. Set View:

{% hint style="info" %}
It's important to set the view field  `start` for every new view start, and to `end` when the view ends.
{% endhint %}

* **Start View:**

```raku
m.MM.setField("exit", false)
m.MM.setField("view", "start")
```

* **End View:**

```raku
m.MM.setField("view", "end")
m.MM.setField("exit", true)
```

#### 3.10. Run the SDK:

```raku
m.MM.control = "RUN"
m.player.setFocus(true)
```

#### 3.11. Device Info:

```raku
deviceInfo = {
  deviceCapabilities: "DEVICE_CAPABILITIES"
}
m.MM.setField("deviceInfo", deviceInfo)
```

### Step 4: Request Information

Report `failed` or `cancelled` requests for the following request types:

* PIR
* MANIFEST
* AUDIO\_CHUNK
* VIDEO\_CHUNK
* DRM
* SUBTITLE

```raku
requestInfo = { 
    requestStatus: <request_status>,    'string (This should be "failed" or "cancelled")
    requestType: <request_type>,        'string (This can be pir, manifest, audio_chunk, video_chunk, drm, subtitle)
    id: "ID",
    error: "ERROR",
    text: "TEXT",
    hostname: "HOSTNAME",
    url: "URL"
}

m.MM.setField("requestInfo", requestInfo)
```

### Step 5: Error Handling

By default, the SDK listens to the video node for errors. To report custom errors, set `enableCustomErrorReporting` flag to `true` in `MMConfig` and report the errors in the following way;

{% hint style="info" %}
Upon setting `enableCustomErrorReporting` flag to true, SDK will stop listening to the video node errors. Only custom errors will be reported.
{% endhint %}

#### 5.1. Video Error Reporting:

```raku
m.MM.error = { 
    errorCode: "ERROR_CODE",
    errorMessage: "ERROR_MESSAGE",
    errorDetails: "ERROR_DETAILS",
    errorSeverity: <error_severity>   'string (This should be "warning" or "fatal")
}
```

{% hint style="info" %}
`error_severity`: Set this to `"warning"` for warnings and set to `"fatal"` for fatal errors.
{% endhint %}

#### 5.2. Ad Error Reporting:

```raku
m.MM.adError = { 
    errorCode: "ERROR_CODE",
    errorMessage: "ERROR_MESSAGE",
    errorDetails: "ERROR_DETAILS",
    errorSeverity: <error_severity>   'string (This should be "warning" or "fatal")
}
```

### Step 6: Ad Data & Ad Events:

```raku
m.mmTask.setField("mmRafEvent", rafEventData)
```

**Sample:** `rafEventData = { obj: rafData, eventType: "Start", ctx: ctx }`

<details>

<summary><strong>Ad Event Type and Mapping</strong></summary>

<table data-search="false"><thead><tr><th>Event Type</th><th>MediaMelon Dashboard Event</th></tr></thead><tbody><tr><td><code>adRequest</code></td><td>AD_REQUEST</td></tr><tr><td><code>adResponse</code></td><td>AD_RESPONSE</td></tr><tr><td><code>PodStart</code></td><td>AD_BREAK_STARTED</td></tr><tr><td><code>PodComplete</code></td><td>AD_BREAK_ENDED</td></tr><tr><td><code>Start</code></td><td>AD_IMPRESSION &#x26; AD_PLAY</td></tr><tr><td><code>Pause</code></td><td>AD_PAUSED</td></tr><tr><td><code>Resume</code></td><td>AD_RESUMED</td></tr><tr><td><code>Complete</code></td><td>AD_COMPLETE</td></tr><tr><td><code>Close</code></td><td>AD_ENDED</td></tr><tr><td><code>FirstQuartile</code></td><td>AD_PLAYED_FIRST_QUARTILE</td></tr><tr><td><code>Midpoint</code></td><td>AD_PLAYED_MID_QUARTILE</td></tr><tr><td><code>ThirdQuartile</code></td><td>AD_PLAYED_THIRD_QUARTILE</td></tr><tr><td><code>Skip</code></td><td>AD_SKIPPED</td></tr><tr><td><code>Click</code></td><td>AD_CLICK</td></tr></tbody></table>

</details>

<details>

<summary><strong>Ad Information (<code>ctx</code>)</strong></summary>

<table data-header-hidden data-search="false"><thead><tr><th width="197.25390625">Field</th><th>Description</th></tr></thead><tbody><tr><td>adTitle</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adId</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adCreativeId</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adClient</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adPosition</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adSystem</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adUrl</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adPodIndex</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adPodPosition</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>adPodLendth</td><td>The total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr></tbody></table>

</details>

### Step 7: Custom Events:

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```raku
m.MM.customEvent = {
    eventName: "EVENT_NAME",
    eventValue: "EVENT_VALUE"
}
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 30 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

#### Release Notes

<details>

<summary>Current Release</summary>

#### v2.11.0[^1]  <sup><sub>**`Jun 29, 2026`**<sub></sup>

* Enhanced internal SDK data reporting
  * Separated all data reporting logic into a dedicated `MMNetworkHandler` module.
  * Added batch-based data reporting with configurable reporting intervals.
  * Improved reliability with exponential backoff retries, jitter, request timeouts, and Dead Letter Queue (DLQ) support.
  * Enabled remote configuration for batch size, reporting interval, retry settings, and the batching feature flag.
* Added support for reporting new ad events, including quartiles, request/response, errors, warnings, skip, and click events.
* Added internal intermediate buffering duration reporting for long buffering sessions to improve real-time buffering monitoring.
* Replaced hardcoded logs with the SDK logging function.
* Added support for reporting device capabilities through `deviceInfo` interface.

</details>

***

<details>

<summary>Previous Releases</summary>

#### v2.10.0[^1]  <sup><sub>**`May 06, 2026`**<sub></sup>

* Added new metadata fields `player ID` and `DRM Level`.
* Fixed play duration offset calculation issue.

#### v2.9.0[^1]  <sup><sub>**`Mar 30, 2026`**<sub></sup>

* Added support for reporting a new field encoding service via `customConfig`.
* Introduced custom event reporting through `customEvent` interface.
* Added FPS reporting in the Rendition event.
* Fixed the `NA` Asset Name issue.

#### v2.8.0[^1]  <sup><sub>**`Feb 06, 2026`**<sub></sup>

* Added `CDN_CHANGE` event functionality.
* Added Seek Duration calculation internally.
* Added Audio and Video Codecs in Rendition Event.

#### v2.7.2[^1]  <sup><sub>**`Jan 23, 2026`**<sub></sup>

* Cleaned up the content change handler

#### v2.7.1[^1]  <sup><sub>**`Jan 06, 2026`**<sub></sup>

* Fixed a bug in HTTP port handling in the case of upnext.

#### v2.7.0  <sup><sub>**`Dec 22, 2025`**<sub></sup>

* Updated network call handling to avoid waiting after the HTTP call.
* Updated Device Resolution string.

#### v2.6.5  <sup><sub>**`Dec 12, 2025`**<sub></sup>

* Device & Network Information fixes
* Fixed Player Resolution
* Preload field addition
* App Session Id field addition
* Fix to consider Exit in Buffering

</details>

[^1]: **Performance Report:** [here](https://docs.mediamelon.com/mediamelon/sdk-performance-metrics/roku/roku-sdk-performance-metrics)


# Roku with RAF SDK

This document describes the Roku MediaMelon Player SDK Integration with the  Roku media player.

**Step 1:** [Include MediaMelon SmartStreaming SDK](#step-1-include-mediamelon-smartstreaming-sdk)

**Step 2:** [Setup a new MediaMelon Task](#step-2-setup-new-mediamelon-task)

**Step 3:** [MediaMelon Code Integrate](#step-3-integrate-mediamelon-code-to-main-application)

**Step 4:** [Error Handling](#step-4-error-handling)

**Step 5:** [Ad Tracking with RAF](#step-5-a-d-tracking-with-raf)

**Step 6:**  [Variables and Description](#step-6-variables-and-description)

### Step 1: Include MediaMelon SmartStreaming SDK <a href="#step-1-include-mediamelon-smartstreaming-sdk" id="step-1-include-mediamelon-smartstreaming-sdk"></a>

To integrate, unzip the MediaMelon Roku library and place the `MMSmartStream` folder in the components directory.

SDK: [MediaMelon Roku SDK](https://mediamelon-builds.s3.us-east-1.amazonaws.com/MM-RELEASE-BUILDS/SDK_RELEASES/Roku/QoE/2.6.2/MMSmartStream.zip)

### Step 2: Setup a new MediaMelon Task <a href="#step-2-setup-new-mediamelon-task" id="step-2-setup-new-mediamelon-task"></a>

Create a new XML file `MMTask.xml` inside your components folder. This is used to link MediaMelon’s `brs`files into your application.

The `MMTask.xml`file should contain the following:

```xml
<component name="MMTask" extends="Task">
  <interface>
    <field id="video" type="node" alwaysNotify="true" />
    <field id="config" type="assocarray" alwaysNotify="true" />
    <field id="customConfig" type="assocarray" alwaysNotify="true" />    
    <field id="contentMetadata" type="assocarray" alwaysNotify="true" />
    <field id="customTags" type="assocarray" alwaysNotify="true" />
    <field id="error" type="assocarray" alwaysNotify="true"/>
    <field id="adError" type="assocarray" alwaysNotify="true"/>
    <field id="view" type="String" alwaysNotify="true" />
    <field id="exit" type="Boolean" alwaysNotify="true" />
    <field id="mmAdData" type="assocarray" alwaysNotify="true" />
    <field id="mmAdPlaying" type="Boolean" alwaysNotify="true" />    
    <field id="sdk_version" type="String" alwaysNotify="true" />
    <field id="seekThreshold" type="Integer" alwaysNotify="true"/>
    <field id="codecs" type="assocarray" alwaysNotify="true" />
    <field id="isVideoLive" type="Boolean" alwaysNotify="true" />
  </interface>
  <script type="text/brightscript" uri="pkg:/components/MMSmartStream/MMSmartStreamWrapper.brs" />
  <script type="text/brightscript" uri="pkg:/components/MMSmartStream/MMSmartStreamEngine.brs" />
  <script type="text/brightscript" uri="pkg:/components//MMSmartStream/MMSmartStreamRokuPlugin.brs" />
  <script type="text/brightscript" uri="pkg:/components/MMSmartStream/Utilities.brs" />
</component>

```

### Step 3: MediaMelon Code Integrate <a href="#step-3-integrate-mediamelon-code-to-main-application" id="step-3-integrate-mediamelon-code-to-main-application"></a>

#### **3.1.** Add MMTask Child Component:&#x20;

Add the MediaMelon `MMTask` as a child component to the main video scene `custom-playback-channel-master/components/MainScene.xml`

```xml
<component name="MainScene" extends="Scene" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://devtools.web.roku.com/schema/RokuSceneGraph.xsd">
<!-- importing main handler -->
<script type="text/brightscript" uri="pkg:/components/MainScene.brs" />
<children>
    <MMTask id="MM"/>
</children>
```

#### 3.2. Create MM Task Node:

In the main application, after the video instance has been created, create a MediaMelon Task node, and pass the Video node to it.

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```brightscript
m.MM = m.top.FindNode("MM")
m.MM.setField("video", m.video)
```

#### 3.3. Set Configuration Details:

```brightscript
MMConfig = {
  customerID: "CUSTOMER_ID"
  subscriberId: "SUBSCRIBER_ID"
  subscriberType: "SUBSCRIBER_TYPE"
  subscriberTag: "SUBSCRIBER_TAG"
  playerName: "Roku"
  disableManifestFetch: false
  domainName: "DOMAIN_NAME"
  appName: "APP_NAME"
  appSdkVersion: "APP_VERSION"
  viewSessionId: "VIEW_SESSION_ID"
  hashSubscriberId: false 'Important
  enableCustomErrorReporting: true 'Important
}
m.MM.setField("config", MMConfig)
```

{% hint style="info" %}

* `disableManifestFetch`: If your workflow restricts the manifest to be accessible from both the player and SDK simultaneously, then you can disable manifest fetch. This is an optional step.
* `hashSubscriberId`: Set to `true` to hash the subscriberId and to `false` to process subscriberId without hashing.
* `enableCustomErrorReporting`: If set to `true` SDK will consider only client-reported errors else if set to `false` SDK will consider errors from the video node.
  {% endhint %}

#### 3.4. Set Content Metadata:

```brightscript
contentMetadata = {
  "assetName": "ASSET_NAME",
  "assetId": "ASSET_ID",
  "videoId": "VIDEO_ID",
  "genre": "GENRE",
  "drmProtection": "DRM_PROTECTION",
  "episodeNumber": "EPISODE_NUMBER",
  "season": "SEASON",
  "seriesTitle": "SERIES_TITLE",
  "contentType": "CONTENT_TYPE",
}
m.MM.setField("contentMetadata", contentMetadata)
```

#### 3.5. Set Custom Configuration Details:

```brightscript
customConfig = {
  cdn: "CDN"
  experimentName: "EXPERIMENT_NAME"
  subPropertyId: "SUB_PROPERTY_ID"
  streamFormat: "STREAM_FORMAT"
  mediaType: "MEDIA_TYPE"
  drmProtection: "DRM_PROTECTION"
}
m.MM.setField("customConfig", customConfig)
```

#### 3.6. Set Codecs:

```brightscript
codecs = {
  video: "VIDEO_CODEC"
  audio: "AUDIO_CODEC"
}
m.MM.setField("codecs", codecs)
```

#### 3.7. Set Custom Metadata:

```brightscript
customMetadata = {
  "CUSTOM_KEY_1": "VALUE_1",
  "CUSTOM_KEY_2": "VALUE_2"
}
m.MM.setField("customTags", customMetadata)
```

#### 3.8. Set Seek Threshold:

By default seek threshold is set to `1.25 seconds` in the SDK.&#x20;

```brightscript
m.MM.setField("seekThreshold", 2)
```

#### 3.9. Set is Video Live:

Set `isVideoLive` to `true` for live video stream and to `false` for VOD stream

```brightscript
m.MM.setField("isVideoLive", true)
```

#### 3.10. Set View:

{% hint style="info" %}
It's important to set the view field  `start` for every new view starts and to `end` when a view ends.
{% endhint %}

* **Start View:**

```brightscript
m.MM.setField("exit", false)
m.MM.setField("view", "start")
```

* **End View:**

```brightscript
m.MM.setField("view", "end")
m.MM.setField("exit", true)
```

#### 3.11. Run the SDK:

```brightscript
m.MM.control = "RUN"
m.player.setFocus(true)
```

### Step 4: Error Handling

By default, SDK listens to the video node for errors. To report custom errors set `enableCustomErrorReporting` flag to `true` in `MMConfig` and report the errors in the following way;

{% hint style="info" %}
Upon setting `enableCustomErrorReporting` flag to true, SDK will stop listening to the video node errors. Only custom errors will be reported.
{% endhint %}

#### 4.1. Video Error Reporting:

```brightscript
m.MM.error = { 
    errorCode: "ERROR_CODE",
    errorMessage: "ERROR_MESSAGE",
    errorDetails: "ERROR_DETAILS"
}
```

#### 4.2. Ad Error Reporting:

```brightscript
m.MM.adError = { 
    errorCode: "ERROR_CODE",
    errorMessage: "ERROR_MESSAGE",
    errorDetails: "ERROR_DETAILS"
}
```

### Step 5: Ad Tracking with RAF

```brightscript
    RAF = Roku_Ads()
    RAF.setAdUrl(vastTag)

    logObj = {
        log: function(evtType = invalid as dynamic, ctx = invalid as dynamic)
            'The below function sends the Ad data to MediaMelon SDK for ad tracking
            sendAdDataToMMSDK(ctx)
    }
    logFunc = function(obj = invalid as dynamic, evtType = invalid as dynamic, ctx = invalid as dynamic)
        obj.log(evtType, ctx)
    end function
    RAF.setTrackingCallback(logFunc, logObj)
    
    adPods = RAF.getAds()
```

```brightscript
function sendAdDataToMMSDK(ctx as object)
    if m.global <> invalid and m.global.MMAnalytics <> invalid
        m.global.MMAnalytics.setField("mmAdData", ctx)
    end if
end function
```

Set the field named `mmAdPlaying` to true when an ad break started as shown below:

```brightscript
'preroll ads
if adPods <> invalid and adPods.count() > 0
        video.control = "stop"
        m.top.playingAd = true
        print "Preroll adPods > " adPods
        m.global.MMAnalytics.setField("mmAdPlaying", true) 'This line is part of MM SDK Integration
        keepPlaying = RAF.showAds(adPods, invalid, view)
 end if

'midroll ads
 if adPods <> invalid and adPods.count() > 0
        'ask the video to stop - the rest is handled in the state=stopped event below
        print "Midroll adPods > " adPods
        m.global.MMAnalytics.setField("mmAdPlaying", true) 'This line is part of MM SDK Integration
        video.control = "stop"
 end if
```

### Step 6: Variables and Description

<table data-header-hidden><thead><tr><th width="242.33333333333331">Variable</th><th width="359">Description</th><th></th></tr></thead><tbody><tr><td>Variable</td><td>Description</td><td>Optional/Mandatory</td></tr><tr><td>PLAYER_NAME</td><td>String containing the Player Name.</td><td>Mandatory</td></tr><tr><td>CUSTOMER_ID</td><td>String containing your MediaMelon-assigned Customer ID.</td><td>Mandatory</td></tr><tr><td>SUBSCRIBER_ID</td><td>String containing your Subscriber’s ID.</td><td>Mandatory</td></tr><tr><td>DOMAIN_NAME</td><td>String containing your section of your subscriber or assets.</td><td>Mandatory</td></tr><tr><td>SUBSCRIBER_TYPE</td><td>String containing the Subscriber Type (e.g. “Free”, “Paid”).</td><td>Mandatory</td></tr><tr><td>SUBSCRIBER_TAG</td><td>String containing additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised not to send sensitive information in this field.</td><td>Optional</td></tr><tr><td>ASSET_ID</td><td>String containing Asset Id.</td><td>Mandatory</td></tr><tr><td>ASSET_NAME</td><td>String containing Asset Name.</td><td>Mandatory</td></tr><tr><td>VIDEO_ID</td><td>String containing your video’s ID.</td><td>Mandatory</td></tr><tr><td>CONTENT_TYPE</td><td>String containing the type of the Content. For example - "Movie", "Special", "Clip", "Scene" or "Episode".</td><td>Mandatory</td></tr><tr><td>GENRE</td><td>String containing the Genre of the content. For example - "Comedy", "Horror".</td><td>Mandatory</td></tr><tr><td>DRM_PROTECTION</td><td>Widevine, Fairplay, Playready, etc. Unknown means content is protected, but the protection type is unknown. For clear contents, do not set this field</td><td>Mandatory</td></tr><tr><td>EPISODE_NUMBER</td><td>String containing sequence number of the Episode.</td><td>Mandatory</td></tr><tr><td>SEASON</td><td>String containing the Season. For example - "Season 1".</td><td>Mandatory</td></tr><tr><td>SERIES_TITLE</td><td>String containing Title of the Series.</td><td>Mandatory</td></tr><tr><td>VIDEO_TYPE</td><td>String containing Video Type. For example - "LIVE", and "VOD".</td><td>Optional</td></tr><tr><td>PLAYER_BRAND</td><td>String containing Player Brand (e.g. “Exo Player”).</td><td>Mandatory</td></tr><tr><td>PLAYER_MODEL</td><td>String containing Player Model. For example - This could be a variant of a player. Say the name of third third-party player used by the organisation. Or any human-readable name of the player.</td><td>Mandatory</td></tr><tr><td>PLAYER_VERSION</td><td>String containing Player Version.</td><td>Mandatory</td></tr><tr><td>CUSTOM_KEY_1</td><td>Custom metadata key can be added here if required.</td><td>Optional</td></tr><tr><td>VALUE_1</td><td>Custom metadata value can be added here if required.</td><td>Optional</td></tr><tr><td>BASE_PLAYER_NAME</td><td>String containing base player name</td><td>Optional</td></tr><tr><td>BASE_PLAYER_VERSION</td><td>String containing base player version</td><td>Optional</td></tr><tr><td>EXPERIMENT_NAME</td><td>You can use this field to categorise views into different experiments, allowing you to filter by this dimension later.</td><td>Optional</td></tr><tr><td>SUB_PROPERTY_ID</td><td>A sub-property is an optional feature that allows you to organize data within a property. For instance, a video platform could use sub-properties to group data by customer, or a media company might use them to differentiate between its various websites.</td><td>Optional</td></tr><tr><td>VIEW_SESSION_ID</td><td>An ID that can be used to link the view with upstream platform services, such as CDN or origin logs, for correlation purposes.</td><td>Optional</td></tr><tr><td><code>hashSubscriberId</code></td><td>To hash the subscriber ID set this boolean variable to <code>true</code>, else set it to <code>false</code>.</td><td>Optional</td></tr><tr><td><code>player</code></td><td>Player Object.</td><td>Mandatory</td></tr><tr><td><code>streamURL</code></td><td>Current playing content stream URL.</td><td>Mandatory</td></tr><tr><td><code>isVideoLive</code></td><td>Set this boolean variable to <code>true</code> if the content is Live else set it to <code>false</code> for VOD content.</td><td>Optional</td></tr></tbody></table>


# MediaMelon Roku SDK Integration with IMA

This document describes the Roku MediaMelon Player IMA SDK Integration with the  Roku media player.

**Step 1:** [Include MediaMelon SmartStreaming SDK](#step-1-include-mediamelon-smartstreaming-sdk)

**Step 2:** [Set up a new MediaMelon Task](#step-2-setup-new-mediamelon-task)

**Step 3:** [MediaMelon Code Integration](#step-3-integrate-mediamelon-code-to-main-application)

**Step 4:** [Error Handling](#step-4-error-handling)

**Step 5:** [Google IMA Ads Integration](#google-ima-a-ds-integration)

**Step 6:** [Custom Events](#google-ima-a-ds-integration-1)

[Release Notes](#release-notes)

### Step 1: Include MediaMelon SmartStreaming SDK <a href="#step-1-include-mediamelon-smartstreaming-sdk" id="step-1-include-mediamelon-smartstreaming-sdk"></a>

To integrate, unzip the MediaMelon Roku library and place the `MMSmartStream` folder in the components directory.

SDK: [MediaMelon Roku IMA SDK](https://sdks.mediamelon.com/roku/ima/2.9.0/MMSmartStream.zip)

### Step 2: Set up a new MediaMelon Task <a href="#step-2-setup-new-mediamelon-task" id="step-2-setup-new-mediamelon-task"></a>

Create a new XML file `MMTask.xml` inside your components folder. This is used to link MediaMelon’s `brs`files into your application.

The `MMTask.xml`file should contain the following:

```xml
<component name="MMTask" extends="Task">
<interface>
    <field id="video" type="node" alwaysNotify="true"/>
    <field id="config" type="assocarray" alwaysNotify="true"/>
    <field id="customConfig" type="assocarray" alwaysNotify="true" /> 
    <field id="contentMetadata" type="assocarray" alwaysNotify="true"/> 
    <field id="customTags" type="assocarray" alwaysNotify="true"/>
    <field id="error" type="assocarray" alwaysNotify="true"/>
    <field id="adError" type="assocarray" alwaysNotify="true"/>
    <field id="view" type="String" alwaysNotify="true"/>
    <field id="exit" type="Boolean" alwaysNotify="true"/>
    <field id="imaads" type="assocarray" alwaysNotify="true"/>
    <field id="isAdImpressionSent" type="Boolean" alwaysNotify="true"/>
    <field id="sdk_version" type="String" alwaysNotify="true"/>
    <field id="seekThreshold" type="Integer" alwaysNotify="true"/>
    <field id="codecs" type="assocarray" alwaysNotify="true" />
    <field id="isVideoLive" type="Boolean" alwaysNotify="true" />
    <field id="customEvent" type="assocarray" alwaysNotify="true" />
</interface>

<script type="text/brightscript" uri="pkg:/Components/MMSmartStream/MMSmartStreamWrapper.brs"/>
<script type="text/brightscript" uri="pkg:/Components/MMSmartStream/MMSmartStreamEngine.brs"/>
<script type="text/brightscript" uri="pkg:/Components/MMSmartStream/MMSmartStreamRokuPlugin.brs"/>
<script type="text/brightscript" uri="pkg:/Components/MMSmartStream/Utilities.brs"/>
</component>
```

### Step 3: MediaMelon Code Integration <a href="#step-3-integrate-mediamelon-code-to-main-application" id="step-3-integrate-mediamelon-code-to-main-application"></a>

#### **3.1.** Add MMTask Child Component:&#x20;

Add the MediaMelon `MMTask` as a child component of the main video scene `custom-playback-channel-master/components/MainScene.xml`

```xml
<component name="MainScene" extends="Scene" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://devtools.web.roku.com/schema/RokuSceneGraph.xsd">
<!-- importing main handler -->
<script type="text/brightscript" uri="pkg:/components/MainScene.brs" />
<children>
    <MMTask id="MM"/>
</children>
```

#### &#x20;3.2. Create MM Task Node:

In the main application, after the video instance has been created, create a MediaMelon Task node, and pass the Video node to it.

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```brightscript
m.MM = m.top.FindNode("MM")
m.MM.setField("video", m.video)
```

#### 3.3. Set Configuration Details:

```javascript
MMConfig = {
  customerID: "CUSTOMER_ID"
  subscriberId: "SUBSCRIBER_ID"
  subscriberType: "SUBSCRIBER_TYPE"
  subscriberTag: "SUBSCRIBER_TAG"
  playerName: "PLAYER_NAME"
  playerVersion: "PLAYER_VERSION"
  basePlayerName: "BASE_PLAYER_NAME"
  basePlayerVersion: "BASE_PLAYER_VERSION"
  domainName: "DOMAIN_NAME"
  appName: "APP_NAME"
  appSdkVersion: "APP_VERSION"
  viewSessionId: "VIEW_SESSION_ID"
  appSessionId: "APP_SESSION_ID"
  hashSubscriberId: false 'Important
  enableCustomErrorReporting: true 'Important
}
m.MM.setField("config", MMConfig)
```

{% hint style="info" %}

* `hashSubscriberId`: Set `true` to hash the subscriberId and to `false` to process the subscriberId without hashing.
* `enableCustomErrorReporting`: If set to `true` SDK will consider only client-reported errors, else if set to `false` SDK will consider errors from the video node. ([Refer Here](#step-4-error-handling))
  {% endhint %}

#### 3.4. Set Content Metadata:

```javascript
contentMetadata = {
  "assetName": "ASSET_NAME",
  "assetId": "ASSET_ID",
  "videoId": "VIDEO_ID",
  "genre": "GENRE",
  "drmProtection": "DRM_PROTECTION",
  "episodeNumber": "EPISODE_NUMBER",
  "season": "SEASON",
  "seriesTitle": "SERIES_TITLE",
  "contentType": "CONTENT_TYPE",
}
m.MM.setField("contentMetadata", contentMetadata)
```

#### 3.5. Set Custom Configuration Details:

```javascript
customConfig = {
  cdn: "CDN"
  experimentName: "EXPERIMENT_NAME"
  subPropertyId: "SUB_PROPERTY_ID"
  streamFormat: "STREAM_FORMAT"
  mediaType: "MEDIA_TYPE"
  drmProtection: "DRM_PROTECTION"
  preload: <boolean>
  encodingService: "ENCODING_SERVICE"
}
m.MM.setField("customConfig", customConfig)
```

#### 3.6. Set Codecs:

```javascript
codecs = {
  video: "VIDEO_CODEC"
  audio: "AUDIO_CODEC"
}
m.MM.setField("codecs", codecs)
```

#### 3.7. Set Custom Metadata:

```javascript
customMetadata = {
  "CUSTOM_KEY_1": "VALUE_1",
  "CUSTOM_KEY_2": "VALUE_2"
}
m.MM.setField("customTags", customMetadata)
```

{% hint style="info" %}
For Custom Metadata, first, provide the mapping in the [SmartSight](https://smartsight3.mediamelon.com/settings) dashboard under the settings section, and send the values to the SDK accordingly.
{% endhint %}

#### 3.8. Set Seek Threshold:

By default seek threshold is set to `2 seconds` in the SDK.&#x20;

```javascript
m.MM.setField("seekThreshold", 5)
```

#### 3.9. Set is Video Live:

Set `isVideoLive` to `true` for live video stream and to `false` for VOD stream

```javascript
m.MM.setField("isVideoLive", true)
```

#### 3.10. Set View:

{% hint style="info" %}
It's important to set the view field  `start` for every new view start, and to `end` when a view ends.
{% endhint %}

* **Start View:**

```javascript
m.MM.setField("exit", false)
m.MM.setField("view", "start")
```

* **End View:**

```javascript
m.MM.setField("view", "end")
m.MM.setField("exit", true)
```

#### 3.11. Run the SDK:

```javascript
m.MM.control = "RUN"
m.player.setFocus(true)
```

### Step 4: Error Handling

By default, the SDK listens to the video node for errors. To report custom errors, set `enableCustomErrorReporting` flag to `true` and report the errors in the following way;

{% hint style="info" %}
Upon setting `enableCustomErrorReporting` flag to `true`, SDK will stop listening to the video node errors. Only custom errors will be reported.
{% endhint %}

#### 4.1. Video Error Reporting:

```javascript
m.MM.error = { 
    errorCode: "ERROR_CODE",
    errorMessage: "ERROR_MESSAGE",
    errorDetails: "ERROR_DETAILS",
    errorSeverity: <error_severity>   'string (This should be "warning" or "fatal")
}
```

{% hint style="info" %}
`error_severity`: Set this to `"warning"` for warnings and set to `"fatal"` for fatal errors.
{% endhint %}

#### 4.2. Ad Error Reporting:

```javascript
m.MM.adError = { 
    errorCode: "ERROR_CODE",
    errorMessage: "ERROR_MESSAGE",
    errorDetails: "ERROR_DETAILS"
}
```

### Step 5: Google IMA Ads Integration <a href="#google-ima-ads-integration" id="google-ima-ads-integration"></a>

This guide demonstrates how to integrate the Mediamelon Roku SDK into a sample video player app with Google Ima Ads. Downloaded the [basic example](https://github.com/googleads/googleads-ima-roku-dai) from GitHub.

#### **5.1. Include MediaMelon Ad Plugin:**

Include `MMImaAdsPlugin.brs`  file into `SDK.xml` as shown below.

```xml
<?xml version = "1.0" encoding = "utf-8" ?>
<component name = "imasdk" extends = "Task">

<script type = "text/brightscript">
    <![CDATA[
        <!-- Your code goes here -->
    ]]>
</script>

<!-- MediaMelon IMA AdPlugin -->
<script type = "text/brightscript" uri="pkg:/Components/MMSmartStream/MMImaAdsPlugin.brs"/>
</component>
```

#### **5.2. Create an IMA Stream Player:**

Call MediaMelon APIs to notify `adBreakStarted` and `adBreakEnded` as shown below.

```javascript
...
sub setupVideoPlayer()
  sdk = m.sdk
  m.player = sdk.createPlayer()
  ...
  m.player.adBreakStarted = Function(adBreakInfo as Object)
    ...
    'MediaMelon API to notify AdBreakStart'
    mmAdBreakStarted(adBreakInfo)
  End Function
  m.player.adBreakEnded = Function(adBreakInfo as Object)
    ...
    'MediaMelon API to notify AdBreakEnd'
    mmAdBreakEnded(adBreakInfo)
  End Function
End Sub
```

#### **5.3. Add Event Listeners and Start the Stream:**

After requesting your stream, add event listeners to track ad progress from the MediaMelon SDK by calling an API `addMediaMelonAdCallbacks` .

```javascript
Sub loadStream()
  sdk = m.sdk
  sdk.initSdk()
  setupVideoPlayer()
  request = sdk.CreateStreamRequest()
  ...
  m.streamManager = Invalid
  While m.streamManager = Invalid
    sleep(50)
    m.streamManager = sdk.getStreamManager()
  End While
  ...
  'MediaMelon Callback Register'
  addMediaMelonAdCallbacks(m.sdk, m.streamManager)
  m.streamManager.start()
End Sub
```

### Step 6: Custom Events <a href="#google-ima-ads-integration" id="google-ima-ads-integration"></a>

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```raku
m.MM.customEvent = {
    eventName: "EVENT_NAME",
    eventValue: "EVENT_VALUE"
}
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 35 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

#### Release Notes

<details>

<summary>Current Release</summary>

#### v2.9.0  <sup><sub>**`Mar 20, 2026`**<sub></sup>

* Added new fields: `Encoding Service`, `App Session ID`, and `Preload`
* Added `Seek Duration` metric and improved `Buffering` calculation
* Added `Custom Event` reporting
* Added `CDN Change` event functionality
* Added `FPS` and `Audio/Video Codec` data points in `Rendition` Change events
* Enhanced `Device` and `Network` information reporting
* Corrected `Device` Resolution and `Player` Resolution data
* Improved **network call handling** to eliminate unnecessary waiting after HTTP calls
* Improved `Bitrate` reporting
* Added `errorSeverity` to mark an error, `warning` or `fatal`.

</details>


# C++ SDK


# MediaMelon C++ Custom SDK Integration Document

This guide is for integrating the MediaMelon Custom SDK for the STB-based Players

**Step 1:** [Add MediaMelon SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Register and Initialize MediaMelon SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Additional Custom Metadata](#step-3-additional-custom-metadata)

**Step 4:** [Network and Stream Information](#step-4-network-and-stream-information)

**Step 5:** [Chunk/Segment Information](#step-5-chunk-segment-information)

**Step 6:** [Player Events](#step-6-player-events)

**Step 7:** [Fallback & Request Status](#step-7-fallback-and-request-status)

**Step 8:** [Ad Data & Ad Events](#step-8-a-d-data-and-ad-events)

**Step 9:** [Custom Events](#step-9-custom-events)

[Release Notes](#release-notes)

### **Step 1: Add** MediaMelon SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Add the provided static (.a) or shared (.so) library to the project.&#x20;

### **Step 2: Register and Initialize** MediaMelon SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

#### Step 2.1: Instantiate and Set SDK Registration Information:

```cpp
#include "cpp_mmsmartstreaming.h"

using namespace MMSmartStreamingSDK;

MMSmartStreaming &mmSmartStreaming = MMSmartStreaming::getInstance();

MMSmartStreaming::registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_CPP", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG", hashSubscriberID);
MMSmartStreaming::reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
MMSmartStreaming::reportPlayerId("PLAYER_ID);
MMSmartStreaming::reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

{% hint style="info" %}
`hashSubscriberID`: Set it to `true` to hash the subscriber ID, and to `false` to process the subscriber ID without hashing.
{% endhint %}

#### Step 2.3: Report Application Information:

```cpp
MMSmartStreaming::reportAppData("APP_NAME", "APP_VERSION");
```

#### Step 2.4: Report Application Session ID:

```cpp
MMSmartStreaming::reportAppSessionID("APP_SESSION_ID");
```

#### Step 2.5: Set Device Information:

```cpp
MMDeviceInformation deviceInfo;
deviceInfo.setDeviceType("DEVICE_TYPE");
deviceInfo.setDeviceBrand("DEVICE_BRAND");      //Device Brand or Manufacturer
deviceInfo.setDeviceModel("DEVICE_MODEL");
deviceInfo.setDeviceOSInfo("DEVICE_OS", "DEVICE_OS_VERSION");  
deviceInfo.setScreenResolution(<screen_width>, <screen_height>);
  
MMSmartStreaming::reportDeviceInfo(deviceInfo);
```

#### Step 2.6: Report Experiment Name & Sub Property ID:

```cpp
MMSmartStreaming::reportExperimentName("EXPERIMENT_NAME");
MMSmartStreaming::reportSubPropertyID("SUB_PROPERTY_ID");
```

#### Step 2.7: Set Content Metadata:

```cpp
MMContentMetadata contentMetadata;
contentMetadata.setAssetInfo("ASSET_ID", "ASSET_NAME", "VIDEO_ID");
contentMetadata.setContentType("CONTENT_TYPE");
contentMetadata.setDrmProtection("DRM_PROTECTION");
contentMetadata.setDrmLevel("DRM_LEVEL");
contentMetadata.setEpisodeNumber("EPISODE_NUMBER");
contentMetadata.setGenre("GENRE");
contentMetadata.setSeason("SEASON");
contentMetadata.setSeriesTitle("SERIES_TITLE");

mmSmartStreaming.reportViewSessionID("VIEW_SESSIOND_ID");
```

#### Step 2.8: Initialize Session with Content Metadata:

```cpp
mmSmartStreaming.initializeSession("STREAM_URL", contentMetadata)
mmSmartStreaming.reportPreload(<bool>);
mmSmartStreaming.reportUserInitiatedPlayback();
```

{% hint style="info" %}
**Preload:** Report the preload attribute after `initializeSession` and before `reportUserInitiatedPlayback`. The preload value is reset inside `initializeSession`, so reporting it before this method will be ignored. If you report it after `reportUserInitiatedPlayback`, the first event will not contain the preload field.
{% endhint %}

### Step 3: Additional Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```cpp
mmSmartStreaming.reportCustomMetadata("KEY1", "VALUE1");
mmSmartStreaming.reportCustomMetadata("KEY2", "VALUE2");
```

### Step 4: Network and Stream Information

#### Step 4.1: Report Network Information:

```cpp
mmSmartStreaming.reportNetworkInfo("CDN",
                                   <asn>,                 //Integer Value
                                   "SOURCE_HOST_NAME", 
                                   "NETWORK_TYPE",        // Network Connection Type
                                   "NETWORK_OPERATOR");
```

{% hint style="info" %}
Use the `reportNetworkInfo` API to report the CDN along with other network information.\
If additional network information is not available, use `reportCDN` instead.
{% endhint %}

#### Step 4.2: Report CDN Information:

```cpp
mmSmartStreaming.reportCDN("CDN");
```

#### Step 4.2: Report Stream Information:

```cpp
mmSmartStreaming.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SORUCE_TYPE");
```

#### Step 4.3: Update Stream URL:

```cpp
mmSmartStreaming.updateStreamURL("NEW_STREAM_URL");
```

#### Step 4.4: Report Video Presentation Information:

```cpp
MMPresentationInfo presentationInfo;
presentationInfo.isLive = false;
presentationInfo.duration = 100*1000; 

mmSmartStreaming.setPresentationInformation(presentationInfo);
```

{% hint style="info" %}

* `isLive`: Set to `true` for live video stream and to `false` for the VOD stream.
* `duration`: Video duration in milliseconds.
  {% endhint %}

#### Step 4.5: Report Track Information:

Call this API with initial values and every time there is a change in the track info. Call this API when the user enables/disables subtitles or when the user changes the audio track.

```cpp
mmSmartStreaming.reportMediaTrackInfo(<is_subtitle_active>, "SUBTITLE_TRACK", "AUDIO_TRACK", <is_vds_active>);
```

{% hint style="info" %}
`is_subtitle_active`: Set it to `true` if the subtitles are active; otherwise, set it to `false`.

`is_vds_active`: Set it to `true` if the type of audio is Virtual Dialogue Sound, otherwise, set it to `false`.
{% endhint %}

#### Step 4.6: Report Rendition:

At the start of the video, create a ReditionInfo object, assign initial rendition values to the object, and report it to the SDK. For any subsequent rendition change, update only the fields that changed in the same RenditionInfo object. Leave the unchanged fields as-is, and report the updated object to the SDK.

```cpp
MMRenditionInfo renditionInfo;
renditionInfo.bitrate = <bitrate>            //Integr Value in bps
renditionInfo.width = <width>                //Integer Value
renditionInfo.height = <height>              //Integer Value
renditionInfo.frameRate = <frame_rate>       //Double Value in fps
renditionInfo.setAudioCodec("ACODEC");
renditionInfo.setVideoCodec("VCODEC");

mmSmartStreaming.reportRenditionInformation(renditionInfo);
```

#### Step 4.7: Update DRM Protection:

{% hint style="danger" %}
`updateDRMType(drmType:)` is **deprecated**. A new API called `updateDRM(drmProtection, drmLevel)` is introduced.
{% endhint %}

```cpp
mmSmartStreaming.updateDRM("DRM_PROTECTION", "DRM_LEVEL);
```

#### Step 4.8: Report Encoding Service:

```cpp
mmSmartStreaming.reportEncodingService("ENCODING_SERVICE");
```

### Step 5: Chunk/Segment Information

#### Step 5.1: Report Download Rate:

Report the latest chunk download rate using this method. Trigger this method for every chunk.

```cpp
mmSmartStreaming.reportDownloadRate(<downloadRate>)  //Integer Value in bps
```

### Step 6: Player Events

#### Step 6.1: Report Player State:

```cpp
mmSmartStreaming.reportPlayerState(MMPlayerState::PLAYING);

Enum: MMPlayerState
- PLAYING
- PAUSED
- STOPPED
```

#### Step 6.2: Report Buffering:

```cpp
mmSmartStreaming.reportBufferingStarted();
mmSmartStreaming.reportBufferingCompleted();
```

#### Step 6.3: Report Seek:

```cpp
mmSmartStreaming.reportPlayerSeekStarted();
mmSmartStreaming.reportPlayerSeekCompleted(<seek_end_position>); //Integer Value in Milli Seconds
```

#### Step 6.4: Report Error:

```cpp
mmSmartStreaming.reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DETAILS");
```

#### Step 6.5: Report Warning:

```cpp
mmSmartStreaming.reportWarning("WARNING_CODE", "WARNING_MESSAGE", "WARNING_DETAILS");
```

#### Step 6.5: Report Playback Position:

Call this every 0.5 sec or 1 sec to report the playback position from the player

```cpp
mmSmartStreaming.reportPlaybackPosition(<playback_position>) //Integer Value in Milli Seconds
```

#### Step 6.6: Report Player Resolution:

```cpp
mmSmartStreaming.reportPlayerResolution(<player_width>, <player_height>);
```

### Step 7: Fallback & Request Status

#### Step 7.1: Report Fallback Event:

```cpp
mmSmartStreaming.reportFallbackEvent("NEW_FALLBACK_STREAM_URL", "FALLBACK_DESCRIPTION");
```

#### Step 7.2: Report Request Status:

Report `FAILED` or `CANCELLED` requests for the following request types:

* PIR
* MANIFEST
* AUDIO\_CHUNK
* VIDEO\_CHUNK
* DRM
* SUBTITLE

```cpp
map<string, string> requestInfoMap;
requestInfoMap["ID"] = "ID";
requestInfoMap["URL"] = "URL";
requestInfoMap["ERROR"] = "ERROR";
requestInfoMap["DESC"] = "DESC";

mmSmartStreaming.reportRequestStatus(RequestStatus::CANCELLED, "REQUEST_TYPE", requestInfoMap);

Enum: RequestStatus
- FAILED
- CANCELLED
```

### Step 8: Ad Data & Ad Events

#### Step 8.1: Report Ad Break Start & End:

```cpp
mmSmartStreaming.reportAdBreakStart();
mmSmartStreaming.reportAdBreakEnd();
```

#### Step 8.2: Report Ad Data, Ad Start & End:

```cpp
MMAdInfo adInfo;
adInfo.adTitle = "AD_TITLE";
adInfo.adId = "AD_ID";
adInfo.adCreativeId = "AD_CREATIVE_ID";
adInfo.adCreativeType = "AD_CREATIVE_TYPE";
adInfo.adClient = "AD_CLIENT"
adInfo.adPosition = "AD_POSITION";                    //pre, mid, post
adInfo.adServer = "AD_SERVER";
adInfo.adResolution = "AD_RESOLUTION";
adInfo.adUrl = "AD_URL";
adInfo.adDuration = <ad_duration>;                    //Integer Value in Milli Seconds
adInfo.adPodIndex = <pod_index>;                      //Integer Value
adInfo.adPositionInPod = <ad_position_in_pod>;        //Integer Value
adInfo.adPodLendth = <pod_length>;                    //Integer Value
adInfo.isBumper = <is_bumper>;                        //Boolean Value

mmSmartStreaming.reportAdInfo(mmadInfo);

mmSmartStreaming.reportAdStart();
mmSmartStreaming.reportAdEnd();
```

<details>

<summary>Ad Info Fields &#x26; Description</summary>

<table data-header-hidden><thead><tr><th width="204.65234375">Field</th><th width="114.8046875">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>adInfo.adTitle</td><td>String</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adInfo.adId</td><td>String</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adInfo.adCreativeId</td><td>String</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adInfo.adCreativeType</td><td>String</td><td>The format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>adInfo.adClient</td><td>String</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adInfo.adPosition</td><td>String</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adInfo.adServer</td><td>String</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adInfo.adResolution</td><td>String</td><td>The resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>adInfo.adUrl</td><td>String</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adInfo.adDuration</td><td>Integer</td><td>The total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>adInfo.adPodIndex</td><td>Integer</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adInfo.adPositionInPod</td><td>Integer</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>adInfo.adPodLendth</td><td>Integer</td><td>The total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr><tr><td>adInfo.isBumper</td><td>Boolean</td><td>A boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr></tbody></table>

</details>

#### Step 8.3: Report Ad Buffering:

Use Ad Buffering APIs to report any buffering that occurs during ad playback. For any buffering event, either content buffering or ad buffering should be reported, but not both.

```cpp
mmSmartStreaming.reportAdBufferingStrated();
mmSmartStreaming.reportAdBufferingCompleted();
```

### Step 9: Custom Events

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```cpp
mmSmartStreaming.reportCustomEvent("EVENT_NAME", "EVENT_VALUE");
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 30 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

#### Release Notes

<details>

<summary>Current Release</summary>

#### v3.4.0  <sup><sub>**`Jul 30, 2026`**<sub></sup>

* Enhanced Internal SDK data reporting
  * Added batch-based data reporting with configurable reporting intervals.
  * Improved reliability with exponential backoff retries, jitter, request timeouts, and Dead Letter Queue (DLQ) support.
  * Enabled remote configuration for batch size, reporting interval, retry settings, and the batching feature flag.
* Added the following new metadata fields:
  * **Player ID** - report it using `reportPlayerId`.
  * **DRM Level** - report it using `setDrmLevel` as part of the `MMContentMetadata`.
* Added a new method `updateDRM` to update DRM Type and DRM Level.
* Buffering events exceeding the stats interval will include the partial buffering time in the stats payload.

</details>

***

<details>

<summary>Previous Releases</summary>

#### v3.3.0  <sup><sub>**`Mar 30, 2026`**<sub></sup>

* Added support for reporting a new field encoding service via `reportEncodingService`.
* Introduced custom event reporting through `reportCustomEvent`.
* Fixed response parsing failures caused by HTTP headers being included in the body under certain conditions (e.g., when using proxy tools like Charles).

#### v3.2.0  <sup><sub>**`Feb 06, 2026`**<sub></sup>

* Added an additional API to report CDN alone.
* Added `CDN_CHANGE` event.
* Added Seek Duration calculation internally.

#### v**3.1.0 &#x20;**<sup><sub>**`Dec 12, 2025`**<sub></sup>

* Preload field addition
* App Session ID field addition
* Fix to consider Exit in Buffering

</details>


# MediaMelon C++ Custom SDK Integration Document with Offline Storage Support

This guide is for integrating the MediaMelon Custom SDK for the STB-based Players with Offline Storage Support.

**Step 1:** [Add MediaMelon SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Register and Initialize MediaMelon SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Additional Custom Metadata](#step-3-additional-custom-metadata)

**Step 4:** [Network and Stream Information](#step-4-network-and-stream-information)

**Step 5:** [Chunk/Segment Information](#step-5-chunk-segment-information)

**Step 6:** [Player Events](#step-6-player-events)

**Step 7:** [Fallback & Request Status](#step-7-fallback-and-request-status)

**Step 8:** [Ad Data & Ad Events](#step-8-a-d-data-and-ad-events)

**Step 9:** [Custom Events](#step-9-custom-events)

**Step 10:** [Offline Storage Support](#step-10-offline-storage-support)

[Release Notes](#release-notes)

### **Step 1: Add** MediaMelon SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Add the provided static (.a) library to the project. (v3.4.0-OFS)

* [Linux](https://sdk.mediamelon.com/cpp/3.4.0-OFS/linux/libMMSMARTSTREAM_CSDK.a)
* [Windows](https://sdk.mediamelon.com/cpp/3.4.0-OFS/windows/libMMSMARTSTREAM_CSDK.a)

### **Step 2: Register and Initialize** MediaMelon SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

#### Step 2.1: Instantiate and Set SDK Registration Information:

```cpp
#include "cpp_mmsmartstreaming.h"

using namespace MMSmartStreamingSDK;

MMSmartStreaming &mmSmartStreaming = MMSmartStreaming::getInstance();

MMSmartStreaming::registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", "SUBSCRIBER_CPP", "DOMAIN_NAME", "SUBSCRIBER_TYPE", "SUBSCRIBER_TAG", hashSubscriberID);
MMSmartStreaming::reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
MMSmartStreaming::reportBasePlayerInfo("BASE_PLAYER_NAME", "BASE_PLAYER_VERSION");
```

{% hint style="info" %}
`hashSubscriberID`: Set it to `true` to hash the subscriber ID, and to `false` to process the subscriber ID without hashing.
{% endhint %}

#### Step 2.3: Report Application Information:

```cpp
MMSmartStreaming::reportAppData("APP_NAME", "APP_VERSION");
```

#### Step 2.4: Report Application Session ID:

```cpp
MMSmartStreaming::reportAppSessionID("APP_SESSION_ID");
```

#### Step 2.5: Set Device Information:

```cpp
MMDeviceInformation deviceInfo;
deviceInfo.setDeviceType("DEVICE_TYPE");
deviceInfo.setDeviceBrand("DEVICE_BRAND");      //Device Brand or Manufacturer
deviceInfo.setDeviceModel("DEVICE_MODEL");
deviceInfo.setDeviceOSInfo("DEVICE_OS", "DEVICE_OS_VERSION");  
deviceInfo.setScreenResolution(<screen_width>, <screen_height>);
  
MMSmartStreaming::reportDeviceInfo(deviceInfo);
```

#### Step 2.6: Report Experiment Name & Sub Property ID:

```cpp
MMSmartStreaming::reportExperimentName("EXPERIMENT_NAME");
MMSmartStreaming::reportSubPropertyID("SUB_PROPERTY_ID");
```

#### Step 2.7: Set Content Metadata:

```cpp
MMContentMetadata contentMetadata;
contentMetadata.setAssetInfo("ASSET_ID", "ASSET_NAME", "VIDEO_ID");
contentMetadata.setContentType("CONTENT_TYPE");
contentMetadata.setDrmProtection("DRM_PROTECTION");
contentMetadata.setEpisodeNumber("EPISODE_NUMBER");
contentMetadata.setGenre("GENRE");
contentMetadata.setSeason("SEASON");
contentMetadata.setSeriesTitle("SERIES_TITLE");

mmSmartStreaming.reportViewSessionID("VIEW_SESSIOND_ID");
```

#### Step 2.8: Initialize Session with Content Metadata:

```cpp
mmSmartStreaming.initializeSession("STREAM_URL", contentMetadata)
mmSmartStreaming.reportPreload(<bool>);
mmSmartStreaming.reportUserInitiatedPlayback();
```

{% hint style="info" %}
**Preload:** Report the preload attribute after `initializeSession` and before `reportUserInitiatedPlayback`. The preload value is reset inside `initializeSession`, so reporting it before this method will be ignored. If you report it after `reportUserInitiatedPlayback`, the first event will not contain the preload field.
{% endhint %}

### Step 3: Additional Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```cpp
mmSmartStreaming.reportCustomMetadata("KEY1", "VALUE1");
mmSmartStreaming.reportCustomMetadata("KEY2", "VALUE2");
```

### Step 4: Network and Stream Information

#### Step 4.1: Report Network Information:

```cpp
mmSmartStreaming.reportNetworkInfo("CDN",
                                   <asn>,                 //Integer Value
                                   "SOURCE_HOST_NAME", 
                                   "NETWORK_TYPE",        // Network Connection Type
                                   "NETWORK_OPERATOR");
```

{% hint style="info" %}
Use the `reportNetworkInfo` API to report the CDN along with other network information.\
If additional network information is not available, use `reportCDN` instead.
{% endhint %}

#### Step 4.2: Report CDN Information:

```cpp
mmSmartStreaming.reportCDN("CDN");
```

#### Step 4.2: Report Stream Information:

```cpp
mmSmartStreaming.reportStreamInfo("STREAM_FORMAT", "MEDIA_TYPE", "SORUCE_TYPE");
```

#### Step 4.3: Update Stream URL:

```cpp
mmSmartStreaming.updateStreamURL("NEW_STREAM_URL");
```

#### Step 4.4: Report Video Presentation Information:

```cpp
MMPresentationInfo presentationInfo;
presentationInfo.isLive = false;
presentationInfo.duration = 100*1000; 

mmSmartStreaming.setPresentationInformation(presentationInfo);
```

{% hint style="info" %}

* `isLive`: Set to `true` for live video stream and to `false` for the VOD stream.
* `duration`: Video duration in milliseconds.
  {% endhint %}

#### Step 4.5: Report Track Information:

Call this API with initial values and every time there is a change in the track info. Call this API when the user enables/disables subtitles or when the user changes the audio track.

```cpp
mmSmartStreaming.reportMediaTrackInfo(<is_subtitle_active>, "SUBTITLE_TRACK", "AUDIO_TRACK", <is_vds_active>);
```

{% hint style="info" %}
`is_subtitle_active`: Set it to `true` if the subtitles are active; otherwise, set it to `false`.

`is_vds_active`: Set it to `true` if the type of audio is Virtual Dialogue Sound, otherwise, set it to `false`.
{% endhint %}

#### Step 4.6: Report Rendition:

At the start of the video, create a ReditionInfo object, assign initial rendition values to the object, and report it to the SDK. For any subsequent rendition change, update only the fields that changed in the same RenditionInfo object. Leave the unchanged fields as-is, and report the updated object to the SDK.

```cpp
MMRenditionInfo renditionInfo;
renditionInfo.bitrate = <bitrate>            //Integr Value in bps
renditionInfo.width = <width>                //Integer Value
renditionInfo.height = <height>              //Integer Value
renditionInfo.frameRate = <frame_rate>       //Double Value in fps
renditionInfo.setAudioCodec("ACODEC");
renditionInfo.setVideoCodec("VCODEC");

mmSmartStreaming.reportRenditionInformation(renditionInfo);
```

#### Step 4.7: Update DRM Type:

```cpp
mmSmartStreaming.updateDRMType("NEW_DRM_TYPE");
```

#### Step 4.8: Report Encoding Service:

```cpp
mmSmartStreaming.reportEncodingService("ENCODING_SERVICE");
```

### Step 5: Chunk/Segment Information

#### Step 5.1: Report Download Rate:

Report the latest chunk download rate using this method. Trigger this method for every chunk.

```cpp
mmSmartStreaming.reportDownloadRate(<downloadRate>)  //Integer Value in bps
```

### Step 6: Player Events

#### Step 6.1: Report Player State:

```cpp
mmSmartStreaming.reportPlayerState(MMPlayerState::PLAYING);

Enum: MMPlayerState
- PLAYING
- PAUSED
- STOPPED
```

#### Step 6.2: Report Buffering:

```cpp
mmSmartStreaming.reportBufferingStarted();
mmSmartStreaming.reportBufferingCompleted();
```

#### Step 6.3: Report Seek:

```cpp
mmSmartStreaming.reportPlayerSeekStarted();
mmSmartStreaming.reportPlayerSeekCompleted(<seek_end_position>); //Integer Value in Milli Seconds
```

#### Step 6.4: Report Error:

```cpp
mmSmartStreaming.reportError("ERROR_CODE", "ERROR_MESSAGE", "ERROR_DETAILS");
```

#### Step 6.5: Report Warning:

```cpp
mmSmartStreaming.reportWarning("WARNING_CODE", "WARNING_MESSAGE", "WARNING_DETAILS");
```

#### Step 6.5: Report Playback Position:

Call this every 0.5 sec or 1 sec to report the playback position from the player

```cpp
mmSmartStreaming.reportPlaybackPosition(<playback_position>) //Integer Value in Milli Seconds
```

#### Step 6.6: Report Player Resolution:

```cpp
mmSmartStreaming.reportPlayerResolution(<player_width>, <player_height>);
```

### Step 7: Fallback & Request Status

#### Step 7.1: Report Fallback Event:

```cpp
mmSmartStreaming.reportFallbackEvent("NEW_FALLBACK_STREAM_URL", "FALLBACK_DESCRIPTION");
```

#### Step 7.2: Report Request Status:

Report `FAILED` or `CANCELLED` requests for the following request types:

* PIR
* MANIFEST
* AUDIO\_CHUNK
* VIDEO\_CHUNK
* DRM
* SUBTITLE

```cpp
map<string, string> requestInfoMap;
requestInfoMap["ID"] = "ID";
requestInfoMap["URL"] = "URL";
requestInfoMap["ERROR"] = "ERROR";
requestInfoMap["DESC"] = "DESC";

mmSmartStreaming.reportRequestStatus(RequestStatus::CANCELLED, "REQUEST_TYPE", requestInfoMap);

Enum: RequestStatus
- FAILED
- CANCELLED
```

### Step 8: Ad Data & Ad Events

#### Step 8.1: Report Ad Break Start & End:

```cpp
mmSmartStreaming.reportAdBreakStart();
mmSmartStreaming.reportAdBreakEnd();
```

#### Step 8.2: Report Ad Data, Ad Start & End:

```cpp
MMAdInfo adInfo;
adInfo.adTitle = "AD_TITLE";
adInfo.adId = "AD_ID";
adInfo.adCreativeId = "AD_CREATIVE_ID";
adInfo.adCreativeType = "AD_CREATIVE_TYPE";
adInfo.adClient = "AD_CLIENT"
adInfo.adPosition = "AD_POSITION";                    //pre, mid, post
adInfo.adServer = "AD_SERVER";
adInfo.adResolution = "AD_RESOLUTION";
adInfo.adUrl = "AD_URL";
adInfo.adDuration = <ad_duration>;                    //Integer Value in Milli Seconds
adInfo.adPodIndex = <pod_index>;                      //Integer Value
adInfo.adPositionInPod = <ad_position_in_pod>;        //Integer Value
adInfo.adPodLendth = <pod_length>;                    //Integer Value
adInfo.isBumper = <is_bumper>;                        //Boolean Value

mmSmartStreaming.reportAdInfo(mmadInfo);

mmSmartStreaming.reportAdStart();
mmSmartStreaming.reportAdEnd();
```

<details>

<summary>Ad Info Fields &#x26; Description</summary>

<table data-header-hidden><thead><tr><th width="204.65234375">Field</th><th width="114.8046875">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>adInfo.adTitle</td><td>String</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adInfo.adId</td><td>String</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adInfo.adCreativeId</td><td>String</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adInfo.adCreativeType</td><td>String</td><td>The format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>adInfo.adClient</td><td>String</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adInfo.adPosition</td><td>String</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adInfo.adServer</td><td>String</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adInfo.adResolution</td><td>String</td><td>The resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>adInfo.adUrl</td><td>String</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adInfo.adDuration</td><td>Integer</td><td>The total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>adInfo.adPodIndex</td><td>Integer</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adInfo.adPositionInPod</td><td>Integer</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>adInfo.adPodLendth</td><td>Integer</td><td>The total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr><tr><td>adInfo.isBumper</td><td>Boolean</td><td>A boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr></tbody></table>

</details>

#### Step 8.3: Report Ad Buffering:

Use Ad Buffering APIs to report any buffering that occurs during ad playback. For any buffering event, either content buffering or ad buffering should be reported, but not both.

```cpp
mmSmartStreaming.reportAdBufferingStrated();
mmSmartStreaming.reportAdBufferingCompleted();
```

### Step 9: Custom Events

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```cpp
mmSmartStreaming.reportCustomEvent("EVENT_NAME", "EVENT_VALUE");
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 35 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

### Step 10: Offline Storage Support

The SDK can persist analytics payloads to local storage when they cannot be delivered to the backend. Payloads are stored when network calls are disabled, when SDK registration fails (e.g., no internet), or when a payload fails to send. Stored payloads are appended as one JSON object per line to:

```
<OFFLINE_STORAGE_PATH>/mediamelon-offline-data.txt
```

#### Step 10.1: Set Offline Storage Path:

Folder where the offline data file is created. The SDK creates the folder if it does not exist.

`MMSmartStreaming::setOfflineStoragePath("OFFLINE_STORAGE_PATH");`&#x20;

#### Step 10.2: Set Offline Storage Maximum Size:

Maximum size of the offline data file. Default is 50 MB. Once the limit is reached, new payloads are dropped.\
\
`MMSmartStreaming::setOfflineStorageMaxSizeBytes(<max_size_bytes>); //50 MB Default`&#x20;

#### Step 10.3: Enable/Disable Network Calls:

Set it to `true` (default) to send payloads over the network, and to `false` to disable all SDK network activity and write payloads to the offline file instead. \
\
`MMSmartStreaming::setNetworkCallsEnabled(<network_calls_enabled>);`&#x20;

#### Release Notes

<details>

<summary>Current Release</summary>

**v3.4.0-OFS &#x20;**<sup><sub>**`Jul 08, 2026`**<sub></sup>

* Added offline storage support - analytics payloads that cannot be delivered are now persisted to a local file.
* Introduced `setNetworkCallsEnabled` to disable all SDK network activity and route payloads directly to offline storage.
* Sessions now continue when SDK registration fails - payloads are captured to offline storage.<br>

</details>

***

<details>

<summary>Previous Releases</summary>

</details>


# React Native


# MediaMelon React Native Video SDK Integration Document

This guide provides detailed instructions on integrating the React Native Video MediaMelon SDK with React Native Video v6.19 player

**Step 1:** [Install MediaMelon React Native SDK](#step-1-install-mediamelon-react-native-sdk)

**Step 2:** [Import SDK Package](#step-2-import-sdk-package)

**Step 3:** [Register and Initialise SDK](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 4:** [Custom Adapter](#step-4-custom-adapter)

[Release Notes](#release-notes)

### Step 1: Install MediaMelon React Native SDK&#x20;

`$REACT_NATIVE_PROJECT = {ReactNativeVideo - v6.19.0}`

The SDK files should be added to the build environment

**Using NPM:**

1. Use this command in your terminal:-

```gradle
npm i mediamelon-js-react-native-sdk@1.5.1
```

**Using JS file:**&#x20;

* Copy `mmsmartstreaming_reactnative.min.js` provided in the release package to the React native project. Example  `$REACT_NATIVE_PROJECT/mmsmartstreaming_reactnative.min.js`

### Step 2: Import SDK Package

`$REACT_NATIVE_PROJECT/App.js`

**Using NPM:**

```javascript
import {MMReactNativeVideoSDK, MMCustomAdapter, MMPlayerState} from 'mediamelon-js-react-native-sdk';
```

**Using JS File:**&#x20;

```javascript
import {MMReactNativeVideoSDK, MMCustomAdapter, MMPlayerState} from './mmsmartstreaming_reactnative.min.js';
```

### Step 3: Register and Initialise SDK <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

Wrap your `Video` component with the `MMReactNativeVideoSDK`.

```javascript
const MMPlayer = MMReactNativeVideoSDK(Video);

<MMPlayer
    source={{ uri: 'STREAM_URL' }}
    ...
    mmOptions={{
      register: {
        customerId: 'CUSTOMER_ID',      
        subscriberId: 'SUBSCRIBER_ID',   
        subscriberType: 'SUBSCRIBER_TYPE',
        subscriberTag:'SUBSCRIBER_TAG',  
        hashSubscriberId: false,
        playerName: 'PLAYER_NAME',
        playerBrand:"PLAYER_BRAND",
        playerModel:"PLAYER_MODEL",
        playerVersion:'PLAYER_VERSION',
        basePlayerName: "BASE_PLAYER_NAME",
        basePlayerVersion: "BASE_PLAYER_VERSION",
        domainName: 'DOMAIN_NAME',
        applicationName: 'APP_NAME',            
        applicationVersion: 'APP_VERSION',      
        deviceMarketingName:'DEVICE_MARKETING_NAME'
      },
      contentMetadata: {
        assetName:'ASSET_NAME',
        assetId:"ASSET_ID",
        videoId:"VIDEO_ID",
        contentType:'CONTENT_TYPE',
        genre:'GENRE',
        drmProtection:'DRM_PROTECTION',
        episodeNumber:'EPISODE_NUMBER',
        season:'SEASON',
        seriesTitle:'SERIES_TITLE',                  
        isLive: false,
      },
      streamInfo:{
        mediaType: 'MEDIA_TYPE',
        streamFormat: 'STREAM_FORMAT',
        sourceType: 'SOURCE_TYPE'
      },
      customTags:{
        "KEY1": "VALUE_STRING1",
        "KEY2": "VALUE_STRING2"
      },
      experimentName: "EXPERIMENT_NAME",
      subPropertyId: "SUB_PROPERTY_ID",
      viewSessionId: "VIEW_SESSION_ID",
      appSessionId: "APP_SESSION_ID",
      deviceId: "DEVICE_ID",
      cdn: "CDN",
      encodingService: "ENCODING_SERVICE",
      enableLogTrace: false
    }}
/>
```

{% hint style="info" %}

* `isLive`: Set to `true` for live video stream and to `false` for the VOD stream.
* `hashSubscriberId`: Set it to `true` to hash the subscriber ID, and to `false` to process the subscriber ID without hashing.
  {% endhint %}

### Step 4: Custom Adapter

#### Step 4.1: Report Player State

Use the Custom Adapter to report player state changes during video playback.

The adapter exposes the method reportPlayerState(state) and accepts an enum value from MMPlayerState.

**Player State Mapping**

* PLAYING → Reported when playback starts or resumes.
* PAUSED → Reported when playback is paused.
* STOPPED → Reported when playback ends or the user exits playback.

```javascript
const mmAdapter = MMCustomAdapter();

mmAdapter.reportPlayerState(MMPlayerState.PLAYING);

Enum: MMPlayerState
- PLAYING
- PAUSED
- STOPPED
```

#### Step 4.2: Report Custom Metadata

Use this method to report any additional metadata that doesn’t fall under predefined fields. This allows flexibility to send custom business-specific or platform-specific information to the SDK. This is the same as `customTags` in the `contentMetadata` object.

```javascript
mmAdapter.reportCustomMetadata("KEY", "VALUE");
```

#### Step 4.3: Update Asset Info

If Asset Information needs to be updated dynamically during the live session without re-initiating the player, then the `updateAssetInfo` API can be used to update the new AssetInfo

{% hint style="info" %}
**Note**

* This API must be called for updating asset info for the live streams only&#x20;
* This API must be called after the Player has started the playback of the live stream&#x20;
* New Asset Info Object will override the previous values. Hence, set all the fields that are required every time calling this API, including all **Custom Tags.**
  {% endhint %}

```javascript
// Create a new assetInfo object with the values need to be updated
var newAssetInfo =  { 
     "assetName": "ASSET_NAME",
     "assetId": "ASSET_ID",
     "videoId": "VIDEO_ID",
     "contentType": "CONTENT_TYPE",
     "drmProtection": "DRM_PROTECTION",
     "episodeNumber": "EPISODE_NUMBER",
     "season": "SEASON",
     "seriesTitle": "SERIES_TITLE",
     "customTags":{
         "key1": "VALUE1",
         "key2": "VALUE2"
     }          
}

// Update the new assetInfo
mmAdapter.updateAssetInfo(newAssetInfo);
```

### Release Notes:

<details>

<summary>Current Release</summary>

#### v1.5.1  <sup><sub>**`July 20, 2026`**<sub></sup>

* Updated SDK to allow multiple registration configs reporting to update the customer ID.&#x20;

#### v1.5.0  <sup><sub>**`May 07, 2026`**<sub></sup>

* Added support for React Native Video Player `v6.19.0`
* Introduced tracking for `buffering` and `seek` events
* Enhanced `rendition` tracking with `bitrate` and `codec` data
* Added `Seek duration` metric
* Introduced new metadata fields: `App Session ID` and `Encoding Service`
* Added `CDN_CHANGE` event support

</details>


# React Native Video v6.4.2 with Mediamelon SDK

This guide provides detailed instructions on integrating the React Native Video MediaMelon SDK with React Native Video v6.4.2 player

**Step 1:** [Prerequisites](#step-1-prerequisites)

**Step 2:** [Set up the build environment](#step-2-set-up-the-build-environment)

**Step 3:** [Import Packages](#step-3-import-packages)

**Step 4:** [Register and Initialise SDK](#step-3-initialize-session-and-report-user-intent-to-playback)

**Step 5:** [Variables and Description](#step-5-variables-and-description)

### Step 1: Prerequisites

* React native video - v6.4.2 application.
* MediaMelon SmartSight SDK `mm_react_native6_sdk.min.js`   file is necessary.

### Step 2: Set up the build environment&#x20;

`$REACT_NATIVE_PROJECT = {ReactNativeVideo - v6.4.2}`

The SDK files should be added to the build environment

**Using NPM:**

1. Use this command in your terminal:-

```gradle
npm i mediamelon-reactnative-video@2.0.0
```

**Using JS file:**&#x20;

* Copy `mm_react_native_sdk.js` provided in the release package to the React native project. Example  `$REACT_NATIVE_PROJECT/mm_react_native6_sdk.min.js`&#x20;

### Step 3: Import Packages

`$REACT_NATIVE_PROJECT/App.js`

**Using NPM:**

```
import mmReactNativeVideo from 'mediamelon-reactnative-video';
```

**Using JS file:**&#x20;

```javascript
import mmReactNativeVideo from './mm_react_native6_sdk.min.js';
```

### Step 4: Register and Initialise SDK <a href="#step-3-initialize-session-and-report-user-intent-to-playback" id="step-3-initialize-session-and-report-user-intent-to-playback"></a>

The SDK must be initialised at the start of each video session. Initialisation includes setting the application context, initialising the playback session, and indicating the intent for playback with the SDK.

{% hint style="info" %}
The `enableLogTrace` feature should be enabled for testing during the integration process. Set this to False before releasing the player to production.
{% endhint %}

{% hint style="info" %}
CUSTOMER\_ID is your MediaMelon assigned Customer ID. If you do not know your Customer ID contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

Wrap your `Video` component with the `mmReactNativeVideo`.

```javascript
const MMPlayer = mmReactNativeVideo(Video);

<MMPlayer
        source={{ uri: 'STREAM_URL' }} 
        style={styles.video} 
        controls={true}  
        resizeMode="contain"
        onLoad = {"HANDEL_ON_LOAD"} // 
        mmOptions={{
          data: {
           application_name: 'APP_NAME',            // (required) the name of your application
           application_version: 'APP_VERSION',      // the version of your application (optional, but encouraged)
           player_name: 'PLAYER_NAME',
           customer_id: 'CUSTOMER_ID',             // (required)
           subscriber_id: 'SUBSCRIBER_ID',
           domain_name: 'DOMAIN_NAME',
           subscriber_type: 'SUBSCRIBER_TYPE',
           subscriber_tag:'SUBSCRIBER_TAG',
           player_brand:"PLAYER_BRAND",
           player_model:"PLAYER_MODEL",
           player_version:'PLAYER_VERSION',
           device_marketing_name:'DEVICE_MARKETING_NAME'
          },
          content_metadata: {                  //optional
            asset_name:'ASSET_NAME',
            asset_id:"ASSET_ID",
            video_Id:"VIDEO_ID",
            content_type:'CONTENT_TYPE',
            genre:'GENRE',
            drm_protection:'DRM_PROTECTION',
            episode_number:'EPISODE_NUMBER',
            season:'SEASON',
            series_title:'SERIES_TITLE',
            video_type:'VIDEO_TYPE',
            is_live: false,
          },
          custom_tags:{                       // optional
            "KEY1": "VALUE_STRING1",
            "KEY2": "VALUE_STRING2"
          },
          enableLogTrace:true,
        }}
/>
```

### Step 5: Variables and Description

<table data-header-hidden><thead><tr><th width="227.33333333333331">Variable</th><th width="359">Description</th><th></th></tr></thead><tbody><tr><td>Variable</td><td>Description</td><td>Optional/Mandatory</td></tr><tr><td>PLAYER_NAME</td><td>String containing the Player Name.</td><td>Mandatory</td></tr><tr><td>CUSTOMER_ID</td><td>String containing your MediaMelon-assigned Customer ID.</td><td>Mandatory</td></tr><tr><td>SUBSCRIBER_ID</td><td>String containing your Subscriber’s ID.</td><td>Mandatory</td></tr><tr><td>DOMAIN_NAME</td><td>String containing your section of your subscriber or assets.</td><td>Mandatory</td></tr><tr><td>SUBSCRIBER_TYPE</td><td>String containing the Subscriber Type (e.g. “Free”, “Paid”).</td><td>Optional</td></tr><tr><td>SUBSCRIBER_TAG</td><td>String containing an additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field.</td><td>Optional</td></tr><tr><td>ASSET_ID</td><td>String containing Asset Id.</td><td>Mandatory</td></tr><tr><td>ASSET_NAME</td><td>String containing Asset Name.</td><td>Mandatory</td></tr><tr><td>VIDEO_ID</td><td>String containing your video’s ID.</td><td>Mandatory</td></tr><tr><td>CONTENT_TYPE</td><td>String containing type of the Content. For example - "Movie", "Special", "Clip", "Scene" "Episode".</td><td>Mandatory</td></tr><tr><td>GENRE</td><td>String containing Genre of the content. For example - "Comedy", "Horror".</td><td>Optional</td></tr><tr><td>DRM_PROTECTION</td><td>Widevine, Fairplay, Playready etc. Unknown means content is protected, but protection type is unknown. For clear contents, do not set this field</td><td>Optional</td></tr><tr><td>EPISODE_NUMBER</td><td>String containing sequence number of the Episode.</td><td>Optional</td></tr><tr><td>SEASON</td><td>String containing the Season. For example - "Season1".</td><td>Optional</td></tr><tr><td>SERIES_TITLE</td><td>String containing Title of the Series.</td><td>Optional</td></tr><tr><td>VIDEO_TYPE</td><td>String containing Video Type. For example - "LIVE", "VOD".</td><td>Optional</td></tr><tr><td>PLAYER_BRAND</td><td>String containing Player Brand (e.g. “Exo Player”).</td><td>Mandatory</td></tr><tr><td>PLAYER_MODEL</td><td>String containing Player Model. For example - This could be a variant of player. Say name of third party player used by organisation. Or any human readable name of the player.</td><td>Mandatory</td></tr><tr><td>PLAYER_VERSION</td><td>String containing Player Version.</td><td>Mandatory</td></tr><tr><td>CUSTOM_METADATA</td><td>Extra custom metadata can be added here if required.</td><td>Optional</td></tr><tr><td><code>hashSubscriberId</code></td><td>To hash the subscriber Id set this boolean variable to <code>true</code>, else set it to <code>false</code>.</td><td>Optional</td></tr><tr><td><code>player</code></td><td>Player Object.</td><td>Mandatory</td></tr><tr><td><code>streamURL</code></td><td>Current playing content stream URL.</td><td>Mandatory</td></tr><tr><td><code>isLive</code></td><td>Set this boolean variable to <code>true</code> if the content is Live else set it to <code>false</code> for VOD content.</td><td>Optional</td></tr></tbody></table>


# Toast SDK

This guide is for integrating the MediaMelon Player SDK  with theToast Cordova Plugin for Smart TV platforms.

The following platforms are supported via the Toast Plugin:

1. sectv-orsay \[Samsung]
2. sectv-tizen \[Samsung]
3. &#x20;tv-webos \[LG]

For the rest of this guide, the sample media application from the link below is taken as the reference media app.

&#x20;Github link for media app used for integration :

{% hint style="info" %}
&#x20;<https://github.com/Samsung/cordova-plugin-toast/tree/master/sample/media>
{% endhint %}

Please note that all the code changes that need to be made are shown below and indicated by the tags `MediaMelon Start` and `MediaMelon End`. Snippets of surrounding code is also provided to act as placeholders and to help you find the right place to insert MediaMelon’s integration code.

![](https://195121302-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MdvF6AnMWuH7LB6LAsd%2F-Mk1FZUSqJb1mszsJlSI%2F-Mk1FxXgf29HPnCmm3bD%2FMM.jpg?alt=media\&token=7bbc7424-9fbd-4cf9-8bf7-48e0a6102342)

Fig 1 describes how the Toast plugin integrates and interacts with the underlying SmartTV platforms (Samsung or LG). Toast is an abstraction layer that makes it simple to write applications for Samsung and LG SmartTVs using a common set of APIs.

The top-most layer in Fig 1 shows the application layer where you can write your apps using Toast’s APIs. In this layer, MediaMelon Player SDK is integrated making it a single integration step irrespective of the underlying SmartTV platform.

In the middle layer, there are platform-specific Toast files which the top-level APIs interact with. Here, certain MediaMelon-specific changes are needed to propagate events and metrics that are not passed-through by Toast.

The final level is the platform level (specific to each SmartTV platform) and this is un-touched by Media Melon’s SmartSight Player SDK integration.

## Step-by-Step integration guide. <a href="#step-by-step-integration-guide." id="step-by-step-integration-guide."></a>

1. Github links for working with Cordova Toast Plugin :

[ GitHub - Samsung/cordova-plugin-toast: Cordova plugin that provides TV Specific functionalities.](https://github.com/Samsung/cordova-plugin-toast)

&#x20;Getting- started scripts for automatic/quick setup:

&#x20;<https://github.com/Samsung/cordova-plugin-toast/tree/master/script>

2\. The following changes/additions are to be made in order to integrate with MediaMelon SmartSight Player SDK:

&#x20;**At the application level:**

&#x20;1\) www/index.html

&#x20;2\) js/media.js

&#x20;**At the Toast level**

&#x20;1\) toast.js \[**sectv-tizen platform only**]

## Application-level changes

&#x20;→ **www/index.html:**

&#x20;Include \<mmsmartstreaming-toast-sdk.js> in the index.html. We use a wrapper to load the SDK -  so that, if there is an error in loading the SDK, the application will not be affected and playback will continue.

```javascript
......
<body>
        <div class="app">
            <h1>The sample app for Media</h1>
   ......
   ...... 
// MediaMelon Start
<script type="text/javascript">

            function mmsdkLoaderScript(scriptUrl) {
                    return new Promise(function (res, rej) {
                            var script = document.createElement('script');
                            script.src = scriptUrl;
                            script.type = 'text/javascript';
                            script.onError = rej;
                            script.async = true;
                            script.onload = res;
                            script.addEventListener('error', rej);
                            script.addEventListener('load', res);
                            document.head.appendChild(script);
                        });
            }

            var event = mmsdkLoaderScript("mmsmartstreaming-toast-sdk.min.js").then(function () {
            console.log("MediaMelon Toast SDK loaded");
            })["catch"](function () {
            console.log("MediaMelon Toast SDK error");
            });
</script>
// MediaMelon End
	
        <script type="text/javascript" src="js/init.js"></script>
        <script type="text/javascript" src="js/media.js"></script>
        <script type="text/javascript" src="js/index.js"></script>
    <script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="toast.js"></script>
</body>
```

→**js/media.js:**

Add the toastMMPlugin variable

```javascript
.....
var jumpNum = 10000;
var fullResolution = ['0%', '0%', '100%', '100%'];
var partialResolution = ['25%', '25%', '50%', '50%'];

// MediaMelon Start
var toastMMPlugin = undefined;
// MediaMelon End
.....
```

After the player instance has been created, create a new Plugin object, register, and report player information as shown below:

```javascript
function playMedia() {
    .....
    .....
    document.body.appendChild(bgContainer);

    // MediaMelon Start
    toastMMPlugin = new ToastJsMMSSIntgr();
    if(toastMMPlugin.getRegistrationStatus() === false){
        toastMMPlugin.registerMMSmartStreaming("<player_name>", "<customer_id>", "<subscriber_id>", "<domain_name>", "<subscriber_type>" , "<subscriber_tag>");
        toastMMPlugin.reportAppInfo("<app_name>", "<app_sdk_version>");
        toastMMPlugin.setDeviceInfo("<device_marketing_name>");
        toastMMPlugin.reportPlayerInfo("<player_brand>", "<player_model>", "<player_version>");
    }
    var mediaSourceURL = 'http://media.w3.org/2010/05/sintel/trailer.mp4'';
    // MediaMelon End
    
    media = toast.Media.getInstance();
    media.open(mediaSourceURL);
```

You can also provide the assetID, assetName, videoID, and custom tags as shown below while setting source information. Please use the mmVideoAssetInfo structure to provide this information.

And then initialize as shown below:

```javascript
.....
 addControlBar();
    
    // MediaMelon Start
    var mmVideoAssetInfo = {
                    "assetName":"ASSETNAME_STRING",
                    "assetId": "ASSETID_STRING",
                    "videoId": "VIDEOID_STRING",
                    "contentType": "Genre of the content (episode, movies, etc)",
		    "drmProtection": "DRM type used (Widevine, Playready, etc)",
	            "episodeNumber": "Episode Number, e.g., 2 or E2",
		    "season":"Season number of the Series Title, e.g, 2 or S2",
		    "seriesTitle": "Series Title",
                    "customTags":{
                        "key1": "VALUE_STRING1",
                        "key2": "VALUE_STRING2",
                        "key3": "VALUE_STRING3"
                    }
                  }

    toastMMPlugin.initialize(mediaSourceURL, mmVideoAssetInfo);
    // MediaMelon End
    
    media.setListener({
        onevent: function(evt) {
        
        // MediaMelon Start
        toastMMPlugin.onToastEvent(evt);
        // MediaMelon End
         
            switch(evt.type) {
                case 'STATE':
.....
```

&#x20;Add the call for reporting error to the Toast Plugin and just before media.play(), call the `reportUserInitiatedPlayback()`api.

```javascript
.....
        },
        onerror: function (err) {
            console.error('MediaError is occured: ' + JSON.stringify(err));
            document.getElementById('log').innerHTML = 'MediaError is occured';
            // MediaMelon Start
            toastMMPlugin.onToastError(err);
            // MediaMelon End
        }
    });
    
    // MediaMelon Start
    toastMMPlugin.reportUserInitiatedPlayback();
    // MediaMelon End
    media.play();
    //You don't have to call setScreenSaver Method. It is configurated by toast.avplay.
}
.....
```

## Toast-level changes

→ **toast.js:**

Please make the following changes toast.js for supporting bitrate change notifications. (**Applicable for sectv-tizen platform only.)**

Add the Media Events:

```javascript
.....
Media.EVENT_SUBTITLE = 'SUBTITLE';
Media.EVENT_ENDED = 'ENDED';

// MediaMelon Start
Media.EVENT_BITRATE_CHANGE = 'BITRATE_CHANGE';
Media.EVENT_RESOLUTION_CHANGE = 'RESOLUTION_CHANGE';
Media.EVENT_TRACKINFO_CHANGE = 'TRACKINFO_CHANGE';
// MediaMelon End


.....
```

Add the respective Media Event handling in Media.mediaEvent() function:

```javascript
.....
       case Media.EVENT_SUBTITLE :
            media._mediaEventCallBack.onevent && media._mediaEventCallBack.onevent(value);
            break;
            
        // MediaMelon Start
        case Media.EVENT_BITRATE_CHANGE :
            media._mediaEventCallBack.onevent && media._mediaEventCallBack.onevent(value);
            break;
        case Media.EVENT_RESOLUTION_CHANGE :
            media._mediaEventCallBack.onevent && media._mediaEventCallBack.onevent(value);
            break;
        case Media.EVENT_TRACKINFO_CHANGE :
            media._mediaEventCallBack.onevent && media._mediaEventCallBack.onevent(value);
            break;
        // MediaMelon End
        
        case Media.EVENT_ENDED :
            media.stop();
.....
 

Add the following code in the getMediaEventValue() function:


.....
    case Media._MEDIA_ERROR :
        reval = {
            'type': type,
            'data': data
        };
        break;
        
    // MediaMelon Start
    case Media.EVENT_BITRATE_CHANGE :
        reval = {
            'type': type,
            'data': {
                'currentBitrate': data
            }
        };
        break;
    case Media.EVENT_RESOLUTION_CHANGE :
        reval = {
            'type': type,
            'data': {
                'currentResolution': data
            }
        };
        break;
    case Media.EVENT_TRACKINFO_CHANGE :
        reval = {
            'type': type,
            'data': {
                'trackInfos': data
            }
        };
        break;
    // MediaMelon End
    
    }
    return reval;
}
.....
```

Add the following code in the open: function(successCallback, errorCallback, args) function:

```javascript
.....
  oncurrentplaytime: function(currentTime) {
                    if(currentMediaState !== Media.STATE_PLAYING && currentTime > 0) {
                        Media.mediaEvent(id,getMediaEventValue(Media.EVENT_STATE,Media.STATE_PLAYING));
                    }
                    console.log('media::Current playtime: ' + currentTime);
                    Media.mediaEvent(id,getMediaEventValue(Media.EVENT_POSITION,currentTime));
                },
                onevent: function(eventType, eventData) {
                    console.log('media::Event type error: ' + eventType + ', eventData: ' + eventData);
                    
                    // MediaMelon Start
                    if (eventType === 'PLAYER_MSG_BITRATE_CHANGE') {
                        let currentBitrate = eventData.split(':')[1];
            		        console.log("MMSS Bitrate: " + currentBitrate);
                        Media.mediaEvent(id,getMediaEventValue(Media.EVENT_BITRATE_CHANGE,currentBitrate));
                    }
                    .....
                    // MediaMelon End
                    
                },
                onerror: function(errorData) {
                    console.log('media::Event type error: ' + errorData);
                    Media.mediaEvent(id,getMediaEventValue(Media._MEDIA_ERROR,errorData));
                }
              .....
              .....
              .....
       function playMedia() {
            webapis.avplay.prepareAsync(function() {
              .....
              .....
                        }
                    }
                }
                
                // MediaMelon Start
                var totalTracks = webapis.avplay.getStreamingProperty("AVAILABLE_BITRATE");
                var bitrate_arr = totalTracks.split(":");
                var trackInfo = [];
                for(var i=0 ; i < bitrate_arr.length; i++){
                    trackInfo.push({'bitrate': bitrate_arr[i]});
                }                
                Media.mediaEvent(id,getMediaEventValue(Media.EVENT_TRACKINFO_CHANGE, trackInfo));
                // MediaMelon End
                
                Media.mediaEvent(id, getMediaEventValue(Media.EVENT_STATE, Media.STATE_PLAYING));
                var duration = webapis.avplay.getDuration();
                .....
                .....
```


# C++ SDK QoE Ads

This guide is for integrating the C++-based MediaMelon Custom Player SDK

### **Step 1:** MediaMelon SDK Files <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

Add and import the required MediaMelon SDK header files provided in the release notes

```cpp
#include "cpp_mmsmartstreaming.h"
```

### **Step 2: Register and Initialise** the MediaMelon Player SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

{% hint style="info" %}
\<customer\_id> as your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](http://40mediamelon.com/)
{% endhint %}

Register the MediaMelon SDK and report the player information and device information as shown below:

```cpp
string component = "component";
string deviceOS = "Linux";

MMSmartStreaming::registerMMSmartStreaming("PLAYER_NAME", "CUSTOMER_ID", component, "SUBSCRIBER_ID","DOMAIN_NAME","SUBSCRIBER_TYPE", "SUBSCRIBER_TAG");
MMSmartStreaming::reportPlayerInfo("PLAYER_BRAND", "PLAYER_MODEL", "PLAYER_VERSION");
MMSmartStreaming::reportDeviceInfo("DEVICE_BRAND", "DEVICE_MODEL", deviceOS,"DEVICE_OS_VERSION", "TELECOM_OPERATOR",<screenWidth:int>,<screenHeight:int>,"DEVICE_TYPE");

//Set content metadata of the video and initialise the session as shown below
MMContentMetadata contentMetadata;
contentMetadata.setAssetInfo("ASSET_ID", "ASSET_NAME", "VIDEO_ID");
contentMetadata.setContentType("CONTENT_TYPE");
contentMetadata.setDrmProtection("DRM_PROTECTION");
contentMetadata.setEpisodeNumber("EPISODE_NUMBER");
contentMetadata.setGenre("GENRE");
contentMetadata.setSeason("SEASON");
contentMetadata.setSeriesTitle("SERIES_TITLE");

MMSmartStreaming::getInstance().initializeSession(QBRModeDisabled,"MEDIA_URL","META_URL", contentMetadata, NULL);
```

### Step 3: Report Custom, Network & Presentation Information

This information should be reported before the video starts playing.

#### Custom Metadata:

Reports custom metadata, in the form of a key-value pair, to analytics.

```cpp
MMSmartStreaming::getInstance().reportCustomMetadata("KEY1", "VALUE1");
MMSmartStreaming::getInstance().reportCustomMetadata("KEY2", "VALUE2");
```

#### Network Type:

Reports the communications network type to analytics.

```cpp
MMSmartStreaming::getInstance().reportNetworkType(<networkType:MMConnectionInfo>);
```

Enum values and their description for the `MMConnectionInfo`  are as below;

<table><thead><tr><th width="312">Enum Value</th><th>Description</th></tr></thead><tbody><tr><td>MMConnectionInfo::Cellular</td><td>Connection type is cellular (generic). If user explicitly knows the kind of connection, 2G or 3G for example, then they should use explicit enum value corresponding to that connection type.</td></tr><tr><td>MMConnectionInfo::Cellular_2G</td><td>Connection type is 2G cellular.</td></tr><tr><td>MMConnectionInfo::Cellular_3G</td><td>Connection type is 3G cellular.</td></tr><tr><td>MMConnectionInfo::Cellular_4G</td><td>Connection type is 4G cellular.</td></tr><tr><td>MMConnectionInfo::Cellular_LTE</td><td>Connection type is LTE cellular.</td></tr><tr><td>MMConnectionInfo::Cellular_5G</td><td>Connection type is 5G cellular.</td></tr><tr><td>MMConnectionInfo::NotReachable</td><td>Connection non reachable.</td></tr><tr><td>MMConnectionInfo::Wifi</td><td>Connection type is WiFi.</td></tr><tr><td>MMConnectionInfo::WiredNetwork</td><td>Connection type is wired.</td></tr></tbody></table>

#### Presentation Information:

Reports the available representations of the video that the player can present.

```cpp
MMPresentationInfo presentationInfo;
presentationInfo.isLive = false;        //video type (true for live video and fasle for VOD)
presentationInfo.duration = 100*1000;   //video duration in milliseconds

MMRepresentation *rep1 = new MMRepresentation(trackIndex:int>,<bitrate:int>,<width:int>,<height:int>,"VCODEC,ACODEC");
presentationInfo.addRepresentation(rep1);
MMRepresentation *rep2 = new MMRepresentation(trackIndex:int>,<bitrate:int>,<width:int>,<height:int>,"VCODEC,ACODEC");
presentationInfo.addRepresentation(rep2);

MMSmartStreaming::getInstance().setPresentationInformation(presentationInfo);
```

### Step 4: Report Player State & Actions

#### Playback Initiation:

Reports that user initiated the playback session. This should be called at different instants depending on the mode of operation of player. In Auto Play Mode, should be the called when payer is fed with the manifest URL for playback In non-Auto Play Mode, should be called when the user presses the play button on the player.

```cpp
MMSmartStreamingSDK::MMSmartStreaming::getInstance().reportUserInitiatedPlayback();
```

#### Player State:

Reports the current player state to analytics.

```cpp
MMSmartStreaming::getInstance().reportPlayerState(<playerState:MMPlayerState>);
```

Enum values and their description for the `MMPlayerState`  are as below;

<table><thead><tr><th width="253">Enum value</th><th>Description</th></tr></thead><tbody><tr><td>MMPlayerState::PLAYING</td><td>Player is playing available content to the screen. Delays due to re-buffering are still considered PLAYING.</td></tr><tr><td>MMPlayerState::PAUSED</td><td>Player is paused</td></tr><tr><td>MMPlayerState::STOPPED</td><td>Playback is stopped, either due to user request or reaching the end of the content.</td></tr></tbody></table>

> **Note:** When the player enters the STOPPED state the current video session is terminated. Re-entering the PLAYING state will result in a new session being logged for the video. The most common reason for this occurring is when a video plays to the end and then the user seeks back to a point earlier in the video.

#### Playback Position:

Reports current playback position in media to analytics. This should be reported every two seconds if possible. Reported playback position should be in ***milliseconds***.

```cpp
MMSmartStreaming::getInstance().reportPlaybackPosition(<playbackPosition:int>);
```

#### **Seek Complete:**

Reports that a seek event is complete, with the new playback starting position in ***milliseconds***. This is the point from which playback will start after the seek.

```cpp
MMSmartStreaming::getInstance().reportPlayerSeekCompleted(<seekEndPosition:int>);
```

#### Buffering:

Reports the start and completion of the buffering.

```cpp
MMSmartStreaming::getInstance().reportBufferingStarted();
MMSmartStreaming::getInstance().reportBufferingCompleted();
```

#### **Error:**

Reports an error encountered during the playback. Playback position should be in ***milliseconds***.

```cpp
MMSmartStreaming::getInstance().reportError("ERROR_MESSAGE", <playbackPosition:int>);
```

#### Chunk Request:

Reports the encoded chunk bitrate when the current playing chunk bitrate is different from the previous chunk bitrate.

```cpp
MMChunkInformation mmChunkInfo;
mmChunkInfo.bitrate = <bitrate:int>; //encoded bitrate in bits per second
MMSmartStreaming::getInstance().reportChunkRequest(mmChunkInfo);
```

#### Download Rate:

Reports current download rate (rate at which chunk is downloaded) to analytics. This should be reported for every chunk download (if possible). If this value is not available on every chunk download, then last updated value with player should be reported every 2 seconds. Reported download rate should be in ***bits per second***.

```cpp
MMSmartStreaming::getInstance().reportDownloadRate(<downloadRate:int>);
```

#### Frame Loss:

Reports cumulative frame loss count to analytics. This is Cumulative count of frames lost in playback session.

```cpp
MMSmartStreaming::getInstance().reportFrameLoss(<frameLossCount:int>);
```

### Step 5: Report Advertisement Analytics

#### Ad Info:

Reports advertisement-related information before or at the time of ad start.

```cpp
MMSmartStreaming::getInstance().reportAdInfo(<adInfo:MMAdInfo>);
```

`MMAdInfo` properties and their respective data types are mentioned below:

<table><thead><tr><th width="210">Property</th><th width="119.33333333333331">Type</th><th>Description</th></tr></thead><tbody><tr><td>adTitle</td><td><code>string</code></td><td>Advertisement title</td></tr><tr><td>adId</td><td><code>string</code></td><td>Advertisement ID</td></tr><tr><td>adDuration</td><td><code>int</code></td><td>Length of the video ad (in milliseconds).</td></tr><tr><td>adClient</td><td><code>string</code></td><td>Client used to play the ad, eg: VAST.</td></tr><tr><td>adServer</td><td><code>string</code></td><td>Ad server (ex. DoubleClick, YuMe, AdTech, Brightroll, etc.)</td></tr><tr><td>adCreativeId</td><td><code>string</code></td><td>The creative ID of the ad.</td></tr><tr><td>adCreativeType</td><td><code>string</code></td><td>Ad MIME type.</td></tr><tr><td>adPodIndex</td><td><code>int</code></td><td>Index of the ad pod.</td></tr><tr><td>adPodLength</td><td><code>int</code></td><td>Length of Pod, starts from 0 if ad in not part of any pod.</td></tr><tr><td>adPodPosition</td><td><code>int</code></td><td>Position of ad in Pod, starts from 0.</td></tr><tr><td>adPosition</td><td><code>string</code></td><td>Position of the ad in the video playback; one of “pre”, “post” or “mid” that represents that the ad played before, after or during playback respectively.</td></tr><tr><td>adBitrate</td><td><code>int</code></td><td>Advertisement bitrate (bits per second).</td></tr><tr><td>adResolution</td><td><code>string</code></td><td>Advertisement video resolution.</td></tr><tr><td>adUrl</td><td><code>string</code></td><td>Tag represented by the ad.</td></tr><tr><td>isBumper</td><td><code>bool</code></td><td>Represents the ad is bumper or not.</td></tr></tbody></table>

#### Ad State:

Reports advertisement playback state.

```cpp
MMSmartStreaming::getInstance().reportAdState(<adState:MMAdState>);
```

Enum values and their description for the `MMAdState`  are as below;

<table><thead><tr><th width="326">Enum value</th><th>Description</th></tr></thead><tbody><tr><td>MMAdState::AD_REQUEST</td><td>Ad is requested [initial state]</td></tr><tr><td>MMAdState::AD_IMPRESSION</td><td>Ad impression happened before ad starts playing</td></tr><tr><td>MMAdState::AD_STARTED</td><td>Ad started playing</td></tr><tr><td>MMAdState::AD_FIRST_QUARTILE</td><td>Ad reached 25% of the ad duration</td></tr><tr><td>MMAdState::AD_MIDPOINT</td><td>Ad reached 50% of the ad duration</td></tr><tr><td>MMAdState::AD_THIRD_QUARTILE</td><td>Ad reached 75% of the ad duration</td></tr><tr><td>MMAdState::AD_COMPLETED</td><td>Ad completed play [terminal state]</td></tr><tr><td>MMAdState::AD_ENDED</td><td>Ad ended before reaching the completion point [terminal state]</td></tr><tr><td>MMAdState::AD_SKIPPED</td><td>Ad is skipped [terminal state]</td></tr><tr><td>MMAdState::AD_PAUSED</td><td>Ad is paused</td></tr><tr><td>MMAdState::AD_RESUMED</td><td>Ad playback session resumed</td></tr><tr><td>MMAdState::AD_BLOCKED</td><td>Ad is blocked [terminal state]</td></tr><tr><td>MMAdState::AD_ERROR</td><td>Unknown error prevented Ad play [terminal state]</td></tr><tr><td>MMAdState::AD_CLICKED</td><td>User clicks an ad to be redirected to its landing page</td></tr></tbody></table>

#### Ad Playback Time:

Reports current advertisement playback position. This should be reported every two seconds if possible. Reported playback position should be in ***milliseconds***.

```cpp
MMSmartStreaming::getInstance().reportAdPlaybackTime(<playbackPosition:int>);
```

#### Ad Error:

Reports error encountered during the advertisement playback. Playback position should be in ***milliseconds***.

```cpp
MMSmartStreaming::getInstance().reportAdError("AD_ERROR_MESSAGE", <playbackPosition:int>);
```

#### Ad Buffering:

Reports the start and completion of the advertisement buffering.

```cpp
MMSmartStreaming::getInstance().reportAdBufferingStarted();
MMSmartStreaming::getInstance().reportAdBufferingCompleted();
```


# Ad Integrations


# Google IMA

## Select your Platform&#x20;

<table data-view="cards"><thead><tr><th></th><th data-hidden></th><th data-hidden></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td></td><td></td><td></td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FmpvuqGMqXdrX1GHTroo5%2Fandroid.jpg?alt=media&amp;token=2eb88f81-2e11-40e8-94f4-76c4d1e46e87">android.jpg</a></td><td><a href="broken://pages/FhS4yRoZSMD4ax9oGYqJ">Broken link</a></td></tr><tr><td></td><td></td><td></td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FWs9rBEVl3uFILQiWaVnK%2Fios.png?alt=media&amp;token=cdc30883-6008-46b5-9876-cca6411d0a26">ios.png</a></td><td><a href="broken://pages/-MkLuklD34cq9z2-Cs_C">Broken link</a></td></tr><tr><td></td><td></td><td></td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2Fg7ZZmnBKkQc0SymuvkeC%2FJS.png?alt=media&amp;token=feb472be-0561-40d2-89e5-ef9b8c1e887f">JS.png</a></td><td><a href="/mediamelon/smartsight-player-sdk-integration/web">Web SDK</a></td></tr></tbody></table>


# FreeWheel


# ServerSide.AI

MediaMelon closely works with Nowtilus to support ad streaming measurement. The integration is seamless and our SDK detects all the events and metadata from Ads coming from Nowtilus and accurately reports them on the Dashboard.

### Select a platform to begin with your integration

<table data-view="cards"><thead><tr><th></th><th data-hidden></th><th data-hidden></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><mark style="color:blue;">Read More -></mark></td><td></td><td></td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FmpvuqGMqXdrX1GHTroo5%2Fandroid.jpg?alt=media&amp;token=2eb88f81-2e11-40e8-94f4-76c4d1e46e87">android.jpg</a></td><td><a href="https://docs.mediamelon.com/mediamelon-jio-ssai/mediamelon-player-sdk-android/exoplayer-sdk-with-nowtilus-ssai">Exoplayer SDK with Nowtilus SSAI</a></td></tr><tr><td><mark style="color:blue;">Read More -></mark></td><td></td><td></td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FZEsgSSWlV8Pp7kbZJmSh%2Fios-logo.png?alt=media&amp;token=0902070b-9b57-4a10-9200-97aa50438637">ios-logo.png</a></td><td><a href="https://docs.mediamelon.com/mediamelon-nowtilus-ssai/nowtilus-demo-app/nowtilus-ios-demo-app-documentation">Nowtilus IOS Demo App Documentation</a></td></tr><tr><td><mark style="color:blue;">Read More -></mark></td><td></td><td></td><td><a href="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2Fg7ZZmnBKkQc0SymuvkeC%2FJS.png?alt=media&amp;token=feb472be-0561-40d2-89e5-ef9b8c1e887f">JS.png</a></td><td><a href="https://docs.mediamelon.com/mediamelon-nowtilus-ssai/mediamelon-player-sdk-web/bitmovin-web-nowtilus-ssai">Bitmovin Web (Nowtilus SSAI)</a></td></tr></tbody></table>


# Android


# Android Custom SDK Performance Metrics

## **v1.2.11**

<details>

<summary><strong>CPU</strong></summary>

|                                                                                                                                         MediaMelon SDK Enabled                                                                                                                                        |                                                                                                                     MediaMelon SDK Disabled                                                                                                                    |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|                                                                                                                                                  10%                                                                                                                                                  |                                                                                                                               8%                                                                                                                               |
| <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FwdsoQbOB3N0TYo0zXmMC%2FScreenshot%202026-01-09%20at%2012.44.39%E2%80%AFPM.png?alt=media&amp;token=afc4c660-3e26-4c76-97a3-82b4dec22ac7" alt="" data-size="original"> | ![](https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2Fwf1QUjgiLBLSMURpqHwj%2FScreenshot%202026-01-09%20at%201.13.23%E2%80%AFPM.png?alt=media\&token=5eaee98c-2d50-487e-94a8-1fc2f6362090) |

</details>

<details>

<summary><strong>Memory</strong></summary>

**MediaMelon SDK Memory Footprint**\
Allocations: 320\
Deallocations: 10\
Total Count: 310\
Shallow Size: 21216\
Shallow Size Changed: 21216

<figure><img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FtsDvAtASnrmiOGPdcr87%2FMemoryProfile.png?alt=media&amp;token=a4d4afe3-4f1f-4f09-82dd-63f0f0a7cfc6" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary><strong>Device Used</strong></summary>

**Name:** Redmi A4

**Model:** 24116RNC1I

**RAM:** 4GB

**CPU:** Snapdragon 4s Gen2 (2GHz)

**OS:** Android 14

</details>

***


# Android Multiplayer Custom SDK Performance Metrics

## **v2.2.3**

<details>

<summary><strong>CPU</strong></summary>

|                                                                                                                                         MediaMelon SDK Enabled                                                                                                                                        |                                                                                                                                        MediaMelon SDK Disabled                                                                                                                                        |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|                                                                                                                                                   9%                                                                                                                                                  |                                                                                                                                                   7%                                                                                                                                                  |
| <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2F3KUJ2vXSNNTfMuODbY7M%2FScreenshot%202026-06-29%20at%2012.30.54%E2%80%AFPM.png?alt=media&amp;token=713d54f2-4464-4d72-8de8-7ab51c48f1be" alt="" data-size="original"> | <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FzX1JmM3yBEmpxk97xJ6o%2FScreenshot%202026-04-10%20at%2012.00.37%E2%80%AFPM.png?alt=media&amp;token=95b8df8e-2309-43b5-8bd2-7a45fb1ef592" alt="" data-size="original"> |

</details>

<details>

<summary>Memory</summary>

**MediaMelon SDK Memory Footprint**\
Allocations: 594\
Deallocations: 114\
Total Count: 480\
Shallow Size: 32488\
Shallow Size Changed: 32488

<figure><img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FJZJrNpOgOpA2J9qjS3xv%2FScreenshot%202026-06-29%20at%2012.46.34%E2%80%AFPM.png?alt=media&amp;token=c7d79ed1-b243-460b-8ed1-074db2e7e58e" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary>Device Used</summary>

**Name:** Redmi A4

**Model:** 24116RNC1I

**RAM:** 4GB

**CPU:** Snapdragon 4s Gen2 (2GHz)

**OS:** Android 14

</details>

## **v2.1.3**

{% hint style="info" %}
Following observations are done with multiple instance created&#x20;
{% endhint %}

<details>

<summary><strong>CPU</strong></summary>

|                                                                                                                                         MediaMelon SDK Enabled                                                                                                                                        |                                                                                                                                        MediaMelon SDK Disabled                                                                                                                                        |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|                                                                                                                                                  10%                                                                                                                                                  |                                                                                                                                                   7%                                                                                                                                                  |
| <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FO4NNHbueaeOeGAAWduhN%2FScreenshot%202026-04-10%20at%2011.12.18%E2%80%AFAM.png?alt=media&amp;token=d6353bff-17e5-4363-b538-81ecd86d3960" alt="" data-size="original"> | <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FzX1JmM3yBEmpxk97xJ6o%2FScreenshot%202026-04-10%20at%2012.00.37%E2%80%AFPM.png?alt=media&amp;token=95b8df8e-2309-43b5-8bd2-7a45fb1ef592" alt="" data-size="original"> |

</details>

<details>

<summary><strong>Memory</strong></summary>

**MediaMelon SDK Memory Footprint**\
Allocations: 541\
Deallocations: 134\
Total Count: 407\
Shallow Size: 26992\
Shallow Size Changed: 26992

<figure><img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FJaQxVI8BuNwnk3l10owJ%2FScreenshot%202026-04-10%20at%2011.15.48%E2%80%AFAM.png?alt=media&amp;token=dc316d5e-f0a3-40dc-99be-be269b4ab56a" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary><strong>Device Used</strong></summary>

**Name:** Redmi A4

**Model:** 24116RNC1I

**RAM:** 4GB

**CPU:** Snapdragon 4s Gen2 (2GHz)

**OS:** Android 14

</details>

***


# Apple


# Apple Custom SDK Performance Metrics

## **v2.16.0**

<details>

<summary><strong>CPU</strong></summary>

|                                                                                                                     MediaMelon SDK Enabled                                                                                                                     |                                                                                                                    MediaMelon SDK Disabled                                                                                                                   |
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|                                                                                                                              3-5%                                                                                                                              |                                                                                                                             3-4%                                                                                                                             |
| <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FxTeaxbLlZY9zS95dfTLA%2Fwith-MM-cpu.png?alt=media&amp;token=7aba5fee-fbbe-4b52-999c-e790b8886c78" alt="" data-size="original"> | <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FhKsiRgae9sPNH2vIPqOy%2Fno-MM-cpu.png?alt=media&amp;token=dbe813bf-f7ee-4ee4-80e8-94598475ff39" alt="" data-size="original"> |

</details>

<details>

<summary><strong>Memory</strong></summary>

|                                                                                                                       MediaMelon SDK Enabled                                                                                                                      |                                                                                                                     MediaMelon SDK Disabled                                                                                                                     |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|                                                                                                                              \~12 MB                                                                                                                              |                                                                                                                             \~11 MB                                                                                                                             |
| <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FOKvPOfeW5bOjuJnd6QW0%2Fwith-MM-memory.png?alt=media&amp;token=ed26e6b0-f783-46c5-b48d-13a32b86cf88" alt="" data-size="original"> | <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FGOGhScFS8yaKdnuH01Dk%2Fno-mm-memory.png?alt=media&amp;token=f3501932-937e-4099-9bbc-879cefa19712" alt="" data-size="original"> |

</details>

<details>

<summary><strong>Device Used</strong></summary>

**Name:** iPhone 14

**Model:** iPhone14,7

**CPU:** A15 Bionic Chip

**OS:** iOS 18

</details>

***


# Apple Custom Multi-Player SDK Performance Metrics

## **v3.1.0**

<details>

<summary><strong>CPU</strong></summary>

|                                                                                                                     MediaMelon SDK Enabled                                                                                                                     |                                                                                                                    MediaMelon SDK Disabled                                                                                                                   |
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|                                                                                                                              3-5%                                                                                                                              |                                                                                                                             3-4%                                                                                                                             |
| <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FxTeaxbLlZY9zS95dfTLA%2Fwith-MM-cpu.png?alt=media&amp;token=7aba5fee-fbbe-4b52-999c-e790b8886c78" alt="" data-size="original"> | <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FhKsiRgae9sPNH2vIPqOy%2Fno-MM-cpu.png?alt=media&amp;token=dbe813bf-f7ee-4ee4-80e8-94598475ff39" alt="" data-size="original"> |

</details>

<details>

<summary><strong>Memory</strong></summary>

|                                                                                                                       MediaMelon SDK Enabled                                                                                                                      |                                                                                                                     MediaMelon SDK Disabled                                                                                                                     |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|                                                                                                                              \~12 MB                                                                                                                              |                                                                                                                             \~11 MB                                                                                                                             |
| <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FOKvPOfeW5bOjuJnd6QW0%2Fwith-MM-memory.png?alt=media&amp;token=ed26e6b0-f783-46c5-b48d-13a32b86cf88" alt="" data-size="original"> | <img src="https://195121302-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MdvF6AnMWuH7LB6LAsd%2Fuploads%2FGOGhScFS8yaKdnuH01Dk%2Fno-mm-memory.png?alt=media&amp;token=f3501932-937e-4099-9bbc-879cefa19712" alt="" data-size="original"> |

</details>

<details>

<summary><strong>Device Used</strong></summary>

**Name:** iPhone 14

**Model:** iPhone14,7

**CPU:** A15 Bionic Chip

**OS:** iOS 18

</details>

***




---

[Next Page](https://docs.mediamelon.com/mediamelon/llms-full.txt/1)

