处理蓝牙耳机键

时间:2020-06-25 06:19:55

标签: android bluetooth android-bluetooth

我正在寻找一种可靠的方法来处理蓝牙耳机上的音量按钮按下。我的测试设备是小米Mi耳机,但此功能应适用于所有基本耳机。

新近配对的耳机音量按钮正在改变音量,但是只有“内部” ...在Android中设置的音量不会改变,静止不动。在这种情况下,似乎只在耳机上改变了音量-Android上设置的最大值也是耳机上的最大值(例如,设备上的1/10音量=耳机上的最大1/10音量)。当我打开“主”应用程序(已经在处理bt连接)并打开SCO时,我可以使用耳机按钮更改通话音量,Android会在屏幕上显示控件。第二种情况很有意思,但是任何方法都足以处理这些键...

我创建了一个新项目并进行了尝试,

  1. MediaSessionCompat-VolumeProviderCompat完全不触发
  2. MediaSessionCompat.Callback,方法onMediaButtonEvent仅通过开/关/呼叫按钮被调用。此外,当我setBluetoothScoOn(true)
  3. 时根本不会调用该方法
  4. ACTION_VENDOR_SPECIFIC_HEADSET_EVENT-耳机启动时,我仅收到一两个AT命令(电池信息),而按一下按钮(SCO处于打开和关闭状态)都没有得到任何数据
  5. 尝试从BluetoothSocket读取,socket.isconnected()true,但是在等待数据的行的下一个socket.getInputStream().read(buffer)上挂起,从未收到单个字节,超时或异常。 。
  6. 很明显,这些点击不是KeyEvent s

相关片段-适用于1.和2。:

private void setupMediaSession() {
    MediaSessionCompat mediaSession = new MediaSessionCompat(this, "PlayerService");
    mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
            MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
    mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
            .setState(PlaybackStateCompat.STATE_PLAYING, 0, 0) //you simulate a player which plays something.
            .build());

    VolumeProviderCompat volumeProvider = new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, /*max volume*/100, /*initial volume level*/50) {
        @Override
        public void onAdjustVolume(int direction) {
            Timber.i("TESTTEST onAdjustVolume direction: %s", direction);
        }
    };
    mediaSession.setPlaybackToRemote(volumeProvider);

    MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() {

        @Override
        public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
            Timber.i("TESTTEST onMediaButtonEvent mediaButtonEvent: %s", mediaButtonEvent.getAction());
            return true;
        }
    };
    mediaSession.setCallback(mMediaSessionCallback);
    AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 48000, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
            AudioTrack.getMinBufferSize(48000, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT), AudioTrack.MODE_STREAM);
    at.play();
    mediaSession.setActive(true);
    Timber.i("TESTTEST setupMediaSession isActive: %s", mediaSession.isActive());
}

3。

private void setupVendorReceiver() {
    IntentFilter intentFilter = new IntentFilter(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
    /*intentFilter.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY +
            '.'+ 911); // Xiaomi*/
    for(int i=0; i< 3000; i++) {
        intentFilter.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY +
                '.' + i);
    }
    registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Timber.i("TESTTEST setupVendor onReceive: %s", intent.getAction());
            for (String key: intent.getExtras().keySet())
            {
                Timber.i( "TESTTEST, "+key + ":"+intent.getExtras().get(key));
                if(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS.equals(key)){
                    Object[] args = (Object[]) intent.getExtras().get(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS);
                    for(Object arg : args){
                        Timber.i( "TESTTEST, arg: %s", arg);
                    }
                }
            }
        }
    }, intentFilter);
}

for 4。

private void socketConnection() {
    Set<BluetoothDevice> bs = BluetoothAdapter.getDefaultAdapter().getBondedDevices();
    for (BluetoothDevice device : bs) {
        Timber.i("TESTTEST device: %s", device);
        try {
            socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
            break;
        } catch (IOException e) {
            Timber.e(e);
        }
    }
    new Thread() {
        @Override
        public void run() {
            InputStream in;
            OutputStream out;
            try {
                socket.connect();
                in = socket.getInputStream();
                out = socket.getOutputStream();
            } catch (IOException e) {
                Timber.e(e);
                socket = null;
                return;
            }

            while (isRunning) {
                try {
                    Timber.i("TESTTEST socket.isConnected() %s", socket.isConnected());
                    if (socket.isConnected()) {
                        int bytesRead = in.read(buffer);
                        Timber.i("TESTTEST bytesRead %s buffer %s", bytesRead, buffer);
                    }
                } catch (IOException e) {
                    Timber.e(e);
                }
            }
        }
    }.start();
}

5。

@Override
public boolean onKeyDown(final int keyCode, KeyEvent event) {
    Timber.i("TESTTEST onKeyDown: %s", keyCode);
    return super.onKeyDown(keyCode, event);
}

在上述摘录中打开配对耳机(ACL),然后运行我的应用程序会显示此日志

com.example.myapplication I/MainActivity: TESTTEST onCreate
com.example.myapplication I/BluetoothSoc: TESTTEST device: 1C:52:16:3E:B4:03
com.example.myapplication I/MainActivity: TESTTEST setupMediaSession isActive: true
com.example.myapplication I/BluetoothSoc: TESTTEST socket.isConnected() true

当按下音量键时,别无其他……有什么建议吗?

PS 1.我找到了HD1-R5耳机的一些文档,

PTT仅适用于MobilitySound加密狗,ICOM和Kenwood收音机。

PTT表示音量键或专用键(在普通型号上接听电话)。还发现了HD1-R6文档,它在规格上看起来完全一样,只有一个例外:它不是上面的行,而是具有

PTT仅适用于POCZELLO,ESChat,WAVE,Kodiak,GroupTalk和其他版本以下的Android手机。

还有YT video使用R6,...这两个设备有什么区别?

PS 2.小米支持HFP/A2DP/HSP/AVRCP配置文件(手动找到here),以上两个MobilitySound耳机都支持HFP,HSP,A2DP

编辑: 接听PS1。-区别在于耳机音量键发送的AT命令。 R5正在发送一些“知名”(例如TETRA doc):

AT+CTKST=0,1
AT+CTKST=0,0

并且R6使用Android文档中在某些示例HERE中记录的命令:

AT+XEVENT=TALK,1
AT+XEVENT=TALK,0

可能没有进行测试,没有任何这些-AT命令取自PR5和PR6,R5和R6的较新版本。仍然常见的小米模型没有以“仅配对模式”(ACL)发送任何内容-如顶部所述,它会更改“内部”音量-并且在SCO开启的情况下,这些AT命令似乎由某些内部命令(本机? )蓝牙控制器,严格地传递给音量控制,并且进一步不传递给套接字/应用程序

0 个答案:

没有答案