Playing sound over speakers while playing music through headphones - android

I have an AudioTrack streaming via headphones. I have to send a SoundPool to built-in speakers only, without interrupting the AudioTrack playing over the headphones. Any hacks gangsters?

Many Android devices use a single output thread in the AudioFlinger / audio HAL for all local playback (earpiece, speaker, wired headset/headphones), making different routing of two tracks simultaneously impossible (which is why on many devices the media streams are forcibly muted if a notification is played and you've got a wired headset attached; because otherwise you'd hear the music in the loudspeaker while the notification is played).
On some devices it might be possible to do what you're looking for if you manage to do a setForceUse(FOR_MEDIA, FORCE_SPEAKER) and use the MUSIC stream type for the stuff you want to play in the loudspeaker, and the VOICE_CALL stream type for the stuff that you want to play in the wired headset.
I'm not sure if there's any way for an application to perform that setForceUse call though. Perhaps you can get at the handleMessage method of the AudioService class through reflection and send it an MSG_SET_FORCE_USE message.. I've never tried it myself so it might fail miserably.
EDIT: I've now tested the setForceUse way of forcing MEDIA streams to the loudspeaker while a wired headset is attached on an actual device, and it does work (though I can't guarantee that it will work across all devices). The implementation was slightly different from what I described above. See my answer to how to turn speaker on/off programatically in android 4.0 for the code I used.

Related

Android bluetooth sco not picking headset microphone after pairing

I'm trying to correctly setup bluetooth SCO in my app. After many attempts it seems that I've found a way to enable it "almost" reliably, in the sense that it works almost always, but in one case: if I launch my app and AFTER this I pair the headset, the headset mic is not picked (the phone mic is picked instead), while the headset earphones are correctly picked.
If instead I pair the headset BEFORE launching the app, everything seems to work fine.
The strange thing is that, even when the phone mic is picked, calling getRoutedDevice() on my AudioRecord object returns the bluetooth headset.
I tried to use SetPreferredDevice on the AudioRecord object, but apparently it has no effect.
The only way I found to ALWAYS pick the headset microphone is to call
audioManager.setMode(AudioManager.MODE_NORMAL);
However in this case, the output comes from the phone speaker and not from the BT headset earphones!
If instead i call:
audioManager.setMode(AudioManager.MODE_IN_CALL);
the output comes consistently (and correctly) from the BT headset earphones, but I have the above mentioned mic issue (pairing the headset after launching the app, the phone mic is picked instead of the BT headset one).
The sequence I am using is:
I have a thread that checks if a bluetooth headset is connected and works pretty much reliably.
When isHeadsetConnected is true I do:
arec.stop(); // my AudioRecord object
atrack.stop(); // my AudioTrack object
audioManager.setMode(AudioManager.MODE_IN_CALL);
audioManager.startBluetoothSco();
In the listener of AudioManager.EXTRA_SCO_AUDIO_STATE, when I receive SCO_AUDIO_STATE_CONNECTED) I do:
audioManager.setBluetoothScoOn(true);
atrack.play();
arec.startRecording();
After struggling a lot, this seems to be the "almost" perfect sequence, with the caveat that it does not work fully if the first pairing is made with the application running.
I've made an attempt to pair the same headset during a Whatsapp call, and the bluetooth headset starts without any problem both input and output, so THERE MUST be a way to accomplish this!
I have read tons of questions/answers but none of these seems to consistently solve my problem.
I am using Android 11 on a CAT S62 Pro.

speech recognition through bluetooth headset in android while playing music

