-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'development' into improve-start-release-workflow
- Loading branch information
Showing
54 changed files
with
2,520 additions
and
1,995 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
android/src/main/java/com/bitmovin/player/reactnative/BitmovinBaseModule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package com.bitmovin.player.reactnative | ||
|
||
import android.util.Log | ||
import com.bitmovin.player.api.Player | ||
import com.bitmovin.player.api.source.Source | ||
import com.bitmovin.player.reactnative.extensions.drmModule | ||
import com.bitmovin.player.reactnative.extensions.offlineModule | ||
import com.bitmovin.player.reactnative.extensions.playerModule | ||
import com.bitmovin.player.reactnative.extensions.sourceModule | ||
import com.bitmovin.player.reactnative.extensions.uiManagerModule | ||
import com.facebook.react.bridge.* | ||
import com.facebook.react.uimanager.UIManagerModule | ||
|
||
private const val MODULE_NAME = "BitmovinBaseModule" | ||
|
||
/** | ||
* Base for Bitmovin React modules. | ||
* | ||
* Provides many helper methods that are promise exception safe. | ||
* | ||
* In general, code should not throw while resolving a [Promise]. Instead, [Promise.reject] should be used. | ||
* This doesn't match Kotlin's error style, which uses exception. The helper methods in this class, provide such | ||
* convenience, they can only be called in a context that will catch any Exception and reject the [Promise]. | ||
* | ||
*/ | ||
abstract class BitmovinBaseModule( | ||
protected val context: ReactApplicationContext, | ||
) : ReactContextBaseJavaModule(context) { | ||
/** | ||
* Runs [block] on the UI thread with [UIManagerModule.addUIBlock] and [TPromise.resolve] [this] with | ||
* its return value. If [block] throws, [Promise.reject] [this] with the [Throwable]. | ||
*/ | ||
protected inline fun <T, R : T> TPromise<T>.resolveOnUiThread( | ||
crossinline block: RejectPromiseOnExceptionBlock.() -> R, | ||
) { | ||
val uiManager = runAndRejectOnException { uiManager } ?: return | ||
uiManager.addUIBlock { | ||
resolveOnCurrentThread { block() } | ||
} | ||
} | ||
|
||
protected val RejectPromiseOnExceptionBlock.playerModule: PlayerModule get() = context.playerModule | ||
?: throw IllegalArgumentException("PlayerModule not found") | ||
|
||
protected val RejectPromiseOnExceptionBlock.uiManager: UIManagerModule get() = context.uiManagerModule | ||
?: throw IllegalStateException("UIManager not found") | ||
|
||
protected val RejectPromiseOnExceptionBlock.sourceModule: SourceModule get() = context.sourceModule | ||
?: throw IllegalStateException("SourceModule not found") | ||
|
||
protected val RejectPromiseOnExceptionBlock.offlineModule: OfflineModule get() = context.offlineModule | ||
?: throw IllegalStateException("OfflineModule not found") | ||
|
||
protected val RejectPromiseOnExceptionBlock.drmModule: DrmModule get() = context.drmModule | ||
?: throw IllegalStateException("DrmModule not found") | ||
|
||
fun RejectPromiseOnExceptionBlock.getPlayer( | ||
nativeId: NativeId, | ||
playerModule: PlayerModule = this.playerModule, | ||
): Player = playerModule.getPlayerOrNull(nativeId) ?: throw IllegalArgumentException("Invalid PlayerId $nativeId") | ||
|
||
fun RejectPromiseOnExceptionBlock.getSource( | ||
nativeId: NativeId, | ||
sourceModule: SourceModule = this.sourceModule, | ||
): Source = sourceModule.getSourceOrNull(nativeId) ?: throw IllegalArgumentException("Invalid SourceId $nativeId") | ||
} | ||
|
||
/** Run [block], returning it's return value. If [block] throws, [Promise.reject] [this] and return null. */ | ||
inline fun <T, R> TPromise<T>.runAndRejectOnException(block: RejectPromiseOnExceptionBlock.() -> R): R? = try { | ||
RejectPromiseOnExceptionBlock.block() | ||
} catch (e: Exception) { | ||
reject(e) | ||
null | ||
} | ||
|
||
/** | ||
* [TPromise.resolve] [this] with [block] return value. | ||
* If [block] throws, [Promise.reject] [this] with the [Throwable]. | ||
*/ | ||
inline fun <T> TPromise<T>.resolveOnCurrentThread( | ||
crossinline block: RejectPromiseOnExceptionBlock.() -> T, | ||
): Unit = runAndRejectOnException { this@resolveOnCurrentThread.resolve(block()) } ?: Unit | ||
|
||
/** Receiver of code that can safely throw when resolving a [Promise]. */ | ||
object RejectPromiseOnExceptionBlock | ||
|
||
/** Compile time wrapper for Promises to type check the resolved type [T]. */ | ||
@JvmInline | ||
value class TPromise<T>(val promise: Promise) { | ||
// Promise only support built-in types. Functions that return [Unit] must resolve to `null`. | ||
fun resolve(value: T): Unit = promise.resolve(value.takeUnless { it is Unit }) | ||
fun reject(throwable: Throwable) { | ||
Log.e(MODULE_NAME, "Failed to execute Bitmovin method", throwable) | ||
promise.reject(throwable) | ||
} | ||
} | ||
|
||
inline val Promise.int get() = TPromise<Int>(this) | ||
inline val Promise.unit get() = TPromise<Unit>(this) | ||
inline val Promise.string get() = TPromise<String>(this) | ||
inline val Promise.double get() = TPromise<Double>(this) | ||
inline val Promise.float get() = TPromise<Float>(this) | ||
inline val Promise.bool get() = TPromise<Boolean>(this) | ||
inline val Promise.map get() = TPromise<ReadableMap>(this) | ||
inline val Promise.array get() = TPromise<ReadableArray>(this) | ||
inline val <T> TPromise<T>.nullable get() = TPromise<T?>(promise) |
44 changes: 14 additions & 30 deletions
44
android/src/main/java/com/bitmovin/player/reactnative/BitmovinCastManagerModule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package com.bitmovin.player.reactnative | ||
|
||
import com.bitmovin.player.api.buffer.BufferLevel | ||
import com.bitmovin.player.api.media.MediaType | ||
import com.bitmovin.player.reactnative.converter.toBufferType | ||
import com.bitmovin.player.reactnative.converter.toJson | ||
import com.facebook.react.bridge.* | ||
import com.facebook.react.module.annotations.ReactModule | ||
|
||
private const val MODULE_NAME = "BufferModule" | ||
private const val INVALID_BUFFER_TYPE = "Invalid buffer type" | ||
|
||
@ReactModule(name = MODULE_NAME) | ||
class BufferModule(context: ReactApplicationContext) : BitmovinBaseModule(context) { | ||
override fun getName() = MODULE_NAME | ||
|
||
/** | ||
* Gets the [BufferLevel] from the Player | ||
* @param nativeId Target player id. | ||
* @param type The [type of buffer][toBufferType] to return the level for. | ||
* @param promise JS promise object. | ||
*/ | ||
@ReactMethod | ||
fun getLevel(nativeId: NativeId, type: String, promise: Promise) { | ||
promise.map.resolveOnUiThread { | ||
val player = getPlayer(nativeId) | ||
val bufferType = type.toBufferTypeOrThrow() | ||
RNBufferLevels( | ||
audio = player.buffer.getLevel(bufferType, MediaType.Audio), | ||
video = player.buffer.getLevel(bufferType, MediaType.Video), | ||
).toJson() | ||
} | ||
} | ||
|
||
/** | ||
* Sets the target buffer level for the chosen buffer type across all media types. | ||
* @param nativeId Target player id. | ||
* @param type The [type of buffer][toBufferType] to set the target level for. | ||
* @param value The value to set. | ||
*/ | ||
@ReactMethod | ||
fun setTargetLevel(nativeId: NativeId, type: String, value: Double, promise: Promise) { | ||
promise.unit.resolveOnUiThread { | ||
getPlayer(nativeId).buffer.setTargetLevel(type.toBufferTypeOrThrow(), value) | ||
} | ||
} | ||
|
||
private fun String.toBufferTypeOrThrow() = toBufferType() ?: throw IllegalArgumentException(INVALID_BUFFER_TYPE) | ||
} | ||
|
||
/** | ||
* Representation of the React Native API `BufferLevels` object. | ||
* This is necessary as we need a unified representation of the different APIs from both Android and iOS. | ||
*/ | ||
data class RNBufferLevels(val audio: BufferLevel, val video: BufferLevel) |
Oops, something went wrong.