Detect usage of Google Cast - android

How to detect if my AndroidTV is currently an Google Cast receiver from mobile/desktop ?
How to detect who is currently an Google Cast sender from Google Cast Receiver perspective?
How to detect if my Android Phone is currently an Google Cast sender?

You could use the Android Media Router API to request all available routes to Cast devices. Then you would then have to connect to each Cast device and then you can determine the app ID or even if media is playing. If you only want to know if your own app is running, then simply filter the Media Router request by that.
Only the receiver would know which senders are connected to it. In your own custom receiver you could keep track of that for your own app.
You might be able to use the Media Router to determine if there is an active route. Not sure if you will be able to tell if it is a Cast route, since these routes could also go to other devices like bluetooth speakers.

To add to Leons answer, we have a callback on the MediaRouter like so to get callback on when our chromecast receiver app is selected
val mMediaRouterCallback = object : MediaRouter.Callback() {
override fun onRouteSelected(router: MediaRouter?, route: MediaRouter.RouteInfo?) {
routeInfo = route
}
override // override appropriate methods here!!
}
val mMediaRouteSelector = MediaRouteSelector.Builder()
.addControlCategory(
CastMediaControlIntent
.categoryForCast(BuildConfig.CHROMECAST_RECEIVER_APP_ID)
).build()
MediaRouter.getInstance(context).addCallback(
mMediaRouteSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN
)
Build selector to work for more than one app. And it is possible to change MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN to broaden your scan.

Related

Android WebRTC cant send DTMF

In my Android WebRTC client to send DTFM tones I use code like this
val audioSource = peerConnectionFactory.createAudioSource(MediaConstraints())
val localAudioTrack = peerConnectionFactory.createAudioTrack("audio", audioSource)
peerConnection.addTrack(localAudioTrack)
peerConnection?.senders?.firstOrNull()?.let {
it.dtmf()?.insertDtmf(code, 400, 50)
}
But it seems tone does not reach a peer, and there is erro message in logcat
dtmf_sender.cc E (line 126): InsertDtmf is called on DtmfSender that can't send DTMF.
No matter what device I use.
Why could it happen?
There are multiple reasons why this could happen, one of them being that the other party in the WebRTC connection does not support the RTP telephone-event
Also, check this example: https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Using_DTMF
(haven't tried it myself though)
Pay attention to this:
"Note, however, that although it's possible to send DTMF using WebRTC, there is currently no way to detect or receive incoming DTMF. WebRTC currently ignores these payloads; this is because WebRTC's DTMF support is primarily intended for use with legacy telephone services"
I have found, problem is that peers are not connected via RTP. I mean WebRTC did not found yet suitable route, basing on ICE candidates gathered, to pass audio traffic.
As only route is constructed, traffic goes on, and sender comes ready to send DTMF tones.
To be ensured that peers are ready to trancieve media, you may look on connection state in PeerConnection.Observer.onIceConnectionChange(), and get sender when state comes to "CONNECTED".

How to handle RTP session in Xamarin forms for Android and IOS?

I am trying make an application that will allow a registered client to make an audio call to another registered client using Wi-Fi(It doesn't require internet).
I was able to successfully register and make call using SIP.
After the call is picked up, I don't know how to handle the RTP stream and connect it with the microphone and speaker of the phone(Android and IOS) to perform normal calling functionality.
I am using Xamarin and SIP Sorcery library. I am new to Xamarin and mobile application development.
Below is a part of code to explain myself a little better:
async Task Call()
{
Console.WriteLine("Start of Calling section");
rtpSession = new RTPMediaSession((int)SDPMediaFormatsEnum.PCMU, AddressFamily.InterNetwork);
// May be somthing like this to connect audio devices to RTP session.
//get microphone
//get speaker
//ConnectAudioDevicesToRtp(rtpSession, microphone, speaker);
// Place the call and wait for the result.
bool callResult = await userAgent.Call(DESTINATION, ssid, userName, registerPassword, domainHost, rtpSession);
if (callResult)
{
Console.WriteLine("Call attempt successful. Start talking");
//I am reaching to this point and need help with how to move forward from here to support audio calling functionality for both Android and IOS
}
else
{
Console.WriteLine("Call attempt failed.");
}
}
Any help or direction would be appreciated. Thank you.
I looked at the documentation from SIP Sorcery, there I found only an example for windows (https://sipsorcery.github.io/sipsorcery/articles/sipuseragent.html), but not for ios or android.
Here is the description from SIP Sorcery for cross platform (https://sipsorcery.github.io/sipsorcery/). I think you need the SIPSorceryMedia.FFmpeg library

Accepting a Call via Bluetooth Headset VoIP

I am working on a VoIP-Android-App and The app needs to be able to accept/decline call thought Bluetooth headset.
But the problem is that after adding connection to SCO
audioManager.startBluetoothSco()
audioManager.isBluetoothScoOn = true
Once I click to the headset button I can hear a sound that usually comes when I accept call using telephony, so I assume that some android system component catch this signal and doesn't throw it further
What I've tried already:
1) Telephony State listener (It is always IDLE)
val tm = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
phoneStateListener = MyPhoneStateListener()
tm.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE)
2) MediaSession + silent noise + media button listener
Doesn't work for the first click, second+ clicks handled correctly
3) MEDIA_BUTTON receiver doesn't work
I found a similar question on SO but without the answer how to make it work
Accepting a Call via Bluetooth Headset
So is there anyway how I can intercept Bluetooth button click from Bluetooth Headset Service?
Accepting a Call via Bluetooth Headset
Adding my answer from there to here too.
These events are handled internally in HeadsetStateMachine (under packages/apps/Bluetooth).
These events are forwarded to IBluetoothHeadsetPhone interface. The single application to which all the events are forwarded is defined at run-time by following binding code in HeadsetStateMachine.java. This is to allow phone manufacturers to forward them to custom phone application instead of default one in cases where default one is not used.
Intent intent = new Intent(IBluetoothHeadsetPhone.class.getName());
intent.setComponent(intent.resolveSystemService(context.getPackageManager(), 0));
if (intent.getComponent() == null || !context.bindService(intent, mConnection, 0)) {
Log.e(TAG, "Could not bind to Bluetooth Headset Phone Service");
}
To make the events get forwarded to your application instead of default phone application you would have to modify aosp code.
You would need to intercept the events at one of HeadsetStateMachine , BluetoothHeadsetPhone proxy or the phone application.
Unfortunately what you are looking for is currently not possible without modifying aosp code. Some headsets like Plantronics have custom BT events which are forwarded to all applications - some of the existing VoIP applications support these custom intents to support at-least answering calls for some of the headsets.

