I'm trying to write an app that will start casting the screen from an Android phone to a TV via miracast. I'm using an HDMI dongle since the TV in question doesn't natively support miracast. I have been trying the code here, but it needs an Application ID which I have got following these steps. My question is, the instructions seem to indicate that I need to register the miracast dongle so it will talk to an unpublished 'debug' app. However, only Google Cast devices are mentioned and that isn't the same protocol as miracast. Do I still need to register the dongle?
Is there a simpler way of programmatically casting to a device via miracast? A requirement is no user interaction, so I can't just display a cast button.
I'm using Android 5.1 if that's relevant.
EDIT: After further research, I realized that Google Cast uses a completely different protocol from Miracast, and thus all the talk of registering the dongle is irrelevant. No registration is required at all to do Miracast in Android. The issue is the API is hidden, see my answer below for details.
Open the “wireless display” settings menu on your Android device and turn on screen sharing. Select the Miracast adapter from the displayed device list and follow the on-screen instructions to complete the set-up process.
First of All, take a Miracast adaptor and connect it to an open HDMI input on your TV. Now change the source of your TV to the adaptor. Go to your Android Device, open wireless display settings, and turn on the screen sharing option. Now select Miracast Adaptor from the displayed device list.
This means that Miracast doesn't need a Wi-Fi signal to work, as it creates its network. In terms of compatibility, Miracast is applicable in modern Windows and Android devices, particularly those that come with Windows 10 and Android devices with version 4.2 or above.
So this is possible, but only on custom versions of Android due to permission problems.
What you need to use
The hidden part of the WifiDisplay API makes it all possible. This file contains examples of how to use the API to cast the display. It appears that Google will release it publicly at some point, although it's still hidden in the latest master of API 23 as far as I can see.
How to access the hidden API
To use hidden APIs, this guide(mirror here) provides a good introduction. If you're using API 22+ however, then that guide won't work as the format of android.jar has changed and classes.dex has been split across multiple files. So this advice is more accurate in that case. Note that the postscript about framework-classes2.dex
must also be done; it isn't optional.
The latest version of the dex2jar
tool fails to turn the .dex file from API 22 into a jar. The solution is mentioned by the author here. I opted to patch the tool instead of changing the dex, as that didn't work for me. Simply change the line the author mentions from throwing a RuntimeException to:
return TypeClass.INT;
How to get permission to use the hidden API
Once that is all done, the next step is giving your app the CONFIGURE_WIFI_DISPLAY
permission. Unfortunately, as you can see here, it has system-level protection. This means that your app must be signed by the same key as the system to use this permission. So unless you have Google's private key, you can't have your app run on normal Android phones. My solution was to build a custom version of CyanogenMod(using this guide), with the permission changed from 'system' to 'normal'. This eliminates the need to bother with signing anything. I also did the same for the CONTROL_WIFI_DISPLAY
permission. Whilst I'm not entirely sure this is necessary, it doesn't hurt. Both these permissions are located in frameworks/base/core/res/AndroidManifest.xml
. Change the lines 2161-2169 from:
<permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
android:protectionLevel="signature" />
<permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
android:protectionLevel="signature" />
To:
<permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
android:protectionLevel="normal" />
<permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
android:protectionLevel="normal" />
Then build CyanogenMod as normal. I can confirm this does work, but this limits your app to running on devices which have this custom version of CyanogenMod installed. Furthermore, installing CyanogenMod on an Android phone will generally invalidate the warranty.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With