mercredi 11 février 2015

startBluetoothSco(), recording audio from bluetooth headset not working correctly

I am trying to record audio from bluetooth headset, startBluetoothSco() works different in different versions of android, Recording audio from bluetooth headset on android 4.2, 4.4, and 5.0. using "Nokia BH-310 and 9xxPlantronics " bluetooth headsets.


SAMPLE_RATE = 8000;



  1. Devices running Android 4.2 records audio from bluetooth device only when when AudioRecord() object is created like this



AudioSource.DEFAULT




mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
bufferSize);



  1. Devices running Android 4.4 records audio from bluetooth device only when when AudioRecord() object is created like this



AudioSource.DEFAULT




mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
bufferSize);


Or



AudioSource.MIC




mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
bufferSize);



  1. Devices running Android 5.0 Lollipop records audio from bluetooth device only when when AudioRecord() object is created like this



AudioSource.VOICE_COMMUNICATION




mRecorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
bufferSize);

//with other AudioSource types (MIC, DEFAULT) sco returns connected state but record from phone mic



LOG for Android 5.0 device connction states




D/inside onRcv﹕ state=0
D/State=﹕ conn -> 0
D/inside onRcv﹕ state=2
D/State=﹕ conn -> 2
D/inside onRcv﹕ state=1
D/inside onRcv﹕ Unregister rcvr
D/inside onRcv﹕ Connected Record from bluetooth

//But still record from phone mic if Audio record object is created using MIC or DEFAULT


Full code i am using to do above is here.



BluetoothManager.java



public class BluetoothRecordingManager {
private static int count = 0;
private static int TIMEOUT = 3000;
private static int COUNTDOWN_INTERVAL = 1000;
private static final int MAX_ATTEPTS_TO_CONNECT = 3;

/**
* This method check for bluetooh settings (bluetooth flag and bluetooth is
* on or off) and decide wheather to record from bluetooth headset or phone
* mic. If settings are not correct then start's recording using phone mic.
*
* @param context
* @param BluetoothRecording :- Interface object
* @param resume :- Pass through
*/
public static void checkAndRecord(final Context context, final OnBluetoothRecording BluetoothRecording, boolean resume) {

if (getBluetoothFlag() && isBluetoothON()) {
Log.d("start bluetooth recording"," calling");
startBluetoothRecording(BluetoothRecording, resume, context);
} else {
// If Bluetooth is OFF Show Toast else Dont Show
if (getBluetoothFlag() && !isBluetoothON()) {
Toast.makeText(context, "bluetooth_off", Toast.LENGTH_LONG).show();
// false because recording not started
BluetoothRecording.onStartRecording(resume, false);
} else {
// false because recording not started
BluetoothRecording.onStartRecording(resume, false);
}
}
}

/**
* Connect to bluetooth headset and start recording if headset failed to
* connect then records normally using phone mic.
*
* @param BluetoothRecording
* @param resume
* @param context
*/
private static void startBluetoothRecording(final OnBluetoothRecording BluetoothRecording, final boolean resume, final Context context) {
final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
//audioManager.setBluetoothScoOn(true);

final CountDownTimer timer = getTimer(BluetoothRecording, audioManager, resume);
Log.d("inside","startBlue rec");

final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
Log.d("inside onRcv","state="+state);
if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state ) {
// cancel Timer
timer.cancel();
Log.d("inside onRcv","Unregister rcvr");
context.unregisterReceiver(this);
Log.d("inside onRcv","Connected Record from bluetooth");
// pass through and true because
// recording from bluetooth so set 8000kHz
BluetoothRecording.onStartRecording(resume, true);
}
}
};

Log.d("calling","registr broadcast rcvr");
context.registerReceiver(broadcastReceiver, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));
// Start the timer

