- Print current now-playing metadata.
- Observe now-playing notifications.
- List origins or clients if available.
- List routes or destinations if available.
Status: baseline complete, needs active-playback follow-up
Command:
swift run mr-now-playing-probeObserved behavior:
MediaRemote read-only now-playing probe
Symbol: MRMediaRemoteGetNowPlayingInfo
Result: callback returned nil dictionary
Meaning:
The helper successfully loads MediaRemote.framework, resolves MRMediaRemoteGetNowPlayingInfo, and receives a callback. On the baseline run, no dictionary was returned.
Follow-up results:
- Active Spotify playback still returned nil MediaRemote now-playing state through the direct read path.
- A metadata-only
MPNowPlayingInfoCenterfixture still returned nil MediaRemote now-playing state through the direct read path. - App-level callbacks with locally evidenced signatures returned
isPlaying=false, PID0, and nil client in both cases.
Next: keep a run loop alive after registering for notifications, then query players/clients and player-specific info.
Status: baseline run complete, private-entitlement variants blocked at launch
Command:
tools/mediaremote-entitlement-experiment.zsh
tools/mediaremote-entitlement-experiment.zsh --identity autoExpected behavior:
The runner builds mr-internal-probe, copies the product into an ignored experiment capture directory, signs copied variants with one candidate entitlement each, records signature details and embedded entitlements, and runs the same internal wrapper request path for every successfully signed variant.
Candidate entitlements:
com.apple.mediaremote.now-playing-read-accesscom.apple.mediaremote.full-now-playing-read-accesscom.apple.mediaremote.device-infocom.apple.nowplaying.entitlement
Observed behavior:
Capture research/MediaRemote/experiments/entitlements/20260716T083329Z:
- Baseline copied helper ran with active Spotify playback and one active Spotify player path.
- Baseline
playerPropertiesandplaybackQueuerequests both returnedkMRMediaRemoteFrameworkErrorDomain Code=3 "Operation not permitted". - Each candidate entitlement embedded successfully according to
codesign -d --entitlements -. - Each private-entitlement variant exited with status 137 before probe output.
- Unified log evidence reports AMFI/amfid
AppleMobileFileIntegrityError Code=-424 "The file is adhoc signed but contains restricted entitlements"for the private-entitled variants.
Capture research/MediaRemote/experiments/entitlements/20260716T083557Z:
--identity autoresolved to a local Apple Development certificate hash.codesignsucceeded for the same four private-entitlement variants.- Signature details confirmed a local Apple Development identity and team association; personal certificate and team identifiers are redacted.
- Each candidate entitlement embedded successfully.
- Each private-entitlement variant still exited with status 137 before probe output.
- Unified log evidence reports taskgated
Unsatisfied entitlements: com.apple.mediaremote.now-playing-read-access, restricted entitlement validation failure, and kernelload code signature error 4.
Capture research/MediaRemote/experiments/entitlements/20260716T083725Z:
- Explicit signing with a local Developer ID Application identity succeeded for the same four private-entitlement variants; the certificate hash is redacted.
- Signature details confirmed a Developer ID Application chain and team association; personal certificate and team identifiers are redacted.
- Each candidate entitlement embedded successfully.
- Each private-entitlement variant still exited with status 137 before probe output.
- Unified log evidence names all four unsatisfied entitlement keys and reports restricted entitlement validation failure plus kernel
load code signature error 4.
Permissions, entitlements, or SIP notes:
Private entitlements can embed successfully in ad-hoc, Apple Development, or Developer ID signatures but still fail code-signature validation at launch. On this macOS 26.5.2 system, these first four candidates do not reach mediaremoted; AMFI kills the helper before MediaRemote can evaluate the request.
Follow-up:
Next useful path is daemon-side observation, an Apple-signed host process, or a non-entitlement metadata route. Normal local signing identities are not enough to satisfy these restricted entitlement checks.
Status: baseline run complete
Command:
tools/mediaremote-daemon-observe.zshObserved behavior:
Capture research/MediaRemote/experiments/daemon-observation/20260716T084110Z ran the built mr-internal-probe while Spotify was playing. The probe resolved one Spotify player path and returned Code 3 for both playerProperties and playbackQueue. The focused unified-log capture shows mediaremoted adding a client for the probe with entitlements=0, logging handlePlaybackQueueRequest, returning Code 3 for that request, then invalidating and removing the client after the probe exits.
Capture research/MediaRemote/experiments/daemon-observation/20260716T084206Z ran the built mr-now-playing-probe --origins --application while Spotify was playing. The probe resolved the local Mac origin and Spotify player path while the global now-playing app/client/info surface remained empty. The focused unified-log capture shows the probe client with entitlements=0, Code 3 responses for playback state/client properties, and daemon-side Code 3 responses for playback queue requests.
Permissions, entitlements, or SIP notes:
This proves the probes reach the daemon as real clients, but not as entitled MediaRemote clients. It also proves the playback queue Code 3 is emitted on the daemon side, while playback state and client properties also fail under the same zero-entitlement client condition.
Follow-up:
Add narrower daemon predicates or safe helper interposition around entitlement-copy functions before exploring mutating commands.
Status: baseline run complete
Command:
tools/mediaremote-interface-capture.zshObserved behavior:
Capture research/MediaRemote/experiments/interfaces/20260716T085016Z built mr-interface-probe and produced grouped Objective-C runtime metadata for now-playing request wrappers, origin/client identity classes, controller classes, and MRXPCConnection.
The recovered interface evidence confirms MRNowPlayingPlayerClientRequests owns cached playback queue, playback state, supported commands, and player properties state; exposes initWithPlayerPath:; and provides the request handlers already exercised by mr-internal-probe.
Permissions, entitlements, or SIP notes:
This capture is read-only runtime metadata. It does not instantiate classes, send XPC messages, query mediaremoted, or mutate playback/routes.
Follow-up:
Use the recovered selectors to map MRXPCConnection message lifetimes and MRNowPlayingClientRequests hydration paths before attempting any new mutating command surface.
Status: baseline run complete
Command:
tools/mediaremote-message-surfaces.zshObserved behavior:
Capture research/MediaRemote/experiments/messages/20260716T085551Z extracted grouped XPC keys, transport symbols, serialization helpers, request/response log strings, cache-update strings, daemon request handlers, and protobuf message symbols from inventory capture research/MediaRemote/captures/20260716T084528Z.
Permissions, entitlements, or SIP notes:
This is a static extraction from local captures. It does not open an XPC connection, query mediaremoted, or mutate media state.
Follow-up:
Map MRXPC_MESSAGE_ID_KEY integer values and correlate MRNowPlayingPlayerClientRequests calls to specific message types or daemon handler names.
Status: baseline run complete
Command:
tools/mediaremote-message-id-callsites.zsh --disassembly research/MediaRemote/experiments/disassembly/20260716T085816Z/mediaremote-disassemble.txtObserved behavior:
Capture research/MediaRemote/experiments/message-ids/20260716T090007Z extracted 192 immediate call sites that pass message type values to MRCreateXPCMessage, sendMessageWithType:queue:reply:, or sendSyncMessageWithType:error:.
The IDs use a domain << 48 | ordinal shape. High-signal now-playing examples include 0x0200000000000007 for RequestNowPlayingPlaybackQueue, 0x020000000000000F for GetPlayerProperties, 0x0200000000000012 for GetPlaybackState, and 0x0200000000000031 for GetSupportedCommands.
Permissions, entitlements, or SIP notes:
This is a static disassembly extraction. It does not open an XPC connection, query mediaremoted, request now-playing state, send commands, or mutate routes.
Follow-up:
Correlate the Code 3 runtime failures with these known message IDs using daemon log predicates or client-side interposition, then compare the same map against macOS 27 beta evidence.
Status: baseline run complete
Command:
tools/mediaremote-xpc-trace-observe.zshObserved behavior:
Capture research/MediaRemote/experiments/daemon-observation/20260716T090922Z ran mr-internal-probe with MRXPCTraceInterpose injected while Spotify was playing.
Client-side message trace:
0x0200000000000018: player path resolution0x020000000000001B: active origin0x0200000000000027: active player paths for local origin0x0200000000000031: supported commands0x020000000000000F: player properties0x0200000000000007: playback queue
The same probe run returned Code 3 for handlePlayerPropertiesRequestWithCompletion: after sending 0x020000000000000F, and Code 3 for enqueuePlaybackQueueRequest:completion: after sending 0x0200000000000007.
Daemon-side evidence:
mediaremoted added the probe as a client with entitlements=0 and logged handlePlaybackQueueRequest returning kMRMediaRemoteFrameworkErrorDomain Code=3 "Operation not permitted" for the active Spotify player path in the same capture window.
Permissions, entitlements, or SIP notes:
The interposer is local-only instrumentation for SIP-disabled/private research. It observes outgoing XPC dictionary message IDs in the probe process; it does not grant entitlement bits, bypass daemon policy, or mutate media state.
Follow-up:
Use the same interposed runner for narrower probes that isolate playback state, supported commands, and available-origin request paths one at a time.
Status: getter isolation complete
Commands:
swift run mr-route-probe
tools/mediaremote-xpc-trace-observe.zsh -- .build/arm64-apple-macosx/debug/mr-route-probe
tools/mediaremote-xpc-trace-observe.zsh -- .build/arm64-apple-macosx/debug/mr-route-probe --localized-name
tools/mediaremote-xpc-trace-observe.zsh -- .build/arm64-apple-macosx/debug/mr-route-probe --uid
tools/mediaremote-xpc-trace-observe.zsh -- .build/arm64-apple-macosx/debug/mr-route-probe --output-devices
tools/mediaremote-xpc-trace-observe.zsh -- .build/arm64-apple-macosx/debug/mr-route-probe --contexts
tools/mediaremote-xpc-trace-observe.zsh -- .build/arm64-apple-macosx/debug/mr-route-probe --routing-context LOCAL
tools/mediaremote-xpc-trace-observe.zsh -- .build/arm64-apple-macosx/debug/mr-route-probe --routing-context SPK-SYNTHETIC-ROUTING-CONTEXTObserved behavior:
Capture research/MediaRemote/experiments/daemon-observation/20260716T092557Z ran the default route probe with MRXPCTraceInterpose injected. The probe resolved the local endpoint as MRAVLocalEndpoint, skipped localized-name and UID getters, skipped output-device copying, and skipped shared output-context queries.
Observed XPC trace:
0x0200000000000018: resolve player path0x0100000000000004: media playback volume0x0300000000000004: picked route volume control capabilities0x0100000000000008: system mute state by unified-log context, not yet mapped by static call-site extraction
Getter isolation:
- Capture
20260716T092614Zwith--localized-namereturned an empty localized name and added no message IDs beyond the default run. - Capture
20260716T092620Zwith--uidreturned UIDLOCALand added no message IDs beyond the default run. - Capture
20260716T092638Zwith--output-devicesreturned zero endpoint output devices and added no message IDs beyond the default run. - Capture
20260716T092644Zwith--contextsreturned nil shared system audio/screen contexts and added no message IDs beyond the default run. - Capture
20260716T093305Zwith--routing-context LOCALreturned an endpoint class only and added no message IDs beyond the default run. - Capture
20260716T093325Zwith--routing-context SPK-SYNTHETIC-ROUTING-CONTEXTreturned an endpoint class only and added no message IDs beyond the default run.
Static disassembly evidence:
_MRAVEndpointGetLocalEndpointforwards to+[MRAVLocalEndpoint sharedLocalEndpointForRoutingContextWithUID:].- The local-endpoint cache-miss path creates or reuses an
MRAVConcreteOutputContext, allocatesMRAVLocalEndpoint, initializes it with the output context, sets local origin, and registers group-session notification observation.
Daemon/log evidence:
mediaremoted added the probe as a client with entitlements=0, then invalidated and removed it after the process exited. The probe emitted route/volume read log entries but no Code 3 and no route-selection or output-device mutation.
Permissions, entitlements, or SIP notes:
This proves endpoint creation is read-only in intent but daemon-visible in behavior. Keep endpoint detail getters, output-device copying, output-context lookup, descriptions, route mutation, and volume mutation behind explicit flags.
Follow-up:
Map which output-context/controller initializer sends the now-playing player-path side path (0x0200000000000018), then compare the same endpoint behavior against the macOS 27 beta SDK.
Run only after the read-only baseline is documented.
- Send a playback command.
- Change playback position.
- Inspect queue or route mutation behavior.
Status: planned
Command:
Expected behavior:
Observed behavior:
Permissions, entitlements, or SIP notes:
Follow-up: