diff --git a/Sources/AVPlayer+Android.swift b/Sources/AVPlayer+Android.swift index 050d0909..bad64e46 100644 --- a/Sources/AVPlayer+Android.swift +++ b/Sources/AVPlayer+Android.swift @@ -11,7 +11,7 @@ import JNI public class AVPlayer: JNIObject { public override static var className: String { "org.uikit.AVPlayer" } - public var onLoaded: ((Error?) -> Void)? + public var onError: ((ExoPlaybackError) -> Void)? public var onVideoReady: (() -> Void)? public var onVideoEnded: (() -> Void)? public var onVideoBuffering: (() -> Void)? @@ -19,7 +19,7 @@ public class AVPlayer: JNIObject { public convenience init(playerItem: AVPlayerItem) { let parentView = JavaSDLView(getSDLView()) try! self.init(arguments: parentView, playerItem.asset) - globalAVPlayer = self + try! self.call(methodName: "setUserContext", arguments: [self.userContext]) } public func play() { @@ -54,31 +54,57 @@ public class AVPlayer: JNIObject { try? call(methodName: "cleanup") } - public struct DataSourceError: Error {} + public struct ExoPlaybackError: Error { + let type: Int + let message: String + } } -private weak var globalAVPlayer: AVPlayer? - @_cdecl("Java_org_uikit_AVPlayer_nativeOnVideoReady") -public func nativeOnVideoReady(env: UnsafeMutablePointer, cls: JavaObject) { - globalAVPlayer?.onLoaded?(nil) - globalAVPlayer?.onLoaded = nil - - globalAVPlayer?.onVideoReady?() +public func nativeOnVideoReady(env: UnsafeMutablePointer, cls: JavaObject, userContext: JavaLong) { + AVPlayer.from(userContext: userContext)?.onVideoReady?() } @_cdecl("Java_org_uikit_AVPlayer_nativeOnVideoEnded") -public func nativeOnVideoEnded(env: UnsafeMutablePointer, cls: JavaObject) { - globalAVPlayer?.onVideoEnded?() +public func nativeOnVideoEnded(env: UnsafeMutablePointer, cls: JavaObject, userContext: JavaLong) { + AVPlayer.from(userContext: userContext)?.onVideoEnded?() } @_cdecl("Java_org_uikit_AVPlayer_nativeOnVideoBuffering") -public func nativeOnVideoBuffering(env: UnsafeMutablePointer, cls: JavaObject) { - globalAVPlayer?.onVideoBuffering?() +public func nativeOnVideoBuffering(env: UnsafeMutablePointer, cls: JavaObject, userContext: JavaLong) { + AVPlayer.from(userContext: userContext)?.onVideoBuffering?() } -@_cdecl("Java_org_uikit_AVPlayer_nativeOnVideoSourceError") -public func nativeOnVideoSourceError(env: UnsafeMutablePointer, cls: JavaObject) { - globalAVPlayer?.onLoaded?(AVPlayer.DataSourceError()) - globalAVPlayer?.onLoaded = nil +@_cdecl("Java_org_uikit_AVPlayer_nativeOnVideoError") +public func nativeOnVideoError( + env: UnsafeMutablePointer, + cls: JavaObject, + type: JavaInt, + message: JavaString, + userContext: JavaLong +) { + let error = AVPlayer.ExoPlaybackError( + type: Int(type), + message: (try? String(javaString: message)) ?? "" + ) + AVPlayer.from(userContext: userContext)?.onError?(error) } + +extension AVPlayer { + static func from(userContext: JavaLong) -> AVPlayer? { + guard let reference = UnsafeRawPointer(bitPattern: Int(userContext)) else { + let msg = "Could not derefence AVPlayer instance from userContext." + print(msg) + assertionFailure(msg) + return nil + } + return Unmanaged.fromOpaque(reference).takeUnretainedValue() + } +} + +extension JNIObject { + var userContext: JavaLong { + let ptr = Unmanaged.passUnretained(self).toOpaque() + return JavaLong(Int(bitPattern: ptr)) + } +} \ No newline at end of file diff --git a/src/main/java/org/uikit/VideoJNI.kt b/src/main/java/org/uikit/VideoJNI.kt index 72e59869..5012b4fc 100644 --- a/src/main/java/org/uikit/VideoJNI.kt +++ b/src/main/java/org/uikit/VideoJNI.kt @@ -8,7 +8,6 @@ import com.google.android.exoplayer2.* import com.google.android.exoplayer2.database.ExoDatabaseProvider import com.google.android.exoplayer2.source.ProgressiveMediaSource import com.google.android.exoplayer2.trackselection.DefaultTrackSelector -import com.google.android.exoplayer2.ui.AspectRatioFrameLayout import com.google.android.exoplayer2.ui.PlayerView import com.google.android.exoplayer2.upstream.* import com.google.android.exoplayer2.upstream.cache.CacheDataSink @@ -45,32 +44,33 @@ class AVURLAsset(parent: SDLActivity, url: String) { class AVPlayer(parent: SDLActivity, asset: AVURLAsset) { internal val exoPlayer: SimpleExoPlayer private var listener: Player.EventListener + private var userContext: Long? = null - external fun nativeOnVideoReady() - external fun nativeOnVideoEnded() - external fun nativeOnVideoBuffering() - external fun nativeOnVideoSourceError() + external fun nativeOnVideoReady(userContext: Long) + external fun nativeOnVideoEnded(userContext: Long) + external fun nativeOnVideoBuffering(userContext: Long) + external fun nativeOnVideoError(type: Int, message: String, userContext: Long) init { - val exoPlayerBuilder = SimpleExoPlayer.Builder(parent.context) - val bandwidthMeter = DefaultBandwidthMeter.Builder(parent.context).build() - exoPlayerBuilder.setBandwidthMeter(bandwidthMeter) - val trackSelector = DefaultTrackSelector(parent.context) - exoPlayerBuilder.setTrackSelector(trackSelector) - - exoPlayer = exoPlayerBuilder.build() + + exoPlayer = SimpleExoPlayer.Builder(parent.context) + .setBandwidthMeter(bandwidthMeter) + .setTrackSelector(trackSelector) + .build() exoPlayer.prepare() exoPlayer.setMediaSource(asset.videoSource) listener = object: Player.EventListener { override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) { - when (playbackState) { - Player.STATE_READY -> nativeOnVideoReady() - Player.STATE_ENDED -> nativeOnVideoEnded() - Player.STATE_BUFFERING -> nativeOnVideoBuffering() - else -> {} + this@AVPlayer.userContext?.let { userContext -> + when (playbackState) { + Player.STATE_READY -> nativeOnVideoReady(userContext) + Player.STATE_ENDED -> nativeOnVideoEnded(userContext) + Player.STATE_BUFFERING -> nativeOnVideoBuffering(userContext) + else -> {} + } } } @@ -82,9 +82,10 @@ class AVPlayer(parent: SDLActivity, asset: AVURLAsset) { } override fun onPlayerError(error: ExoPlaybackException) { - if (error.type == ExoPlaybackException.TYPE_SOURCE) { - nativeOnVideoSourceError() + this@AVPlayer.userContext?.let { userContext -> Log.e("SDL", "ExoPlaybackException occurred") + val message = error.message ?: "unknown" + nativeOnVideoError(error.type, message, userContext) } } } @@ -92,6 +93,10 @@ class AVPlayer(parent: SDLActivity, asset: AVURLAsset) { exoPlayer.addListener(listener) } + fun setUserContext(ctx: Long) { + this.userContext = ctx + } + fun play() { // ExoPlayer API to play the video exoPlayer.playWhenReady = true