try {
// Android 2.2 onwards supports BT SCO for non-voice call use case
// Check the Android version whether it supports or not.
if(audioManager.isBluetoothScoAvailableOffCall()){
if(audioManager.isBluetoothScoOn()){
Log.d("SCO","stopped SCO");
// audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.stopBluetoothSco();
timer.start();
Log.d("Starting sco","start");
audioManager.startBluetoothSco();
}else {
timer.start();
Log.d("Starting sco","start");
audioManager.startBluetoothSco();
}
}else {
Log.d("Sco","Not availiable");
}
} catch (Exception e) {
Log.d("sco elsepart startBluetoothSCO"," "+e);
timer.cancel();
context.unregisterReceiver(broadcastReceiver);
BluetoothRecording.onStartRecording(resume, false);
}
}

/**
* set the Timeout
*
* @param BluetoothRecording
* @param audioManager
* @param resume
* @return
*/
private static CountDownTimer getTimer(final OnBluetoothRecording BluetoothRecording, final AudioManager audioManager, final boolean resume) {
return new CountDownTimer(TIMEOUT, COUNTDOWN_INTERVAL) {
@Override
public void onTick(long millisUntilFinished) {
// Do Nothing
}

@Override
public void onFinish() {
// stopBluetoothSCO() and start Normal Recording
audioManager.stopBluetoothSco();

// false because recording button is already clicked but still not recording.
BluetoothRecording.onStartRecording(resume, false);
}
};
}

/**
* Return's the bluetooth state
*
* @return
*/
private static boolean isBluetoothON() {
/*BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null) {
return bluetoothAdapter.isEnabled();
} else {
return false;
}*/
return true;
}

/**
* Return's the bluetoothFlag state
*
* @return
*/
private static boolean getBluetoothFlag() {

return true;
}
}


MainActivity.java


This is how i am creating audio record object and starting recording.



public class MainActivity extends Activity implements AdapterView.OnItemSelectedListener {

public static final int SAMPLE_RATE = 8000;
private AudioRecord mRecorder;
private File mRecording;
private short[] mBuffer;
private final String startRecordingLabel = "Start recording";
private final String stopRecordingLabel = "Stop recording";
private boolean mIsRecording = false;
private ProgressBar mProgressBar;
float iGain = 1.0f;
CheckBox gain;
Button showPref;
OnBluetoothRecording bluetoothRecording;
protected int bitsPerSamples = 16;

@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);

initRecorder()

button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View v) {
if (!mIsRecording) {
BluetoothRecordingManager.checkAndRecord(getApplicationContext(), new OnBluetoothRecording() {

@Override
public void onStartRecording(boolean state, boolean bluetoothFlag) {

Log.d("CallBack", "starting Recording");
if (!mIsRecording) {
button.setText(stopRecordingLabel);
mIsRecording = true;
mRecorder.startRecording();
mRecording = getFile("raw");
startBufferedWrite(mRecording);
} else {
Log.d("stop", "else part of start");
button.setText(startRecordingLabel);
mIsRecording = false;
mRecorder.stop();
File waveFile = getFile("wav");
try {
rawToWave(mRecording, waveFile);
} catch (IOException e) {
Toast.makeText(MainActivity.this, e.getMessage(),
Toast.LENGTH_SHORT).show();
}
Toast.makeText(MainActivity.this,
"Recorded to " + waveFile.getName(),
Toast.LENGTH_SHORT).show();
}
}

@Override
public void onCancelRecording() {
}
}, true);
} else {
Log.d("stop", "stopped recording");
button.setText(startRecordingLabel);
mIsRecording = false;
mRecorder.stop();
File waveFile = getFile("wav");
try {
rawToWave(mRecording, waveFile);
} catch (IOException e) {
Toast.makeText(MainActivity.this, e.getMessage(),
Toast.LENGTH_SHORT).show();
}
final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
//audioManager.setMode(AudioManager.MODE_NORMAL);
if (audioManager.isBluetoothScoOn()) {
Log.d("SCO", "stopped SCO");
audioManager.stopBluetoothSco();
}
Toast.makeText(MainActivity.this,
"Recorded to " + waveFile.getName(),
Toast.LENGTH_SHORT).show();
}
}
});
}
private void initRecorder() {
int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
mBuffer = new short[bufferSize];

Log.d("Creating Obj", "" + Mic);
mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
bufferSize);
}
}

Aucun commentaire:

Enregistrer un commentaire