Auto answer calls simulating a headset - android

I'm trying to answer calls programmatically. (I'm not even going to discuss about using reflection as this only works in froyo and earlier versions). My approach was to send a headset button event to answer the call. Unfortunately this only works if a headset is connected to the phone so I send a broadcast to make the phone think that a headset is connected like this:
Intent headSetUnPluggedintent = new Intent(Intent.ACTION_HEADSET_PLUG);
headSetUnPluggedintent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
headSetUnPluggedintent.putExtra("state", 1); // 0 = unplugged 1 = Headset with microphone 2 = Headset without microphone
headSetUnPluggedintent.putExtra("name", "Headset");
sendOrderedBroadcast(headSetUnPluggedintent, null);
The call is successfuly answered. BUT after that I must "disconnect" the headset otherwise there is no audio (as it is redirected to the fake headset). So I send another broadcast like the previous one setting the "state" key to 0. But it doesn't work. The virtual headset is still connected. Can anyone help with this?
Seems like this headache went away with a simple project-Clean. It was just Eclipse making fun of me AGAIN. The code works fine now.

Related

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.

Mute voice recognition bleep in Bluetooth Earpiece Android

I'm trying to get continuous voice recognition to work for a custom app on Android, using an ML18 bluetooth headset (by plantronics). I've managed to get rid of the beep produced by my phone by using the answers posted here and managed to route all other media to my bluetooth device using this.
However my bluetooth device is still beeping every time I call SpeechRecognizer.startListening.
Is there something I can do about this, or is this possibly hardwired into the software of the bluetooth device?
If you want to see specific sections of code, let me know. I do not think much of it is relevant however, as the two links above already cover the code that seems most relevant to me. Thanks in advance!
EDIT: So based on the comment below, I've modified my code into the following:
The start listening simply mutes all stream but the alarm stream (undone by unmuting all streams again).
public void startListening() {
if (canListen) {
Log.v(TAG, "Starting Listening");
Intent recognizerIntent = createRecognizerIntent();
recognizer.cancel();
recognizer.startListening(recognizerIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
((AudioManager) getApplicationContext().getSystemService(
Context.AUDIO_SERVICE)).setStreamSolo(
AudioManager.STREAM_ALARM, true);
}
}
}
The Bluetooth receiver does this when the device is connected:
AudioManager localAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
localAudioManager.setMode(AudioManager.MODE_NORMAL);
localAudioManager.setBluetoothScoOn(true);
localAudioManager.startBluetoothSco();
And then in the ACTION_SCO_AUDIO_STATE_UPDATED it sets the mode to AudioManager.MODE_IN_CALL.
Currently the behaviour is as follows:
When I first start the app and connect the bluetooth device, as well as trigger the continuous recognition loop, all works as expected. Yet after a first reply has been uttered (using TTS), the beep returns... Again, any help would be appreciated :)

Access data from SCO Socket

I have 2 Android phones and I have managed to convert one of them as Headset (Yes, I did root the phone for that).
When an incoming call is received to the phone, the headset-emulated phone is able to take headset related actions like - pick call, disconnect call, etc. However, only functionality that's missing is the transfer of Audio from Phone to headset-emulated-device.
Does anyone have prior experience in establishing SCO connection between 2 android phones and access voice data ?
(As of now, I am not concerned of Sound quality).
I came across A2DP, but it's only uni-directional. Only SCO is bidirectional voice data transfer.
Any help or pointers will be highly appreciated.
I have done this with reflection. It only worked on certain devices though. Not all. Although I didn't root the device.
Class cls = Class.forName("android.bluetooth.BluetoothDevice");
Method method = cls.getDeclaredMethod("createScoSocket", (Class[])null);
BluetoothSocket scoSocket = (BluetoothSocket)method.invoke(device, null);
scoSocket.connect();
Also there is the AudioManager.startBluetoothSco() and AudioManager.setBluetoothScoOn(true) methods that you have to use when playing your audio.

Route audio to bluetooth A2DP device while ringing [Android]

