feat: add contentprotectionerror player event on all platforms#859
feat: add contentprotectionerror player event on all platforms#859tvanlaerhoven wants to merge 2 commits into
Conversation
Co-Authored-By: tom.vanlaerhoven <tom.vanlaerhoven@dolby.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
There was a problem hiding this comment.
🚩 iOS volumeChangeListener is never detached (pre-existing)
The volumeChangeListener is declared at ios/THEOplayerRCTMainEventHandler.swift:45 and attached at line 162, but dettachListeners() (lines 380-515) never removes it — unlike every other listener in the file (play, pause, error, etc.). This is a pre-existing resource leak, not introduced by this PR, but the new contentProtectionErrorListener was correctly added to both attach and detach methods, so the PR author clearly followed the pattern. Worth fixing separately.
(Refers to line 45)
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Good catch — confirmed this is pre-existing and out of scope for this PR. The volumeChangeListener is indeed attached but never removed in dettachListeners(). Worth fixing in a separate PR.
PlayerEventTypes.CONTENT_PROTECTION_ERROR does not exist in THEOplayerSDK-core 11.5.0. The bridge property (onNativeContentProtectionError) is kept so it can be wired up when the iOS SDK adds this event type. Co-Authored-By: tom.vanlaerhoven <tom.vanlaerhoven@dolby.com>
| var onNativeRateChange: RCTDirectEventBlock? | ||
| var onNativeWaiting: RCTDirectEventBlock? | ||
| var onNativeCanPlay: RCTDirectEventBlock? | ||
| var onNativeContentProtectionError: RCTDirectEventBlock? |
There was a problem hiding this comment.
🔴 Content protection error event never fires on iOS because the native SDK listener is never attached
The native SDK listener for content protection errors is never registered (attachListeners() at ios/THEOplayerRCTMainEventHandler.swift:82-358) despite all bridge wiring being in place, so iOS users will never receive this event.
Impact: The contentprotectionerror event will silently never fire on iOS, even though the changelog claims iOS support.
Missing listener variable, attachment, and detachment in THEOplayerRCTMainEventHandler
Every other event in this handler follows a three-part pattern:
- A listener variable (e.g.,
private var errorListener: EventListener?at line 52) - An attachment in
attachListeners()(e.g.,self.errorListener = player.addEventListener(type: PlayerEventTypes.ERROR) { ... }at line 263) - A detachment in
dettachListeners()(e.g.,player.removeEventListener(type: PlayerEventTypes.ERROR, listener: errorListener)at line 444)
For contentProtectionError, all three are missing:
- No
private var contentProtectionErrorListener: EventListener?variable - No
player.addEventListener(type: PlayerEventTypes.CONTENT_PROTECTION_ERROR)call inattachListeners() - No corresponding
removeEventListenerindettachListeners()
The bridge property is correctly exported (ios/THEOplayerRCTBridge.m:50), the setter is wired (ios/THEOplayerRCTView.swift:473-477), and the event block property exists (ios/THEOplayerRCTMainEventHandler.swift:33), but without the listener, the THEOplayer iOS SDK event is never captured.
Prompt for agents
The iOS THEOplayerRCTMainEventHandler needs three additions to actually listen for the CONTENT_PROTECTION_ERROR event from the THEOplayer SDK:
1. Add a listener variable in the MARK: player Listeners section (around line 58, after videoResizeListener):
private var contentProtectionErrorListener: EventListener?
2. Add listener attachment in attachListeners() (after canPlay attachment around line 328), following the same pattern as other listeners:
self.contentProtectionErrorListener = player.addEventListener(type: PlayerEventTypes.CONTENT_PROTECTION_ERROR) { [weak self] event in
if DEBUG_THEOPLAYER_EVENTS { PrintUtils.printLog(logText: "[NATIVE] Received CONTENT_PROTECTION_ERROR event from THEOplayer") }
if let forwardedEvent = self?.onNativeContentProtectionError {
forwardedEvent(["error": ["errorCode": String(event.errorObject.code.rawValue), "errorMessage": event.errorObject.message]])
}
}
3. Add listener detachment in dettachListeners() (after canPlay detachment around line 476):
if let contentProtectionErrorListener = self.contentProtectionErrorListener {
player.removeEventListener(type: PlayerEventTypes.CONTENT_PROTECTION_ERROR, listener: contentProtectionErrorListener)
}
Note: The exact event type name and errorObject properties should match the THEOplayer iOS SDK API. Check the SDK documentation for the correct PlayerEventTypes constant and error property access pattern.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
This is intentional. The initial commit did include the full three-part listener pattern (contentProtectionErrorListener variable + attachListeners + dettachListeners), but the iOS CI build failed with:
error: type 'PlayerEventTypes' has no member 'CONTENT_PROTECTION_ERROR'
THEOplayerSDK-core 11.5.0 (installed by CI) does not expose PlayerEventTypes.CONTENT_PROTECTION_ERROR. The listener was removed in commit 2cdd56f to unblock the build.
The bridge wiring is kept in place so the listener can be re-added when the iOS SDK exposes this event type in a future release.
Summary
Adds a new
contentprotectionerrorplayer event forwarded from the native THEOplayer SDKs on Web and Android. iOS bridge wiring is in place but the native listener is deferred until the iOS SDK exposesPlayerEventTypes.CONTENT_PROTECTION_ERROR(not available in THEOplayerSDK-core 11.5.0).TypeScript API:
PlayerEventType.CONTENT_PROTECTION_ERROR = 'contentprotectionerror'added to the enumContentProtectionErrorEventinterface with anerror: ContentProtectionErrorObjectpayloadContentProtectionErrorObjectcarrieserrorCode,errorMessage, and optional DRM-specific fields:url,status,statusText,response,systemCodeDefaultContentProtectionErrorEventimplementation class +NativeContentProtectionErrorEventnative bridge interfacePlatform forwarding:
WebEventForwarderlistens on'contentprotectionerror'from the Web SDK, mapserrorObjectfields (code, message, url, status, statusText, response, systemCode) intoDefaultContentProtectionErrorEventPlayerEventEmitterregistersPlayerEventTypes.CONTENTPROTECTIONERROR, forwardserrorObject.codeandmessageviaPayloadBuilder.error()onNativeContentProtectionError) registered inTHEOplayerRCTBridge.m,THEOplayerRCTView.swift, andTHEOplayerRCTMainEventHandler.swift. Native SDK listener deferred —PlayerEventTypes.CONTENT_PROTECTION_ERRORdoes not exist in THEOplayerSDK-core 11.5.0.onNativeContentProtectionErrorcallback wired in the render methodFollows the same pattern as existing error events (
ErrorEvent,ChromecastErrorEvent).Link to Devin session: https://dolby.devinenterprise.com/sessions/76fe44cf882d4024aa2714622570d537
Requested by: @tvanlaerhoven