Programmatically connect to paired Bluetooth speaker and play audio

前端 未结 4 1639
陌清茗
陌清茗 2020-12-15 22:59

In our app, I\'d like to connect to a previously paired A2DP Bluetooth Speaker and direct audio playback to it, using Android v4.2 or later.

I can successfully creat

相关标签:
4条回答
  • 2020-12-15 23:56

    This one works for me. After receive BluetoothA2dp.STATE_CONNECTED, you can play music as normal.

    public class A2DPActivity extends Activity {
    
    protected static final String TAG = "ZS-A2dp";
    
    Button mBtPlay;
    
    BluetoothAdapter mBtAdapter;
    BluetoothA2dp mA2dpService;
    
    AudioManager mAudioManager;
    MediaPlayer mPlayer;
    
    BroadcastReceiver mReceiver = new BroadcastReceiver() {
    
        @Override
        public void onReceive(Context ctx, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG, "receive intent for action : " + action);
            if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
                int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_DISCONNECTED);
                if (state == BluetoothA2dp.STATE_CONNECTED) {
                    setIsA2dpReady(true);
                    playMusic();
                } else if (state == BluetoothA2dp.STATE_DISCONNECTED) {
                    setIsA2dpReady(false);
                }
            } else if (action.equals(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED)) {
                int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_NOT_PLAYING);
                if (state == BluetoothA2dp.STATE_PLAYING) {
                    Log.d(TAG, "A2DP start playing");
                    Toast.makeText(A2DPActivity.this, "A2dp is playing", Toast.LENGTH_SHORT).show();
                } else {
                    Log.d(TAG, "A2DP stop playing");
                    Toast.makeText(A2DPActivity.this, "A2dp is stopped", Toast.LENGTH_SHORT).show();
                }
            }
        }
    
    };
    
    boolean mIsA2dpReady = false;
    void setIsA2dpReady(boolean ready) {
        mIsA2dpReady = ready;
        Toast.makeText(this, "A2DP ready ? " + (ready ? "true" : "false"), Toast.LENGTH_SHORT).show();
    }
    
    private ServiceListener mA2dpListener = new ServiceListener() {
    
        @Override
        public void onServiceConnected(int profile, BluetoothProfile a2dp) {
            Log.d(TAG, "a2dp service connected. profile = " + profile);
            if (profile == BluetoothProfile.A2DP) {
                mA2dpService = (BluetoothA2dp) a2dp;
                if (mAudioManager.isBluetoothA2dpOn()) {
                    setIsA2dpReady(true);
                    playMusic();
                } else {
                    Log.d(TAG, "bluetooth a2dp is not on while service connected");
                }
            }
        }
    
        @Override
        public void onServiceDisconnected(int profile) {
            setIsA2dpReady(false);
        }
    
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout ll = new LinearLayout(this);
        setContentView(ll);
    
        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        registerReceiver(mReceiver, new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED));
        registerReceiver(mReceiver, new IntentFilter(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED));
    
        mBtAdapter = BluetoothAdapter.getDefaultAdapter();
        mBtAdapter.getProfileProxy(this, mA2dpListener , BluetoothProfile.A2DP);
    
    }
    
    @Override
    protected void onDestroy() {
        mBtAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dpService);
        releaseMediaPlayer();
        unregisterReceiver(mReceiver);
        super.onDestroy();
    }
    
    @Override
    protected void onPause() {
        releaseMediaPlayer();
        super.onPause();
    }
    
    private void releaseMediaPlayer() {
        if (mPlayer != null) {
            mPlayer.release();
            mPlayer = null;
        }
    }
    
    private void playMusic() {
        mPlayer = new MediaPlayer();
        AssetManager assetManager = this.getAssets();
        AssetFileDescriptor fd;
        try {
            fd = assetManager.openFd("Radioactive.mp3");
            Log.d(TAG, "fd = " + fd);
            mPlayer.setDataSource(fd.getFileDescriptor());
            mPlayer.prepare();
            Log.d(TAG, "start play music");
            mPlayer.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    

    }

    0 讨论(0)
  • 2020-12-15 23:56
    mMediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
                        .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
                        .setLegacyStreamType(AudioManager.STREAM_MUSIC)
                        //.setUsage(AudioAttributes.USAGE_ALARM)
                        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                        .build());
    

    By Commenting .setUsage(AudioAttributes.USAGE_ALARM) line, it work for me.

    0 讨论(0)
  • 2020-12-16 00:04

    Ted,

    I have the same issue like you when I tried with BluetoothHeadset. I guess my work around may work with A2DP. Since my headset only support Handsfree profile. I am only test with BluetoothHeadset.

    No need to establish RFComm channel.

    For me. After you connected to BluetoothHeadsetService, 1. check whether audio is already connected

    mBluetoothSpeaker.isAudioConnected(btSpeaker);
    

    2. if not, establish audio connection

    mBluetoothSpeaker.startVoiceRecognition(btSpeaker);
    

    3. register BroadcastReceiver for BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED and BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED

    registerReceiver(mReceiver, new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED));
    registerReceiver(mReceiver, new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED));
    

    4. BroadcastReceiver

    protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            int state = BluetoothHeadset.STATE_DISCONNECTED;
            int previousState = intent.getIntExtra(BluetoothHeadset.EXTRA_PREVIOUS_STATE, BluetoothHeadset.STATE_DISCONNECTED);
            if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
                state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_DISCONNECTED);
                if (state == BluetoothHeadset.STATE_CONNECTED) {
                    mConnectedHeadset = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    mInfoTextview.append("\n\nDevice name = " + mConnectedHeadset.getName());
    
                    // Audio should not be connected yet but just to make sure.
                    if (mBluetoothHeadset.isAudioConnected(mConnectedHeadset)) {
                        Log.d(TAG, "Headset audio connected already");
                    } else {
                        if (!mBluetoothHeadset.startVoiceRecognition(mConnectedHeadset)) {
                            Log.e(TAG, "maybe you do not call stopVoiceRecognition previously");
                            mBluetoothHeadset.stopVoiceRecognition(mConnectedHeadset);
                            mBluetoothHeadset.startVoiceRecognition(mConnectedHeadset);
                        }
                    }
                }
                else if (state == BluetoothHeadset.STATE_DISCONNECTED) {
                    mConnectedHeadset = null;
                }
            }
            else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED))// audio
            {
                state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
                    // Bluetooth audio connected. you send audio stream to headset now!!!
                    mAudioManager.setMode(AudioManager.STREAM_VOICE_CALL);
                    mMediaPlayer = new MediaPlayer();
                    AssetManager assetManager = getAssets();
                    try {
            AssetFileDescriptor fd = assetManager.openFd("Radioactive.mp3");
            mMediaPlayer.setDataSource(fd.getFileDescriptor());
                        // set audio stream type to STREAM_VOICE_CALL will send audio to headset
                        // @see <a href="http://developer.android.com/reference/android/media/AudioManager.html#startBluetoothSco()">SCO</a>
                        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
            mMediaPlayer.prepare();
            Log.d(TAG, "start play music");
            mMediaPlayer.start();
            } catch (IOException e) {
            e.printStackTrace();
            }
                }
                else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
                    if (mMediaPlayer != null) {
                    mMediaPlayer.stop();
                    mMediaPlayer = null;
                    }
                    mBluetoothHeadset.stopVoiceRecognition(mConnectedHeadset);
                }
            }   
        }
    };
    
    0 讨论(0)
  • 2020-12-16 00:04

    Had the same problem, but found that older post:

    Programmatically connect to paired Bluetooth device

    In short, in order to connect to a paired a2dp device, you simply have to invoke BluetoothA2dp.connect(myPairedA2dpDevice), but right now that method is hidden from the public API, which is not helpful. So you access it through Java reflection. It's kind of a hack, but the way Google put it, there doesn't seem to be a clean solution for now.

    0 讨论(0)
提交回复
热议问题