I am trying to identify how to route a very short audio stream (a notification) to a bluetooth headphone that is already paired with the device, while the device is ringing.
When I play any audio at any time, it is routed to the bluetooth device, no problem.
But if I try to start playing the audio when receiving an android.intent.action.PHONE_STATE, in RINGING state, the audio is not routed as expected.
I can see that the AudioManager's setBluetoothA2dpOn method has became deprecated, but I actually tried it but is seems has no effect.
I have tried the MediaRouter object, but I can see that MediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_AUDIO) points to the RouteInfo of the Bluetooth device while the device is ringing, and the AudioManager.isBluetoothA2dpOn is true.
So, can any one tell me why the audio route is like this in the ringing moment? is there any way to force the audio to be routed to the Bluetooth device in such case?
[UPDATED]
I have tried again today and I have discovered something that may be the cause of the problem.
I have created a BroadcaseReceiver to detect the change in the android.intent.action.PHONE_STATE. if an intent is received and the state is currently ringing, check for AudioManager's mode and you will find it is MODE_NORMAL. but few seconds later the phone will start actually ringing and the mode is going to be changed into MODE_RINGTONE. trying to manually set the mode using the method setMode(AudioManager.MODE_NORMAL) is useless then, the state remains MODE_RINGTONE even after setting it to MODE_NORMAL.
Now, I think the cause of the problem is that in the MODE_RINGTONE mode, all the streams are directed to the phone speaker and here there is no way offered by the android system to change the mode.
I think the Media player realease the bluetooth connection when the phone is ringing. You can try to obtain the bluetooth audio connection and see if Media player now play through your obtained connection. You can use my class at my answer Using the Android RecognizerIntent with a bluetooth headset and see if it works. The audio in the class is Sco only.
As stated in the JavaDoc for the StartBluetoothSco method:
Note that the phone application always has the priority on the usage of the SCO connection for telephony. If this method is called while the phone is in call it will be ignored. Similarly, if a call is received or sent while an application is using the SCO connection, the connection will be lost for the application and NOT returned automatically when the call ends.`
I tried to start sco then play a music clip in normal mode, it played to the Bluetooth headset without problems, although I couldnot stop the microphone that caused the input stream plays to the headset. I then tried to call my target phone from another phone while the music is still playing, I found that the stream has got redirected automatically to the phone speaker. After the ringing mode is finished, the stream did not get redirected again to the Bluetooth headset and I think that behavior is normal according to what is stated in the JavaDoc above.
My guessing is that Android tries to protect the ringing and in-call modes as possible in order not to allow any unwanted interference from applications. In other words, when in ringing mode then no sound is going to be played to the headset until the call is accepted, and you cannot even change the AudioManager mode from ringing to another mode, your call for mode setter will be ignored.
I have tried the AudioTrack instead of MediaPlayer, but that makes no difference.
I have then tried the TextToSpeech engine like this:
in the main activity, initialize on create:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textToSpeech=new TextToSpeech(this, this);
textToSpeech.setLanguage(Locale.US);
textToSpeech.addEarcon("[wwww]", "XXXXXXXXXXXXXXXXXXXXXXX", R.raw.a);
}
in the broadcast receiver class when rining starting the Bluetooth utility class and adding the below to the onScoAudioConnected method
textToSpeech.playEarcon("[wwww]", TextToSpeech.QUEUE_FLUSH, null);
This did not work too.

How to capture or reroute navigation voice stream

There is a problem when using Google Navigation on Android with a Bluetooth device. Navigation sends the audio for the turn-by-turn instructions over the A2DP stream. I have a Motorola T605 Bluetooth car kit and it supports HFP and A2DP. I often just listen to the old fashioned car radio though. In this scenario I never hear turn-by-turn directions because my live A2DP stream is being sent to the radio AUX input but I am listening to the radio instead. My app has a feature where it reads out SMS messages to me. I have it set up so you can pick the stream you want to use for this. I prefer using AudioManager.STREAM_VOICE_CALL since it uses a dedicated separate speaker on the T605.
I have looked into a few ways to handle this:
1) Reroute notifications to Bluetooth SCO instead of A2DP. I have not fund a way to do this. I am able to send TTS messages I create over this path and it works great (I have an SMS reader built into my app). I tried activating SCO but the turn-by-turn instructions stream moves to the phone internal speaker instead of the voice call stream like I would prefer.
2) Capture the navigation messages and echo them back over the SCO path. I can't find a way to intercept or capture the navigation stream though. Does Google Navigation use the TTS engine or its own methods to create the voice output? It would be great to just get the directions in a text string since I could easily send that to the TTS engine and route it where I want like I do with SMS strings.
You can see my app source here: http://code.google.com/p/a2dpvolume/
Any thoughts?
Unfortunately I think you're SOOL when it comes to rerouting the navigation messages to BT SCO. I would expect the navigation app to use either the TTS or NOTIFICATION stream type to play the messages, and both of those stream types follow the MEDIA routing strategy (for NOTIFICATIONs that is at least typically true when there's no active voice call).
Although the behavior is up to each vendor to decide, my guess is that you'll find that in most implementations streams that follow the MEDIA routing strategy won't ever be routed to BT SCO, except during an ongoing voice call that is routed to BT SCO.
The best you could do in terms of routing is to force the routing to the loudspeaker, or to "anything but A2DP" (which means wired headset if one is attached, or the loudspeaker otherwise).
Here's how you could do that (I haven't verified that this works on every phone out there):
Class audioSystemClass = Class.forName("android.media.AudioSystem");
Method setForceUse = audioSystemClass.getMethod("setForceUse",
int.class,
int.class);
// 1 == FOR_MEDIA, 10 == FORCE_NO_BT_A2DP (FORCE_SPEAKER would be 1).
setForceUse.invoke(null, 1, 10);

Categories

Resources