android - 无法从蓝牙麦克风获取音频

标签 android android-bluetooth audiotrack audiorecord headset

我想从蓝牙耳机获取音频并在蓝牙耳机本身上播放。我可以在 lollipop(5.1.1)(Samsung note 3 neo) 上执行此操作,但在 android(7.0)(Redmi Note 4) 上不起作用。 我首先创建一个音轨,然后启动一个新线程来从麦克风读取音频。首先,它开始从音素读取音频。单击蓝牙按钮后,它将启动蓝牙 SCO。

有人可以帮忙吗?


    package surya.com.audiorecord;

    import android.Manifest;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.content.pm.PackageManager;
    import android.media.AudioFormat;
    import android.media.AudioManager;
    import android.media.AudioRecord;
    import android.media.AudioTrack;
    import android.media.MediaRecorder;
    import android.os.Build;
    import android.os.Bundle;
    import android.support.v4.app.ActivityCompat;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;

    import java.nio.ByteBuffer;
    import java.util.concurrent.atomic.AtomicBoolean;

    /**
     * Sample that demonstrates how to record from a Bluetooth HFP microphone using {@link AudioRecord}.
     */
    public class BluetoothRecordActivity extends AppCompatActivity {

        private static final String TAG = BluetoothRecordActivity.class.getCanonicalName();

        private static final int SAMPLING_RATE_IN_HZ = 16000;

        private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;

        private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;

        /**
         * Factor by that the minimum buffer size is multiplied. The bigger the factor is the less
         * likely it is that samples will be dropped, but more memory will be used. The minimum buffer
         * size is determined by {@link AudioRecord#getMinBufferSize(int, int, int)} and depends on the
         * recording settings.
         */
        private static final int BUFFER_SIZE_FACTOR = 2;

        /**
         * Size of the buffer where the audio data is stored by Android
         */
        private static final int BUFFER_SIZE = AudioRecord.getMinBufferSize(SAMPLING_RATE_IN_HZ,
                CHANNEL_CONFIG, AUDIO_FORMAT) * BUFFER_SIZE_FACTOR;

        /**
         * Signals whether a recording is in progress (true) or not (false).
         */
        private final AtomicBoolean recordingInProgress = new AtomicBoolean(false);


        private AudioRecord recorder = null;

        private AudioManager audioManager;

        private Thread recordingThread = null;

        private Button startButton;

        private Button stopButton;

        private Button bluetoothButton;
        AudioTrack mAudioTrack;

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

            audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
            try {
                outputBufferSize = AudioTrack.getMinBufferSize(16000,
                        AudioFormat.CHANNEL_IN_STEREO,
                        AudioFormat.ENCODING_PCM_16BIT);
                mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 16000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, outputBufferSize, AudioTrack.MODE_STREAM);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    mAudioTrack.setVolume(100);
                }
                mAudioTrack.play();
            } catch (Exception e) {
                e.printStackTrace();
            }


            startButton = (Button) findViewById(R.id.btnStart);
            startButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    startRecording();
                }
            });

            stopButton = (Button) findViewById(R.id.btnStop);
            stopButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    stopRecording();
                }
            });


            bluetoothButton = (Button) findViewById(R.id.btnBluetooth);
            bluetoothButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    activateBluetoothSco();
                }
            });


            requestAudioPermissions();


        }

        int outputBufferSize;

        @Override
        protected void onResume() {
            super.onResume();

            ButtonEnableSetters();

            registerReceiver(bluetoothStateReceiver, new IntentFilter(
                    AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));
        }

        private void ButtonEnableSetters() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    bluetoothButton.setEnabled(calculateBluetoothButtonState());
                    startButton.setEnabled(calculateStartRecordButtonState());
                    stopButton.setEnabled(calculateStopRecordButtonState());
                }
            });
        }

        @Override
        protected void onPause() {
            super.onPause();

            stopRecording();
            unregisterReceiver(bluetoothStateReceiver);
        }

        private void startRecording() {
            // Depending on the device one might has to change the AudioSource, e.g. to DEFAULT
            // or VOICE_COMMUNICATION
            recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
                    SAMPLING_RATE_IN_HZ, CHANNEL_CONFIG, AUDIO_FORMAT, BUFFER_SIZE);

            recorder.startRecording();

            recordingInProgress.set(true);
            try {
                recordingThread = new Thread(new RecordingRunnable(), "Recording Thread");
                recordingThread.start();

            } catch (Exception e) {
                e.printStackTrace();
            }
            ButtonEnableSetters();

        }

        private void stopRecording() {
            if (null == recorder) {
                return;
            }

            recordingInProgress.set(false);

            recorder.stop();

            recorder.release();

            recorder = null;

            recordingThread = null;

            ButtonEnableSetters();

        }

        private void activateBluetoothSco() {
            if (!audioManager.isBluetoothScoAvailableOffCall()) {
                Log.e(TAG, "SCO ist not available, recording is not possible");
                return;
            }

            if (!audioManager.isBluetoothScoOn()) {
                audioManager.startBluetoothSco();
                audioManager.setBluetoothScoOn(true);
            }
        }

        private void bluetoothStateChanged(BluetoothState state) {
            Log.i(TAG, "Bluetooth state changed to:" + state);

            if (BluetoothState.UNAVAILABLE == state && recordingInProgress.get()) {
                stopRecording();
            }
            ButtonEnableSetters();


        }

        private boolean calculateBluetoothButtonState() {
            return !audioManager.isBluetoothScoOn();
        }

        private boolean calculateStartRecordButtonState() {
            return audioManager.isBluetoothScoOn() && !recordingInProgress.get();
        }

        private boolean calculateStopRecordButtonState() {
            return audioManager.isBluetoothScoOn() && recordingInProgress.get();
        }

        private class RecordingRunnable implements Runnable {

            @Override
            public void run() {
                if (mAudioTrack != null) {
                    if (mAudioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) {
                        mAudioTrack.play();
                    } else {
                        mAudioTrack.stop();
                        mAudioTrack.flush();

                        mAudioTrack.play();
                    }
                }

    //            final File file = new File(Environment.getExternalStorageDirectory(), "recording.pcm");
                final ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE);

                while (recordingInProgress.get()) {
                    int result = recorder.read(buffer, BUFFER_SIZE);
                    if (result  0
                            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        // permission was granted, yay!
    //                    recordAudio();
                        activateBluetoothSco();
                        startRecording();
                    } else {
                        // permission denied, boo! Disable the
                        // functionality that depends on this permission.
                        Toast.makeText(this, "Permissions Denied to record audio", Toast.LENGTH_LONG).show();
                    }
                    return;
                }
            }
        }

        private final BroadcastReceiver bluetoothStateReceiver = new BroadcastReceiver() {

            private BluetoothState bluetoothState = BluetoothState.UNAVAILABLE;

            @Override
            public void onReceive(Context context, Intent intent) {
                int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
                switch (state) {
                    case AudioManager.SCO_AUDIO_STATE_CONNECTED:
                        Log.i(TAG, "Bluetooth HFP Headset is connected");
                        handleBluetoothStateChange(BluetoothState.AVAILABLE);
                        break;
                    case AudioManager.SCO_AUDIO_STATE_CONNECTING:
                        Log.i(TAG, "Bluetooth HFP Headset is connecting");
                        handleBluetoothStateChange(BluetoothState.UNAVAILABLE);
                    case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
                        Log.i(TAG, "Bluetooth HFP Headset is disconnected");
                        handleBluetoothStateChange(BluetoothState.UNAVAILABLE);
                        break;
                    case AudioManager.SCO_AUDIO_STATE_ERROR:
                        Log.i(TAG, "Bluetooth HFP Headset is in error state");
                        handleBluetoothStateChange(BluetoothState.UNAVAILABLE);
                        break;
                }
            }

            private void handleBluetoothStateChange(BluetoothState state) {
                if (bluetoothState == state) {
                    return;
                }

                bluetoothState = state;
                bluetoothStateChanged(state);
            }
        };

    }

这是项目源代码 https://bitbucket.org/surya945/audiorecord

最佳答案

  • 欢迎来到 stackoverflow
  • 我认为您的问题与
  • 有关
  • build.gardle(module:app) 中的 TargetSdkVersion
  • 检查这个

enter image description here

关于android - 无法从蓝牙麦克风获取音频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54492486/

相关文章:

android - Roboguice 注入(inject)适配器

android - 什么时候使用 System.exit(0) 和 System.exit(2)?

android - 当您的应用程序安装在 Android 上时,您可以运行 Intent 或脚本吗?

android启动蓝牙sco不在 Lollipop 中路由麦克风

android - 如何检测连接的蓝牙外围设备(自拍杆)的点击事件?

Android Ble 扫描回调未连续触发

java - Android 设备有多少个核心?我可以使用多少个线程来获得最佳性能?

java - 如何通过AudioTrack播放大型PCM文件? (目前出现错误)

java - 当我使用 Java 在 Android 上生成正弦波时噪音很大

将 MIC 直接传输到电话扬声器的 Android 程序