I am currently recognizing Hot word(like "ok google") using pocketsphinx library.
The app works fine except that it always uses only the phone's mic to recognize the speech.
My use case is something like this:
I listen for a hot word and use the MediaPlayer to play some music.
Keep listening for next commands while keeping the music being played and react accordingly.
The app works fine and the music is played via the bluetooth headset and the voice is also simultaneously recognized, but it always uses the phone's mic. Even though the bluetooth headset is connected or not connected, it still uses the phone's mic.
I tried using:
AudioManager mAudioManager =
(AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
mAudioManager.setMode(AudioManager.MODE_IN_CALL);
mAudioManager.startBluetoothSco();
I tried using:
AudioManager mAudioManager =
(AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
mAudioManager.startBluetoothSco();
In both the approaches, it cuts off the music and listens in bluetooth mic.
I need an approach where the Music player is not cut from bluetooth headset but still I am able to speech recognize from bluetooth headset.
For example:
I was listening to music via bluetooth headset.
I opened voice recording app(https://play.google.com/store/apps/details?id=com.andrwq.recorder)
I am able to record the audio through bluetooth headset even while listening to music.
This makes me feel that it is possible but I don't know how.
Please help me out. Thanks in advance.
It is correct to start SCO mode, after that pocketsphinx will listen for bluetooth headset.
To disable phone microphone while in sco mode use am.setMicrophoneMute(true);
To play audio through SCO you need the player to play through STREAM_VOICE_CALL. Maybe player must be restarted after SCO switch.

android route specific audio to bluetooth headset

i'm trying to write an app that will get audio notifications and will stream them on a bluetooth headset. i want this done while other audio frames are playing through the device's speaker (for instance, there is a song playing on another app).
i only want the audio notification to play on the headset, other audio frames should still come out of the speaker.
right now, it doesn't matter whether the other audio frame will pause while the notification is played on the headset or not.
i've looked and found no example of how to do this.
is it at all possible?
can someone direct me?
with regards,
Tamir.

Play audio over an active phone call, so other end can hear it

A and B are talking on the phone. During the call, A presses a button that pulls audio from a resource and plays it over the phone call to B.
Is this possible using the Android framework? The goal is for the person on the other end of the call to hear the audio.
If it's not possible, is it a hardware limitation or a limit of the Android framework?
I believe that you cannot achieve that, according to the documentation HERE :
Note: You can play back the audio data only to the standard output device.
Currently, that is the mobile device speaker or a Bluetooth headset.
You cannot play sound files in the conversation audio during a call.
According to http://developer.android.com/reference/android/media/AudioManager.html, there are a number of channels though which audio can be played:
STREAM_ALARM The audio stream for alarms
STREAM_DTMF The audio stream for DTMF Tones
STREAM_MUSIC The audio stream for music playback
STREAM_NOTIFICATION The audio stream for notifications
STREAM_RING The audio stream for the phone ring
STREAM_SYSTEM The audio stream for system sounds
STREAM_VOICE_CALL The audio stream for phone calls
These are what the android framework allows for. It would seem to me that two are of potential interest to you: STREAM_DTMF or, more likely, STREAM_VOICE_CALL. I haven't experimented personally, but if I was trying to do this, I would start by trying those two.

In Android, is there any way to route the audio to A2DP using "MODE_IN_COMMUNICATION"?

If I set AudioManager mode to MODE_IN_COMMUNICATION, and set the Media Player stream to STREAM_VOICE_CALL, I can route the audio to the speakerphone or the internal handset speaker just fine. And if it's routed to the internal speaker, and a wired headset is plugged int, it automatically routes to it. However, I can't figure out a way to route the audio to an A2DP headset (without changing the audio mode to MODE_NORMAL, or the stream to STREAM_MUSIC). My problem is that using MODE_NORMAL and STREAM_VOICE_CALL causes problems on some devices, and using STREAM_MUSIC is a problem if there is already music playing in the background, then my app "mixes" with that background music.
So, I was hoping that there was a way to force the audio to the A2DP headset using the MODE_IN_COMMUNICATION and STREAM_VOICE_CALL combination. Is that possible?
Perhaps it works on some devices, but if you care about compatibility across the majority of devices then the answer is "No".
When the phone state is MODE_IN_CALL or MODE_IN_COMMUNICATION all streams will typically follow the PHONE routing strategy. This means that routing to A2DP will not be allowed since:
1) A2DP doesn't support two-way voice anyway.
2) If your BT accessory supports the Hands-free profile it will use a SCO link for the voice audio, and the ACL channel used for A2DP should be closed to avoid interference between the two.

Categories

Resources