从蓝牙命令控制 AVAudioRecorder
Posted
技术标签:
【中文标题】从蓝牙命令控制 AVAudioRecorder【英文标题】:Control AVAudioRecorder from bluetooth commands 【发布时间】:2019-06-18 11:47:27 【问题描述】:我有这个应用程序,允许用户记录周围的东西。然后,当他们拥有蓝牙配件(例如耳机)时,他们应该能够通过蓝牙设备上的播放/暂停按钮开始/停止录制会话。
我已经使用 MPRemoteCommandCenter` 成功实现了启动会话
let rcCenter = MPRemoteCommandCenter.shared()
rcCenter.nextTrackCommand.isEnabled = false
rcCenter.nextTrackCommand.addTarget _ in return .success
rcCenter.previousTrackCommand.isEnabled = false
rcCenter.previousTrackCommand.addTarget _ in return .success
rcCenter.togglePlayPauseCommand.isEnabled = true
rcCenter.playCommand.isEnabled = true
rcCenter.pauseCommand.isEnabled = true
rcCenter.stopCommand.isEnabled = true
rcCenter.togglePlayPauseCommand.addTarget(self, action: #selector(remotePlayPauseAction(_:)))
rcCenter.playCommand.addTarget(self, action: #selector(remotePlayPauseAction(_:)))
rcCenter.pauseCommand.addTarget(self, action: #selector(remotePlayPauseAction(_:)))
rcCenter.stopCommand.addTarget(self, action: #selector(remotePlayPauseAction(_:)))
但是,它从来没有遇到我的蓝牙暂停/停止操作。直到我在设备的控制台中看到这个,我才知道发生了什么:
默认 18:19:46.609673 +0700 bluetoothd 收到来自设备的“获取播放状态”请求
默认 18:19:46.671092 +0700 bluetoothd 从设备接收到 AVRCP 播放命令
// 发送音频会话状态,因为应用正在录制等等……
默认 18:19:48.246780 +0700 bluetoothd AudiosendThread 开始
当应用不录制时触发 -> 从蓝牙接收播放命令 -> 开始录制 -> 将会话发送到蓝牙。
然后,我将再次按下播放/暂停按钮并获取此日志:
default 18:20:09.650855 +0700 bluetoothd 收到电话挂断事件 (AT+CHUP) 来自设备默认 18:20:09.651273 +0700 bluetoothd 发现正在进行的虚拟通话 - Acking 设备并通知上层。
=> 手机似乎正在接收结束通话信号(请注意,没有通话正在进行,只是会话中的录音)
那么,我该如何处理这个事件呢?我试过用CallKit
但还是没用:
let callCenter = CXCallObserver()
callCenter.setDelegate(self, queue: nil)
func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall)
print("Hi!") // not jump in!
更新
我已尝试切换回旧式处理程序:
UIApplication.shared.beginReceivingRemoteControlEvents()
becomeFirstResponder()
/////////////////
override func remoteControlReceived(with event: UIEvent?)
guard let event = event, event.type == .remoteControl else return
// Start / pause actions
仍然得到相同的结果(可以开始但不能停止,像以前一样获取事件play
和call hangup
)。现在我的猜测已经切换到AVAudioSession
的模式和类别,但仍然没有任何线索。
do
let session = AVAudioSession.shared()
// What is the correct params here?
// try session.setCategory(.playAndRecord, mode: .voiceChat, options: [.allowBluetoothA2DP, .allowBluetooth])
// try session.setCategory(.record, options: .allowBluetooth)
session.setActive(true)
catch print(error)
【问题讨论】:
您找到解决方案了吗?我有同样的问题。 我的猜测是您只能从远程命令控制启动但不能触发停止记录,因为它们的模式 (audio/recording/call
) 冲突。安卓好像也有这个问题。
好的,所以我发现,根据蓝牙设备,我们可以通过蓝牙按钮控制录制。我有一个专门用于录制的特殊蓝牙设备,它会发出 AVRCP 事件,并且 AVRCP 事件暂停和恢复仅在该蓝牙设备上正确触发。但是,我正在使用更主流的蓝牙设备(例如 Jaybirds X3)来体验您的行为。一旦我找到我正在测试的设备的更多信息和解决方案,我会发布答案。
【参考方案1】:
问题似乎与蓝牙硬件有关。对不起,如果有什么建议,我不能给你太多。
我正在做一些不使用 AVAudioProducer 的荒谬 C++ 录制逻辑(我正在使用 AudioToolBox 框架),但我基本上遇到了和你一样的问题。
我尝试过的所有市场设备(Jabra OTE23、Jaybird X3、Sony WH1000XM2、官方星际迷航通信徽章)都表现出相同的行为,只要打开麦克风,蓝牙设备就会认为它正在进行虚拟通话并会只发出调用 AVRCP 事件。由于某种原因,iOS 似乎没有办法监听这些调用 AVRCP 事件。
我公司有一台内部设备(可能是意外)在麦克风打开且设备处于录音状态时同时发出暂停和挂断事件。结果,我可以暂停和恢复录制。但是请注意,此设备专为录制音频等而设计。在此处记录以供证明:
default 15:38:53.994336 -0500 bluetoothd Received call hangup event (AT+CHUP) from device <private>
default 15:38:53.998181 -0500 bluetoothd Found ongoing virtual call - Acking device and notifying upper layers.
default 15:38:54.001477 -0500 locationd service mask 0x1 event type 2 event 104 result 0
default 15:38:54.186054 -0500 powerlogHelperd "msg":"CLCopyAppsUsingLocation", "event":"activity"
default 15:38:54.473038 -0500 bluetoothd Received AVRCP Pause command from device <private>
default 15:38:54.475637 -0500 BTAvrcp Request: Command = <Pause>, SenderDevice = <M’s iPhone>, SenderBundleIdentifier = <BTAvrcp>, SenderPID = <419>, commandID = <B46341E9-7B98-4ACE-94A3-D84A8F4A63B1>, remote control interface = <com.apple.AVRCP>, appOptions = <0>, options = <kMRMediaRemoteOptionSourceID = "00:13:8A:20:1C:70";> (null) for origin-M’s iPhone-1280262988/client-com.mmodal.SDK.SettingsTest-1015 (SettingsTest)/player-MediaRemote-DefaultPlayer
为什么这款设备的行为与其他主流设备不同?我还不知道。我真的只是希望 iOS(和 android)能够监听所有原始 AVRCP 事件,但现在似乎并非如此。
蓝牙是一个疯狂的技术栈...
【讨论】:
以上是关于从蓝牙命令控制 AVAudioRecorder的主要内容,如果未能解决你的问题,请参考以下文章