title: How to record audio from bluetooth headset (startBluetoothSco() )
body: <p>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 "<strong><em>Nokia BH-310 and 9xxPlantronics</em></strong>" bluetooth headsets.</p>
  
  <p>SAMPLE_RATE = 8000;</p>
  
  <ol>
  <li>Devices running  Android 4.2 records audio from bluetooth device only when when AudioRecord() object is created like this   </li>
  </ol>
  
  <blockquote>
    <p>AudioSource.DEFAULT</p>
  </blockquote>
  
  <pre><code>mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE,
                      AudioFormat.CHANNEL_IN_MONO,     AudioFormat.ENCODING_PCM_16BIT,
                      bufferSize);
  </code></pre>
  
  <ol start="2">
  <li>Devices running  Android 4.4 records audio from bluetooth device only when when AudioRecord() object is created like this   </li>
  </ol>
  
  <blockquote>
    <p>AudioSource.DEFAULT</p>
  </blockquote>
  
  <pre><code>    mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE,
                      AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
                      bufferSize);
  </code></pre>
  
  <p>Or</p>
  
  <blockquote>
    <p>AudioSource.MIC</p>
  </blockquote>
  
  <pre><code>    mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,
                      AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
                      bufferSize);
  </code></pre>
  
  <ol start="3">
  <li>Devices running  Android 5.0 Lollipop records audio from bluetooth device only when when AudioRecord() object is created like this   </li>
  </ol>
  
  <blockquote>
    <p>AudioSource.VOICE_COMMUNICATION</p>
  </blockquote>
  
  <pre><code>    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
  </code></pre>
  
  <blockquote>
    <p>LOG for Android 5.0 device connction states</p>
  </blockquote>
  
  <pre><code>D/inside onRcv﹕ state=0
  D/State=﹕ conn -&gt; 0
  D/inside onRcv﹕ state=2
  D/State=﹕ conn -&gt; 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
  </code></pre>
  
  <p><strong>Full code i am using to do above is here.</strong></p>
  
  <pre><code>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() &amp;&amp; isBluetoothON()) {
          Log.d("start bluetooth recording"," calling");
          startBluetoothRecording(BluetoothRecording, resume, context);
      } else {
          // If Bluetooth is OFF Show Toast else Dont Show
          if (getBluetoothFlag() &amp;&amp; !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;
  }
     }
  </code></pre>
  
  <p>MainActivity.java</p>
  
  <p>This is how i am creating audio record object and starting recording.</p>
  
  <pre><code>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);
  }
  }
  </code></pre>