From 033b2279a75f7f9ad7fbd53aca743c116f1408eb Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Tue, 17 Oct 2023 15:10:57 +0200 Subject: [PATCH 01/50] feat(docs): update docs to use jsdoc references --- src/hooks/usePlayer.ts | 2 +- src/player.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hooks/usePlayer.ts b/src/hooks/usePlayer.ts index e1cc9284..405b26ae 100644 --- a/src/hooks/usePlayer.ts +++ b/src/hooks/usePlayer.ts @@ -2,7 +2,7 @@ import { useRef } from 'react'; import { Player, PlayerConfig } from '../player'; /** - * React hook that creates and returns a reference to a `Player` instance + * React hook that creates and returns a reference to a {@link Player} instance * that can be used inside any component. */ export function usePlayer(config?: PlayerConfig): Player { diff --git a/src/player.ts b/src/player.ts index 7455342e..9a8e9c5a 100644 --- a/src/player.ts +++ b/src/player.ts @@ -166,22 +166,22 @@ export class Player extends NativeInstance { */ source?: Source; /** - * Whether the native `Player` object has been created. + * Whether the native {@link Player} object has been created. */ isInitialized = false; /** - * Whether the native `Player` object has been disposed. + * Whether the native {@link Player} object has been disposed. */ isDestroyed = false; /** - * The `AnalyticsApi` for interactions regarding the `Player`'s analytics. + * The {@link AnalyticsApi} for interactions regarding the {@link Player}'s analytics. * * `undefined` if the player was created without analytics support. */ analytics?: AnalyticsApi = undefined; /** - * Allocates the native `Player` instance and its resources natively. + * Allocates the native {@link Player} instance and its resources natively. */ initialize = () => { if (!this.isInitialized) { @@ -201,7 +201,7 @@ export class Player extends NativeInstance { }; /** - * Destroys the native `Player` and releases all of its allocated resources. + * Destroys the native {@link Player} and releases all of its allocated resources. */ destroy = () => { if (!this.isDestroyed) { From 90e0e4c6f44afb337fa090b0f6c18322b128661b Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Tue, 17 Oct 2023 16:04:37 +0200 Subject: [PATCH 02/50] feat(bufferapi): implement bufferApi interface and types --- src/bufferApi.ts | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ src/player.ts | 5 ++++ 2 files changed, 70 insertions(+) create mode 100644 src/bufferApi.ts diff --git a/src/bufferApi.ts b/src/bufferApi.ts new file mode 100644 index 00000000..5a119b50 --- /dev/null +++ b/src/bufferApi.ts @@ -0,0 +1,65 @@ +/** + * Represents different types of media. + */ +export enum MediaType { + /** + * Combined audio and video media type. + */ + MEDIATYPE_AUDIO_AND_VIDEO = 0, //TODO: Android has 2 enum values: Audio, Video +} + +/** + * Represents different types of buffered data. + */ +export enum BufferType { + /** + * Represents the buffered data starting at the current playback time. + */ + FORWARD_DURATION = 0, + /** + * Represents the buffered data up until the current playback time. + */ + BACKWARD_DURATION = 1, +} + +/** + * Holds different information about the buffer levels. + */ +export interface BufferLevel { + /** + * The amount of currently buffered data, e.g. audio or video buffer level. + */ + level?: number; + /** + * The target buffer level the player tries to maintain. + */ + targetLevel?: number; + /** + * The media type the buffer data applies to. + */ + media?: MediaType; + /** + * The buffer type the buffer data applies to. + */ + type?: BufferType; +} + +/** + * Provides the means to configure buffer settings and to query the current buffer state. + * Accessible through Player.buffer. + */ +export interface BufferApi { + /** + * Returns the {@link BufferLevel} for the chosen {@link BufferType|buffer type} and {@link MediaType|media type} of the active Source. + * @param type The type of buffer to return the level for. + * @param media TODO: android only + * @returns a {@link BufferLevel} where {@link BufferLevel.level} and {@link BufferLevel.targetLevel} is `0.0` if there is no active playback session. + */ + getLevel: (type: BufferType, media: MediaType) => BufferLevel; + /** + * Sets the target buffer level for the chosen buffer type across all {@link MediaType|MediaTypes}. + * @param type TODO: android only + * @param value The value to set. + */ + setTargetLevel: (type: BufferType, value: number) => void; +} diff --git a/src/player.ts b/src/player.ts index 9a8e9c5a..1c08ac6c 100644 --- a/src/player.ts +++ b/src/player.ts @@ -13,6 +13,7 @@ import { Thumbnail } from './thumbnail'; import { AnalyticsApi } from './analytics/player'; import { RemoteControlConfig } from './remoteControlConfig'; import { BufferConfig } from './bufferConfig'; +import { BufferApi } from './bufferapi'; const PlayerModule = NativeModules.PlayerModule; @@ -179,6 +180,10 @@ export class Player extends NativeInstance { * `undefined` if the player was created without analytics support. */ analytics?: AnalyticsApi = undefined; + /** + * The {@link BufferApi} for interactions regarding the buffer. + */ + buffer?: BufferApi; // TODO: default value? /** * Allocates the native {@link Player} instance and its resources natively. From 1204768b5e1a6d96cbbd3c52cccbbbf0b615dd53 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Tue, 17 Oct 2023 16:05:20 +0200 Subject: [PATCH 03/50] feat(bufferapi): fix bufferapi imports --- src/index.ts | 1 + src/player.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 0c8fcba1..ddfeebb6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,3 +19,4 @@ export * from './audioTrack'; export * from './media'; export * from './tweaksConfig'; export * from './bufferConfig'; +export * from './bufferApi'; diff --git a/src/player.ts b/src/player.ts index 1c08ac6c..f37684fd 100644 --- a/src/player.ts +++ b/src/player.ts @@ -13,7 +13,7 @@ import { Thumbnail } from './thumbnail'; import { AnalyticsApi } from './analytics/player'; import { RemoteControlConfig } from './remoteControlConfig'; import { BufferConfig } from './bufferConfig'; -import { BufferApi } from './bufferapi'; +import { BufferApi } from './bufferApi'; const PlayerModule = NativeModules.PlayerModule; @@ -183,7 +183,7 @@ export class Player extends NativeInstance { /** * The {@link BufferApi} for interactions regarding the buffer. */ - buffer?: BufferApi; // TODO: default value? + buffer?: BufferApi; // TODO: default value? optional?? /** * Allocates the native {@link Player} instance and its resources natively. From c3dbb47445eb54bfff7673bbadb79dc6f6fa6fb4 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Tue, 17 Oct 2023 16:06:59 +0200 Subject: [PATCH 04/50] feat(docs): update and fix docs formatting and referencing --- src/player.ts | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/player.ts b/src/player.ts index f37684fd..bc9e76ea 100644 --- a/src/player.ts +++ b/src/player.ts @@ -18,7 +18,7 @@ import { BufferApi } from './bufferApi'; const PlayerModule = NativeModules.PlayerModule; /** - * Object used to configure a new `Player` instance. + * Object used to configure a new {@link Player} instance. */ export interface PlayerConfig extends NativeInstanceConfig { /** @@ -153,13 +153,13 @@ export interface PlaybackConfig { } /** - * Loads, controls and renders audio and video content represented through `Source`s. A player - * instance can be created via the `usePlayer` hook and will idle until one or more `Source`s are - * loaded. Once `load` is called, the player becomes active and initiates necessary downloads to + * Loads, controls and renders audio and video content represented through {@link Source|Sources}. A player + * instance can be created via the {@link usePlayer} hook and will idle until one or more {@link Source|Sources} are + * loaded. Once {@link load} is called, the player becomes active and initiates necessary downloads to * start playback of the loaded source(s). * - * Can be attached to `PlayerView` component in order to use Bitmovin's Player Web UI. - * @see PlayerView + * Can be attached to {@link PlayerView} component in order to use Bitmovin's Player Web UI. + * @see {@link PlayerView} */ export class Player extends NativeInstance { /** @@ -217,14 +217,14 @@ export class Player extends NativeInstance { }; /** - * Loads a new `Source` from `sourceConfig` into the player. + * Loads a new {@link Source} from {@link sourceConfig} into the player. */ load = (sourceConfig: SourceConfig) => { this.loadSource(new Source(sourceConfig)); }; /** - * Loads the downloaded content from `OfflineContentManager` into the player. + * Loads the downloaded content from {@link OfflineContentManager} into the player. */ loadOfflineContent = ( offlineContentManager: OfflineContentManager, @@ -238,7 +238,7 @@ export class Player extends NativeInstance { }; /** - * Loads the given `Source` into the player. + * Loads the given {@link Source} into the player. */ loadSource = (source: Source) => { source.initialize(); @@ -247,7 +247,7 @@ export class Player extends NativeInstance { }; /** - * Unloads all `Source`s from the player. + * Unloads all {@link Source|Sources} from the player. */ unload = () => { PlayerModule.unload(this.nativeId); @@ -280,7 +280,7 @@ export class Player extends NativeInstance { /** * Shifts the time to the given `offset` in seconds from the live edge. The resulting offset has to be within the - * timeShift window as specified by `maxTimeShift` (which is a negative value) and 0. When the provided `offset` is + * timeShift window as specified by `maxTimeShift` (which is a negative value) and `0`. When the provided `offset` is * positive, it will be interpreted as a UNIX timestamp in seconds and converted to fit into the timeShift window. * When the provided `offset` is negative, but lower than `maxTimeShift`, then it will be clamped to `maxTimeShift`. * Has no effect for VoD. @@ -306,7 +306,7 @@ export class Player extends NativeInstance { }; /** - * Sets the player's volume between 0 (silent) and 100 (max volume). + * Sets the player's volume between `0` (silent) and `100` (max volume). * * @param volume - The volume level to set. */ @@ -324,7 +324,7 @@ export class Player extends NativeInstance { /** * @returns The current playback time in seconds. * - * For VoD streams the returned time ranges between 0 and the duration of the asset. + * For VoD streams the returned time ranges between `0` and the duration of the asset. * * For live streams it can be specified if an absolute UNIX timestamp or a value * relative to the playback start should be returned. @@ -336,7 +336,7 @@ export class Player extends NativeInstance { }; /** - * @returns The total duration in seconds of the current video or INFINITY if it’s a live stream. + * @returns The total duration in seconds of the current video or `Infinity` if it’s a live stream. */ getDuration = async (): Promise => { return PlayerModule.duration(this.nativeId); @@ -406,7 +406,7 @@ export class Player extends NativeInstance { }; /** - * @returns An array containing AudioTrack objects for all available audio tracks. + * @returns An array containing {@link AudioTrack} objects for all available audio tracks. */ getAvailableAudioTracks = async (): Promise => { return PlayerModule.getAvailableAudioTracks(this.nativeId); @@ -427,7 +427,7 @@ export class Player extends NativeInstance { }; /** - * @returns An array containing SubtitleTrack objects for all available subtitle tracks. + * @returns An array containing {@link SubtitleTrack} objects for all available subtitle tracks. */ getAvailableSubtitles = async (): Promise => { return PlayerModule.getAvailableSubtitles(this.nativeId); @@ -471,7 +471,7 @@ export class Player extends NativeInstance { }; /** - * The current time shift of the live stream in seconds. This value is always 0 if the active `source` is not a + * The current time shift of the live stream in seconds. This value is always `0` if the active {@link Source|source} is not a * live stream or no sources are loaded. */ getTimeShift = async (): Promise => { @@ -479,8 +479,8 @@ export class Player extends NativeInstance { }; /** - * The limit in seconds for time shifting. This value is either negative or 0 and it is always 0 if the active - * `source` is not a live stream or no sources are loaded. + * The limit in seconds for time shifting. This value is either negative or `0` and it is always `0` if the active + * {@link Source|source} is not a live stream or no sources are loaded. */ getMaxTimeShift = async (): Promise => { return PlayerModule.getMaxTimeShift(this.nativeId); @@ -497,11 +497,12 @@ export class Player extends NativeInstance { }; /** - * @returns a `Thumbnail` for the specified playback time for the currently active source if available. + * @returns a {@link Thumbnail} for the specified playback time for the currently active source if available. * Supported thumbnail formats are: - * - `WebVtt` configured via `SourceConfig.thumbnailTrack`, on all supported platforms + * - `WebVtt` configured via {@link SourceConfig.thumbnailTrack}, on all supported platforms * - HLS `Image Media Playlist` in the multivariant playlist, Android-only * - DASH `Image Adaptation Set` as specified in DASH-IF IOP, Android-only + * * If a `WebVtt` thumbnail track is provided, any potential in-manifest thumbnails are ignored on Android. */ getThumbnail = async (time: number): Promise => { @@ -509,7 +510,7 @@ export class Player extends NativeInstance { }; /** - * Whether casting to a cast-compatible remote device is available. `CastAvailableEvent` signals when + * Whether casting to a cast-compatible remote device is available. {@link CastAvailableEvent} signals when * casting becomes available. * * @platform iOS, Android @@ -538,7 +539,7 @@ export class Player extends NativeInstance { }; /** - * Stops casting the current video. Has no effect if `isCasting` is false. + * Stops casting the current video. Has no effect if {@link isCasting} is false. * * @platform iOS, Android */ From 7a961e94aabb4a990b010dde3cc5d9048acabb5d Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Wed, 18 Oct 2023 12:29:01 +0200 Subject: [PATCH 05/50] feat(bufferapi): add buffer module for android --- .../player/reactnative/BufferModule.kt | 67 +++++++++++++++++++ .../player/reactnative/RNPlayerViewPackage.kt | 1 + .../reactnative/converter/JsonConverter.kt | 43 ++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt new file mode 100644 index 00000000..eaf7e51a --- /dev/null +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -0,0 +1,67 @@ +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.JsonConverter +import com.facebook.react.bridge.* +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.UIManagerModule + +private const val MODULE_NAME = "BufferModule" + +@ReactModule(name = MODULE_NAME) +class BufferModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) { + data class RNBufferLevels(val audio: BufferLevel, val video: BufferLevel) + + /** + * JS exported module name. + */ + override fun getName() = MODULE_NAME + + /** + * Gets the buffer level from the Player + * @param nativeId Native Id of the collector instance. + * @param type The type of buffer to return the level for. + * @param promise JS promise object. + */ + @ReactMethod + fun getLevel(nativeId: NativeId, type: Int, promise: Promise) { + uiManager()?.addUIBlock { _ -> + val player = playerModule()?.getPlayer(nativeId) ?: return@addUIBlock + val bufferType = JsonConverter.toBufferType(type) + val bufferLevels = RNBufferLevels( + player.buffer.getLevel(bufferType, MediaType.Audio), + player.buffer.getLevel(bufferType, MediaType.Video), + ) + JsonConverter.fromRNBufferLevels(bufferLevels)?.let { + promise.resolve(it) + } + } + } + + /** + * Sets the target buffer level for the chosen buffer type across all media types. + * + * @param nativeId Target player id. + * @param type The type of the buffer to set the target level for. + * @param value The value to set. + */ + @ReactMethod + fun setTargetLevel(nativeId: NativeId, type: Int, value: Double) { + uiManager()?.addUIBlock { _ -> + playerModule()?.getPlayer(nativeId)?.buffer?.setTargetLevel(JsonConverter.toBufferType(type), value) + } + } + + /** + * Helper function that gets the instantiated `UIManagerModule` from modules registry. + */ + private fun uiManager(): UIManagerModule? = + context.getNativeModule(UIManagerModule::class.java) + + /** + * Helper function that gets the instantiated `PlayerModule` from modules registry. + */ + private fun playerModule(): PlayerModule? = + context.getNativeModule(PlayerModule::class.java) +} \ No newline at end of file diff --git a/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewPackage.kt b/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewPackage.kt index f5eb9f8f..0fa03228 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewPackage.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewPackage.kt @@ -29,6 +29,7 @@ class RNPlayerViewPackage : ReactPackage { FullscreenHandlerModule(reactContext), CustomMessageHandlerModule(reactContext), BitmovinCastManagerModule(reactContext), + BufferModule(reactContext), ) } diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index 486c6bba..9070f932 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -19,7 +19,9 @@ import com.bitmovin.player.api.advertising.AdSource import com.bitmovin.player.api.advertising.AdSourceType import com.bitmovin.player.api.advertising.AdvertisingConfig import com.bitmovin.player.api.buffer.BufferConfig +import com.bitmovin.player.api.buffer.BufferLevel import com.bitmovin.player.api.buffer.BufferMediaTypeConfig +import com.bitmovin.player.api.buffer.BufferType import com.bitmovin.player.api.casting.RemoteControlConfig import com.bitmovin.player.api.drm.WidevineConfig import com.bitmovin.player.api.event.PlayerEvent @@ -27,6 +29,7 @@ import com.bitmovin.player.api.event.SourceEvent import com.bitmovin.player.api.event.data.CastPayload import com.bitmovin.player.api.event.data.SeekPosition import com.bitmovin.player.api.media.AdaptationConfig +import com.bitmovin.player.api.media.MediaType import com.bitmovin.player.api.media.audio.AudioTrack import com.bitmovin.player.api.media.subtitle.SubtitleTrack import com.bitmovin.player.api.media.thumbnail.Thumbnail @@ -42,6 +45,7 @@ import com.bitmovin.player.api.source.TimelineReferencePoint import com.bitmovin.player.api.ui.ScalingMode import com.bitmovin.player.api.ui.StyleConfig import com.bitmovin.player.reactnative.BitmovinCastManagerOptions +import com.bitmovin.player.reactnative.BufferModule import com.bitmovin.player.reactnative.extensions.getBooleanOrNull import com.bitmovin.player.reactnative.extensions.getName import com.bitmovin.player.reactnative.extensions.getOrDefault @@ -1147,6 +1151,45 @@ class JsonConverter { isEnabled = it.getBoolean("isEnabled"), ) } + + @JvmStatic + fun fromBufferLevel(bufferLevel: BufferLevel?): WritableMap? { + if (bufferLevel == null) { + return null + } + + return Arguments.createMap().apply { + putDouble("level", bufferLevel.level) + putDouble("targetLevel", bufferLevel.targetLevel) + putInt("media", when(bufferLevel.media) { + MediaType.Audio -> 0 + MediaType.Video -> 1 + }) + putInt("type", when(bufferLevel.type) { + BufferType.ForwardDuration -> 0 + BufferType.BackwardDuration -> 1 + }) + } + } + + @JvmStatic + fun fromRNBufferLevels(bufferLevels: BufferModule.RNBufferLevels?): WritableMap? { + if (bufferLevels == null) { + return null + } + + return Arguments.createMap().apply { + putMap("audio", fromBufferLevel(bufferLevels.audio)) + putMap("video", fromBufferLevel(bufferLevels.video)) + } + } + + @JvmStatic + fun toBufferType(json: Int?): BufferType = when (json) { + 0 -> BufferType.ForwardDuration + 1 -> BufferType.BackwardDuration + else -> BufferType.ForwardDuration + } } } From 2c73d754ded91f87bbac6860d8b4600dec5a3c05 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Wed, 18 Oct 2023 12:29:21 +0200 Subject: [PATCH 06/50] feat(bufferapi): add buffer api --- src/bufferApi.ts | 58 +++++++++++++++++++++++++++++++++++++++--------- src/player.ts | 2 +- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/bufferApi.ts b/src/bufferApi.ts index 5a119b50..c7f38f1f 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -1,11 +1,21 @@ +import { NativeModules } from 'react-native'; + +const BufferModule = NativeModules.BufferModule; + /** * Represents different types of media. */ export enum MediaType { /** - * Combined audio and video media type. + * Audio media type. + * @platform Android */ - MEDIATYPE_AUDIO_AND_VIDEO = 0, //TODO: Android has 2 enum values: Audio, Video + AUDIO = 0, + /** + * Video media type. + * @platform Android + */ + VIDEO = 1, } /** @@ -44,22 +54,50 @@ export interface BufferLevel { type?: BufferType; } +/** + * Collection of {@link BufferLevel} objects + */ +export interface BufferLevels { + /** + * {@link BufferLevel} for {@link MediaType.Audio}. + */ + audio: BufferLevel; + /** + * {@link BufferLevel} for {@link MediaType.Video}. + */ + video: BufferLevel; +} + /** * Provides the means to configure buffer settings and to query the current buffer state. - * Accessible through Player.buffer. + * Accessible through {@link Player.buffer}. */ -export interface BufferApi { +export class BufferApi { + /** + * The native player id that this analytics api is attached to. + */ + readonly nativeId: string; + + constructor(playerId: string) { + this.nativeId = playerId; + } + /** * Returns the {@link BufferLevel} for the chosen {@link BufferType|buffer type} and {@link MediaType|media type} of the active Source. * @param type The type of buffer to return the level for. - * @param media TODO: android only - * @returns a {@link BufferLevel} where {@link BufferLevel.level} and {@link BufferLevel.targetLevel} is `0.0` if there is no active playback session. + * @returns a {@link BufferLevels} that contains {@link BufferLevel} values for audio and video. */ - getLevel: (type: BufferType, media: MediaType) => BufferLevel; + getLevel = async (type: BufferType): Promise => { + return BufferModule.getLevel(this.nativeId, type); + }; + /** - * Sets the target buffer level for the chosen buffer type across all {@link MediaType|MediaTypes}. - * @param type TODO: android only + * Sets the target buffer level for the chosen buffer {@link BufferType|type} across all {@link MediaType}s. + * + * @param type The type of the buffer to set the target level for. On iOS only {@link BufferType.FORWARD_DURATION} is supported. * @param value The value to set. */ - setTargetLevel: (type: BufferType, value: number) => void; + setTargetLevel = async (type: BufferType, value: number): Promise => { + return BufferModule.setTargetLevel(this.nativeId, type, value); + }; } diff --git a/src/player.ts b/src/player.ts index bc9e76ea..f94660f3 100644 --- a/src/player.ts +++ b/src/player.ts @@ -183,7 +183,7 @@ export class Player extends NativeInstance { /** * The {@link BufferApi} for interactions regarding the buffer. */ - buffer?: BufferApi; // TODO: default value? optional?? + buffer: BufferApi = new BufferApi(this.nativeId); /** * Allocates the native {@link Player} instance and its resources natively. From 0981e22bb14ea2659a798b7ef429d552ecd4ba54 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Wed, 18 Oct 2023 12:58:09 +0200 Subject: [PATCH 07/50] feat(formatting): apply ktlint rules --- .../player/reactnative/BufferModule.kt | 2 +- .../reactnative/converter/JsonConverter.kt | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index eaf7e51a..8e650d57 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -64,4 +64,4 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB */ private fun playerModule(): PlayerModule? = context.getNativeModule(PlayerModule::class.java) -} \ No newline at end of file +} diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index 9070f932..01716e85 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -1161,14 +1161,20 @@ class JsonConverter { return Arguments.createMap().apply { putDouble("level", bufferLevel.level) putDouble("targetLevel", bufferLevel.targetLevel) - putInt("media", when(bufferLevel.media) { - MediaType.Audio -> 0 - MediaType.Video -> 1 - }) - putInt("type", when(bufferLevel.type) { - BufferType.ForwardDuration -> 0 - BufferType.BackwardDuration -> 1 - }) + putInt( + "media", + when (bufferLevel.media) { + MediaType.Audio -> 0 + MediaType.Video -> 1 + }, + ) + putInt( + "type", + when (bufferLevel.type) { + BufferType.ForwardDuration -> 0 + BufferType.BackwardDuration -> 1 + }, + ) } } From f65ecc7b86b23ff0d2dc46623068446865865995 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Wed, 18 Oct 2023 13:10:51 +0200 Subject: [PATCH 08/50] feat(docs): fix typedocs references --- src/bufferApi.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bufferApi.ts b/src/bufferApi.ts index c7f38f1f..f7b52c4c 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -59,11 +59,11 @@ export interface BufferLevel { */ export interface BufferLevels { /** - * {@link BufferLevel} for {@link MediaType.Audio}. + * {@link BufferLevel} for {@link MediaType.AUDIO}. */ audio: BufferLevel; /** - * {@link BufferLevel} for {@link MediaType.Video}. + * {@link BufferLevel} for {@link MediaType.VIDEO}. */ video: BufferLevel; } From acd6b8ee8d4e18d39079703e96e91fce6348a6d1 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Wed, 18 Oct 2023 17:07:48 +0200 Subject: [PATCH 09/50] docs(bufferapi): add missing docs and improve formatting --- .../player/reactnative/BufferModule.kt | 11 +++++-- .../reactnative/converter/JsonConverter.kt | 33 +++++++++++-------- src/bufferApi.ts | 4 +-- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index 8e650d57..a7486999 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -11,6 +11,11 @@ private const val MODULE_NAME = "BufferModule" @ReactModule(name = MODULE_NAME) class BufferModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) { + /** + * Collection of [BufferLevel] objects + * @param audio [BufferLevel] for [MediaType.Audio]. + * @param video [BufferLevel] for [MediaType.Video]. + */ data class RNBufferLevels(val audio: BufferLevel, val video: BufferLevel) /** @@ -19,9 +24,9 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB override fun getName() = MODULE_NAME /** - * Gets the buffer level from the Player - * @param nativeId Native Id of the collector instance. - * @param type The type of buffer to return the level for. + * Gets the [buffer level][BufferLevel] from the Player + * @param nativeId Target player id. + * @param type The [type of buffer][JsonConverter.toBufferType] to return the level for. * @param promise JS promise object. */ @ReactMethod diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index 01716e85..cac748ca 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -70,9 +70,9 @@ import java.util.UUID class JsonConverter { companion object { /** - * Converts an arbitrary `json` to `PlayerConfig`. - * @param json JS object representing the `PlayerConfig`. - * @return The generated `PlayerConfig` if successful, `null` otherwise. + * Converts an arbitrary `json` to [PlayerConfig]. + * @param json JS object representing the [PlayerConfig]. + * @return The generated [PlayerConfig] if successful, `null` otherwise. */ @JvmStatic fun toPlayerConfig(json: ReadableMap?): PlayerConfig { @@ -121,9 +121,9 @@ class JsonConverter { } /** - * Converts any JS object into a `BufferMediaTypeConfig` object. - * @param json JS object representing the `BufferMediaTypeConfig`. - * @return The generated `BufferMediaTypeConfig` if successful, `null` otherwise. + * Converts any JS object into a [BufferMediaTypeConfig] object. + * @param json JS object representing the [BufferMediaTypeConfig]. + * @return The generated [BufferMediaTypeConfig] if successful, `null` otherwise. */ @JvmStatic fun toBufferMediaTypeConfig(json: ReadableMap?): BufferMediaTypeConfig? { @@ -138,9 +138,9 @@ class JsonConverter { } /** - * Converts any JS object into a `BufferConfig` object. - * @param json JS object representing the `BufferConfig`. - * @return The generated `BufferConfig` if successful, `null` otherwise. + * Converts any JS object into a [BufferConfig] object. + * @param json JS object representing the [BufferConfig]. + * @return The generated [BufferConfig] if successful, `null` otherwise. */ @JvmStatic fun toBufferConfig(json: ReadableMap?): BufferConfig? { @@ -215,9 +215,9 @@ class JsonConverter { } /** - * Converts an arbitrary `json` to `SourceOptions`. - * @param json JS object representing the `SourceOptions`. - * @return The generated `SourceOptions`. + * Converts an arbitrary `json` to [SourceOptions]. + * @param json JS object representing the [SourceOptions]. + * @return The generated [SourceOptions]. */ @JvmStatic fun toSourceOptions(json: ReadableMap?): SourceOptions { @@ -1190,8 +1190,15 @@ class JsonConverter { } } + /** + * Maps an integer value into the corresponding [BufferType] value. + * + * Currently `0` is mapped to [BufferType.ForwardDuration], and `1` to [BufferType.BackwardDuration]. + * Other values fall back to [BufferType.ForwardDuration] + * @param value The integer value to seek a [BufferType] for. + */ @JvmStatic - fun toBufferType(json: Int?): BufferType = when (json) { + fun toBufferType(value: Int?): BufferType = when (value) { 0 -> BufferType.ForwardDuration 1 -> BufferType.BackwardDuration else -> BufferType.ForwardDuration diff --git a/src/bufferApi.ts b/src/bufferApi.ts index f7b52c4c..f798eeea 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -83,8 +83,8 @@ export class BufferApi { } /** - * Returns the {@link BufferLevel} for the chosen {@link BufferType|buffer type} and {@link MediaType|media type} of the active Source. - * @param type The type of buffer to return the level for. + * Gets the {@link BufferLevel|buffer level} from the Player + * @param type The {@link BufferType|type of buffer} to return the level for. * @returns a {@link BufferLevels} that contains {@link BufferLevel} values for audio and video. */ getLevel = async (type: BufferType): Promise => { From 68182ed806c02b759e3a907228498a5b28ffe836 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Thu, 19 Oct 2023 11:20:03 +0200 Subject: [PATCH 10/50] feat(bufferapi): add buffer module for ios --- BufferModule.m | 8 +++ BufferModule.swift | 88 +++++++++++++++++++++++++++++ ios/RCTConvert+BitmovinPlayer.swift | 65 +++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 BufferModule.m create mode 100644 BufferModule.swift diff --git a/BufferModule.m b/BufferModule.m new file mode 100644 index 00000000..8b4225fe --- /dev/null +++ b/BufferModule.m @@ -0,0 +1,8 @@ +#import + +@interface RCT_EXTERN_REMAP_MODULE(BufferModule, BufferModule, NSObject) + +RCT_EXTERN_METHOD(getLevel:(NSString *)nativeId type:(nonnull NSNumber *)type resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(setTargetLevel:(NSString *)nativeId type:(nonnull NSNumber *)type value:(nonnull NSNumber *)value) + +@end diff --git a/BufferModule.swift b/BufferModule.swift new file mode 100644 index 00000000..c3997db5 --- /dev/null +++ b/BufferModule.swift @@ -0,0 +1,88 @@ +import BitmovinPlayer + +@objc(BufferModule) +class BufferModule: NSObject, RCTBridgeModule { + /** + * Collection of `BufferLevel` objects + * - Parameter audio: `BufferLevel` for `MediaType.Audio`. + * - Parameter video: `BufferLevel` for `MediaType.Video`. + */ + struct RNBufferLevels { + let audio: BufferLevel + let video: BufferLevel + } + + /// React bridge reference. + @objc var bridge: RCTBridge! + + /// PlayerModule instance fetched from the bridge's registry + @objc var playerModule: PlayerModule? { + bridge.module(for: PlayerModule.self) as? PlayerModule + } + + /// JS module name. + static func moduleName() -> String! { + "BufferModule" + } + + /// Module requires main thread initialization. + static func requiresMainQueueSetup() -> Bool { + true + } + + /// Use `UIManager.addBlock` to enqueue module methods on UI thread. + var methodQueue: DispatchQueue! { + bridge.uiManager.methodQueue + } + + /** + - Gets the `BufferLevel` from the Player + - Parameter nativeId: Native Id of the the player instance. + - Parameter type: The type of buffer to return the level for. + - Parameter resolver: JS promise resolver. + - Parameter rejecter: JS promise rejecter. + */ + @objc(getLevel:type:resolver:rejecter:) + func getLevel( + _ playerId: NativeId, + type: NSNumber, + resolver resolve: @escaping RCTPromiseResolveBlock, + rejecter reject: @escaping RCTPromiseRejectBlock + ) { + bridge.uiManager.addUIBlock { [weak self] _, _ in + guard let bufferApi = self?.playerModule?.retrieve(playerId)?.buffer else { + reject("[BufferModule]", "Could not find player with ID (\(playerId))", nil) + return + } + guard let bufferType = RCTConvert.bufferType(type) else { + reject("[BufferModule]", "Invalid buffer type", nil) + return + } + + let level = bufferApi.getLevel(bufferType) + let bufferLevels = RNBufferLevels(audio: level, video: level) + resolve(RCTConvert.toJson(bufferLevels: bufferLevels)) + } + } + + /** + * Sets the target level in seconds for the forward buffer. + - Parameter nativeId: Target player id. + - Parameter type: The type of the buffer to set the target level for. + - Parameter value: The value to set. + */ + @objc(setTargetLevel:type:value:) + func setTargetLevel(_ playerId: NativeId, type: NSNumber, value: TimeInterval) { + bridge.uiManager.addUIBlock { [weak self] _, _ in + guard + let bufferApi = self?.playerModule?.retrieve(playerId)?.buffer, + let bufferType = RCTConvert.bufferType(type), + bufferType == .forwardDuration + else { + return + } + + bufferApi.setTargetLevel(value) + } + } +} diff --git a/ios/RCTConvert+BitmovinPlayer.swift b/ios/RCTConvert+BitmovinPlayer.swift index 6ad84e87..54e94ca9 100644 --- a/ios/RCTConvert+BitmovinPlayer.swift +++ b/ios/RCTConvert+BitmovinPlayer.swift @@ -1091,4 +1091,69 @@ extension RCTConvert { #endif return pictureInPictureConfig } + + /** + * Utility method to instantiate a `BufferType` from an Integer. + * Currently `0` is mapped to `BufferType.forwardDuration`, and `1` to `BufferType.backwardDuration`. + * Other values fall back to `BufferType.forwardDuration` + * - Parameter value: Integer value representing the `BufferType`. + * - Returns: The `BufferType` corresponding to `value`. + */ + static func bufferType(_ value: NSNumber?) -> BufferType? { + guard let value = value as? Int else { + return nil + } + + switch value { + case 0: + return .forwardDuration + case 1: + return .backwardDuration + default: + return .forwardDuration + } + } + + /** + Utility method to get a json dictionary value from a `BufferLevel` object. + - Parameter bufferLevel: The `BufferLevel` to convert to json format. + - Parameter mediaType: The `MediaType` value to pass through. + - Returns: The generated json dictionary. + */ + static func toJson(bufferLevel: BufferLevel?, mediaType: Int) -> [String: Any]? { + guard let bufferLevel = bufferLevel else { + return nil + } + + let type: Int + switch bufferLevel.type { + case .forwardDuration: + type = 0 + case .backwardDuration: + type = 1 + } + + return [ + "level": bufferLevel.level, + "targetLevel": bufferLevel.targetLevel, + "media": mediaType, + "type": type + ] + } + + /** + Utility method to get a json dictionary value from a `BufferModule.RNBufferLevels` object. + - Parameter bufferLevels: The `BufferModule.RNBufferLevels` to convert to json format. + - Returns: The generated json dictionary. + */ + static func toJson(bufferLevels: BufferModule.RNBufferLevels?) -> [String: Any]? { + guard let bufferLevels = bufferLevels else { + return nil + } + + return [ + "audio": toJson(bufferLevel: bufferLevels.audio, mediaType: 0), + "video": toJson(bufferLevel: bufferLevels.video, mediaType: 1), + ] + } } From 0c1660d328f7359b3d029020631eb0e3646ef355 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Thu, 19 Oct 2023 11:22:17 +0200 Subject: [PATCH 11/50] docs(bufferapi): fix docs in bufferApi.ts --- src/bufferApi.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bufferApi.ts b/src/bufferApi.ts index f798eeea..165d36bf 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -8,12 +8,10 @@ const BufferModule = NativeModules.BufferModule; export enum MediaType { /** * Audio media type. - * @platform Android */ AUDIO = 0, /** * Video media type. - * @platform Android */ VIDEO = 1, } @@ -92,7 +90,7 @@ export class BufferApi { }; /** - * Sets the target buffer level for the chosen buffer {@link BufferType|type} across all {@link MediaType}s. + * Sets the target buffer level for the chosen buffer {@link BufferType|type} across all {@link MediaType|Mediatypes}. * * @param type The type of the buffer to set the target level for. On iOS only {@link BufferType.FORWARD_DURATION} is supported. * @param value The value to set. From 18f5b05a00d871f008cb45fb6c8adf1f35b2b9cf Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Thu, 19 Oct 2023 11:27:32 +0200 Subject: [PATCH 12/50] feat(bufferapi): codestyle improvements --- .../main/java/com/bitmovin/player/reactnative/BufferModule.kt | 4 +++- .../bitmovin/player/reactnative/converter/JsonConverter.kt | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index a7486999..58d7cbcb 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -54,7 +54,9 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB @ReactMethod fun setTargetLevel(nativeId: NativeId, type: Int, value: Double) { uiManager()?.addUIBlock { _ -> - playerModule()?.getPlayer(nativeId)?.buffer?.setTargetLevel(JsonConverter.toBufferType(type), value) + val player = playerModule()?.getPlayer(nativeId) ?: return@addUIBlock + val bufferType = JsonConverter.toBufferType(type) + player.buffer.setTargetLevel(bufferType, value) } } diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index cac748ca..475f2306 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -1195,7 +1195,8 @@ class JsonConverter { * * Currently `0` is mapped to [BufferType.ForwardDuration], and `1` to [BufferType.BackwardDuration]. * Other values fall back to [BufferType.ForwardDuration] - * @param value The integer value to seek a [BufferType] for. + * @param value Integer value representing the [BufferType]. + * @return The [BufferType] corresponding to [value]. */ @JvmStatic fun toBufferType(value: Int?): BufferType = when (value) { From cde574d303dd9a88b7bce88f71859e29b45b519b Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Thu, 19 Oct 2023 11:54:22 +0200 Subject: [PATCH 13/50] feat(docs): remove docs changes They will be put in a different docs-centric PR --- src/player.ts | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/player.ts b/src/player.ts index f94660f3..3298f118 100644 --- a/src/player.ts +++ b/src/player.ts @@ -18,7 +18,7 @@ import { BufferApi } from './bufferApi'; const PlayerModule = NativeModules.PlayerModule; /** - * Object used to configure a new {@link Player} instance. + * Object used to configure a new `Player` instance. */ export interface PlayerConfig extends NativeInstanceConfig { /** @@ -153,13 +153,13 @@ export interface PlaybackConfig { } /** - * Loads, controls and renders audio and video content represented through {@link Source|Sources}. A player - * instance can be created via the {@link usePlayer} hook and will idle until one or more {@link Source|Sources} are - * loaded. Once {@link load} is called, the player becomes active and initiates necessary downloads to + * Loads, controls and renders audio and video content represented through `Source`s. A player + * instance can be created via the `usePlayer` hook and will idle until one or more `Source`s are + * loaded. Once `load` is called, the player becomes active and initiates necessary downloads to * start playback of the loaded source(s). * - * Can be attached to {@link PlayerView} component in order to use Bitmovin's Player Web UI. - * @see {@link PlayerView} + * Can be attached to `PlayerView` component in order to use Bitmovin's Player Web UI. + * @see PlayerView */ export class Player extends NativeInstance { /** @@ -217,14 +217,14 @@ export class Player extends NativeInstance { }; /** - * Loads a new {@link Source} from {@link sourceConfig} into the player. + * Loads a new `Source` from `sourceConfig` into the player. */ load = (sourceConfig: SourceConfig) => { this.loadSource(new Source(sourceConfig)); }; /** - * Loads the downloaded content from {@link OfflineContentManager} into the player. + * Loads the downloaded content from `OfflineContentManager` into the player. */ loadOfflineContent = ( offlineContentManager: OfflineContentManager, @@ -238,7 +238,7 @@ export class Player extends NativeInstance { }; /** - * Loads the given {@link Source} into the player. + * Loads the given `Source` into the player. */ loadSource = (source: Source) => { source.initialize(); @@ -247,7 +247,7 @@ export class Player extends NativeInstance { }; /** - * Unloads all {@link Source|Sources} from the player. + * Unloads all `Source`s from the player. */ unload = () => { PlayerModule.unload(this.nativeId); @@ -280,7 +280,7 @@ export class Player extends NativeInstance { /** * Shifts the time to the given `offset` in seconds from the live edge. The resulting offset has to be within the - * timeShift window as specified by `maxTimeShift` (which is a negative value) and `0`. When the provided `offset` is + * timeShift window as specified by `maxTimeShift` (which is a negative value) and 0. When the provided `offset` is * positive, it will be interpreted as a UNIX timestamp in seconds and converted to fit into the timeShift window. * When the provided `offset` is negative, but lower than `maxTimeShift`, then it will be clamped to `maxTimeShift`. * Has no effect for VoD. @@ -306,7 +306,7 @@ export class Player extends NativeInstance { }; /** - * Sets the player's volume between `0` (silent) and `100` (max volume). + * Sets the player's volume between 0 (silent) and 100 (max volume). * * @param volume - The volume level to set. */ @@ -324,7 +324,7 @@ export class Player extends NativeInstance { /** * @returns The current playback time in seconds. * - * For VoD streams the returned time ranges between `0` and the duration of the asset. + * For VoD streams the returned time ranges between 0 and the duration of the asset. * * For live streams it can be specified if an absolute UNIX timestamp or a value * relative to the playback start should be returned. @@ -336,7 +336,7 @@ export class Player extends NativeInstance { }; /** - * @returns The total duration in seconds of the current video or `Infinity` if it’s a live stream. + * @returns The total duration in seconds of the current video or INFINITY if it’s a live stream. */ getDuration = async (): Promise => { return PlayerModule.duration(this.nativeId); @@ -406,7 +406,7 @@ export class Player extends NativeInstance { }; /** - * @returns An array containing {@link AudioTrack} objects for all available audio tracks. + * @returns An array containing AudioTrack objects for all available audio tracks. */ getAvailableAudioTracks = async (): Promise => { return PlayerModule.getAvailableAudioTracks(this.nativeId); @@ -427,7 +427,7 @@ export class Player extends NativeInstance { }; /** - * @returns An array containing {@link SubtitleTrack} objects for all available subtitle tracks. + * @returns An array containing SubtitleTrack objects for all available subtitle tracks. */ getAvailableSubtitles = async (): Promise => { return PlayerModule.getAvailableSubtitles(this.nativeId); @@ -471,7 +471,7 @@ export class Player extends NativeInstance { }; /** - * The current time shift of the live stream in seconds. This value is always `0` if the active {@link Source|source} is not a + * The current time shift of the live stream in seconds. This value is always 0 if the active `source` is not a * live stream or no sources are loaded. */ getTimeShift = async (): Promise => { @@ -479,8 +479,8 @@ export class Player extends NativeInstance { }; /** - * The limit in seconds for time shifting. This value is either negative or `0` and it is always `0` if the active - * {@link Source|source} is not a live stream or no sources are loaded. + * The limit in seconds for time shifting. This value is either negative or 0 and it is always 0 if the active + * `source` is not a live stream or no sources are loaded. */ getMaxTimeShift = async (): Promise => { return PlayerModule.getMaxTimeShift(this.nativeId); @@ -497,12 +497,11 @@ export class Player extends NativeInstance { }; /** - * @returns a {@link Thumbnail} for the specified playback time for the currently active source if available. + * @returns a `Thumbnail` for the specified playback time for the currently active source if available. * Supported thumbnail formats are: - * - `WebVtt` configured via {@link SourceConfig.thumbnailTrack}, on all supported platforms + * - `WebVtt` configured via `SourceConfig.thumbnailTrack`, on all supported platforms * - HLS `Image Media Playlist` in the multivariant playlist, Android-only * - DASH `Image Adaptation Set` as specified in DASH-IF IOP, Android-only - * * If a `WebVtt` thumbnail track is provided, any potential in-manifest thumbnails are ignored on Android. */ getThumbnail = async (time: number): Promise => { @@ -510,7 +509,7 @@ export class Player extends NativeInstance { }; /** - * Whether casting to a cast-compatible remote device is available. {@link CastAvailableEvent} signals when + * Whether casting to a cast-compatible remote device is available. `CastAvailableEvent` signals when * casting becomes available. * * @platform iOS, Android @@ -539,7 +538,7 @@ export class Player extends NativeInstance { }; /** - * Stops casting the current video. Has no effect if {@link isCasting} is false. + * Stops casting the current video. Has no effect if `isCasting` is false. * * @platform iOS, Android */ From fb5b4b42950fce8178c526b87f081096556b02b1 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Thu, 19 Oct 2023 11:55:19 +0200 Subject: [PATCH 14/50] feat(docs): remove docs changes --- src/hooks/usePlayer.ts | 2 +- src/player.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hooks/usePlayer.ts b/src/hooks/usePlayer.ts index 405b26ae..e1cc9284 100644 --- a/src/hooks/usePlayer.ts +++ b/src/hooks/usePlayer.ts @@ -2,7 +2,7 @@ import { useRef } from 'react'; import { Player, PlayerConfig } from '../player'; /** - * React hook that creates and returns a reference to a {@link Player} instance + * React hook that creates and returns a reference to a `Player` instance * that can be used inside any component. */ export function usePlayer(config?: PlayerConfig): Player { diff --git a/src/player.ts b/src/player.ts index 3298f118..6893a9e0 100644 --- a/src/player.ts +++ b/src/player.ts @@ -167,15 +167,15 @@ export class Player extends NativeInstance { */ source?: Source; /** - * Whether the native {@link Player} object has been created. + * Whether the native `Player` object has been created. */ isInitialized = false; /** - * Whether the native {@link Player} object has been disposed. + * Whether the native `Player` object has been disposed. */ isDestroyed = false; /** - * The {@link AnalyticsApi} for interactions regarding the {@link Player}'s analytics. + * The `AnalyticsApi` for interactions regarding the `Player`'s analytics. * * `undefined` if the player was created without analytics support. */ @@ -186,7 +186,7 @@ export class Player extends NativeInstance { buffer: BufferApi = new BufferApi(this.nativeId); /** - * Allocates the native {@link Player} instance and its resources natively. + * Allocates the native `Player` instance and its resources natively. */ initialize = () => { if (!this.isInitialized) { @@ -206,7 +206,7 @@ export class Player extends NativeInstance { }; /** - * Destroys the native {@link Player} and releases all of its allocated resources. + * Destroys the native `Player` and releases all of its allocated resources. */ destroy = () => { if (!this.isDestroyed) { From ebcacca70f16e31adfbf48017ca2b6ffbbd008bf Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Thu, 19 Oct 2023 11:59:48 +0200 Subject: [PATCH 15/50] feat(docs): remove docs changes --- .../player/reactnative/BufferModule.kt | 11 +++----- .../reactnative/converter/JsonConverter.kt | 26 +++++++++---------- src/bufferApi.ts | 4 +-- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index 58d7cbcb..65254c91 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -11,11 +11,6 @@ private const val MODULE_NAME = "BufferModule" @ReactModule(name = MODULE_NAME) class BufferModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) { - /** - * Collection of [BufferLevel] objects - * @param audio [BufferLevel] for [MediaType.Audio]. - * @param video [BufferLevel] for [MediaType.Video]. - */ data class RNBufferLevels(val audio: BufferLevel, val video: BufferLevel) /** @@ -24,9 +19,9 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB override fun getName() = MODULE_NAME /** - * Gets the [buffer level][BufferLevel] from the Player - * @param nativeId Target player id. - * @param type The [type of buffer][JsonConverter.toBufferType] to return the level for. + * Gets the buffer level from the Player + * @param nativeId Native Id of the collector instance. + * @param type The type of buffer to return the level for. * @param promise JS promise object. */ @ReactMethod diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index 475f2306..56540822 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -70,9 +70,9 @@ import java.util.UUID class JsonConverter { companion object { /** - * Converts an arbitrary `json` to [PlayerConfig]. - * @param json JS object representing the [PlayerConfig]. - * @return The generated [PlayerConfig] if successful, `null` otherwise. + * Converts an arbitrary `json` to `PlayerConfig`. + * @param json JS object representing the `PlayerConfig`. + * @return The generated `PlayerConfig` if successful, `null` otherwise. */ @JvmStatic fun toPlayerConfig(json: ReadableMap?): PlayerConfig { @@ -121,9 +121,9 @@ class JsonConverter { } /** - * Converts any JS object into a [BufferMediaTypeConfig] object. - * @param json JS object representing the [BufferMediaTypeConfig]. - * @return The generated [BufferMediaTypeConfig] if successful, `null` otherwise. + * Converts any JS object into a `BufferMediaTypeConfig` object. + * @param json JS object representing the `BufferMediaTypeConfig`. + * @return The generated `BufferMediaTypeConfig` if successful, `null` otherwise. */ @JvmStatic fun toBufferMediaTypeConfig(json: ReadableMap?): BufferMediaTypeConfig? { @@ -138,9 +138,9 @@ class JsonConverter { } /** - * Converts any JS object into a [BufferConfig] object. - * @param json JS object representing the [BufferConfig]. - * @return The generated [BufferConfig] if successful, `null` otherwise. + * Converts any JS object into a `BufferConfig` object. + * @param json JS object representing the `BufferConfig`. + * @return The generated `BufferConfig` if successful, `null` otherwise. */ @JvmStatic fun toBufferConfig(json: ReadableMap?): BufferConfig? { @@ -215,9 +215,9 @@ class JsonConverter { } /** - * Converts an arbitrary `json` to [SourceOptions]. - * @param json JS object representing the [SourceOptions]. - * @return The generated [SourceOptions]. + * Converts an arbitrary `json` to `SourceOptions`. + * @param json JS object representing the `SourceOptions`. + * @return The generated `SourceOptions`. */ @JvmStatic fun toSourceOptions(json: ReadableMap?): SourceOptions { @@ -1199,7 +1199,7 @@ class JsonConverter { * @return The [BufferType] corresponding to [value]. */ @JvmStatic - fun toBufferType(value: Int?): BufferType = when (value) { + fun toBufferType(json: Int?): BufferType = when (json) { 0 -> BufferType.ForwardDuration 1 -> BufferType.BackwardDuration else -> BufferType.ForwardDuration diff --git a/src/bufferApi.ts b/src/bufferApi.ts index 165d36bf..d9616f62 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -81,8 +81,8 @@ export class BufferApi { } /** - * Gets the {@link BufferLevel|buffer level} from the Player - * @param type The {@link BufferType|type of buffer} to return the level for. + * Returns the {@link BufferLevel} for the chosen {@link BufferType|buffer type} and {@link MediaType|media type} of the active Source. + * @param type The type of buffer to return the level for. * @returns a {@link BufferLevels} that contains {@link BufferLevel} values for audio and video. */ getLevel = async (type: BufferType): Promise => { From 2ea57b4a6a4e0cffc25a8c89365fa4e5ca897191 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Thu, 19 Oct 2023 12:06:23 +0200 Subject: [PATCH 16/50] docs(bufferapi): fix documentation --- .../com/bitmovin/player/reactnative/BufferModule.kt | 12 ++++++++---- .../player/reactnative/converter/JsonConverter.kt | 2 +- src/bufferApi.ts | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index 65254c91..d1362355 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -11,6 +11,11 @@ private const val MODULE_NAME = "BufferModule" @ReactModule(name = MODULE_NAME) class BufferModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) { + /** + * Collection of [BufferLevel] objects + * @param audio [BufferLevel] for [MediaType.Audio]. + * @param video [BufferLevel] for [MediaType.Video]. + */ data class RNBufferLevels(val audio: BufferLevel, val video: BufferLevel) /** @@ -19,9 +24,9 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB override fun getName() = MODULE_NAME /** - * Gets the buffer level from the Player - * @param nativeId Native Id of the collector instance. - * @param type The type of buffer to return the level for. + * Gets the [buffer level][BufferLevel] from the Player + * @param nativeId Target player id. + * @param type The [type of buffer][JsonConverter.toBufferType] to return the level for. * @param promise JS promise object. */ @ReactMethod @@ -41,7 +46,6 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB /** * Sets the target buffer level for the chosen buffer type across all media types. - * * @param nativeId Target player id. * @param type The type of the buffer to set the target level for. * @param value The value to set. diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index 56540822..36b2fc4b 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -1199,7 +1199,7 @@ class JsonConverter { * @return The [BufferType] corresponding to [value]. */ @JvmStatic - fun toBufferType(json: Int?): BufferType = when (json) { + fun toBufferType(value: Int?): BufferType = when (value) { 0 -> BufferType.ForwardDuration 1 -> BufferType.BackwardDuration else -> BufferType.ForwardDuration diff --git a/src/bufferApi.ts b/src/bufferApi.ts index d9616f62..165d36bf 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -81,8 +81,8 @@ export class BufferApi { } /** - * Returns the {@link BufferLevel} for the chosen {@link BufferType|buffer type} and {@link MediaType|media type} of the active Source. - * @param type The type of buffer to return the level for. + * Gets the {@link BufferLevel|buffer level} from the Player + * @param type The {@link BufferType|type of buffer} to return the level for. * @returns a {@link BufferLevels} that contains {@link BufferLevel} values for audio and video. */ getLevel = async (type: BufferType): Promise => { From 5c7f68e3f2b60258f986c10cccff095d0ef88cd0 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Thu, 19 Oct 2023 13:13:32 +0200 Subject: [PATCH 17/50] feat(bufferapi): fix swiftlint warnings --- BufferModule.swift | 18 +++++++++--------- ios/RCTConvert+BitmovinPlayer.swift | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/BufferModule.swift b/BufferModule.swift index c3997db5..8fc55da9 100644 --- a/BufferModule.swift +++ b/BufferModule.swift @@ -1,37 +1,37 @@ import BitmovinPlayer @objc(BufferModule) -class BufferModule: NSObject, RCTBridgeModule { +public class BufferModule: NSObject, RCTBridgeModule { /** * Collection of `BufferLevel` objects * - Parameter audio: `BufferLevel` for `MediaType.Audio`. * - Parameter video: `BufferLevel` for `MediaType.Video`. */ - struct RNBufferLevels { + internal struct RNBufferLevels { let audio: BufferLevel let video: BufferLevel } - /// React bridge reference. - @objc var bridge: RCTBridge! + // swiftlint:disable:next implicitly_unwrapped_optional + @objc public var bridge: RCTBridge! /// PlayerModule instance fetched from the bridge's registry @objc var playerModule: PlayerModule? { bridge.module(for: PlayerModule.self) as? PlayerModule } - /// JS module name. - static func moduleName() -> String! { + // swiftlint:disable:next implicitly_unwrapped_optional + public static func moduleName() -> String! { "BufferModule" } /// Module requires main thread initialization. - static func requiresMainQueueSetup() -> Bool { + public static func requiresMainQueueSetup() -> Bool { true } - /// Use `UIManager.addBlock` to enqueue module methods on UI thread. - var methodQueue: DispatchQueue! { + // swiftlint:disable:next implicitly_unwrapped_optional + public var methodQueue: DispatchQueue! { bridge.uiManager.methodQueue } diff --git a/ios/RCTConvert+BitmovinPlayer.swift b/ios/RCTConvert+BitmovinPlayer.swift index 7960a961..7cacf9da 100644 --- a/ios/RCTConvert+BitmovinPlayer.swift +++ b/ios/RCTConvert+BitmovinPlayer.swift @@ -1168,7 +1168,7 @@ extension RCTConvert { - Returns: The generated json dictionary. */ static func toJson(bufferLevel: BufferLevel?, mediaType: Int) -> [String: Any]? { - guard let bufferLevel = bufferLevel else { + guard let bufferLevel else { return nil } @@ -1194,7 +1194,7 @@ extension RCTConvert { - Returns: The generated json dictionary. */ static func toJson(bufferLevels: BufferModule.RNBufferLevels?) -> [String: Any]? { - guard let bufferLevels = bufferLevels else { + guard let bufferLevels else { return nil } From a33b50c25bb90441b268f9b263dda67388d6bb6d Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Thu, 19 Oct 2023 13:15:13 +0200 Subject: [PATCH 18/50] feat(bufferapi): add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c49b00a..3a2e3894 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - `PlayerView.isPictureInPictureRequested` to programatically create a Picture in Picture request - `PlayerView.scalingMode` to allow changing the video scaling mode - `PlayerViewConfig` with a `UiConfig` to the `PlayerView` to enable configuration of the visual presentation and behaviour +- `Player.buffer` namespace to control buffer preferences and to query the current buffer state. ### Changed From 5cae0fe6c2265fd7af1aa64b0e748c807d00da97 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Thu, 19 Oct 2023 13:24:08 +0200 Subject: [PATCH 19/50] feat(bufferapi): fix buffer module location --- BufferModule.m => ios/BufferModule.m | 0 BufferModule.swift => ios/BufferModule.swift | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename BufferModule.m => ios/BufferModule.m (100%) rename BufferModule.swift => ios/BufferModule.swift (100%) diff --git a/BufferModule.m b/ios/BufferModule.m similarity index 100% rename from BufferModule.m rename to ios/BufferModule.m diff --git a/BufferModule.swift b/ios/BufferModule.swift similarity index 100% rename from BufferModule.swift rename to ios/BufferModule.swift From b0ca8170add8bc6bc8f6abec3aaabfe157e0208b Mon Sep 17 00:00:00 2001 From: Michele Pozzi <96702967+123mpozzi@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:27:54 +0200 Subject: [PATCH 20/50] feat(bufferapi): fix `setTargetLevel` on iOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roland Kákonyi --- ios/BufferModule.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ios/BufferModule.swift b/ios/BufferModule.swift index 8fc55da9..8dd4eef4 100644 --- a/ios/BufferModule.swift +++ b/ios/BufferModule.swift @@ -72,7 +72,8 @@ public class BufferModule: NSObject, RCTBridgeModule { - Parameter value: The value to set. */ @objc(setTargetLevel:type:value:) - func setTargetLevel(_ playerId: NativeId, type: NSNumber, value: TimeInterval) { + func setTargetLevel(_ playerId: NativeId, type: NSNumber, value: NSNumber) { + let targetLevel = value.doubleValue bridge.uiManager.addUIBlock { [weak self] _, _ in guard let bufferApi = self?.playerModule?.retrieve(playerId)?.buffer, @@ -82,7 +83,7 @@ public class BufferModule: NSObject, RCTBridgeModule { return } - bufferApi.setTargetLevel(value) + bufferApi.setTargetLevel(targetLevel) } } } From f57810589c0b93d2f4af52ba23e5e170e215580a Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Fri, 20 Oct 2023 14:48:37 +0200 Subject: [PATCH 21/50] feat(bufferapi): move RN only types to the bottom of the Kotlin file --- .../bitmovin/player/reactnative/BufferModule.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index d1362355..159dbc68 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -11,13 +11,6 @@ private const val MODULE_NAME = "BufferModule" @ReactModule(name = MODULE_NAME) class BufferModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) { - /** - * Collection of [BufferLevel] objects - * @param audio [BufferLevel] for [MediaType.Audio]. - * @param video [BufferLevel] for [MediaType.Video]. - */ - data class RNBufferLevels(val audio: BufferLevel, val video: BufferLevel) - /** * JS exported module name. */ @@ -70,4 +63,11 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB */ private fun playerModule(): PlayerModule? = context.getNativeModule(PlayerModule::class.java) + + /** + * Collection of [BufferLevel] objects + * @param audio [BufferLevel] for [MediaType.Audio]. + * @param video [BufferLevel] for [MediaType.Video]. + */ + data class RNBufferLevels(val audio: BufferLevel, val video: BufferLevel) } From fb87736f34f23a5ec852cf4a9c8d1117a9683bfd Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Fri, 20 Oct 2023 14:54:08 +0200 Subject: [PATCH 22/50] feat(bufferapi): move RN-only types on the bottom of `RCTConvert+BitmovinPlayer.swift` --- ios/BufferModule.swift | 10 ---------- ios/RCTConvert+BitmovinPlayer.swift | 12 +++++++++++- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ios/BufferModule.swift b/ios/BufferModule.swift index 8dd4eef4..4f1f8f2e 100644 --- a/ios/BufferModule.swift +++ b/ios/BufferModule.swift @@ -2,16 +2,6 @@ import BitmovinPlayer @objc(BufferModule) public class BufferModule: NSObject, RCTBridgeModule { - /** - * Collection of `BufferLevel` objects - * - Parameter audio: `BufferLevel` for `MediaType.Audio`. - * - Parameter video: `BufferLevel` for `MediaType.Video`. - */ - internal struct RNBufferLevels { - let audio: BufferLevel - let video: BufferLevel - } - // swiftlint:disable:next implicitly_unwrapped_optional @objc public var bridge: RCTBridge! diff --git a/ios/RCTConvert+BitmovinPlayer.swift b/ios/RCTConvert+BitmovinPlayer.swift index 7cacf9da..79ad0519 100644 --- a/ios/RCTConvert+BitmovinPlayer.swift +++ b/ios/RCTConvert+BitmovinPlayer.swift @@ -1193,7 +1193,7 @@ extension RCTConvert { - Parameter bufferLevels: The `BufferModule.RNBufferLevels` to convert to json format. - Returns: The generated json dictionary. */ - static func toJson(bufferLevels: BufferModule.RNBufferLevels?) -> [String: Any]? { + static func toJson(bufferLevels: RNBufferLevels?) -> [String: Any]? { guard let bufferLevels else { return nil } @@ -1220,3 +1220,13 @@ internal struct RNPlayerViewConfig { internal struct UiConfig { let playbackSpeedSelectionEnabled: Bool } + +/** + * Collection of `BufferLevel` objects + * - Parameter audio: `BufferLevel` for `MediaType.Audio`. + * - Parameter video: `BufferLevel` for `MediaType.Video`. + */ +internal struct RNBufferLevels { + let audio: BufferLevel + let video: BufferLevel +} From 6e920febbc6fb988c7bb88dc238be1d323e3ef0b Mon Sep 17 00:00:00 2001 From: Michele Pozzi <96702967+123mpozzi@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:56:45 +0200 Subject: [PATCH 23/50] feat(bufferapi): fix docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roland Kákonyi --- src/bufferApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bufferApi.ts b/src/bufferApi.ts index 165d36bf..ea4d32c5 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -82,7 +82,7 @@ export class BufferApi { /** * Gets the {@link BufferLevel|buffer level} from the Player - * @param type The {@link BufferType|type of buffer} to return the level for. + * @param type The {@link BufferType} to return the level for. * @returns a {@link BufferLevels} that contains {@link BufferLevel} values for audio and video. */ getLevel = async (type: BufferType): Promise => { From 46d5e9390ff1c9c5c5b5068a2bc9433d99515cf9 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <96702967+123mpozzi@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:57:32 +0200 Subject: [PATCH 24/50] feat(bufferapi): nit docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roland Kákonyi --- src/bufferApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bufferApi.ts b/src/bufferApi.ts index ea4d32c5..eb4852e1 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -90,7 +90,7 @@ export class BufferApi { }; /** - * Sets the target buffer level for the chosen buffer {@link BufferType|type} across all {@link MediaType|Mediatypes}. + * Sets the target buffer level for the chosen buffer {@link BufferType} across all {@link MediaType} options. * * @param type The type of the buffer to set the target level for. On iOS only {@link BufferType.FORWARD_DURATION} is supported. * @param value The value to set. From 64ff2b62fe7608c44f761f3e329695fd6b383e23 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <96702967+123mpozzi@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:58:25 +0200 Subject: [PATCH 25/50] feat(bufferapi): update docs on specific iOS behaviour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roland Kákonyi --- src/bufferApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bufferApi.ts b/src/bufferApi.ts index eb4852e1..28f99126 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -93,7 +93,7 @@ export class BufferApi { * Sets the target buffer level for the chosen buffer {@link BufferType} across all {@link MediaType} options. * * @param type The type of the buffer to set the target level for. On iOS only {@link BufferType.FORWARD_DURATION} is supported. - * @param value The value to set. + * @param value The value to set. On iOS and tvOS when passing `0`, the player will choose an appropriate forward buffer duration suitable for most use-cases. On Android setting to `0` will have no effect. */ setTargetLevel = async (type: BufferType, value: number): Promise => { return BufferModule.setTargetLevel(this.nativeId, type, value); From f270dddd6bec6de9c273462a910a13f350cf3f3a Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Fri, 20 Oct 2023 15:01:16 +0200 Subject: [PATCH 26/50] feat(bufferapi): add tvOS in BufferMediaTypeConfig docs --- src/bufferConfig.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bufferConfig.ts b/src/bufferConfig.ts index e185bd41..552e00d6 100644 --- a/src/bufferConfig.ts +++ b/src/bufferConfig.ts @@ -5,10 +5,10 @@ export interface BufferMediaTypeConfig { /** * The amount of data in seconds the player tries to buffer in advance. * - * iOS only: If set to `0`, the player will choose an appropriate forward buffer duration suitable + * iOS and tvOS, only: If set to `0`, the player will choose an appropriate forward buffer duration suitable * for most use-cases. * - * Default value is `0` on iOS, `50` on Android + * Default value is `0` on iOS and tvOS, `50` on Android */ forwardDuration?: number; } From b94cbb65a6d8fbe440ae0e3005eed5de55942601 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <96702967+123mpozzi@users.noreply.github.com> Date: Fri, 20 Oct 2023 15:02:41 +0200 Subject: [PATCH 27/50] feat(bufferapi): update docs with tvOS too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roland Kákonyi --- src/bufferApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bufferApi.ts b/src/bufferApi.ts index 28f99126..0831c2c5 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -92,7 +92,7 @@ export class BufferApi { /** * Sets the target buffer level for the chosen buffer {@link BufferType} across all {@link MediaType} options. * - * @param type The type of the buffer to set the target level for. On iOS only {@link BufferType.FORWARD_DURATION} is supported. + * @param type The type of the buffer to set the target level for. On iOS and tvOS, only {@link BufferType.FORWARD_DURATION} is supported. * @param value The value to set. On iOS and tvOS when passing `0`, the player will choose an appropriate forward buffer duration suitable for most use-cases. On Android setting to `0` will have no effect. */ setTargetLevel = async (type: BufferType, value: number): Promise => { From 5c0d1c3e8e720e0df6df6a3eb47c330a7608cc82 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Fri, 20 Oct 2023 15:19:26 +0200 Subject: [PATCH 28/50] feat(bufferapi): move RNBufferLevels to correct place Also fix formatting with `./gradlew ktlintFormat` --- .../bitmovin/player/reactnative/BufferModule.kt | 14 +++++++------- .../player/reactnative/converter/JsonConverter.kt | 3 +-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index 159dbc68..f2f72071 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -63,11 +63,11 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB */ private fun playerModule(): PlayerModule? = context.getNativeModule(PlayerModule::class.java) - - /** - * Collection of [BufferLevel] objects - * @param audio [BufferLevel] for [MediaType.Audio]. - * @param video [BufferLevel] for [MediaType.Video]. - */ - data class RNBufferLevels(val audio: BufferLevel, val video: BufferLevel) } + +/** + * Collection of [BufferLevel] objects + * @param audio [BufferLevel] for [MediaType.Audio]. + * @param video [BufferLevel] for [MediaType.Video]. + */ +data class RNBufferLevels(val audio: BufferLevel, val video: BufferLevel) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index 27df7af4..364d4cdd 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -47,8 +47,8 @@ import com.bitmovin.player.api.ui.ScalingMode import com.bitmovin.player.api.ui.StyleConfig import com.bitmovin.player.api.ui.UiConfig import com.bitmovin.player.reactnative.BitmovinCastManagerOptions -import com.bitmovin.player.reactnative.RNPlayerViewConfigWrapper import com.bitmovin.player.reactnative.BufferModule +import com.bitmovin.player.reactnative.RNPlayerViewConfigWrapper import com.bitmovin.player.reactnative.extensions.getBooleanOrNull import com.bitmovin.player.reactnative.extensions.getName import com.bitmovin.player.reactnative.extensions.getOrDefault @@ -1174,7 +1174,6 @@ class JsonConverter { pictureInPictureConfig = toPictureInPictureConfig(json.getMap("pictureInPictureConfig")), ) - @JvmStatic fun fromBufferLevel(bufferLevel: BufferLevel?): WritableMap? { if (bufferLevel == null) { From ed8ab2fd996e85534915bfa9a1cfc50cb1c13211 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Fri, 20 Oct 2023 15:23:42 +0200 Subject: [PATCH 29/50] feat(bufferapi): fix `RNBufferLevels` imports --- .../player/reactnative/converter/JsonConverter.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index 364d4cdd..cc65da38 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -47,7 +47,7 @@ import com.bitmovin.player.api.ui.ScalingMode import com.bitmovin.player.api.ui.StyleConfig import com.bitmovin.player.api.ui.UiConfig import com.bitmovin.player.reactnative.BitmovinCastManagerOptions -import com.bitmovin.player.reactnative.BufferModule +import com.bitmovin.player.reactnative.RNBufferLevels import com.bitmovin.player.reactnative.RNPlayerViewConfigWrapper import com.bitmovin.player.reactnative.extensions.getBooleanOrNull import com.bitmovin.player.reactnative.extensions.getName @@ -61,10 +61,7 @@ import com.bitmovin.player.reactnative.extensions.toList import com.bitmovin.player.reactnative.extensions.toReadableArray import com.bitmovin.player.reactnative.extensions.toReadableMap import com.bitmovin.player.reactnative.ui.RNPictureInPictureHandler -import com.facebook.react.bridge.Arguments -import com.facebook.react.bridge.ReadableArray -import com.facebook.react.bridge.ReadableMap -import com.facebook.react.bridge.WritableMap +import com.facebook.react.bridge.* import java.util.UUID /** @@ -1201,7 +1198,7 @@ class JsonConverter { } @JvmStatic - fun fromRNBufferLevels(bufferLevels: BufferModule.RNBufferLevels?): WritableMap? { + fun fromRNBufferLevels(bufferLevels: RNBufferLevels?): WritableMap? { if (bufferLevels == null) { return null } From eeda72498961b3d906577a8eb01a7b4c7629118f Mon Sep 17 00:00:00 2001 From: Michele Pozzi <96702967+123mpozzi@users.noreply.github.com> Date: Fri, 20 Oct 2023 15:58:51 +0200 Subject: [PATCH 30/50] feat(bufferapi): make getter one-line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Žiga Vehovec --- .../main/java/com/bitmovin/player/reactnative/BufferModule.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index f2f72071..bb726ca7 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -55,8 +55,7 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB /** * Helper function that gets the instantiated `UIManagerModule` from modules registry. */ - private fun uiManager(): UIManagerModule? = - context.getNativeModule(UIManagerModule::class.java) + private fun uiManager(): UIManagerModule? = context.getNativeModule(UIManagerModule::class.java) /** * Helper function that gets the instantiated `PlayerModule` from modules registry. From cabdb30c175d059a46b8c53363811647ae9a0713 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Fri, 20 Oct 2023 16:04:00 +0200 Subject: [PATCH 31/50] feat(bufferapi): remove docs from module `getName` as it is explicit enough --- .../main/java/com/bitmovin/player/reactnative/BufferModule.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index bb726ca7..e08f5243 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -11,9 +11,6 @@ private const val MODULE_NAME = "BufferModule" @ReactModule(name = MODULE_NAME) class BufferModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) { - /** - * JS exported module name. - */ override fun getName() = MODULE_NAME /** From e24d3f7cee263b28c6ffd57d248a108806b8d4f9 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <96702967+123mpozzi@users.noreply.github.com> Date: Fri, 20 Oct 2023 16:05:50 +0200 Subject: [PATCH 32/50] feat(bufferapi): fix docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Žiga Vehovec --- src/bufferApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bufferApi.ts b/src/bufferApi.ts index 0831c2c5..13b76dfa 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -72,7 +72,7 @@ export interface BufferLevels { */ export class BufferApi { /** - * The native player id that this analytics api is attached to. + * The native player id that this buffer api is attached to. */ readonly nativeId: string; From 0800385801d82099a3b65274248b0cd5ef512020 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Fri, 20 Oct 2023 16:17:55 +0200 Subject: [PATCH 33/50] feat(bufferapi): make getter one-line --- .../main/java/com/bitmovin/player/reactnative/BufferModule.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index e08f5243..c271c1b1 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -57,8 +57,7 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB /** * Helper function that gets the instantiated `PlayerModule` from modules registry. */ - private fun playerModule(): PlayerModule? = - context.getNativeModule(PlayerModule::class.java) + private fun playerModule(): PlayerModule? = context.getNativeModule(PlayerModule::class.java) } /** From b54a7ac9e3c764a7e419c3e11a20b683f976df96 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Fri, 20 Oct 2023 16:20:36 +0200 Subject: [PATCH 34/50] feat(bufferapi): remove docs from `RNBufferLevels` --- .../java/com/bitmovin/player/reactnative/BufferModule.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index c271c1b1..b67ba1c6 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -60,9 +60,4 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB private fun playerModule(): PlayerModule? = context.getNativeModule(PlayerModule::class.java) } -/** - * Collection of [BufferLevel] objects - * @param audio [BufferLevel] for [MediaType.Audio]. - * @param video [BufferLevel] for [MediaType.Video]. - */ data class RNBufferLevels(val audio: BufferLevel, val video: BufferLevel) From de6762a25d004d9d7241d7825c441d297a57e7a6 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Fri, 20 Oct 2023 16:23:46 +0200 Subject: [PATCH 35/50] feat(bufferapi): simplify entry on CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36d544e3..480e01a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Added -- `Player.buffer` namespace to control buffer preferences and to query the current buffer state. +- `Player.buffer` to control buffer preferences and to query the current buffer state ## [0.13.0] (2023-10-20) From 6e7ca13d6f669ddf79ec4c777b71ddbff453bf7d Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Mon, 23 Oct 2023 13:25:59 +0200 Subject: [PATCH 36/50] feat(bufferapi): map bufferType to Strings instead of Int --- .../player/reactnative/BufferModule.kt | 8 ++--- .../reactnative/converter/JsonConverter.kt | 28 ++++++++++----- ios/RCTConvert+BitmovinPlayer.swift | 35 ++++++++++--------- src/bufferApi.ts | 6 ++-- 4 files changed, 45 insertions(+), 32 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index b67ba1c6..4d0c3d32 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -14,13 +14,13 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB override fun getName() = MODULE_NAME /** - * Gets the [buffer level][BufferLevel] from the Player + * Gets the [BufferLevel] from the Player * @param nativeId Target player id. * @param type The [type of buffer][JsonConverter.toBufferType] to return the level for. * @param promise JS promise object. */ @ReactMethod - fun getLevel(nativeId: NativeId, type: Int, promise: Promise) { + fun getLevel(nativeId: NativeId, type: String, promise: Promise) { uiManager()?.addUIBlock { _ -> val player = playerModule()?.getPlayer(nativeId) ?: return@addUIBlock val bufferType = JsonConverter.toBufferType(type) @@ -37,11 +37,11 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB /** * Sets the target buffer level for the chosen buffer type across all media types. * @param nativeId Target player id. - * @param type The type of the buffer to set the target level for. + * @param type The [type of buffer][JsonConverter.toBufferType] to set the target level for. * @param value The value to set. */ @ReactMethod - fun setTargetLevel(nativeId: NativeId, type: Int, value: Double) { + fun setTargetLevel(nativeId: NativeId, type: String, value: Double) { uiManager()?.addUIBlock { _ -> val player = playerModule()?.getPlayer(nativeId) ?: return@addUIBlock val bufferType = JsonConverter.toBufferType(type) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index cc65da38..0245f514 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -1178,6 +1178,18 @@ class JsonConverter { } return Arguments.createMap().apply { + /** + * Converts any [BufferType] value into its json representation. + * @param bufferType [BufferType] value. + * @return The produced JS string. + */ + @JvmStatic + fun fromBufferType(bufferType: BufferType?): String? = when (bufferType) { + BufferType.ForwardDuration -> "forwardDuration" + BufferType.BackwardDuration -> "backwardDuration" + else -> null + } + putDouble("level", bufferLevel.level) putDouble("targetLevel", bufferLevel.targetLevel) putInt( @@ -1210,17 +1222,15 @@ class JsonConverter { } /** - * Maps an integer value into the corresponding [BufferType] value. - * - * Currently `0` is mapped to [BufferType.ForwardDuration], and `1` to [BufferType.BackwardDuration]. - * Other values fall back to [BufferType.ForwardDuration] - * @param value Integer value representing the [BufferType]. - * @return The [BufferType] corresponding to [value]. + * Maps a JS string into the corresponding [BufferType] value. + * If the string is not recognized, it returns [BufferType.ForwardDuration]. + * @param json JS string representing the [BufferType]. + * @return The [BufferType] corresponding to [json]. */ @JvmStatic - fun toBufferType(value: Int?): BufferType = when (value) { - 0 -> BufferType.ForwardDuration - 1 -> BufferType.BackwardDuration + fun toBufferType(json: String?): BufferType = when (json) { + "forwardDuration" -> BufferType.ForwardDuration + "backwardDuration" -> BufferType.BackwardDuration else -> BufferType.ForwardDuration } } diff --git a/ios/RCTConvert+BitmovinPlayer.swift b/ios/RCTConvert+BitmovinPlayer.swift index a75a8e5a..9ea9b4f4 100644 --- a/ios/RCTConvert+BitmovinPlayer.swift +++ b/ios/RCTConvert+BitmovinPlayer.swift @@ -1153,21 +1153,20 @@ extension RCTConvert { } /** - * Utility method to instantiate a `BufferType` from an Integer. - * Currently `0` is mapped to `BufferType.forwardDuration`, and `1` to `BufferType.backwardDuration`. - * Other values fall back to `BufferType.forwardDuration` - * - Parameter value: Integer value representing the `BufferType`. - * - Returns: The `BufferType` corresponding to `value`. + * Maps a JS string into the corresponding `BufferType` value. + * If the string is not recognized, it returns `BufferType.forwardDuration`. + * - Parameter json: JS string representing the `BufferType`. + * - Returns: The `BufferType` corresponding to `json` */ - static func bufferType(_ value: NSNumber?) -> BufferType? { - guard let value = value as? Int else { + static func bufferType(_ json: String?) -> BufferType? { + guard let json = json as? String else { return nil } - switch value { - case 0: + switch json { + case "forwardDuration": return .forwardDuration - case 1: + case "backwardDuration": return .backwardDuration default: return .forwardDuration @@ -1175,10 +1174,9 @@ extension RCTConvert { } /** - Utility method to get a json dictionary value from a `BufferLevel` object. - - Parameter bufferLevel: The `BufferLevel` to convert to json format. - - Parameter mediaType: The `MediaType` value to pass through. - - Returns: The generated json dictionary. + * Converts any `BufferType` value into its json representation. + * - Parameter bufferType: `BufferType` value. + * - Returns: The produced JS string. */ static func toJson(bufferLevel: BufferLevel?, mediaType: Int) -> [String: Any]? { guard let bufferLevel else { @@ -1187,11 +1185,16 @@ extension RCTConvert { let type: Int switch bufferLevel.type { + static func toJson(bufferType: BufferType) -> String? { + switch bufferType { case .forwardDuration: - type = 0 + return "forwardDuration" case .backwardDuration: - type = 1 + return "backwardDuration" + default: + return nil } + } return [ "level": bufferLevel.level, diff --git a/src/bufferApi.ts b/src/bufferApi.ts index 13b76dfa..795973b5 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -23,11 +23,11 @@ export enum BufferType { /** * Represents the buffered data starting at the current playback time. */ - FORWARD_DURATION = 0, + FORWARD_DURATION = 'forwardDuration', /** * Represents the buffered data up until the current playback time. */ - BACKWARD_DURATION = 1, + BACKWARD_DURATION = 'backwardDuration', } /** @@ -92,7 +92,7 @@ export class BufferApi { /** * Sets the target buffer level for the chosen buffer {@link BufferType} across all {@link MediaType} options. * - * @param type The type of the buffer to set the target level for. On iOS and tvOS, only {@link BufferType.FORWARD_DURATION} is supported. + * @param type The {@link BufferType} to set the target level for. On iOS and tvOS, only {@link BufferType.FORWARD_DURATION} is supported. * @param value The value to set. On iOS and tvOS when passing `0`, the player will choose an appropriate forward buffer duration suitable for most use-cases. On Android setting to `0` will have no effect. */ setTargetLevel = async (type: BufferType, value: number): Promise => { From 5b8f4499f9f9f61b25aa2da976471ed5bfccbb67 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Mon, 23 Oct 2023 13:34:12 +0200 Subject: [PATCH 37/50] feat(bufferapi): update bufferApi with bufferMedia mapping using Strings instead of Int --- .../reactnative/converter/JsonConverter.kt | 36 +++++++++++-------- ios/BufferModule.m | 4 +-- ios/BufferModule.swift | 4 +-- ios/RCTConvert+BitmovinPlayer.swift | 24 +++++++------ src/bufferApi.ts | 4 +-- 5 files changed, 41 insertions(+), 31 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index 0245f514..a5aff7c0 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -1171,13 +1171,18 @@ class JsonConverter { pictureInPictureConfig = toPictureInPictureConfig(json.getMap("pictureInPictureConfig")), ) + /** + * Converts any [MediaType] value into its json representation. + * @param mediaType [MediaType] value. + * @return The produced JS string. + */ @JvmStatic - fun fromBufferLevel(bufferLevel: BufferLevel?): WritableMap? { - if (bufferLevel == null) { - return null - } + fun fromMediaType(mediaType: MediaType?): String? = when (mediaType) { + MediaType.Audio -> "audio" + MediaType.Video -> "video" + else -> null + } - return Arguments.createMap().apply { /** * Converts any [BufferType] value into its json representation. * @param bufferType [BufferType] value. @@ -1190,21 +1195,22 @@ class JsonConverter { else -> null } + @JvmStatic + fun fromBufferLevel(bufferLevel: BufferLevel?): WritableMap? { + if (bufferLevel == null) { + return null; + } + + return Arguments.createMap().apply { putDouble("level", bufferLevel.level) putDouble("targetLevel", bufferLevel.targetLevel) - putInt( + putString( "media", - when (bufferLevel.media) { - MediaType.Audio -> 0 - MediaType.Video -> 1 - }, + fromMediaType(bufferLevel.media), ) - putInt( + putString( "type", - when (bufferLevel.type) { - BufferType.ForwardDuration -> 0 - BufferType.BackwardDuration -> 1 - }, + fromBufferType(bufferLevel.type), ) } } diff --git a/ios/BufferModule.m b/ios/BufferModule.m index 8b4225fe..26e20abf 100644 --- a/ios/BufferModule.m +++ b/ios/BufferModule.m @@ -2,7 +2,7 @@ @interface RCT_EXTERN_REMAP_MODULE(BufferModule, BufferModule, NSObject) -RCT_EXTERN_METHOD(getLevel:(NSString *)nativeId type:(nonnull NSNumber *)type resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(setTargetLevel:(NSString *)nativeId type:(nonnull NSNumber *)type value:(nonnull NSNumber *)value) +RCT_EXTERN_METHOD(getLevel:(NSString *)nativeId type:(nonnull NSString *)type resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(setTargetLevel:(NSString *)nativeId type:(nonnull NSString *)type value:(nonnull NSNumber *)value) @end diff --git a/ios/BufferModule.swift b/ios/BufferModule.swift index 4f1f8f2e..b1a30ae1 100644 --- a/ios/BufferModule.swift +++ b/ios/BufferModule.swift @@ -35,7 +35,7 @@ public class BufferModule: NSObject, RCTBridgeModule { @objc(getLevel:type:resolver:rejecter:) func getLevel( _ playerId: NativeId, - type: NSNumber, + type: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock ) { @@ -62,7 +62,7 @@ public class BufferModule: NSObject, RCTBridgeModule { - Parameter value: The value to set. */ @objc(setTargetLevel:type:value:) - func setTargetLevel(_ playerId: NativeId, type: NSNumber, value: NSNumber) { + func setTargetLevel(_ playerId: NativeId, type: String, value: NSNumber) { let targetLevel = value.doubleValue bridge.uiManager.addUIBlock { [weak self] _, _ in guard diff --git a/ios/RCTConvert+BitmovinPlayer.swift b/ios/RCTConvert+BitmovinPlayer.swift index 9ea9b4f4..172b7e2c 100644 --- a/ios/RCTConvert+BitmovinPlayer.swift +++ b/ios/RCTConvert+BitmovinPlayer.swift @@ -1178,13 +1178,6 @@ extension RCTConvert { * - Parameter bufferType: `BufferType` value. * - Returns: The produced JS string. */ - static func toJson(bufferLevel: BufferLevel?, mediaType: Int) -> [String: Any]? { - guard let bufferLevel else { - return nil - } - - let type: Int - switch bufferLevel.type { static func toJson(bufferType: BufferType) -> String? { switch bufferType { case .forwardDuration: @@ -1196,11 +1189,22 @@ extension RCTConvert { } } + /** + Utility method to get a json dictionary value from a `BufferLevel` object. + - Parameter bufferLevel: The `BufferLevel` to convert to json format. + - Parameter mediaType: The `MediaType` value to pass through. + - Returns: The generated json dictionary. + */ + static func toJson(bufferLevel: BufferLevel?, mediaType: String) -> [String: Any]? { + guard let bufferLevel else { + return nil + } + return [ "level": bufferLevel.level, "targetLevel": bufferLevel.targetLevel, "media": mediaType, - "type": type + "type": toJson(bufferType: bufferLevel.type) ] } @@ -1215,8 +1219,8 @@ extension RCTConvert { } return [ - "audio": toJson(bufferLevel: bufferLevels.audio, mediaType: 0), - "video": toJson(bufferLevel: bufferLevels.video, mediaType: 1), + "audio": toJson(bufferLevel: bufferLevels.audio, mediaType: "audio"), + "video": toJson(bufferLevel: bufferLevels.video, mediaType: "video"), ] } } diff --git a/src/bufferApi.ts b/src/bufferApi.ts index 795973b5..5043cab2 100644 --- a/src/bufferApi.ts +++ b/src/bufferApi.ts @@ -9,11 +9,11 @@ export enum MediaType { /** * Audio media type. */ - AUDIO = 0, + AUDIO = 'audio', /** * Video media type. */ - VIDEO = 1, + VIDEO = 'video', } /** From a0b00ce2ef28efaa316700049bcb3b3671b464d7 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Mon, 23 Oct 2023 13:35:13 +0200 Subject: [PATCH 38/50] feat(bufferapi): remove optionals when not needed on swift --- ios/BufferModule.swift | 12 ++++-------- ios/RCTConvert+BitmovinPlayer.swift | 18 +++--------------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/ios/BufferModule.swift b/ios/BufferModule.swift index b1a30ae1..f175ab4d 100644 --- a/ios/BufferModule.swift +++ b/ios/BufferModule.swift @@ -44,11 +44,7 @@ public class BufferModule: NSObject, RCTBridgeModule { reject("[BufferModule]", "Could not find player with ID (\(playerId))", nil) return } - guard let bufferType = RCTConvert.bufferType(type) else { - reject("[BufferModule]", "Invalid buffer type", nil) - return - } - + let bufferType = RCTConvert.bufferType(type) let level = bufferApi.getLevel(bufferType) let bufferLevels = RNBufferLevels(audio: level, video: level) resolve(RCTConvert.toJson(bufferLevels: bufferLevels)) @@ -65,10 +61,10 @@ public class BufferModule: NSObject, RCTBridgeModule { func setTargetLevel(_ playerId: NativeId, type: String, value: NSNumber) { let targetLevel = value.doubleValue bridge.uiManager.addUIBlock { [weak self] _, _ in + let bufferType = RCTConvert.bufferType(type) guard - let bufferApi = self?.playerModule?.retrieve(playerId)?.buffer, - let bufferType = RCTConvert.bufferType(type), - bufferType == .forwardDuration + bufferType == .forwardDuration, + let bufferApi = self?.playerModule?.retrieve(playerId)?.buffer else { return } diff --git a/ios/RCTConvert+BitmovinPlayer.swift b/ios/RCTConvert+BitmovinPlayer.swift index 172b7e2c..32b68d19 100644 --- a/ios/RCTConvert+BitmovinPlayer.swift +++ b/ios/RCTConvert+BitmovinPlayer.swift @@ -1158,11 +1158,7 @@ extension RCTConvert { * - Parameter json: JS string representing the `BufferType`. * - Returns: The `BufferType` corresponding to `json` */ - static func bufferType(_ json: String?) -> BufferType? { - guard let json = json as? String else { - return nil - } - + static func bufferType(_ json: String) -> BufferType { switch json { case "forwardDuration": return .forwardDuration @@ -1195,11 +1191,7 @@ extension RCTConvert { - Parameter mediaType: The `MediaType` value to pass through. - Returns: The generated json dictionary. */ - static func toJson(bufferLevel: BufferLevel?, mediaType: String) -> [String: Any]? { - guard let bufferLevel else { - return nil - } - + static func toJson(bufferLevel: BufferLevel, mediaType: String) -> [String: Any] { return [ "level": bufferLevel.level, "targetLevel": bufferLevel.targetLevel, @@ -1213,11 +1205,7 @@ extension RCTConvert { - Parameter bufferLevels: The `BufferModule.RNBufferLevels` to convert to json format. - Returns: The generated json dictionary. */ - static func toJson(bufferLevels: RNBufferLevels?) -> [String: Any]? { - guard let bufferLevels else { - return nil - } - + static func toJson(bufferLevels: RNBufferLevels) -> [String: Any] { return [ "audio": toJson(bufferLevel: bufferLevels.audio, mediaType: "audio"), "video": toJson(bufferLevel: bufferLevels.video, mediaType: "video"), From 24f6205665202344e2ff3ec57cbdffb0b9f818b3 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Mon, 23 Oct 2023 13:53:00 +0200 Subject: [PATCH 39/50] feat(bufferapi): add `toMediaType` on Android On iOS it should not be needed as the value is just passed through because iOS just support combined audio+video MediaType --- .../player/reactnative/converter/JsonConverter.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index a5aff7c0..bead36b7 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -1239,6 +1239,19 @@ class JsonConverter { "backwardDuration" -> BufferType.BackwardDuration else -> BufferType.ForwardDuration } + + /** + * Maps a JS string into the corresponding [MediaType] value. + * If the string is not recognized, it returns [MediaType.Audio]. + * @param json JS string representing the [MediaType]. + * @return The [MediaType] corresponding to [json]. + */ + @JvmStatic + fun toMediaType(json: String?): MediaType = when (json) { + "audio" -> MediaType.Audio + "video" -> MediaType.Video + else -> MediaType.Audio + } } } From 245d413e0f81d2455d76205f22b400731cc7c551 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Mon, 23 Oct 2023 14:03:05 +0200 Subject: [PATCH 40/50] feat(bufferapi): remove optionals when not needed on Android --- .../reactnative/converter/JsonConverter.kt | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index bead36b7..d52b28fb 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -1174,7 +1174,7 @@ class JsonConverter { /** * Converts any [MediaType] value into its json representation. * @param mediaType [MediaType] value. - * @return The produced JS string. + * @return The produced JS string, or `null` if not recognized. */ @JvmStatic fun fromMediaType(mediaType: MediaType?): String? = when (mediaType) { @@ -1186,7 +1186,7 @@ class JsonConverter { /** * Converts any [BufferType] value into its json representation. * @param bufferType [BufferType] value. - * @return The produced JS string. + * @return The produced JS string, or `null` if not recognized. */ @JvmStatic fun fromBufferType(bufferType: BufferType?): String? = when (bufferType) { @@ -1196,12 +1196,8 @@ class JsonConverter { } @JvmStatic - fun fromBufferLevel(bufferLevel: BufferLevel?): WritableMap? { - if (bufferLevel == null) { - return null; - } - - return Arguments.createMap().apply { + fun fromBufferLevel(bufferLevel: BufferLevel): WritableMap = + Arguments.createMap().apply { putDouble("level", bufferLevel.level) putDouble("targetLevel", bufferLevel.targetLevel) putString( @@ -1213,19 +1209,13 @@ class JsonConverter { fromBufferType(bufferLevel.type), ) } - } @JvmStatic - fun fromRNBufferLevels(bufferLevels: RNBufferLevels?): WritableMap? { - if (bufferLevels == null) { - return null - } - - return Arguments.createMap().apply { + fun fromRNBufferLevels(bufferLevels: RNBufferLevels): WritableMap = + Arguments.createMap().apply { putMap("audio", fromBufferLevel(bufferLevels.audio)) putMap("video", fromBufferLevel(bufferLevels.video)) } - } /** * Maps a JS string into the corresponding [BufferType] value. From f868d9d5dd943a052808bcb863f92f21eded140f Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Mon, 23 Oct 2023 14:10:31 +0200 Subject: [PATCH 41/50] feat(bufferapi): fix swiftlint warnings --- ios/RCTConvert+BitmovinPlayer.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/RCTConvert+BitmovinPlayer.swift b/ios/RCTConvert+BitmovinPlayer.swift index 32b68d19..643751b6 100644 --- a/ios/RCTConvert+BitmovinPlayer.swift +++ b/ios/RCTConvert+BitmovinPlayer.swift @@ -1192,7 +1192,7 @@ extension RCTConvert { - Returns: The generated json dictionary. */ static func toJson(bufferLevel: BufferLevel, mediaType: String) -> [String: Any] { - return [ + [ "level": bufferLevel.level, "targetLevel": bufferLevel.targetLevel, "media": mediaType, @@ -1206,7 +1206,7 @@ extension RCTConvert { - Returns: The generated json dictionary. */ static func toJson(bufferLevels: RNBufferLevels) -> [String: Any] { - return [ + [ "audio": toJson(bufferLevel: bufferLevels.audio, mediaType: "audio"), "video": toJson(bufferLevel: bufferLevels.video, mediaType: "video"), ] From 1aa5620f538eb3ef8f47381dc924fa6452001b89 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Mon, 23 Oct 2023 14:11:03 +0200 Subject: [PATCH 42/50] feat(bufferapi): fix doc return value --- ios/RCTConvert+BitmovinPlayer.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RCTConvert+BitmovinPlayer.swift b/ios/RCTConvert+BitmovinPlayer.swift index 643751b6..6403b97d 100644 --- a/ios/RCTConvert+BitmovinPlayer.swift +++ b/ios/RCTConvert+BitmovinPlayer.swift @@ -1172,7 +1172,7 @@ extension RCTConvert { /** * Converts any `BufferType` value into its json representation. * - Parameter bufferType: `BufferType` value. - * - Returns: The produced JS string. + * - Returns: The produced JS string, or `nil` if not recognized. */ static func toJson(bufferType: BufferType) -> String? { switch bufferType { From eb22eed5a800ac4a45573b8b5a405f904bab54e9 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Mon, 23 Oct 2023 14:39:43 +0200 Subject: [PATCH 43/50] feat(bufferapi): fix unnecessary check on safe call on Android --- .../main/java/com/bitmovin/player/reactnative/BufferModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index 4d0c3d32..d27f5987 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -28,7 +28,7 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB player.buffer.getLevel(bufferType, MediaType.Audio), player.buffer.getLevel(bufferType, MediaType.Video), ) - JsonConverter.fromRNBufferLevels(bufferLevels)?.let { + JsonConverter.fromRNBufferLevels(bufferLevels).let { promise.resolve(it) } } From a9af0b6c5702c698be831d89811f9e20fdd2177a Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Mon, 23 Oct 2023 14:51:06 +0200 Subject: [PATCH 44/50] feat(bufferapi): add new docs to BufferLevels We should explain why that object is there and its importance --- .../main/java/com/bitmovin/player/reactnative/BufferModule.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index d27f5987..869866df 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -60,4 +60,8 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB private fun playerModule(): PlayerModule? = context.getNativeModule(PlayerModule::class.java) } +/** + * 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) From 96d27e2bfa89a5e2e6578da2ac24029c525c8e27 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Mon, 23 Oct 2023 14:57:10 +0200 Subject: [PATCH 45/50] feat(bufferapi): update docs of `BufferLevels` --- ios/RCTConvert+BitmovinPlayer.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ios/RCTConvert+BitmovinPlayer.swift b/ios/RCTConvert+BitmovinPlayer.swift index 6403b97d..40c54373 100644 --- a/ios/RCTConvert+BitmovinPlayer.swift +++ b/ios/RCTConvert+BitmovinPlayer.swift @@ -1246,7 +1246,8 @@ internal struct RNUiConfig { } /** - * Collection of `BufferLevel` objects + * 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. * - Parameter audio: `BufferLevel` for `MediaType.Audio`. * - Parameter video: `BufferLevel` for `MediaType.Video`. */ From 8f4340eb71a7db365b908159dadbb2736fe86692 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Tue, 24 Oct 2023 10:45:30 +0200 Subject: [PATCH 46/50] feat(bufferapi): remove nullable in `fromMediaType` --- .../bitmovin/player/reactnative/converter/JsonConverter.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index d52b28fb..4a203a1f 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -1174,13 +1174,12 @@ class JsonConverter { /** * Converts any [MediaType] value into its json representation. * @param mediaType [MediaType] value. - * @return The produced JS string, or `null` if not recognized. + * @return The produced JS string. */ @JvmStatic - fun fromMediaType(mediaType: MediaType?): String? = when (mediaType) { + fun fromMediaType(mediaType: MediaType): String = when (mediaType) { MediaType.Audio -> "audio" MediaType.Video -> "video" - else -> null } /** From d2ff9eacb1334cb7ab04d2ddd020def9e522bd52 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Tue, 24 Oct 2023 10:47:50 +0200 Subject: [PATCH 47/50] feat(bufferapi): make `toMediaType` and `toBufferType` nullable as JSON handlers shouldn't handle logic, and this forces the kotlin compiler to tell us to cover every case (so it is safer to handle new cases added in the future) --- .../com/bitmovin/player/reactnative/BufferModule.kt | 6 +++++- .../player/reactnative/converter/JsonConverter.kt | 12 ++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt index 869866df..88b48d0b 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt @@ -24,6 +24,10 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB uiManager()?.addUIBlock { _ -> val player = playerModule()?.getPlayer(nativeId) ?: return@addUIBlock val bufferType = JsonConverter.toBufferType(type) + if (bufferType == null) { + promise.reject("Error: ", "Invalid buffer type") + return@addUIBlock + } val bufferLevels = RNBufferLevels( player.buffer.getLevel(bufferType, MediaType.Audio), player.buffer.getLevel(bufferType, MediaType.Video), @@ -44,7 +48,7 @@ class BufferModule(private val context: ReactApplicationContext) : ReactContextB fun setTargetLevel(nativeId: NativeId, type: String, value: Double) { uiManager()?.addUIBlock { _ -> val player = playerModule()?.getPlayer(nativeId) ?: return@addUIBlock - val bufferType = JsonConverter.toBufferType(type) + val bufferType = JsonConverter.toBufferType(type) ?: return@addUIBlock player.buffer.setTargetLevel(bufferType, value) } } diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index 4a203a1f..d0e626ff 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -1220,26 +1220,26 @@ class JsonConverter { * Maps a JS string into the corresponding [BufferType] value. * If the string is not recognized, it returns [BufferType.ForwardDuration]. * @param json JS string representing the [BufferType]. - * @return The [BufferType] corresponding to [json]. + * @return The [BufferType] corresponding to [json], or `null` if the conversion fails. */ @JvmStatic - fun toBufferType(json: String?): BufferType = when (json) { + fun toBufferType(json: String?): BufferType? = when (json) { "forwardDuration" -> BufferType.ForwardDuration "backwardDuration" -> BufferType.BackwardDuration - else -> BufferType.ForwardDuration + else -> null } /** * Maps a JS string into the corresponding [MediaType] value. * If the string is not recognized, it returns [MediaType.Audio]. * @param json JS string representing the [MediaType]. - * @return The [MediaType] corresponding to [json]. + * @return The [MediaType] corresponding to [json], or `null` if the conversion fails. */ @JvmStatic - fun toMediaType(json: String?): MediaType = when (json) { + fun toMediaType(json: String?): MediaType? = when (json) { "audio" -> MediaType.Audio "video" -> MediaType.Video - else -> MediaType.Audio + else -> null } } } From 0ada2f8de55bda6c7a3c484b522c5f3a0eb4fac8 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Tue, 24 Oct 2023 10:54:20 +0200 Subject: [PATCH 48/50] feat(bufferapi): fix docs --- .../com/bitmovin/player/reactnative/converter/JsonConverter.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index d0e626ff..900a564b 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -1218,7 +1218,6 @@ class JsonConverter { /** * Maps a JS string into the corresponding [BufferType] value. - * If the string is not recognized, it returns [BufferType.ForwardDuration]. * @param json JS string representing the [BufferType]. * @return The [BufferType] corresponding to [json], or `null` if the conversion fails. */ @@ -1231,7 +1230,6 @@ class JsonConverter { /** * Maps a JS string into the corresponding [MediaType] value. - * If the string is not recognized, it returns [MediaType.Audio]. * @param json JS string representing the [MediaType]. * @return The [MediaType] corresponding to [json], or `null` if the conversion fails. */ From 18ecdcba353344ac79a0cc81129a26309a036b85 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Tue, 24 Oct 2023 13:02:29 +0200 Subject: [PATCH 49/50] feat(bufferapi): make `toBufferType` nullable in Swift --- ios/BufferModule.swift | 5 ++++- ios/RCTConvert+BitmovinPlayer.swift | 7 +++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ios/BufferModule.swift b/ios/BufferModule.swift index f175ab4d..df5173bc 100644 --- a/ios/BufferModule.swift +++ b/ios/BufferModule.swift @@ -44,7 +44,10 @@ public class BufferModule: NSObject, RCTBridgeModule { reject("[BufferModule]", "Could not find player with ID (\(playerId))", nil) return } - let bufferType = RCTConvert.bufferType(type) + guard let bufferType = RCTConvert.bufferType(type) else { + reject("[BufferModule]", "Invalid buffer type: (\(type))", nil) + return + } let level = bufferApi.getLevel(bufferType) let bufferLevels = RNBufferLevels(audio: level, video: level) resolve(RCTConvert.toJson(bufferLevels: bufferLevels)) diff --git a/ios/RCTConvert+BitmovinPlayer.swift b/ios/RCTConvert+BitmovinPlayer.swift index 40c54373..b439cb0f 100644 --- a/ios/RCTConvert+BitmovinPlayer.swift +++ b/ios/RCTConvert+BitmovinPlayer.swift @@ -1154,18 +1154,17 @@ extension RCTConvert { /** * Maps a JS string into the corresponding `BufferType` value. - * If the string is not recognized, it returns `BufferType.forwardDuration`. * - Parameter json: JS string representing the `BufferType`. - * - Returns: The `BufferType` corresponding to `json` + * - Returns: The `BufferType` corresponding to `json`, or `nil` if the conversion fails. */ - static func bufferType(_ json: String) -> BufferType { + static func bufferType(_ json: String) -> BufferType? { switch json { case "forwardDuration": return .forwardDuration case "backwardDuration": return .backwardDuration default: - return .forwardDuration + return nil } } From 6f38a5b6ce68f4a0b23f46ef94ba54f6d27dd3f2 Mon Sep 17 00:00:00 2001 From: Michele Pozzi <123.mpozzi@gmail.com> Date: Wed, 25 Oct 2023 09:50:56 +0200 Subject: [PATCH 50/50] feat(bufferapi): remove nullable in `fromBufferType` We should take advantage of compilers to get compile time errors when a new value isn't handled instead of using default. --- .../bitmovin/player/reactnative/converter/JsonConverter.kt | 5 ++--- ios/RCTConvert+BitmovinPlayer.swift | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt index 24d057bd..17775248 100644 --- a/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +++ b/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt @@ -1208,13 +1208,12 @@ class JsonConverter { /** * Converts any [BufferType] value into its json representation. * @param bufferType [BufferType] value. - * @return The produced JS string, or `null` if not recognized. + * @return The produced JS string. */ @JvmStatic - fun fromBufferType(bufferType: BufferType?): String? = when (bufferType) { + fun fromBufferType(bufferType: BufferType): String = when (bufferType) { BufferType.ForwardDuration -> "forwardDuration" BufferType.BackwardDuration -> "backwardDuration" - else -> null } @JvmStatic diff --git a/ios/RCTConvert+BitmovinPlayer.swift b/ios/RCTConvert+BitmovinPlayer.swift index 45790355..b2074293 100644 --- a/ios/RCTConvert+BitmovinPlayer.swift +++ b/ios/RCTConvert+BitmovinPlayer.swift @@ -1190,16 +1190,14 @@ extension RCTConvert { /** * Converts any `BufferType` value into its json representation. * - Parameter bufferType: `BufferType` value. - * - Returns: The produced JS string, or `nil` if not recognized. + * - Returns: The produced JS string. */ - static func toJson(bufferType: BufferType) -> String? { + static func toJson(bufferType: BufferType) -> String { switch bufferType { case .forwardDuration: return "forwardDuration" case .backwardDuration: return "backwardDuration" - default: - return nil } }