With a joined PTChannelManager channel and setAccessoryButtonEventsEnabled(true) completing successfully, what supported condition makes a classic Bluetooth headset's AVRCP Play event start PTT transmission instead of routing to a media app?
The headset microphone and physical Stop button work. The next physical Start press produces no didBeginTransmittingFrom callback, while an on-screen Start request works again.
Tested environment
Observed on 3 October 2026:
iPhone 13 Pro Max, iOS 26.6.1.
Xcode 26.6, macOS 26.5.2.
boAt Rockerz 255 Pro+, classic Bluetooth A2DP/HFP.
Push to Talk capability, microphone permission, and audio/push-to-talk background modes enabled.
Default half-duplex transmission mode and Ready service status retained.
Isolation and setup
The reproduction uses an independent UIKit controller initialized before the host app runtime. No React Native, Expo audio module, Live Activity, MPRemoteCommandCenter, Now Playing metadata, audio player, transcription, or backend participates.
The controller retains its channel manager, leaves a restored channel before joining a fresh channel, and enables accessory button events in didJoinChannel.
The revised test configures the audio session at launch, before manager initialization:
let session = AVAudioSession.sharedInstance()
try session.setCategory(.playAndRecord,
mode: .voiceChat,
options: [.allowBluetoothHFP])
The relevant join callback is:
func channelManager(_ channelManager: PTChannelManager,
didJoinChannel channelUUID: UUID,
reason: PTChannelJoinReason) {
channelManager.setAccessoryButtonEventsEnabled(true,
channelUUID: channelUUID) { error in
// The test logs successful completion here.
}
}
PTT owns audio activation/deactivation; the diagnostic never calls setActive. In didActivate, it reapplies the same category/mode/options, clears a speaker override, selects an available HFP input, waits for the route to settle, and starts an AVAudioEngine input tap. It verifies HFP input/output and incoming frame counts; samples are discarded. It removes the tap and stops the engine on Stop/deactivation.
The full focused sample was already supplied privately to DTS. Its controller was tested on the physical phone through the native-only launch path. The standalone Xcode project packaging passed an unsigned iPhoneOS build, but has not independently been installed on the phone.
Reproduction
Connect the headset, launch the diagnostic, grant microphone permission, and join a fresh PTT channel.
Confirm that enabling accessory events succeeds.
Tap on-screen Start, which calls requestBeginTransmitting(channelUUID:).
Wait for HFP input/output and incoming audio frames to be verified.
Press and release the headset multifunction button. The delegate reports didEndTransmittingFrom with handsfree/headset source (raw 3); PTT deactivates audio and the channel remains joined.
Press and release the same headset button again. Expected: PTT begin callback and microphone activation. Observed: no begin callback; Console shows AVRCP Play routed to Music.
Tap on-screen Start again: transmission works. Headset Stop works again.
Selected evidence
The revised launch-configuration test produced this native trace on 3 October (UTC):
04:32:10 launch: native-only; launch audio configuration v2
04:32:10 category=PlayAndRecord; mode=VoiceChat; options=4
04:32:11 fresh channel joined
04:32:11 accessory mapping accepted
04:32:19 app start requested
04:32:19 BEGIN source=2
04:32:20 available inputs=MicrophoneBuiltIn,BluetoothHFP
04:32:20 discard engine running
04:32:21 HEADSET VERIFIED: BluetoothHFP input/output; frames=4096
04:32:22 END source=3
04:32:23 audio deactivated
No physical-headset BEGIN appeared in the native event snapshot copied at 04:32:49 UTC. Selected Console observations from the same run, converted from IST to UTC:
04:32:30.529053 AVRCP Play routed to com.apple.Music
04:32:30.535720 Music launch failed: NotFound
04:32:35.852134 the same command timed out after 5.326288 seconds
Music had been removed during troubleshooting. Before removal, the user observed Music opening; the supplied timestamped excerpts were captured after removal. Removal explains the launch failure, but does not explain why the joined PTT channel is bypassed.
An earlier native-only fresh-channel control also showed Play routing to Music before any app-requested transmission, with no BEGIN or audio activation in the callback trace. That earlier control configured the category in didActivate; it was not a fresh-start test of the revised launch-configuration variant. The revised test above establishes that configuring the category at launch did not fix the post-Stop failure.
Questions
I reviewed the accessory mapping explanation in https://developer.apple.com/forums/thread/804205 and the launch audio configuration guidance in WWDC22 session 10117.
Is a discrete AVRCP Play command from this type of consumer headset supported for PTT Start in this state, or is a different command form required?
Does the playback-mode qualifier in that forum guidance require an additional supported setup step? Could the category/route sequence described above bypass accessory mapping despite successful completion?
What targeted diagnostic or controlled configuration would distinguish accessory-command compatibility from an iOS routing defect?
The observations establish a routing/callback mismatch in this tested configuration; I am not assuming an iOS defect or that the headset is unsupported.
0
0
8