How to record sound from a Bluetooth headset (startBluetoothSco ())

I'm trying to record audio from a bluetooth headset, startBluetoothSco () works differently in different versions of Android, recording sound from a bluetooth headset on Android 4.2, 4.4 and 5.0. using the " Nokia BH-310 and 9xxPlantronics " Bluetooth headsets.

SAMPLE_RATE = 8000;

  • Android 4.2 devices only record sound from a Bluetooth device when an AudioRecord () object like this is created

AudioSource.DEFAULT

mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize); 
  1. Android 4.4 devices only record audio from a Bluetooth device when an AudioRecord () object like this is created

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. Android 5.0 Lollipop devices only record audio from a Bluetooth device when an AudioRecord () object like this is created

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 connection 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 

The full code that I use 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 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 the bluetooth state * * @return */ private static boolean isBluetoothON() { /*BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter != null) { return bluetoothAdapter.isEnabled(); } else { return false; }*/ return true; } /** * Return the bluetoothFlag state * * @return */ private static boolean getBluetoothFlag() { return true; } } 

MainActivity.java

This is how I create an audio object and start 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); } } 
+6
source share

Source: https://habr.com/ru/post/982311/


All Articles