Amazon Fire TV devices support the DIAL (Discovery-and-Launch) protocol through the Whisperplay service.
DIAL (Discovery-and-Launch) protocol is an open protocol that enables your Fire TV app to be discoverable and launchable from another device via a second-screen app. Both Fire TV and the second-screen device must be on the same network.
DIAL is not a bit-streaming or screen mirroring API, it enables apps on a second-screen device to find and launch apps on a Fire TV (with an optional payload). In most cases, you own and implement both the second-screen app (to send a launch message), and the corresponding Fire TV app, aka first-screen app (to receive that message).
For more information about the open DIAL protocol and to register your app with the DIAL service, see the DIAL website.
In the simplest case (launch-only), DIAL functionality does not require any changes to your Amazon Fire TV app's code, but you do need to modify your app's manifest and resources to indicate support for DIAL and to accept launch intents. An example of this core, launch-only interaction is illustrated in the following diagram:
In most cases, though, you will also want to modify your first-screen (Fire TV) app’s code to process DIAL launch parameters (e.g. deep-links) and to provide feedback to the DIAL server's additionalDataUrl .
In general, the following five steps should be followed to leverage most DIAL features and provide the best customer experience:
The following sections list changes you must make to your Fire TV app.
There are two changes you must make to your Android manifest ( AndroidManifest.xml ) to support DIAL:
In the portion of your manifest, add the following element:
application . > meta-data android:name="whisperplay" android:resource="@xml/whisperplay"/> . application>
Next, add the DEFAULT intent category (XML below) to your primary (main) activity's element. As described in the next section, you may also define your own custom launch action for DIAL to invoke.
activity android:name=".MainActivity" android:label="@string/title_activity_main" > . intent-filter> action android:name="android.intent.action.MAIN" /> category android:name="android.intent.category.LAUNCHER"/> category android:name="android.intent.category.DEFAULT" /> intent-filter> activity>
Add a file called whisperplay.xml to your app's resources, in your app's res/xml/ directory.
Important: As of DIAL 2.2.1 there have been several enhancements made to the CORS authorization model. You MUST migrate to the new field in your whisperplay.xml file as shown in the code below. The format has changed from the previous mechanism, so you may need to review and update your entries.
YourDialAppName https://www.example.com https://*.test.com package:com.example.dialapp android.intent.action.MAIN YourDeleteAction
CORS support via
Please be sure to review the DIAL spec v2.2.1, section 6.6 for more details on the additional requirements for CORS authorization and client origins. The Amazon implementation requires your app to specify a collection of authorized CORS origins within your first-screen app’s whisperplay.xml file (see example above). The format allows for wildcard matches using the "*" character which will match zero-to-many characters. Note that certain insecure URI schemes (including file: http:, ftp: and others) are explicitly forbidden regardless of whether they appear in your authorized list.
Take care when specifying your authorized origins to not be overly permissive. For example, if you want to authorize both https://test.amazon.com and https://amazon.com DO NOT specify your authorized origin as *amazon.com. This is overly permissive and may inadvertently authorize an unexpected origin such as https://evilamazon.com. Instead, you could define the collection as shown below which ensures all origins are based on the domain you own:
https://*.amazon.com https://amazon.com
Important: It is strongly recommended to add both first-screen ( ) and second-screen ( ORIGIN header ) to your DIAL application to take full advantage of the enhanced security it offers for the customer.
If your app accepts a DIAL payload (information that can be passed to your app via the DIAL launch request), that payload will be delivered as a String Intent extra with the key com.amazon.extra.DIAL_PARAM . The additionalDataUrl used by your first-screen app to optionally POST additional information is delivered as another String Intent extra with the key com.amazon.extra.DIAL_ADDITIONAL_DATA_URL . It is safe to assume that the additionalDataUrl will be in the form http://127.0.0.1:8009/apps//dial_data to which your first-screen app may POST data.
Important: as of Android API 28 (Fire OS 7), your first-screen app may run into issues posting to the additionalDataUrl due to additional cleartext protections imposed by the OS. It is recommended you review the options here: https://developer.android.com/training/articles/security-config#CleartextTrafficPermitted.
If you would like to enable very rudimentary two-way communication or a simple feedback mechanism from your first-screen app back to your second-screen app, you may opt to use DIAL’s additionalDataUrl field. A common use case for this would be to share a session token or some other information tied to your first-screen application’s state. You can think of this as an XML document that your first-screen application makes available to your second-screen app that persists as long as the Fire TV is not rebooted. In order for the Fire TV app to successfully POST to the additionalDataUrl , the corresponding origin must be registered in the collection in whisperplay.xml .
Refer to the DIAL docs v2.2.1, section 6.3 on the specific formats expected and provided by the additional data mechanism for both first- and second-screen apps.
The following sections list changes you need to make to the second-screen app.
On the second-screen app (aka the DIAL client), implement the client specification of the DIAL protocol. DIAL discovery is built on top of the UPnP/SSDP specification. In a background activity or thread, send a UDP M-SEARCH request with the search target as "urn:dial-multiscreen-org:service:dial:1" .
Fire TV responds to the M-SEARCH request with a response containing a unique service name (USN), the location/URL to obtain a device description, and the search target. Additionally, there may be an extra WAKEUP header included indicating the TV currently has the capability to be woken from suspend mode using magic packets (refer to the DIAL 2.2.1 spec, section 7 for more details). Since it is possible to receive multiple M-SEARCH responses from the device, you must extract unique devices based on the USN.
The following is a sample request and response.
Sample M-SEARCH Request:
M-SEARCH * HTTP/1.1 HOST: 239.255.255.250:1900 MAN: "ssdp:discover" MX: 10 ST: urn:dial-multiscreen-org:service:dial:1 USER-AGENT: OS/version product/version
Sample M-SEARCH Response:
HTTP/1.1 200 OK USN: uuid:7b077d4c-a222-5b72-0000-0000182185c7::urn:dial-multiscreen-org:service:dial:1 CACHE-CONTROL: max-age=1800 EXT: ST: urn:dial-multiscreen-org:service:dial:1 LOCATION: http://192.168.1.141:60000/upnp/dev/7b077d4c-a222-5b72-0000-0000182185c7/desc SERVER: Linux/4.4.120 UPnP/1.0 Cling/2.0
Next, to obtain more information about the device, send an HTTP request using the device description location URL in the M-SEARCH response. The response contains an important attribute in its header called Application-URL , referred to as the DIAL REST Service. This Application-URL is subsequently used to interact with the app on the device. From the response body, it is useful to extract and store the device-friendly name, model name, and manufacturer to display these values to the user.
After the processing of the M-SEARCH and device descriptions requests is complete, the list of devices found can be presented to the user in the UI.
Before launching the app on the device, it is useful to detect the state of the app on the device (and optionally read additionalData to load cached information from your first-screen app). To get the state of the app, once the user selects a device to launch the app on, send an HTTP GET request to the DIAL REST service with the app name as the resource name. The app name in the request must match the name registered in the DIAL registry (and specified in your whisperplay.xml file).
If the app name is not recognized and/or the app is not installed, an HTTP 404 error is returned. The user could be presented the option on the second-screen device to install the app on the first-screen device from the Appstore, but this functionality is out of scope for the DIAL protocol.
If the HTTP request is successful, the DIAL server responds with an HTTP 200 OK response. The response body contains an attribute that informs the state of the app — hidden , stopped , running , or is installable (note that installable and hidden are not currently supported by the Fire TV DIAL server), and any XML-formatted additionalData that was previously POSTed to the additionalDataUrl by the first-screen app.
Next, launching the first-screen app is as simple as sending an HTTP POST request to the DIAL REST Service with the app name as the resource name, and optional payload in the request body to send to the app as a launch parameter. A common use case could be a link to video or music content to play within the app. The DIAL server launches the app with the specified launch intent and includes the optional payload sent by the mobile app in the com.amazon.extra.DIAL_PARAM intent extra. If the second-screen app expects additional data from the first-screen app, the additionalDataUrl from the request parameter as specified in DIAL protocol is sent in the com.amazon.extra.DIAL_ADDITIONAL_DATA_URL intent to the first-screen app (see Step C: Handle Launch Intents and additionalDataUrl).
The first-screen app is responsible for handling actions in response to the payload sent from the second-screen app. Subsequent GET requests issued by any second-screen app can be used to read any additional data that was POSTed by the first-screen Fire TV app (e.g. a viewing session token to synchronize multiple clients).
As with any app development, care must be taken to clean up and close network connection resources, handle exceptions, launch threads in non-UI blocking threads, and fail gracefully when network operations fail.
Last updated: Nov 12, 2021