I'm looking to pair A2DP stereo sound with the interrupt functionality of AudioManager's MODE_IN_COMMUNICATION. The purpose of this pairing is to insert snippets of custom music into AM/FM broadcasts by using the music as something that "dials" the Android device and stops the AM/FM broadcast.
I have this working decently with SCO using the following code to start the "phone call".
Here is the AudioManager code:
AudioManager localAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
localAudioManager.setMode(0);
localAudioManager.setBluetoothScoOn(true);
localAudioManager.startBluetoothSco();
localAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
Here is the MediaPlayer I'm trying to play:
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build());
mediaPlayer.setDataSource("https://wmbr.org/WMBR_Archive_128.m3u");
mediaPlayer.prepare();
mediaPlayer.start();
The audio produced by this code is low-quality and mono as opposed to stereo. I would like to change that.
The issue is that the Android Dev site for startBluetoothSco says:
Even if a SCO connection is established, the following restrictions apply on audio output streams so that they can be routed to SCO headset: - the stream type must be STREAM_VOICE_CALL - the format must be mono - the sampling must be 16kHz or 8kHz
Is there any existing way to combine stereo sound and the interrupt functionality?
Additional context: in this answer it seems that MODE_IN_COMMUNICATION and MODE_IN_CALL use the PHONE routing strategy. He also says
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.
I'm assuming this means my only option is a custom routing strategy, and I'm not sure what that entails.
Related
I am trying to record both Uplink and Downlink voice using Android. Regardless the law and everything, i am already aware, so please do not put comments related to the law.
The code below works fine, except when i mute the microphone, it wont record the downlink voice.
I am using Android 8.1. I've tried using a third party app called ACR on the same device, and it works fine, while i am muted, it still records the downlink voice.
val audioManager = applicationContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val maximumVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL)
audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, maximumVolume, 0)
val audioSource = MediaRecorder.AudioSource.MIC
val mediaRecorder = MediaRecorder()
mediaRecorder.apply {
setAudioSource(audioSource)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
setAudioChannels(audioChannels)
setAudioSamplingRate(audioSamplingRate)
setAudioEncodingBitRate(audioEncodingBitRate)
setOutputFile(path)
prepare()
start()
This is not an issue. You set the MediaRecorder to use MIC as input, so if you MUTE the microphone it's obliviously that the input signat is lost/muted. When you use "downlink" word I expected to see a different input source as VOICECALL or DOWNLINK instead of MIC. Trying to record a voicecall using the MIC it's wrong in my opinion because: (1) you have to set max volume to speaker and redirect the voicecall through it (2) while recording a voicecall from the MIC the caller hears ALL what it happens around your device and all what you're saying to other people (3) this method records much noise and echoes. The right way is to record from VOICECALL but most of new devices (using newer Android version) prevents to record from this source and allows it only at System Apps. ACR uses a workaround by calling hidden API methods, but this method could stop stop work at any time due to Android updates.
So, I'm trying to record a wave file from and Bluetooth Headset.
This is what I use to record
recorder = AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION,
8000,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
BUFFER_SIZE)
And before starting recording I'm beginning and audio communication with my headset using
var am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
am!!.mode = 0
am!!.isBluetoothScoOn = true
am!!.startBluetoothSco()
am!!.mode = AudioManager.MODE_IN_COMMUNICATION
Well, it works wonders when recording in Android 6 (marshmallow), but when recording in Android 7 (nougat), it keeps recording from my phone's microphone and not the Bluetooth headset. Looking in the documentation, I didn't find anything regarding changes in Bluetooth SCO between versions. So.... what am I missing?
We had a similar problem when we tried to record a Bluetooth voice call. The problem was that the application started recording as soon as it received the telephony broadcast of the outgoing call, but the Bluetooth interface only connected a couple of milliseconds after the call has started.
We eventually solved this problem by applying a simple sleep before starting to record, and this fixed the problem.
I am connecting a mobile device with Android OS 4.1 to a Bluetooth device (device class = 1792), using BluetoothSco to route audio (voice). I've setup a BluetoothSocket using createRfcommSocketToServiceRecord successfully.
My settings:
Using AudioRecord and AudioTrack with frequency = 8000, MediaRecorder.AudioSource.MIC as the source for AudioRecord , AudioManager.STREAM_VOICE_CALL for the AudioTrack, and trying both MODE_IN_COMMUNICATION and MODE_IN_CALL for the AudioManager mode.
without success. I don't get audio on my device.
My questions:
Should I use MODE_IN_COMMUNICATION or MODE_IN_CALL?
Need I switch to MODE_NORMAL or other mode in order to play on device?
Can you suggest a code flow to make SCO audio play on a device?
Can you point out some working code to review?
Notes:
The "Media audio" profile (A2DP) is disabled on the device - only "Call audio" profile (HFP) is enabled.
Will gladly share some code, yet given existing SO Q&As it will probably look the same.
Regards.
I am able to receive, hangup and dial a number from my headset to android mobile which are connected via bluetooth.
Now, once I receive a in-coming call of mobile in headset, I need to speak with the called person from headset. I need to stream my voice via bluetooth to android mobile. I am searching for this code.
Crawled n number of post but could not get appropriate answer, Currently am using below but its not working...
AudioManager audioManager;
audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.startBluetoothSco();
audioManager.setBluetoothScoOn(true);
audioManager.setSpeakerphoneOn(true);
I am not sure after this what line of code I need to write to achieve my requirement
Note: I receive in-coming call by sending mmOutStream.write("ATA\r".getBytes()); this AT command to my Android mobile.
Please correct and guide me to perform audio stream.
You should set speakerphone to false, otherwise your output will be re-directed there. It is enough to do this:
audioManager.setSpeakerphoneOn(false);
audioManager.startBluetoothSco();
audioManager.setBluetoothScoOn(true);
Also, you can optionally set microphone to un-mute state (just in case previous state was muted):
mAudioManager.setMicrophoneMute(false);
I have a non-A2DP single ear BT headset (Plantronics 510) and would like to use it with my Android HTC Magic to listen to low quality audio like podcasts/audio books.
After much googling I found that only phone call audio can be routed to the non-A2DP BT headsets. (I would like to know if you have found a ready solution to route all kinds of audio to non-A2DP BT headsets)
So I figured, somehow programmatically I can channel the audio to the stream that carries phone call audio. This way I will fool the phone to carry my mp3 audio to my BT headset. I wrote following simple code.
import android.content.*;
import android.app.Activity;
import android.os.Bundle;
import android.media.*;
import java.io.*;
import android.util.Log;
public class BTAudioActivity extends Activity
{
private static final String TAG = "BTAudioActivity";
private MediaPlayer mPlayer = null;
private AudioManager amanager = null;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
amanager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
amanager.setBluetoothScoOn(true);
amanager.setMode(AudioManager.MODE_IN_CALL);
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(new FileInputStream(
"/sdcard/sample.mp3").getFD());
mPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
mPlayer.prepare();
mPlayer.start();
} catch(Exception e) {
Log.e(TAG, e.toString());
}
}
#Override
public void onDestroy()
{
mPlayer.stop();
amanager.setMode(AudioManager.MODE_NORMAL);
amanager.setBluetoothScoOn(false);
super.onDestroy();
}
}
As you can see I tried combinations of various methods that I thought will fool the phone to believe my audio is a phone call:
Using MediaPlayer's setAudioStreamType(STREAM_VOICE_CALL)
using AudioManager's setBluetoothScoOn(true)
using AudioManager's setMode(MODE_IN_CALL)
But none of the above worked. If I remove the AudioManager calls in the above code, the audio plays from speaker and if I replace them as shown above then the audio stops coming from speakers, but it doesn't come through the BT headset. So this might be a partial success.
I have checked that the BT headset works alright with phone calls.
There must be a reason for Android not supporting this. But I can't let go of the feeling that it is not possible to programmatically reroute the audio. Any ideas?
P.S. above code needs following permission
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
This thread may be long dead but for those who might be trying the same thing, some notes from the AudioManager docs may be useful. It looks like the missing element is the startBluetoothSco() command but there are restrictions on the use of this channel. From the Android Dev site here:
public void startBluetoothSco () Since: API Level 8 Start bluetooth SCO
audio connection.
Requires Permission:
MODIFY_AUDIO_SETTINGS.
This method can be used by
applications wanting to send and
received audio to/from a bluetooth SCO
headset while the phone is not in
call.
As the SCO connection establishment
can take several seconds, applications
should not rely on the connection to
be available when the method returns
but instead register to receive the
intent ACTION_SCO_AUDIO_STATE_CHANGED
and wait for the state to be
SCO_AUDIO_STATE_CONNECTED.
As the connection is not guaranteed to
succeed, applications must wait for
this intent with a timeout.
When finished with the SCO connection
or if the establishment times out, the
application must call
stopBluetoothSco() to clear the
request and turn down the bluetooth
connection.
Even if a SCO connection is
established, the following
restrictions apply on audio output
streams so that they can be routed to
SCO headset: - the stream type must be
STREAM_VOICE_CALL - the format must be
mono - the sampling must be 16kHz or
8kHz
The following restrictions apply on
input streams: - the format must be
mono - the sampling must be 8kHz
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.
See Also stopBluetoothSco()
ACTION_SCO_AUDIO_STATE_CHANGED
Note that I have not tested this, I'm just passing along a lead I found in researching a similar project. I think Jayesh was close to the solution and the restrictions above may have been what was keeping it from working.
To turn on:
localAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
localAudioManager.setMode(0);
localAudioManager.setBluetoothScoOn(true);
localAudioManager.startBluetoothSco();
localAudioManager.setMode(AudioManager.MODE_IN_CALL);
To turn off:
localAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
localAudioManager.setBluetoothScoOn(false);
localAudioManager.stopBluetoothSco();
localAudioManager.setMode(AudioManager.MODE_NORMAL);
I took it from here
Great Work it is working fine for me please do bit modification in your code it'll work perfectly i.e.
mPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
to
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
There should be a ALSA route path configured for Media player, so that it can open a different audio path and then route your audio to BT headset.
Cannot see a clear accepted working application so putting a new answer. This application routes music and audio to Non A2dp headsets. Try my application and find the source code also in github for reference code. https://github.com/sauravpradhan/AnySound2BT