How to get MediaRouteSelector to show available MiraCast and Chromecast devices?

I am trying to get my Media Route Selector to show both MiraCast and Chromecast devices. I have a Chromecast receiver app and also make use of the Presentation API in Android so ideally the user should only have to click the media router button and chose the device they have without even having to think about it. I was following this guide (https://developer.android.com/guide/topics/media/mediarouter.html#selector) to achieve this and in the picture it shows both a Chromecast and wireless display available in the route selector. However, after adding the control categories I still only see the Chromecast.
Here is the relevant code.
mMediaRouteSelector = new MediaRouteSelector.Builder()
.addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
.addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)
.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
.addControlCategory(CastMediaControlIntent.categoryForCast(CAST_APP_ID))
.build();
...
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
I have tried changing the callback flag also but saw no change.
EDIT:
I ended up creating a custom dialog factory for the router button and using a separate layout that includes a button that will send the user to wireless display settings. Not exactly the solution I was looking for but it appears that what I was actually trying to do is not supported.

How can I avoid or dismiss Android's Bluetooth pairing notification when I am doing programmatic pairing?

I have an app where I am programmatically controlling Bluetooth pairing and unpairing. I can pair before connection and unpair afterwards. The reason I need to do this is specific to my application and not in the scope of my question.
Basically what I am doing is:
Get a reference ib to IBluetooth object as described in this answer
Register a BroadcastReceiver for android.bluetooth.device.action.PAIRING_REQUEST
Call ib.createBond(address)
Wait for BroadcastReceiver to trigger
Convert user pin into bytes with convertPinToBytes()
Call ib.setPin(address, pinBytes) from within BroadcastReceiver
Anyways, this approach works great, except for the fact that when I do the pairing, I get a notification in the Status bar requesting that the user enter a PIN to complete the pairing. But this is in fact unnecessary, because by the time the user sees this, my app has already used setPin(). I'd really like for that notification to either a) not appear at all, or b) be dismissed automatically somehow.
I realize this may not even be possible, but I thought I would ask in case someone has a creative idea.
Try setting the confirmation first in the PAIRING_REQUEST
BluetoothDevice device = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
device.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
device.getClass().getMethod("cancelPairingUserInput").invoke(device);
This worked for me between two Android devices using RFCOMM but I'm not entering any PINs
Since Android API 19 Google switched these Methods to public Methods, so there is no need for Reflection any more. :)
Do this in the PAIRING_REQUEST notification event:
BluetoothDevice localBluetoothDevice = (BluetoothDevice)intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
Class localClass = localBluetoothDevice.getClass();
Class[] arrayOfClass = new Class[0];
localClass.getMethod("cancelPairingUserInput", arrayOfClass).invoke(paramBluetoothDevice, null)).booleanValue();
But you gotta tell me how did you pair your remote device without the user to enter Passkey/PIN? off course, you know the PIN for the remote device which is trying to pair to your device but how did you provide that PIN to the remote device.

Categories

Resources