I have a bluetooth headset (which can play stereo music) connected to my android phone (Android 4.4.3). Now I want my code to play a stereo music and record audio from that headset, both at high sampling rates (44100). I followed the solutions in the following posts.
How to record sound using bluetooth headset
Capture Audio through Bluetooth Headset paired with Android Device
My basic code looks like this.
Permissions:
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.RECORD_AUDIO
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.BROADCAST_STICKY
android.permission.BLUETOOTH
Code to turn on Bluetooth Sco:
m_amAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
public void turnOnBluetooth() {
final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state) {
System.err.println("bluetooth connected");
unregisterReceiver(this);
} else if (AudioManager.SCO_AUDIO_STATE_DISCONNECTED == state) {
System.err.println("bluetooth disconnected");
}
}
};
registerReceiver(broadcastReceiver, new IntentFilter(
AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));
try {
if (m_amAudioManager.isBluetoothScoAvailableOffCall()) {
if (m_amAudioManager.isBluetoothScoOn()) {
m_amAudioManager.stopBluetoothSco();
m_amAudioManager.startBluetoothSco();
System.err.println("Bluetooth SCO On!");
} else {
System.err.println("Bluetooth Sco Off!");
m_amAudioManager.startBluetoothSco();
}
} else {
System.err.println("Bluetooth SCO not available");
}
} catch (Exception e) {
System.err.println("sco elsepart startBluetoothSCO " + e);
unregisterReceiver(broadcastReceiver);
}
}
Code to play a stereo music:
public void playMusic(){
this.mediaPlayer = new MediaPlayer();
this.mediaPlayer
.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
this.mediaPlayer.setDataSource(Environment.getExternalStorageDirectory().
getAbsolutePath()+ "/"+ folderName + "/stereo.wav");
// change type to STREAM_VOICE_CALL can partly solve the problem
// but reduces the quality of the music, which is critical in my case
this.mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
this.mediaPlayer.prepare();
this.mediaPlayer.start();
}
Code to record audio:
public void recordAudio() {
AudioRecorder recorder = new AudioRecord(
audioSource, // MediaRecorder.AudioSource.MIC
RECORDER_SAMPLERATE, // 44100
RECORDER_CHANNELS, // AudioFormat.CHANNEL_IN_MONO
RECORDER_AUDIO_ENCODING, // AudioFormat.ENCODING_PCM_16BIT
bufferSize // obtained by AudioRecord.getMinBufferSize()
);
int i = recorder.getState();
if (i == 1)
recorder.startRecording();
// then read bytes from the recorder
}
How here are the problems.
Case 1: if I call the following sequence
turnOnBluetooth();
playMusic();
recordAudio();
The music plays through the phone's speaker rather than the bluetooth headset. The recorder can record sound from the bluetooth headset's mic but at very low sampling rate (8kHz).
Case 2: if I do not call turnOnBluetooth(), i.e., execute the following sequence
playMusic();
recordAudio();
The music plays through the bluetooth headset now, but the recorder only records audio from the phone's built-in mic.
I also tried to change the mode of the AudioManager by
m_amAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
and set the audio route by
m_amAudioManager.setSpeakerphoneOn(false);
m_amAudioManager.setBluetoothScoOn(true);
The result is the same to case 1. And if I set
m_amAudioManager.setBluetoothScoOn(false);
It repeats case 2.
I have worked on this for a few days and the above behavior is puzzling me a lot. Have I missed anything in audio settings? Or do I need more sophisticated control with the bluetooth headset's settings? Thanks for reading this and any suggestion is welcome. Thank you!