如何录制蓝牙耳机的音频(startBluetoothSco())

时间:2015-02-11 09:08:42

标签: android audio bluetooth audio-recording bluetooth-sco

我正在尝试从蓝牙耳机录制音频,startBluetoothSco()在不同版本的android中工作不同,在Android 4.2,4.4和5.0上录制来自蓝牙耳机的音频。使用“ 诺基亚BH-310和9xxPlantronics ”蓝牙耳机。

SAMPLE_RATE = 8000;

  1. 只有当像这样创建AudioRecord()对象时,运行Android 4.2的设备才会记录来自蓝牙设备的音频
  2.   

    AudioSource.DEFAULT

    mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE,
                        AudioFormat.CHANNEL_IN_MONO,     AudioFormat.ENCODING_PCM_16BIT,
                        bufferSize);
    
    1. 只有当像这样创建AudioRecord()对象时,运行Android 4.4的设备才会记录来自蓝牙设备的音频
    2.   

      AudioSource.DEFAULT

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

      或者

        

      AudioSource.MIC

          mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,
                          AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
                          bufferSize);
      
      1. 运行Android 5.0 Lollipop的设备只有在创建AudioRecord()对象时才会记录蓝牙设备的音频
      2.   

        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设备连接状态

        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
        

        我上面用的完整代码就在这里。

        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

        这就是我创建录音对象和开始录音的方式。

        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);
        }
        }
        

0 个答案:

没有答案