Skip to content

feat: add contentprotectionerror player event on all platforms#859

Open
tvanlaerhoven wants to merge 2 commits into
developfrom
devin/1782482584-content-protection-error-event
Open

feat: add contentprotectionerror player event on all platforms#859
tvanlaerhoven wants to merge 2 commits into
developfrom
devin/1782482584-content-protection-error-event

Conversation

@tvanlaerhoven

@tvanlaerhoven tvanlaerhoven commented Jun 26, 2026

Copy link
Copy Markdown
Member

Summary

Adds a new contentprotectionerror player 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 exposes PlayerEventTypes.CONTENT_PROTECTION_ERROR (not available in THEOplayerSDK-core 11.5.0).

TypeScript API:

  • PlayerEventType.CONTENT_PROTECTION_ERROR = 'contentprotectionerror' added to the enum
  • ContentProtectionErrorEvent interface with an error: ContentProtectionErrorObject payload
  • ContentProtectionErrorObject carries errorCode, errorMessage, and optional DRM-specific fields: url, status, statusText, response, systemCode
  • DefaultContentProtectionErrorEvent implementation class + NativeContentProtectionErrorEvent native bridge interface

Platform forwarding:

  • Web: WebEventForwarder listens on 'contentprotectionerror' from the Web SDK, maps errorObject fields (code, message, url, status, statusText, response, systemCode) into DefaultContentProtectionErrorEvent
  • Android: PlayerEventEmitter registers PlayerEventTypes.CONTENTPROTECTIONERROR, forwards errorObject.code and message via PayloadBuilder.error()
  • iOS: Bridge property (onNativeContentProtectionError) registered in THEOplayerRCTBridge.m, THEOplayerRCTView.swift, and THEOplayerRCTMainEventHandler.swift. Native SDK listener deferred — PlayerEventTypes.CONTENT_PROTECTION_ERROR does not exist in THEOplayerSDK-core 11.5.0.
  • THEOplayerView.tsx: onNativeContentProtectionError callback wired in the render method

Follows the same pattern as existing error events (ErrorEvent, ChromecastErrorEvent).

Link to Devin session: https://dolby.devinenterprise.com/sessions/76fe44cf882d4024aa2714622570d537
Requested by: @tvanlaerhoven


Open in Devin Review

Co-Authored-By: tom.vanlaerhoven <tom.vanlaerhoven@dolby.com>
@tvanlaerhoven tvanlaerhoven self-assigned this Jun 26, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

Open in Devin Review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 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)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

var onNativeRateChange: RCTDirectEventBlock?
var onNativeWaiting: RCTDirectEventBlock?
var onNativeCanPlay: RCTDirectEventBlock?
var onNativeContentProtectionError: RCTDirectEventBlock?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 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:

  1. A listener variable (e.g., private var errorListener: EventListener? at line 52)
  2. An attachment in attachListeners() (e.g., self.errorListener = player.addEventListener(type: PlayerEventTypes.ERROR) { ... } at line 263)
  3. 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 in attachListeners()
  • No corresponding removeEventListener in dettachListeners()

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.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant