29 Commits

Author SHA1 Message Date
b1b5fa1717 Add quality selector 2025-10-20 01:24:18 +02:00
7f04c16e3e Add video track handling on web 2025-10-20 00:25:36 +02:00
959c23d6f2 Add audio track support 2025-10-20 00:13:46 +02:00
958778e647 Fix media session for web 2025-10-19 22:00:26 +02:00
c49b2f17f2 Add error handling for the web 2025-10-19 16:47:15 +02:00
ccf9497313 Add optional mimeType string in source object 2025-10-14 12:09:16 +02:00
bcc084e083 Handle media sessions 2025-10-13 23:46:18 +02:00
c356fa10ec Rework everything to use videojs instead of shaka 2025-10-13 22:42:11 +02:00
f3fdb8b648 Fix event listeners this 2025-10-12 17:21:09 +02:00
52a22aa10e Fix typescript issues 2025-10-10 14:09:16 +02:00
771196dd0f Some cleanup 2025-10-10 14:05:32 +02:00
82ff34fa9c Fix package lock 2025-10-10 14:05:32 +02:00
b2cf9d63f1 Map source 2025-10-10 14:05:32 +02:00
937d34d73e Implement event handlers for web 2025-10-10 14:05:32 +02:00
a092578cab Implement html video properties using headless video 2025-10-10 14:05:32 +02:00
d6803b2b4c Implement VideoView for web 2025-10-10 14:05:32 +02:00
6703499e60 Scaffold web 2025-10-10 14:05:32 +02:00
ecf5849f2c fixup! Add shaka as an optional dependency and fix their type 2025-10-10 14:05:32 +02:00
8ad923750b wip: Biome config (TO DELETE LATER) 2025-10-10 14:05:32 +02:00
796c0edfa0 Add shaka as an optional dependency and fix their type 2025-10-10 14:05:32 +02:00
57039bb564 Add shell.nix & editorconfig 2025-10-10 14:05:32 +02:00
Krzysztof Moch
9b74665fb4 chore: update release script (#4727) 2025-10-08 13:39:19 +02:00
Krzysztof Moch
1671c63dab feat(android): support flexible page sizes (#4726) 2025-10-08 13:14:53 +02:00
Krzysztof Moch
02044de0e9 feat: add notification controls (#4721) 2025-10-06 16:36:52 +02:00
Krzysztof Moch
375fbeb0eb feat: bump nitro modules (#4720) 2025-10-03 16:14:47 +02:00
Krzysztof Moch
4ebc9b7f05 feat(android): add surface type prop (#4719) 2025-10-03 15:58:29 +02:00
Krzysztof Moch
a97581ab8a chore: release 7.0.0-alpha.5 2025-10-02 13:33:03 +02:00
Krzysztof Moch
58a268c022 chore: cleanup events code 2025-10-02 13:31:21 +02:00
07b55755d1 refactor: event handler to use add/remove style (#4708) 2025-10-02 12:53:32 +02:00
106 changed files with 4012 additions and 1828 deletions

9
.editorconfig Normal file
View File

@@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2

5
biome.json Normal file
View File

@@ -0,0 +1,5 @@
{
"formatter": {
"useEditorconfig": true
}
}

1526
bun.lock

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,7 @@
"allowUnusedLabels": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"lib": ["ESNext"],
"lib": ["ESNext", "dom"],
"module": "ESNext",
"moduleResolution": "bundler",
"noEmit": true,

View File

@@ -87,17 +87,17 @@ import { VideoPlayer } from 'react-native-video';
const player = new VideoPlayer('https://example.com/video.mp4');
player.onLoad = (data) => {
player.addEventListener('onLoad', (data) => {
console.log('Video loaded! Duration:', data.duration);
};
});
player.onProgress = (data) => {
player.addEventListener('onProgress', (data) => {
console.log('Current time:', data.currentTime);
};
});
player.onError = (error) => {
player.addEventListener('onError', (error) => {
console.error('Player Error:', error.code, error.message);
};
});
player.play();
```

View File

@@ -53,6 +53,7 @@ export default App;
| `autoEnterPictureInPicture` | `boolean` | No | `false` | Whether the video should automatically enter PiP mode when it starts playing and the app is backgrounded (behavior might vary by platform). |
| `resizeMode` | `'contain' \| 'cover' \| 'stretch' \| 'none'` | No | `'none'` | How the video should be resized to fit the view. |
| `keepScreenAwake` | `boolean` | No | `true` | Whether to keep the device screen awake while the video view is mounted. |
| `surfaceType` | `'surface' \| 'texture'` | No (Android only) | `'surface'` | (Android) Underlying native view type. `'surface'` uses a SurfaceView (better performance, no transforms/overlap), `'texture'` uses a TextureView (supports animations, transforms, overlapping UI) at a small performance cost. Ignored on iOS. |
## Events
@@ -105,3 +106,25 @@ Available methods on the `VideoViewRef`:
| `enterPictureInPicture()` | `() => void` | Programmatically requests the video view to enter picture-in-picture mode. |
| `exitPictureInPicture()` | `() => void` | Programmatically requests the video view to exit picture-in-picture mode. |
| `canEnterPictureInPicture()` | `() => boolean` | Checks if picture-in-picture mode is currently available and supported. Returns `true` if PiP can be entered, `false` otherwise. |
## Android: Choosing a surface type
On Android the default rendering path uses a `SurfaceView` (set via `surfaceType="surface"`) for optimal decoding performance and lower latency. However `SurfaceView` lives in a separate window and can't be:
- Animated with transforms (scale, rotate, opacity fade)
- Clipped by parent views (rounded corners, masks)
- Overlapped reliably with sibling views (z-order issues)
If you need those UI effects, switch to `TextureView`:
```tsx
<VideoView
player={player}
surfaceType="texture"
style={{ width: 300, height: 170, borderRadius: 16, overflow: 'hidden' }}
resizeMode="cover"
controls
/>
```
Use `TextureView` only when required, as it can be slightly less performant and may increase power consumption on some devices.

View File

@@ -8,7 +8,7 @@ PODS:
- hermes-engine (0.77.2):
- hermes-engine/Pre-built (= 0.77.2)
- hermes-engine/Pre-built (0.77.2)
- NitroModules (0.28.0):
- NitroModules (0.29.8):
- DoubleConversion
- glog
- hermes-engine
@@ -1565,7 +1565,7 @@ PODS:
- React-logger (= 0.77.2)
- React-perflogger (= 0.77.2)
- React-utils (= 0.77.2)
- ReactNativeVideo (7.0.0-alpha.4):
- ReactNativeVideo (7.0.0-alpha.5):
- DoubleConversion
- glog
- hermes-engine
@@ -1844,7 +1844,7 @@ SPEC CHECKSUMS:
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
glog: eb93e2f488219332457c3c4eafd2738ddc7e80b8
hermes-engine: 8eb265241fa1d7095d3a40d51fd90f7dce68217c
NitroModules: 1e4150c3e3676e05209234a8a5e0e8886fc0311a
NitroModules: b4cd8f92604355343f12fc93772ff5a19571d41f
RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82
RCTDeprecation: 85b72250b63cfb54f29ca96ceb108cb9ef3c2079
RCTRequired: 567cb8f5d42b990331bfd93faad1d8999b1c1736
@@ -1904,7 +1904,7 @@ SPEC CHECKSUMS:
ReactAppDependencyProvider: f334cebc0beed0a72490492e978007082c03d533
ReactCodegen: 474fbb3e4bb0f1ee6c255d1955db76e13d509269
ReactCommon: 7763e59534d58e15f8f22121cdfe319040e08888
ReactNativeVideo: f365bc4f1a57ab50ddb655cda2f47bc06698a53b
ReactNativeVideo: 705a2a90d9f04afff9afd90d4ef194e1bc1135d5
ReactNativeVideoDrm: 62840ae0e184f711a2e6495c18e342a74cb598f8
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
Yoga: 31a098f74c16780569aebd614a0f37a907de0189

View File

@@ -1,19 +1,21 @@
{
"name": "react-native-video-example",
"version": "7.0.0-alpha.4",
"version": "7.0.0-alpha.5",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"lint": "eslint .",
"typecheck": "tsc",
"start": "react-native start --client-logs"
"start": "react-native start --client-logs",
"bundle-install": "bundle install",
"pods": "cd ios && pod install && cd .."
},
"dependencies": {
"@react-native-community/slider": "^4.5.6",
"react": "18.3.1",
"react-native": "^0.77.0",
"react-native-nitro-modules": "^0.28.0",
"react-native-nitro-modules": "^0.29.0",
"react-native-video": "*",
"@twg/react-native-video-drm": "*"
},

View File

@@ -146,6 +146,7 @@ const VideoDemo = () => {
player.playWhenInactive = settings.playWhenInactive;
player.mixAudioMode = settings.mixAudioMode;
player.ignoreSilentSwitchMode = settings.ignoreSilentSwitchMode;
player.showNotificationControls = settings.showNotificationControls;
}, [settings, player]);
const handleSeek = (val: number) => {
@@ -315,6 +316,13 @@ const VideoDemo = () => {
value={settings.playWhenInactive}
onValueChange={(value) => updateSetting('playWhenInactive', value)}
/>
<SwitchControl
label="Notification Controls"
value={settings.showNotificationControls}
onValueChange={(value) =>
updateSetting('showNotificationControls', value)
}
/>
</View>
</View>

View File

@@ -17,6 +17,7 @@ export interface VideoSettings {
ignoreSilentSwitchMode: IgnoreSilentSwitchMode;
playInBackground: boolean;
playWhenInactive: boolean;
showNotificationControls: boolean;
}
export const defaultSettings: VideoSettings = {
@@ -32,4 +33,5 @@ export const defaultSettings: VideoSettings = {
ignoreSilentSwitchMode: 'auto',
playInBackground: true,
playWhenInactive: false,
showNotificationControls: true,
};

View File

@@ -103,5 +103,14 @@ export const getVideoSource = (type: VideoType): VideoConfig => {
type: 'vtt',
},
],
metadata: {
title: 'Big Buck Bunny',
artist: 'Blender Foundation',
imageUri:
'https://peach.blender.org/wp-content/uploads/title_anouncement.jpg',
subtitle: 'By the Blender Institute',
description:
'Big Buck Bunny is a short computer-animated comedy film by the Blender Institute, part of the Blender Foundation. It was made using Blender, a free and open-source 3D creation suite.',
},
} as VideoConfig;
};

View File

@@ -1,7 +1,7 @@
{
"name": "react-native-video-monorepo",
"packageManager": "bun@1.1.42",
"version": "7.0.0-alpha.4",
"version": "7.0.0-alpha.5",
"private": true,
"repository": "https://github.com/TheWidlarzGroup/react-native-video",
"author": "TheWidlarzGroup <hi@thewidlarzgroup.com> (https://github.com/TheWidlarzGroup)",
@@ -64,7 +64,8 @@
"release": true
},
"hooks": {
"before:release": "bun run --cwd packages/react-native-video build"
"before:release": "bun run --cwd packages/react-native-video build && bun run --cwd packages/drm-plugin build",
"before:git": "bun install && bun example bundle-install && bun example pods && git add bun.lock && git add example/ios/Podfile.lock"
},
"plugins": {
"@release-it/bumper": {
@@ -73,6 +74,10 @@
"file": "packages/react-native-video/package.json",
"path": "version"
},
{
"file": "packages/drm-plugin/package.json",
"path": "version"
},
{
"file": "example/package.json",
"path": "version"
@@ -91,6 +96,10 @@
"type": "fix",
"section": "Bug Fixes 🐛"
},
{
"type": "refactor",
"section": "Code Refactoring 🛠"
},
{
"type": "chore(deps)",
"section": "Dependency Upgrades 📦"

View File

@@ -13,6 +13,12 @@
# include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/ReactNativeVideoDrm+autolinking.cmake)
# ```
# Define a flag to check if we are building properly
add_definitions(-DBUILDING_REACTNATIVEVIDEODRM_WITH_GENERATED_CMAKE_PROJECT)
# Enable Raw Props parsing in react-native (for Nitro Views)
add_definitions(-DRN_SERIALIZABLE_STATE)
# Add all headers that were generated by Nitrogen
include_directories(
"../nitrogen/generated/shared/c++"
@@ -32,12 +38,9 @@ target_sources(
../nitrogen/generated/android/c++/JHybridPluginManagerSpec.cpp
)
# Define a flag to check if we are building properly
add_definitions(-DBUILDING_REACTNATIVEVIDEODRM_WITH_GENERATED_CMAKE_PROJECT)
# From node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake
# Used in node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake
target_compile_definitions(
target_compile_definitions(
ReactNativeVideoDrm PRIVATE
-DFOLLY_NO_CONFIG=1
-DFOLLY_HAVE_CLOCK_GETTIME=1

View File

@@ -35,8 +35,7 @@ int initialize(JavaVM* vm) {
[]() -> std::shared_ptr<HybridObject> {
static DefaultConstructableObject<JHybridPluginManagerSpec::javaobject> object("com/margelo/nitro/videodrm/PluginManager");
auto instance = object.create();
auto globalRef = jni::make_global(instance);
return globalRef->cthis()->shared();
return instance->cthis()->shared();
}
);
});

View File

@@ -14,11 +14,11 @@
namespace margelo::nitro::videodrm::bridge::swift {
// pragma MARK: std::shared_ptr<HybridPluginManagerSpec>
std::shared_ptr<HybridPluginManagerSpec> create_std__shared_ptr_HybridPluginManagerSpec_(void* _Nonnull swiftUnsafePointer) {
std::shared_ptr<HybridPluginManagerSpec> create_std__shared_ptr_HybridPluginManagerSpec_(void* NON_NULL swiftUnsafePointer) noexcept {
ReactNativeVideoDrm::HybridPluginManagerSpec_cxx swiftPart = ReactNativeVideoDrm::HybridPluginManagerSpec_cxx::fromUnsafe(swiftUnsafePointer);
return std::make_shared<margelo::nitro::videodrm::HybridPluginManagerSpecSwift>(swiftPart);
}
void* _Nonnull get_std__shared_ptr_HybridPluginManagerSpec_(std__shared_ptr_HybridPluginManagerSpec_ cppType) {
void* NON_NULL get_std__shared_ptr_HybridPluginManagerSpec_(std__shared_ptr_HybridPluginManagerSpec_ cppType) noexcept {
std::shared_ptr<margelo::nitro::videodrm::HybridPluginManagerSpecSwift> swiftWrapper = std::dynamic_pointer_cast<margelo::nitro::videodrm::HybridPluginManagerSpecSwift>(cppType);
#ifdef NITRO_DEBUG
if (swiftWrapper == nullptr) [[unlikely]] {

View File

@@ -32,19 +32,19 @@ namespace margelo::nitro::videodrm::bridge::swift {
* Specialized version of `std::shared_ptr<HybridPluginManagerSpec>`.
*/
using std__shared_ptr_HybridPluginManagerSpec_ = std::shared_ptr<HybridPluginManagerSpec>;
std::shared_ptr<HybridPluginManagerSpec> create_std__shared_ptr_HybridPluginManagerSpec_(void* _Nonnull swiftUnsafePointer);
void* _Nonnull get_std__shared_ptr_HybridPluginManagerSpec_(std__shared_ptr_HybridPluginManagerSpec_ cppType);
std::shared_ptr<HybridPluginManagerSpec> create_std__shared_ptr_HybridPluginManagerSpec_(void* NON_NULL swiftUnsafePointer) noexcept;
void* NON_NULL get_std__shared_ptr_HybridPluginManagerSpec_(std__shared_ptr_HybridPluginManagerSpec_ cppType) noexcept;
// pragma MARK: std::weak_ptr<HybridPluginManagerSpec>
using std__weak_ptr_HybridPluginManagerSpec_ = std::weak_ptr<HybridPluginManagerSpec>;
inline std__weak_ptr_HybridPluginManagerSpec_ weakify_std__shared_ptr_HybridPluginManagerSpec_(const std::shared_ptr<HybridPluginManagerSpec>& strong) { return strong; }
inline std__weak_ptr_HybridPluginManagerSpec_ weakify_std__shared_ptr_HybridPluginManagerSpec_(const std::shared_ptr<HybridPluginManagerSpec>& strong) noexcept { return strong; }
// pragma MARK: Result<void>
using Result_void_ = Result<void>;
inline Result_void_ create_Result_void_() {
inline Result_void_ create_Result_void_() noexcept {
return Result<void>::withValue();
}
inline Result_void_ create_Result_void_(const std::exception_ptr& error) {
inline Result_void_ create_Result_void_(const std::exception_ptr& error) noexcept {
return Result<void>::withError(error);
}

View File

@@ -1,6 +1,6 @@
{
"name": "@twg/react-native-video-drm",
"version": "0.1.0",
"version": "7.0.0-alpha.5",
"description": "DRM plugin for react-native-video",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
@@ -40,8 +40,8 @@
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
"prepare": "bun run build",
"build": "bob build",
"specs": "nitro-codegen",
"release": "release-it --only-version"
"specs": "nitrogen",
"release": "release-it --preRelease alpha --npm.tag=next"
},
"keywords": [
"react-native",
@@ -71,12 +71,12 @@
"eslint": "^8.51.0",
"eslint-config-prettier": "9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"nitro-codegen": "^0.28.0",
"nitrogen": "^0.29.0",
"prettier": "^3.0.3",
"react": "18.3.1",
"react-native": "^0.77.0",
"react-native-builder-bob": "^0.40.13",
"react-native-nitro-modules": "^0.28.0",
"react-native-nitro-modules": "^0.29.0",
"release-it": "^17.10.0",
"typescript": "^5.8.3",
"react-native-video": "*"

View File

@@ -120,7 +120,7 @@ android {
externalNativeBuild {
cmake {
cppFlags "-O2 -frtti -fexceptions -Wall -fstack-protector-all"
arguments "-DANDROID_STL=c++_shared"
arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
abiFilters (*reactNativeArchitectures())
}
}

View File

@@ -1,9 +1,9 @@
RNVideo_kotlinVersion=1.9.24
RNVideo_minKotlinVersion=1.8.0
RNVideo_minSdkVersion=23
RNVideo_targetSdkVersion=34
RNVideo_compileSdkVersion=34
RNVideo_ndkversion=26.1.10909125
RNVideo_minSdkVersion=24
RNVideo_targetSdkVersion=35
RNVideo_compileSdkVersion=35
RNVideo_ndkversion=27.1.12297006
RNVideo_useExoplayerDash=true
RNVideo_useExoplayerHls=true

View File

@@ -42,7 +42,11 @@ fun VideoPlaybackService.Companion.stopService(
serviceConnection: VideoPlaybackServiceConnection
) {
try {
NitroModules.applicationContext?.currentActivity?.unbindService(serviceConnection)
// Unregister the player first; this might stop the service if no players remain
serviceConnection.unregisterPlayer(player)
// Ask service (if still connected) to stop when idle
try { serviceConnection.serviceBinder?.service?.stopIfNoPlayers() } catch (_: Exception) {}
// Then unbind
NitroModules.applicationContext?.currentActivity?.unbindService(serviceConnection)
} catch (_: Exception) {}
}

View File

@@ -6,9 +6,11 @@ import androidx.annotation.OptIn
import androidx.core.net.toUri
import androidx.media3.common.MediaItem
import androidx.media3.common.C
import androidx.media3.common.MediaMetadata
import androidx.media3.common.MimeTypes
import androidx.media3.common.util.UnstableApi
import com.margelo.nitro.video.BufferConfig
import com.margelo.nitro.video.CustomVideoMetadata
import com.margelo.nitro.video.HybridVideoPlayerSource
import com.margelo.nitro.video.LivePlaybackParams
import com.margelo.nitro.video.NativeDrmParams
@@ -39,6 +41,10 @@ fun createMediaItemFromVideoConfig(
mediaItemBuilder.setLiveConfiguration(getLiveConfiguration(livePlaybackParams))
}
source.config.metadata?.let { metadata ->
mediaItemBuilder.setMediaMetadata(getCustomMetadata(metadata))
}
return PluginsRegistry.shared.overrideMediaItemBuilder(
source,
mediaItemBuilder
@@ -122,3 +128,14 @@ fun getLiveConfiguration(
return liveConfiguration.build()
}
fun getCustomMetadata(metadata: CustomVideoMetadata): MediaMetadata {
return MediaMetadata.Builder()
.setDisplayTitle(metadata.title)
.setTitle(metadata.title)
.setSubtitle(metadata.subtitle)
.setDescription(metadata.description)
.setArtist(metadata.artist)
.setArtworkUri(metadata.imageUri?.toUri())
.build()
}

View File

@@ -77,6 +77,10 @@ fun buildExternalSubtitlesMediaSource(context: Context, source: HybridVideoPlaye
.setUri(source.uri.toUri())
.setSubtitleConfigurations(getSubtitlesConfiguration(source.config))
source.config.metadata?.let { metadata ->
mediaItemBuilderWithSubtitles.setMediaMetadata(getCustomMetadata(metadata))
}
val mediaItemBuilder = PluginsRegistry.shared.overrideMediaItemBuilder(
source,
mediaItemBuilderWithSubtitles

View File

@@ -0,0 +1,147 @@
package com.twg.video.core.services.playback
import android.content.Context
import android.app.PendingIntent
import android.content.Intent
import android.util.Log
import androidx.annotation.OptIn
import androidx.media3.common.MediaMetadata
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.session.CommandButton
import androidx.media3.session.DefaultMediaNotificationProvider
import androidx.media3.session.MediaSession
import com.google.common.collect.ImmutableList
import androidx.core.os.bundleOf
import android.os.Bundle
import com.margelo.nitro.NitroModules
import com.twg.video.core.LibraryError
@OptIn(UnstableApi::class)
class CustomMediaNotificationProvider(context: Context) : DefaultMediaNotificationProvider(context) {
init {
setSmallIcon(androidx.media3.session.R.drawable.media3_notification_small_icon)
}
fun getContext(): Context {
return NitroModules.applicationContext ?: run {
throw LibraryError.ApplicationContextNotFound
}
}
override fun getNotificationContentTitle(metadata: MediaMetadata): CharSequence? {
return metadata.title
?: metadata.displayTitle
?: metadata.subtitle
?: metadata.description
?: "${getAppName()} is playing"
}
override fun getNotificationContentText(metadata: MediaMetadata): CharSequence? {
return metadata.artist
?: metadata.subtitle
?: metadata.description
}
companion object {
private const val SEEK_INTERVAL_MS = 10000L
private const val TAG = "CustomMediaNotificationProvider"
enum class COMMAND(val stringValue: String) {
NONE("NONE"),
SEEK_FORWARD("COMMAND_SEEK_FORWARD"),
SEEK_BACKWARD("COMMAND_SEEK_BACKWARD"),
TOGGLE_PLAY("COMMAND_TOGGLE_PLAY"),
PLAY("COMMAND_PLAY"),
PAUSE("COMMAND_PAUSE")
}
fun commandFromString(value: String): COMMAND =
when (value) {
COMMAND.SEEK_FORWARD.stringValue -> COMMAND.SEEK_FORWARD
COMMAND.SEEK_BACKWARD.stringValue -> COMMAND.SEEK_BACKWARD
COMMAND.TOGGLE_PLAY.stringValue -> COMMAND.TOGGLE_PLAY
COMMAND.PLAY.stringValue -> COMMAND.PLAY
COMMAND.PAUSE.stringValue -> COMMAND.PAUSE
else -> COMMAND.NONE
}
fun handleCommand(command: COMMAND, session: MediaSession) {
// TODO: get somehow ControlsConfig here - for now hardcoded 10000ms
when (command) {
COMMAND.SEEK_BACKWARD -> session.player.seekTo(session.player.contentPosition - SEEK_INTERVAL_MS)
COMMAND.SEEK_FORWARD -> session.player.seekTo(session.player.contentPosition + SEEK_INTERVAL_MS)
COMMAND.TOGGLE_PLAY -> handleCommand(if (session.player.isPlaying) COMMAND.PAUSE else COMMAND.PLAY, session)
COMMAND.PLAY -> session.player.play()
COMMAND.PAUSE -> session.player.pause()
else -> Log.w(TAG, "Received COMMAND.NONE - was there an error?")
}
}
}
private fun getAppName(): String {
return try {
val context = getContext()
val pm = context.packageManager
val label = pm.getApplicationLabel(context.applicationInfo)
label.toString()
} catch (e: Exception) {
return "Unknown"
}
}
override fun getMediaButtons(
session: MediaSession,
playerCommands: Player.Commands,
mediaButtonPreferences: ImmutableList<CommandButton>,
showPauseButton: Boolean
): ImmutableList<CommandButton> {
val rewind = CommandButton.Builder()
.setDisplayName("Rewind")
.setSessionCommand(androidx.media3.session.SessionCommand(
COMMAND.SEEK_BACKWARD.stringValue,
Bundle.EMPTY
))
.setIconResId(androidx.media3.session.R.drawable.media3_icon_skip_back_10)
.setExtras(bundleOf(COMMAND_KEY_COMPACT_VIEW_INDEX to 0))
.build()
val toggle = CommandButton.Builder()
.setDisplayName(if (showPauseButton) "Pause" else "Play")
.setSessionCommand(androidx.media3.session.SessionCommand(
COMMAND.TOGGLE_PLAY.stringValue,
Bundle.EMPTY
))
.setIconResId(
if (showPauseButton) androidx.media3.session.R.drawable.media3_icon_pause
else androidx.media3.session.R.drawable.media3_icon_play
)
.setExtras(bundleOf(COMMAND_KEY_COMPACT_VIEW_INDEX to 1))
.build()
val forward = CommandButton.Builder()
.setDisplayName("Forward")
.setSessionCommand(androidx.media3.session.SessionCommand(
COMMAND.SEEK_FORWARD.stringValue,
Bundle.EMPTY
))
.setIconResId(androidx.media3.session.R.drawable.media3_icon_skip_forward_10)
.setExtras(bundleOf(COMMAND_KEY_COMPACT_VIEW_INDEX to 2))
.build()
return ImmutableList.of(rewind, toggle, forward)
}
override fun addNotificationActions(
mediaSession: MediaSession,
mediaButtons: ImmutableList<CommandButton>,
builder: androidx.core.app.NotificationCompat.Builder,
actionFactory: androidx.media3.session.MediaNotification.ActionFactory
): IntArray {
// Use default behavior to add actions from our custom buttons and return compact indices
val compact = super.addNotificationActions(mediaSession, mediaButtons, builder, actionFactory)
return if (compact.isEmpty()) intArrayOf(0, 1, 2) else compact
}
}

View File

@@ -4,13 +4,41 @@ import android.os.Bundle
import androidx.annotation.OptIn
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.session.CommandButton
import androidx.media3.session.MediaSession
import androidx.media3.session.SessionCommand
import androidx.media3.session.SessionResult
import com.google.common.util.concurrent.ListenableFuture
import com.google.common.collect.ImmutableList
@OptIn(UnstableApi::class)
class VideoPlaybackCallback : MediaSession.Callback {
// For Android 13+
private fun buildCustomButtons(): ImmutableList<CommandButton> {
val rewind = CommandButton.Builder()
.setDisplayName("Rewind")
.setSessionCommand(
SessionCommand(
CustomMediaNotificationProvider.Companion.COMMAND.SEEK_BACKWARD.stringValue,
Bundle.EMPTY
)
)
.setIconResId(androidx.media3.session.R.drawable.media3_icon_skip_back_10)
.build()
val forward = CommandButton.Builder()
.setDisplayName("Forward")
.setSessionCommand(
SessionCommand(
CustomMediaNotificationProvider.Companion.COMMAND.SEEK_FORWARD.stringValue,
Bundle.EMPTY
)
)
.setIconResId(androidx.media3.session.R.drawable.media3_icon_skip_forward_10)
.build()
return ImmutableList.of(rewind, forward)
}
override fun onConnect(session: MediaSession, controller: MediaSession.ControllerInfo): MediaSession.ConnectionResult {
try {
@@ -23,36 +51,46 @@ class VideoPlaybackCallback : MediaSession.Callback {
).setAvailableSessionCommands(
MediaSession.ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon()
.add(
SessionCommand(
VideoPlaybackService.Companion.COMMAND.SEEK_FORWARD.stringValue,
Bundle.EMPTY
)
SessionCommand(
CustomMediaNotificationProvider.Companion.COMMAND.SEEK_FORWARD.stringValue,
Bundle.EMPTY
)
)
.add(
SessionCommand(
VideoPlaybackService.Companion.COMMAND.SEEK_BACKWARD.stringValue,
Bundle.EMPTY
CustomMediaNotificationProvider.Companion.COMMAND.SEEK_BACKWARD.stringValue,
Bundle.EMPTY
)
)
.build()
)
.build()
.add(
SessionCommand(
CustomMediaNotificationProvider.Companion.COMMAND.TOGGLE_PLAY.stringValue,
Bundle.EMPTY
)
).build()
).build()
} catch (e: Exception) {
return MediaSession.ConnectionResult.reject()
}
}
override fun onPostConnect(session: MediaSession, controller: MediaSession.ControllerInfo) {
session.setCustomLayout(buildCustomButtons())
super.onPostConnect(session, controller)
}
override fun onCustomCommand(
session: MediaSession,
controller: MediaSession.ControllerInfo,
customCommand: SessionCommand,
args: Bundle
): ListenableFuture<SessionResult> {
VideoPlaybackService.Companion.handleCommand(
VideoPlaybackService.Companion.commandFromString(
customCommand.customAction
), session
CustomMediaNotificationProvider.Companion.handleCommand(
CustomMediaNotificationProvider.Companion.commandFromString(
customCommand.customAction
), session
)
return super.onCustomCommand(session, controller, customCommand, args)
}
}

View File

@@ -1,30 +1,22 @@
package com.twg.video.core.services.playback
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.os.Binder
import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import androidx.annotation.OptIn
import androidx.core.app.NotificationCompat
import androidx.lifecycle.OnLifecycleEvent
import androidx.media3.common.util.BitmapLoader
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.CommandButton
import androidx.media3.session.DefaultMediaNotificationProvider
import androidx.media3.session.SimpleBitmapLoader
import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService
import androidx.media3.session.MediaStyleNotificationHelper
import androidx.media3.session.SessionCommand
import androidx.media3.ui.R
import com.margelo.nitro.NitroModules
import com.margelo.nitro.video.HybridVideoPlayer
import okhttp3.internal.immutableListOf
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class VideoPlaybackServiceBinder(val service: VideoPlaybackService): Binder()
@@ -32,26 +24,12 @@ class VideoPlaybackServiceBinder(val service: VideoPlaybackService): Binder()
class VideoPlaybackService : MediaSessionService() {
private var mediaSessionsList = mutableMapOf<HybridVideoPlayer, MediaSession>()
private var binder = VideoPlaybackServiceBinder(this)
private var sourceActivity: Class<Activity>? = null
private var placeholderCanceled = false
private var sourceActivity: Class<Activity>? = null // retained for future deep-links; currently unused
// Controls for Android 13+ - see buildNotification function
private val commandSeekForward = SessionCommand(COMMAND.SEEK_FORWARD.stringValue, Bundle.EMPTY)
private val commandSeekBackward = SessionCommand(COMMAND.SEEK_BACKWARD.stringValue, Bundle.EMPTY)
@SuppressLint("PrivateResource")
private val seekForwardBtn = CommandButton.Builder()
.setDisplayName("forward")
.setSessionCommand(commandSeekForward)
.setIconResId(R.drawable.exo_notification_fastforward)
.build()
@SuppressLint("PrivateResource")
private val seekBackwardBtn = CommandButton.Builder()
.setDisplayName("backward")
.setSessionCommand(commandSeekBackward)
.setIconResId(R.drawable.exo_notification_rewind)
.build()
override fun onCreate() {
super.onCreate()
setMediaNotificationProvider(CustomMediaNotificationProvider(this))
}
// Player Registry
fun registerPlayer(player: HybridVideoPlayer, from: Class<Activity>) {
@@ -60,27 +38,54 @@ class VideoPlaybackService : MediaSessionService() {
}
sourceActivity = from
val mediaSession = MediaSession.Builder(this, player.player)
val builder = MediaSession.Builder(this, player.player)
.setId("RNVideoPlaybackService_" + player.hashCode())
.setCallback(VideoPlaybackCallback())
.setCustomLayout(immutableListOf(seekBackwardBtn, seekForwardBtn))
.build()
// Ensure tapping the notification opens the app via sessionActivity
try {
val launchIntent = packageManager.getLaunchIntentForPackage(packageName)
if (launchIntent != null) {
launchIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
val contentIntent = PendingIntent.getActivity(
this,
0,
launchIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
builder.setSessionActivity(contentIntent)
}
} catch (_: Exception) {}
val mediaSession = builder.build()
mediaSessionsList[player] = mediaSession
addSession(mediaSession)
// Manually trigger initial notification creation for the registered player
// This ensures the player notification appears immediately, even if not playing
onUpdateNotification(mediaSession, true)
}
fun unregisterPlayer(player: HybridVideoPlayer) {
hidePlayerNotification(player.player)
val session = mediaSessionsList.remove(player)
session?.release()
if (mediaSessionsList.isEmpty()) {
cleanup()
stopSelf()
stopIfNoPlayers()
}
fun updatePlayerPreferences(player: HybridVideoPlayer) {
val session = mediaSessionsList[player]
if (session == null) {
// If not registered but now needs it, register
if (player.playInBackground || player.showNotificationControls) {
val activity = try { NitroModules.applicationContext?.currentActivity } catch (_: Exception) { null }
if (activity != null) registerPlayer(player, activity.javaClass)
}
return
}
// If no longer needs registration, unregister and possibly stop service
if (!player.playInBackground && !player.showNotificationControls) {
unregisterPlayer(player)
stopIfNoPlayers()
return
}
}
@@ -93,235 +98,41 @@ class VideoPlaybackService : MediaSessionService() {
return binder
}
override fun onUpdateNotification(session: MediaSession, startInForegroundRequired: Boolean) {
val notification = buildNotification(session)
val notificationId = session.player.hashCode()
val notificationManager: NotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
// Always cancel the placeholder notification once we have a real player notification
if (!placeholderCanceled) {
notificationManager.cancel(PLACEHOLDER_NOTIFICATION_ID)
placeholderCanceled = true
}
if (startInForegroundRequired) {
startForeground(notificationId, notification)
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationManager.createNotificationChannel(
NotificationChannel(
NOTIFICATION_CHANEL_ID,
NOTIFICATION_CHANEL_ID,
NotificationManager.IMPORTANCE_LOW
)
)
}
if (session.player.currentMediaItem == null) {
notificationManager.cancel(notificationId)
return
}
notificationManager.notify(notificationId, notification)
}
}
override fun onTaskRemoved(rootIntent: Intent?) {
stopForegroundSafely()
cleanup()
stopSelf()
}
override fun onDestroy() {
stopForegroundSafely()
cleanup()
val notificationManager: NotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationManager.deleteNotificationChannel(NOTIFICATION_CHANEL_ID)
}
super.onDestroy()
}
private fun buildNotification(session: MediaSession): Notification {
val returnToPlayer = Intent(this, sourceActivity ?: this.javaClass).apply {
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
}
/*
* On Android 13+ controls are automatically handled via media session
* On Android 12 and bellow we need to add controls manually
*/
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
NotificationCompat.Builder(this, NOTIFICATION_CHANEL_ID)
.setSmallIcon(androidx.media3.session.R.drawable.media3_icon_circular_play)
.setStyle(MediaStyleNotificationHelper.MediaStyle(session))
.setContentIntent(PendingIntent.getActivity(this, 0, returnToPlayer, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE))
.build()
} else {
val playerId = session.player.hashCode()
// Action for COMMAND.SEEK_BACKWARD
val seekBackwardIntent = Intent(this, VideoPlaybackService::class.java).apply {
putExtra("PLAYER_ID", playerId)
putExtra("ACTION", COMMAND.SEEK_BACKWARD.stringValue)
}
val seekBackwardPendingIntent = PendingIntent.getService(
this,
playerId * 10,
seekBackwardIntent,
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
// ACTION FOR COMMAND.TOGGLE_PLAY
val togglePlayIntent = Intent(this, VideoPlaybackService::class.java).apply {
putExtra("PLAYER_ID", playerId)
putExtra("ACTION", COMMAND.TOGGLE_PLAY.stringValue)
}
val togglePlayPendingIntent = PendingIntent.getService(
this,
playerId * 10 + 1,
togglePlayIntent,
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
// ACTION FOR COMMAND.SEEK_FORWARD
val seekForwardIntent = Intent(this, VideoPlaybackService::class.java).apply {
putExtra("PLAYER_ID", playerId)
putExtra("ACTION", COMMAND.SEEK_FORWARD.stringValue)
}
val seekForwardPendingIntent = PendingIntent.getService(
this,
playerId * 10 + 2,
seekForwardIntent,
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
NotificationCompat.Builder(this, NOTIFICATION_CHANEL_ID)
// Show controls on lock screen even when user hides sensitive content.
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setSmallIcon(androidx.media3.session.R.drawable.media3_icon_circular_play)
// Add media control buttons that invoke intents in your media service
.addAction(androidx.media3.session.R.drawable.media3_icon_rewind, "Seek Backward", seekBackwardPendingIntent) // #0
.addAction(
if (session.player.isPlaying) {
androidx.media3.session.R.drawable.media3_icon_pause
} else {
androidx.media3.session.R.drawable.media3_icon_play
},
"Toggle Play",
togglePlayPendingIntent
) // #1
.addAction(androidx.media3.session.R.drawable.media3_icon_fast_forward, "Seek Forward", seekForwardPendingIntent) // #2
// Apply the media style template
.setStyle(MediaStyleNotificationHelper.MediaStyle(session).setShowActionsInCompactView(0, 1, 2))
.setContentTitle(session.player.mediaMetadata.title)
.setContentText(session.player.mediaMetadata.description)
.setContentIntent(PendingIntent.getActivity(this, 0, returnToPlayer, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE))
.setLargeIcon(session.player.mediaMetadata.artworkUri?.let { session.bitmapLoader.loadBitmap(it).get() })
.setOngoing(true)
.build()
}
}
private fun hidePlayerNotification(player: ExoPlayer) {
val notificationManager: NotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(player.hashCode())
}
private fun hideAllNotifications() {
val notificationManager: NotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancelAll()
private fun stopForegroundSafely() {
try {
stopForeground(STOP_FOREGROUND_REMOVE)
} catch (_: Exception) {}
}
private fun cleanup() {
hideAllNotifications()
stopForegroundSafely()
stopSelf()
mediaSessionsList.forEach { (_, session) ->
session.release()
}
mediaSessionsList.clear()
placeholderCanceled = false
}
private fun createPlaceholderNotification(): Notification {
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationManager.createNotificationChannel(
NotificationChannel(
NOTIFICATION_CHANEL_ID,
NOTIFICATION_CHANEL_ID,
NotificationManager.IMPORTANCE_LOW
)
)
// Stop the service if there are no active media sessions (no players need it)
fun stopIfNoPlayers() {
if (mediaSessionsList.isEmpty()) {
cleanup()
}
return NotificationCompat.Builder(this, NOTIFICATION_CHANEL_ID)
.setSmallIcon(androidx.media3.session.R.drawable.media3_icon_circular_play)
.setContentTitle("Media playback")
.setContentText("Preparing playback")
.build()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !placeholderCanceled) {
startForeground(PLACEHOLDER_NOTIFICATION_ID, createPlaceholderNotification())
}
intent?.let {
val playerId = it.getIntExtra("PLAYER_ID", -1)
val actionCommand = it.getStringExtra("ACTION")
if (playerId < 0) {
Log.w(TAG, "Received Command without playerId")
return super.onStartCommand(intent, flags, startId)
}
if (actionCommand == null) {
Log.w(TAG, "Received Command without action command")
return super.onStartCommand(intent, flags, startId)
}
val session = mediaSessionsList.values.find { s -> s.player.hashCode() == playerId } ?: return super.onStartCommand(intent, flags, startId)
handleCommand(commandFromString(actionCommand), session)
}
return super.onStartCommand(intent, flags, startId)
}
companion object {
private const val SEEK_INTERVAL_MS = 10000L
private const val TAG = "VideoPlaybackService"
private const val PLACEHOLDER_NOTIFICATION_ID = 9999
const val NOTIFICATION_CHANEL_ID = "RNVIDEO_SESSION_NOTIFICATION"
const val VIDEO_PLAYBACK_SERVICE_INTERFACE = SERVICE_INTERFACE
enum class COMMAND(val stringValue: String) {
NONE("NONE"),
SEEK_FORWARD("COMMAND_SEEK_FORWARD"),
SEEK_BACKWARD("COMMAND_SEEK_BACKWARD"),
TOGGLE_PLAY("COMMAND_TOGGLE_PLAY"),
PLAY("COMMAND_PLAY"),
PAUSE("COMMAND_PAUSE")
}
fun commandFromString(value: String): COMMAND =
when (value) {
COMMAND.SEEK_FORWARD.stringValue -> COMMAND.SEEK_FORWARD
COMMAND.SEEK_BACKWARD.stringValue -> COMMAND.SEEK_BACKWARD
COMMAND.TOGGLE_PLAY.stringValue -> COMMAND.TOGGLE_PLAY
COMMAND.PLAY.stringValue -> COMMAND.PLAY
COMMAND.PAUSE.stringValue -> COMMAND.PAUSE
else -> COMMAND.NONE
}
fun handleCommand(command: COMMAND, session: MediaSession) {
// TODO: get somehow ControlsConfig here - for now hardcoded 10000ms
when (command) {
COMMAND.SEEK_BACKWARD -> session.player.seekTo(session.player.contentPosition - SEEK_INTERVAL_MS)
COMMAND.SEEK_FORWARD -> session.player.seekTo(session.player.contentPosition + SEEK_INTERVAL_MS)
COMMAND.TOGGLE_PLAY -> handleCommand(if (session.player.isPlaying) COMMAND.PAUSE else COMMAND.PLAY, session)
COMMAND.PLAY -> session.player.play()
COMMAND.PAUSE -> session.player.pause()
else -> Log.w(TAG, "Received COMMAND.NONE - was there an error?")
}
}
}
}

View File

@@ -25,7 +25,10 @@ class VideoPlaybackServiceConnection (private val player: WeakReference<HybridVi
}
serviceBinder = binder as? VideoPlaybackServiceBinder
serviceBinder?.service?.registerPlayer(player, activity.javaClass)
// Only register when the player actually needs background service/notification
if (player.playInBackground || player.showNotificationControls) {
serviceBinder?.service?.registerPlayer(player, activity.javaClass)
}
} catch (err: Exception) {
Log.e("VideoPlaybackServiceConnection", "Could not bind to playback service", err)
}

View File

@@ -102,6 +102,23 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec() {
field = value
}
override var showNotificationControls: Boolean = false
set(value) {
val wasRunning = (field || playInBackground)
val shouldRun = (value || playInBackground)
if (shouldRun && !wasRunning) {
VideoPlaybackService.startService(context, videoPlaybackServiceConnection)
}
if (!shouldRun && wasRunning) {
VideoPlaybackService.stopService(this, videoPlaybackServiceConnection)
}
field = value
// Inform service to refresh notification/session layout
try { videoPlaybackServiceConnection.serviceBinder?.service?.updatePlayerPreferences(this) } catch (_: Exception) {}
}
// Player Properties
override var currentTime: Double by mainThreadProperty(
get = { player.currentPosition.toDouble() / 1000.0 },
@@ -172,16 +189,18 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec() {
override var playInBackground: Boolean = false
set(value) {
// playback in background was disabled and is now enabled
if (value == true && field == false) {
val shouldRun = (value || showNotificationControls)
val wasRunning = (field || showNotificationControls)
if (shouldRun && !wasRunning) {
VideoPlaybackService.startService(context, videoPlaybackServiceConnection)
field = true
}
// playback in background was enabled and is now disabled
else if (field == true) {
if (!shouldRun && wasRunning) {
VideoPlaybackService.stopService(this, videoPlaybackServiceConnection)
field = false
}
field = value
// Update preferences to refresh notifications/registration
try { videoPlaybackServiceConnection.serviceBinder?.service?.updatePlayerPreferences(this) } catch (_: Exception) {}
}
override var playWhenInactive: Boolean = false
@@ -323,7 +342,7 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec() {
}
private fun release() {
if (playInBackground) {
if (playInBackground || showNotificationControls) {
VideoPlaybackService.stopService(this, videoPlaybackServiceConnection)
}

View File

@@ -5,7 +5,16 @@ import com.facebook.proguard.annotations.DoNotStrip
@DoNotStrip
class HybridVideoPlayerSourceFactory: HybridVideoPlayerSourceFactorySpec() {
override fun fromUri(uri: String): HybridVideoPlayerSourceSpec {
val config = NativeVideoConfig(uri, null, null, null, null, true)
val config = NativeVideoConfig(
uri = uri,
externalSubtitles = null,
drm = null,
headers = null,
bufferConfig = null,
metadata = null,
initializeOnCreation = true
)
return HybridVideoPlayerSource(config)
}

View File

@@ -78,6 +78,12 @@ class HybridVideoViewViewManager(nitroId: Int): HybridVideoViewViewManagerSpec()
videoView.get()?.keepScreenAwake = value
}
override var surfaceType: SurfaceType
get() = videoView.get()?.surfaceType ?: SurfaceType.SURFACE
set(value) {
videoView.get()?.surfaceType = value
}
// View callbacks
override var onPictureInPictureChange: ((Boolean) -> Unit)? = null
set(value) {

View File

@@ -8,6 +8,7 @@ import android.os.Build
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
@@ -22,6 +23,7 @@ import com.facebook.react.bridge.ReactApplicationContext
import com.margelo.nitro.NitroModules
import com.margelo.nitro.video.HybridVideoPlayer
import com.margelo.nitro.video.ResizeMode
import com.margelo.nitro.video.SurfaceType
import com.margelo.nitro.video.VideoViewEvents
import com.twg.video.core.LibraryError
import com.twg.video.core.VideoManager
@@ -36,6 +38,8 @@ import com.twg.video.core.extensions.toAspectRatioFrameLayout
import com.twg.video.core.utils.PictureInPictureUtils
import com.twg.video.core.utils.PictureInPictureUtils.createDisabledPictureInPictureParams
import com.twg.video.core.utils.SmallVideoPlayerOptimizer
import com.twg.video.R.layout.player_view_surface
import com.twg.video.R.layout.player_view_texture
@UnstableApi
class VideoView @JvmOverloads constructor(
@@ -90,6 +94,20 @@ class VideoView @JvmOverloads constructor(
var pictureInPictureEnabled: Boolean = false
var surfaceType: SurfaceType = SurfaceType.SURFACE
set(value) {
if (field == value) return
field = value
runOnMainThread {
removeView(playerView)
playerView.player = null
playerView = createPlayerView()
playerView.player = hybridPlayer?.player
addView(playerView)
}
}
var resizeMode: ResizeMode = ResizeMode.NONE
set(value) {
field = value
@@ -101,7 +119,9 @@ class VideoView @JvmOverloads constructor(
var keepScreenAwake: Boolean
get() = playerView.keepScreenOn
set(value) {
playerView.keepScreenOn = value
runOnMainThread {
playerView.keepScreenOn = value
}
}
var events = object : VideoViewEvents {
@@ -114,15 +134,7 @@ class VideoView @JvmOverloads constructor(
}
var onNitroIdChange: ((Int?) -> Unit)? = null
var playerView = PlayerView(context).apply {
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
setShutterBackgroundColor(Color.TRANSPARENT)
setShowSubtitleButton(true)
useController = false
// Apply optimizations based on video player size if needed
configureForSmallPlayer()
}
var playerView = createPlayerView()
var isInFullscreen: Boolean = false
set(value) {
field = value
@@ -153,6 +165,22 @@ class VideoView @JvmOverloads constructor(
playerView.resizeMode = resizeMode.toAspectRatioFrameLayout()
}
@SuppressLint("InflateParams")
private fun createPlayerView(): PlayerView {
return when (surfaceType) {
SurfaceType.SURFACE -> LayoutInflater.from(context).inflate(player_view_surface, null) as PlayerView
SurfaceType.TEXTURE -> LayoutInflater.from(context).inflate(player_view_texture, null) as PlayerView
}.apply {
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
setShutterBackgroundColor(Color.TRANSPARENT)
setShowSubtitleButton(true)
useController = false
// Apply optimizations based on video player size if needed
configureForSmallPlayer()
}
}
private val layoutRunnable = Runnable {
measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),

View File

@@ -0,0 +1,7 @@
<androidx.media3.ui.PlayerView
android:id="@+id/player_view_surface"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:surface_type="surface_view" />

View File

@@ -0,0 +1,7 @@
<androidx.media3.ui.PlayerView
android:id="@+id/player_view_texture"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:surface_type="texture_view" />

View File

@@ -0,0 +1,323 @@
import Foundation
import MediaPlayer
class NowPlayingInfoCenterManager {
static let shared = NowPlayingInfoCenterManager()
private let SEEK_INTERVAL_SECONDS: Double = 10
private weak var currentPlayer: AVPlayer?
private var players = NSHashTable<AVPlayer>.weakObjects()
private var observers: [Int: NSKeyValueObservation] = [:]
private var playbackObserver: Any?
private var playTarget: Any?
private var pauseTarget: Any?
private var skipForwardTarget: Any?
private var skipBackwardTarget: Any?
private var playbackPositionTarget: Any?
private var seekTarget: Any?
private var togglePlayPauseTarget: Any?
private let remoteCommandCenter = MPRemoteCommandCenter.shared()
var receivingRemoteControlEvents = false {
didSet {
if receivingRemoteControlEvents {
DispatchQueue.main.async {
VideoManager.shared.setRemoteControlEventsActive(true)
UIApplication.shared.beginReceivingRemoteControlEvents()
}
} else {
DispatchQueue.main.async {
UIApplication.shared.endReceivingRemoteControlEvents()
VideoManager.shared.setRemoteControlEventsActive(false)
}
}
}
}
deinit {
cleanup()
}
func registerPlayer(player: AVPlayer) {
if players.contains(player) {
return
}
if receivingRemoteControlEvents == false {
receivingRemoteControlEvents = true
}
if let oldObserver = observers[player.hashValue] {
oldObserver.invalidate()
}
observers[player.hashValue] = observePlayers(player: player)
players.add(player)
if currentPlayer == nil {
setCurrentPlayer(player: player)
}
}
func removePlayer(player: AVPlayer) {
if !players.contains(player) {
return
}
if let observer = observers[player.hashValue] {
observer.invalidate()
}
observers.removeValue(forKey: player.hashValue)
players.remove(player)
if currentPlayer == player {
currentPlayer = nil
updateNowPlayingInfo()
}
if players.allObjects.isEmpty {
cleanup()
}
}
public func cleanup() {
observers.removeAll()
players.removeAllObjects()
if let playbackObserver {
currentPlayer?.removeTimeObserver(playbackObserver)
}
invalidateCommandTargets()
MPNowPlayingInfoCenter.default().nowPlayingInfo = [:]
receivingRemoteControlEvents = false
}
private func setCurrentPlayer(player: AVPlayer) {
if player == currentPlayer {
return
}
if let playbackObserver {
currentPlayer?.removeTimeObserver(playbackObserver)
}
currentPlayer = player
registerCommandTargets()
updateNowPlayingInfo()
playbackObserver = player.addPeriodicTimeObserver(
forInterval: CMTime(value: 1, timescale: 4),
queue: .global(),
using: { [weak self] _ in
self?.updateNowPlayingInfo()
}
)
}
private func registerCommandTargets() {
invalidateCommandTargets()
playTarget = remoteCommandCenter.playCommand.addTarget { [weak self] _ in
guard let self, let player = self.currentPlayer else {
return .commandFailed
}
if player.rate == 0 {
player.play()
}
return .success
}
pauseTarget = remoteCommandCenter.pauseCommand.addTarget { [weak self] _ in
guard let self, let player = self.currentPlayer else {
return .commandFailed
}
if player.rate != 0 {
player.pause()
}
return .success
}
skipBackwardTarget = remoteCommandCenter.skipBackwardCommand.addTarget {
[weak self] _ in
guard let self, let player = self.currentPlayer else {
return .commandFailed
}
let newTime =
player.currentTime()
- CMTime(seconds: self.SEEK_INTERVAL_SECONDS, preferredTimescale: .max)
player.seek(to: newTime)
return .success
}
skipForwardTarget = remoteCommandCenter.skipForwardCommand.addTarget {
[weak self] _ in
guard let self, let player = self.currentPlayer else {
return .commandFailed
}
let newTime =
player.currentTime()
+ CMTime(seconds: self.SEEK_INTERVAL_SECONDS, preferredTimescale: .max)
player.seek(to: newTime)
return .success
}
playbackPositionTarget = remoteCommandCenter.changePlaybackPositionCommand
.addTarget { [weak self] event in
guard let self, let player = self.currentPlayer else {
return .commandFailed
}
if let event = event as? MPChangePlaybackPositionCommandEvent {
player.seek(
to: CMTime(seconds: event.positionTime, preferredTimescale: .max)
)
return .success
}
return .commandFailed
}
// Handler for togglePlayPauseCommand, sent by Apple's Earpods wired headphones
togglePlayPauseTarget = remoteCommandCenter.togglePlayPauseCommand.addTarget
{ [weak self] _ in
guard let self, let player = self.currentPlayer else {
return .commandFailed
}
if player.rate == 0 {
player.play()
} else {
player.pause()
}
return .success
}
}
private func invalidateCommandTargets() {
remoteCommandCenter.playCommand.removeTarget(playTarget)
remoteCommandCenter.pauseCommand.removeTarget(pauseTarget)
remoteCommandCenter.skipForwardCommand.removeTarget(skipForwardTarget)
remoteCommandCenter.skipBackwardCommand.removeTarget(skipBackwardTarget)
remoteCommandCenter.changePlaybackPositionCommand.removeTarget(
playbackPositionTarget
)
remoteCommandCenter.togglePlayPauseCommand.removeTarget(
togglePlayPauseTarget
)
}
public func updateNowPlayingInfo() {
guard let player = currentPlayer, let currentItem = player.currentItem
else {
invalidateCommandTargets()
MPNowPlayingInfoCenter.default().nowPlayingInfo = [:]
return
}
// commonMetadata is metadata from asset, externalMetadata is custom metadata set by user
// externalMetadata should override commonMetadata to allow override metadata from source
// When the metadata has the tag "iTunSMPB" or "iTunNORM" then the metadata is not converted correctly and comes [nil, nil, ...]
// This leads to a crash of the app
let metadata: [AVMetadataItem] = {
let common = processMetadataItems(currentItem.asset.commonMetadata)
let external = processMetadataItems(currentItem.externalMetadata)
return Array(common.merging(external) { _, new in new }.values)
}()
let titleItem =
AVMetadataItem.metadataItems(
from: metadata,
filteredByIdentifier: .commonIdentifierTitle
).first?.stringValue ?? ""
let artistItem =
AVMetadataItem.metadataItems(
from: metadata,
filteredByIdentifier: .commonIdentifierArtist
).first?.stringValue ?? ""
// I have some issue with this - setting artworkItem when it not set dont return nil but also is crashing application
// this is very hacky workaround for it
let imgData = AVMetadataItem.metadataItems(
from: metadata,
filteredByIdentifier: .commonIdentifierArtwork
).first?.dataValue
let image = imgData.flatMap { UIImage(data: $0) } ?? UIImage()
let artworkItem = MPMediaItemArtwork(boundsSize: image.size) { _ in image }
let newNowPlayingInfo: [String: Any] = [
MPMediaItemPropertyTitle: titleItem,
MPMediaItemPropertyArtist: artistItem,
MPMediaItemPropertyArtwork: artworkItem,
MPMediaItemPropertyPlaybackDuration: currentItem.duration.seconds,
MPNowPlayingInfoPropertyElapsedPlaybackTime: currentItem.currentTime()
.seconds.rounded(),
MPNowPlayingInfoPropertyPlaybackRate: player.rate,
MPNowPlayingInfoPropertyIsLiveStream: CMTIME_IS_INDEFINITE(
currentItem.asset.duration
),
]
let currentNowPlayingInfo =
MPNowPlayingInfoCenter.default().nowPlayingInfo ?? [:]
MPNowPlayingInfoCenter.default().nowPlayingInfo =
currentNowPlayingInfo.merging(newNowPlayingInfo) { _, new in new }
}
private func findNewCurrentPlayer() {
if let newPlayer = players.allObjects.first(where: {
$0.rate != 0
}) {
setCurrentPlayer(player: newPlayer)
}
}
// We will observe players rate to find last active player that info will be displayed
private func observePlayers(player: AVPlayer) -> NSKeyValueObservation {
return player.observe(\.rate) { [weak self] player, change in
guard let self else { return }
let rate = change.newValue
// case where there is new player that is not paused
// In this case event is triggered by non currentPlayer
if rate != 0 && self.currentPlayer != player {
self.setCurrentPlayer(player: player)
return
}
// case where currentPlayer was paused
// In this case event is triggered by currentPlayer
if rate == 0 && self.currentPlayer == player {
self.findNewCurrentPlayer()
}
}
}
private func processMetadataItems(_ items: [AVMetadataItem]) -> [String:
AVMetadataItem]
{
var result = [String: AVMetadataItem]()
for item in items {
if let id = item.identifier?.rawValue, !id.isEmpty, result[id] == nil {
result[id] = item
}
}
return result
}
}

View File

@@ -95,6 +95,16 @@ class VideoManager {
updateAudioSessionConfiguration()
}
// MARK: - Remote Control Events
func setRemoteControlEventsActive(_ active: Bool) {
if isAudioSessionManagementDisabled || remoteControlEventsActive == active {
return
}
remoteControlEventsActive = active
requestAudioSessionUpdate()
}
// MARK: - Audio Session Management
private func activateAudioSession() {
if isAudioSessionActive {
@@ -133,7 +143,11 @@ class VideoManager {
player.mixAudioMode == .donotmix
}
if isAnyPlayerPlaying || anyPlayerNeedsNotMixWithOthers {
let anyPlayerNeedsNotificationControls = players.allObjects.contains { player in
player.showNotificationControls
}
if isAnyPlayerPlaying || anyPlayerNeedsNotMixWithOthers || anyPlayerNeedsNotificationControls || remoteControlEventsActive {
activateAudioSession()
} else {
deactivateAudioSession()
@@ -162,6 +176,10 @@ class VideoManager {
player.playInBackground
}
let anyPlayerNeedsNotificationControls = players.allObjects.contains { player in
player.showNotificationControls
}
if isAudioSessionManagementDisabled {
return
}
@@ -172,7 +190,7 @@ class VideoManager {
earpiece: false, // TODO: Pass actual value after we add prop
pip: anyViewNeedsPictureInPicture,
backgroundPlayback: anyPlayerNeedsBackgroundPlayback,
notificationControls: false // TODO: Pass actual value after we add prop
notificationControls: anyPlayerNeedsNotificationControls
)
let audioMixingMode = determineAudioMixingMode()

View File

@@ -22,6 +22,7 @@ extension HybridVideoPlayer: VideoPlayerObserverDelegate {
func onRateChanged(rate: Float) {
eventEmitter.onPlaybackRateChange(Double(rate))
NowPlayingInfoCenterManager.shared.updateNowPlayingInfo()
updateAndEmitPlaybackState()
}

View File

@@ -158,6 +158,16 @@ class HybridVideoPlayer: HybridVideoPlayerSpec, NativeVideoPlayerSpec {
return player.rate != 0
}
var showNotificationControls: Bool = false {
didSet {
if showNotificationControls {
NowPlayingInfoCenterManager.shared.registerPlayer(player: player)
} else {
NowPlayingInfoCenterManager.shared.removePlayer(player: player)
}
}
}
func initialize() throws -> Promise<Void> {
return Promise.async { [weak self] in
guard let self else {
@@ -174,6 +184,7 @@ class HybridVideoPlayer: HybridVideoPlayerSpec, NativeVideoPlayerSpec {
}
func release() {
NowPlayingInfoCenterManager.shared.removePlayer(player: player)
self.player.replaceCurrentItem(with: nil)
self.playerItem = nil
@@ -270,6 +281,7 @@ class HybridVideoPlayer: HybridVideoPlayerSpec, NativeVideoPlayerSpec {
self.source = source
self.playerItem = try await self.initializePlayerItem()
self.player.replaceCurrentItem(with: self.playerItem)
NowPlayingInfoCenterManager.shared.updateNowPlayingInfo()
promise.resolve(withResult: ())
}

View File

@@ -8,12 +8,22 @@
import Foundation
class HybridVideoPlayerSourceFactory: HybridVideoPlayerSourceFactorySpec {
func fromVideoConfig(config: NativeVideoConfig) throws -> any HybridVideoPlayerSourceSpec {
func fromVideoConfig(config: NativeVideoConfig) throws
-> any HybridVideoPlayerSourceSpec
{
return try HybridVideoPlayerSource(config: config)
}
func fromUri(uri: String) throws -> HybridVideoPlayerSourceSpec {
let config = NativeVideoConfig(uri: uri, externalSubtitles: nil, drm: nil, headers: nil, bufferConfig: nil, initializeOnCreation: true)
let config = NativeVideoConfig(
uri: uri,
externalSubtitles: nil,
drm: nil,
headers: nil,
bufferConfig: nil,
metadata: nil,
initializeOnCreation: true
)
return try HybridVideoPlayerSource(config: config)
}
}

View File

@@ -138,6 +138,9 @@ class HybridVideoViewViewManager: HybridVideoViewViewManagerSpec {
}
}
// Android only - no-op on iOS
var surfaceType: SurfaceType = .surface
func enterFullscreen() throws {
guard let view else {
throw VideoViewError.viewIsDeallocated.error()

View File

@@ -148,6 +148,9 @@ import AVKit
controller.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
controller.view.backgroundColor = .clear
// We manage this manually in NowPlayingInfoCenterManager
controller.updatesNowPlayingInfoCenter = false
if #available(iOS 16.0, *) {
if let initialSpeed = controller.speeds.first(where: { $0.rate == player.rate }) {
controller.selectSpeed(initialSpeed)

View File

@@ -13,6 +13,12 @@
# include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/ReactNativeVideo+autolinking.cmake)
# ```
# Define a flag to check if we are building properly
add_definitions(-DBUILDING_REACTNATIVEVIDEO_WITH_GENERATED_CMAKE_PROJECT)
# Enable Raw Props parsing in react-native (for Nitro Views)
add_definitions(-DRN_SERIALIZABLE_STATE)
# Add all headers that were generated by Nitrogen
include_directories(
"../nitrogen/generated/shared/c++"
@@ -44,12 +50,9 @@ target_sources(
../nitrogen/generated/android/c++/JHybridVideoViewViewManagerFactorySpec.cpp
)
# Define a flag to check if we are building properly
add_definitions(-DBUILDING_REACTNATIVEVIDEO_WITH_GENERATED_CMAKE_PROJECT)
# From node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake
# Used in node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake
target_compile_definitions(
target_compile_definitions(
ReactNativeVideo PRIVATE
-DFOLLY_NO_CONFIG=1
-DFOLLY_HAVE_CLOCK_GETTIME=1

View File

@@ -75,8 +75,7 @@ int initialize(JavaVM* vm) {
[]() -> std::shared_ptr<HybridObject> {
static DefaultConstructableObject<JHybridVideoPlayerFactorySpec::javaobject> object("com/margelo/nitro/video/HybridVideoPlayerFactory");
auto instance = object.create();
auto globalRef = jni::make_global(instance);
return globalRef->cthis()->shared();
return instance->cthis()->shared();
}
);
HybridObjectRegistry::registerHybridObjectConstructor(
@@ -84,8 +83,7 @@ int initialize(JavaVM* vm) {
[]() -> std::shared_ptr<HybridObject> {
static DefaultConstructableObject<JHybridVideoPlayerSourceFactorySpec::javaobject> object("com/margelo/nitro/video/HybridVideoPlayerSourceFactory");
auto instance = object.create();
auto globalRef = jni::make_global(instance);
return globalRef->cthis()->shared();
return instance->cthis()->shared();
}
);
HybridObjectRegistry::registerHybridObjectConstructor(
@@ -93,8 +91,7 @@ int initialize(JavaVM* vm) {
[]() -> std::shared_ptr<HybridObject> {
static DefaultConstructableObject<JHybridVideoViewViewManagerFactorySpec::javaobject> object("com/margelo/nitro/video/HybridVideoViewViewManagerFactory");
auto instance = object.create();
auto globalRef = jni::make_global(instance);
return globalRef->cthis()->shared();
return instance->cthis()->shared();
}
);
});

View File

@@ -0,0 +1,70 @@
///
/// JCustomVideoMetadata.hpp
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © 2025 Marc Rousavy @ Margelo
///
#pragma once
#include <fbjni/fbjni.h>
#include "CustomVideoMetadata.hpp"
#include <optional>
#include <string>
namespace margelo::nitro::video {
using namespace facebook;
/**
* The C++ JNI bridge between the C++ struct "CustomVideoMetadata" and the the Kotlin data class "CustomVideoMetadata".
*/
struct JCustomVideoMetadata final: public jni::JavaClass<JCustomVideoMetadata> {
public:
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/video/CustomVideoMetadata;";
public:
/**
* Convert this Java/Kotlin-based struct to the C++ struct CustomVideoMetadata by copying all values to C++.
*/
[[maybe_unused]]
[[nodiscard]]
CustomVideoMetadata toCpp() const {
static const auto clazz = javaClassStatic();
static const auto fieldTitle = clazz->getField<jni::JString>("title");
jni::local_ref<jni::JString> title = this->getFieldValue(fieldTitle);
static const auto fieldSubtitle = clazz->getField<jni::JString>("subtitle");
jni::local_ref<jni::JString> subtitle = this->getFieldValue(fieldSubtitle);
static const auto fieldDescription = clazz->getField<jni::JString>("description");
jni::local_ref<jni::JString> description = this->getFieldValue(fieldDescription);
static const auto fieldArtist = clazz->getField<jni::JString>("artist");
jni::local_ref<jni::JString> artist = this->getFieldValue(fieldArtist);
static const auto fieldImageUri = clazz->getField<jni::JString>("imageUri");
jni::local_ref<jni::JString> imageUri = this->getFieldValue(fieldImageUri);
return CustomVideoMetadata(
title != nullptr ? std::make_optional(title->toStdString()) : std::nullopt,
subtitle != nullptr ? std::make_optional(subtitle->toStdString()) : std::nullopt,
description != nullptr ? std::make_optional(description->toStdString()) : std::nullopt,
artist != nullptr ? std::make_optional(artist->toStdString()) : std::nullopt,
imageUri != nullptr ? std::make_optional(imageUri->toStdString()) : std::nullopt
);
}
public:
/**
* Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java.
*/
[[maybe_unused]]
static jni::local_ref<JCustomVideoMetadata::javaobject> fromCpp(const CustomVideoMetadata& value) {
return newInstance(
value.title.has_value() ? jni::make_jstring(value.title.value()) : nullptr,
value.subtitle.has_value() ? jni::make_jstring(value.subtitle.value()) : nullptr,
value.description.has_value() ? jni::make_jstring(value.description.value()) : nullptr,
value.artist.has_value() ? jni::make_jstring(value.artist.value()) : nullptr,
value.imageUri.has_value() ? jni::make_jstring(value.imageUri.value()) : nullptr
);
}
};
} // namespace margelo::nitro::video

View File

@@ -25,6 +25,8 @@ namespace margelo::nitro::video { struct BufferConfig; }
namespace margelo::nitro::video { struct LivePlaybackParams; }
// Forward declaration of `Resolution` to properly resolve imports.
namespace margelo::nitro::video { struct Resolution; }
// Forward declaration of `CustomVideoMetadata` to properly resolve imports.
namespace margelo::nitro::video { struct CustomVideoMetadata; }
#include <memory>
#include "HybridVideoPlayerSourceSpec.hpp"
@@ -53,6 +55,8 @@ namespace margelo::nitro::video { struct Resolution; }
#include "JLivePlaybackParams.hpp"
#include "Resolution.hpp"
#include "JResolution.hpp"
#include "CustomVideoMetadata.hpp"
#include "JCustomVideoMetadata.hpp"
namespace margelo::nitro::video {

View File

@@ -23,6 +23,8 @@ namespace margelo::nitro::video { struct BufferConfig; }
namespace margelo::nitro::video { struct LivePlaybackParams; }
// Forward declaration of `Resolution` to properly resolve imports.
namespace margelo::nitro::video { struct Resolution; }
// Forward declaration of `CustomVideoMetadata` to properly resolve imports.
namespace margelo::nitro::video { struct CustomVideoMetadata; }
// Forward declaration of `VideoInformation` to properly resolve imports.
namespace margelo::nitro::video { struct VideoInformation; }
// Forward declaration of `VideoOrientation` to properly resolve imports.
@@ -52,6 +54,8 @@ namespace margelo::nitro::video { enum class VideoOrientation; }
#include "JLivePlaybackParams.hpp"
#include "Resolution.hpp"
#include "JResolution.hpp"
#include "CustomVideoMetadata.hpp"
#include "JCustomVideoMetadata.hpp"
#include "VideoInformation.hpp"
#include "JVideoInformation.hpp"
#include "VideoOrientation.hpp"

View File

@@ -72,6 +72,15 @@ namespace margelo::nitro::video {
auto __result = method(_javaPart);
return __result->cthis()->shared_cast<JHybridVideoPlayerEventEmitterSpec>();
}
bool JHybridVideoPlayerSpec::getShowNotificationControls() {
static const auto method = javaClassStatic()->getMethod<jboolean()>("getShowNotificationControls");
auto __result = method(_javaPart);
return static_cast<bool>(__result);
}
void JHybridVideoPlayerSpec::setShowNotificationControls(bool showNotificationControls) {
static const auto method = javaClassStatic()->getMethod<void(jboolean /* showNotificationControls */)>("setShowNotificationControls");
method(_javaPart, showNotificationControls);
}
VideoPlayerStatus JHybridVideoPlayerSpec::getStatus() {
static const auto method = javaClassStatic()->getMethod<jni::local_ref<JVideoPlayerStatus>()>("getStatus");
auto __result = method(_javaPart);

View File

@@ -51,6 +51,8 @@ namespace margelo::nitro::video {
// Properties
std::shared_ptr<HybridVideoPlayerSourceSpec> getSource() override;
std::shared_ptr<HybridVideoPlayerEventEmitterSpec> getEventEmitter() override;
bool getShowNotificationControls() override;
void setShowNotificationControls(bool showNotificationControls) override;
VideoPlayerStatus getStatus() override;
double getDuration() override;
double getVolume() override;

View File

@@ -11,6 +11,8 @@
namespace margelo::nitro::video { class HybridVideoPlayerSpec; }
// Forward declaration of `ResizeMode` to properly resolve imports.
namespace margelo::nitro::video { enum class ResizeMode; }
// Forward declaration of `SurfaceType` to properly resolve imports.
namespace margelo::nitro::video { enum class SurfaceType; }
#include <memory>
#include "HybridVideoPlayerSpec.hpp"
@@ -18,6 +20,8 @@ namespace margelo::nitro::video { enum class ResizeMode; }
#include "JHybridVideoPlayerSpec.hpp"
#include "ResizeMode.hpp"
#include "JResizeMode.hpp"
#include "SurfaceType.hpp"
#include "JSurfaceType.hpp"
#include <functional>
#include "JFunc_void_bool.hpp"
#include "JFunc_void.hpp"
@@ -99,6 +103,15 @@ namespace margelo::nitro::video {
static const auto method = javaClassStatic()->getMethod<void(jboolean /* keepScreenAwake */)>("setKeepScreenAwake");
method(_javaPart, keepScreenAwake);
}
SurfaceType JHybridVideoViewViewManagerSpec::getSurfaceType() {
static const auto method = javaClassStatic()->getMethod<jni::local_ref<JSurfaceType>()>("getSurfaceType");
auto __result = method(_javaPart);
return __result->toCpp();
}
void JHybridVideoViewViewManagerSpec::setSurfaceType(SurfaceType surfaceType) {
static const auto method = javaClassStatic()->getMethod<void(jni::alias_ref<JSurfaceType> /* surfaceType */)>("setSurfaceType");
method(_javaPart, JSurfaceType::fromCpp(surfaceType));
}
std::optional<std::function<void(bool /* isInPictureInPicture */)>> JHybridVideoViewViewManagerSpec::getOnPictureInPictureChange() {
static const auto method = javaClassStatic()->getMethod<jni::local_ref<JFunc_void_bool::javaobject>()>("getOnPictureInPictureChange_cxx");
auto __result = method(_javaPart);

View File

@@ -61,6 +61,8 @@ namespace margelo::nitro::video {
void setResizeMode(ResizeMode resizeMode) override;
bool getKeepScreenAwake() override;
void setKeepScreenAwake(bool keepScreenAwake) override;
SurfaceType getSurfaceType() override;
void setSurfaceType(SurfaceType surfaceType) override;
std::optional<std::function<void(bool /* isInPictureInPicture */)>> getOnPictureInPictureChange() override;
void setOnPictureInPictureChange(const std::optional<std::function<void(bool /* isInPictureInPicture */)>>& onPictureInPictureChange) override;
std::optional<std::function<void(bool /* fullscreen */)>> getOnFullscreenChange() override;

View File

@@ -11,7 +11,9 @@
#include "NativeVideoConfig.hpp"
#include "BufferConfig.hpp"
#include "CustomVideoMetadata.hpp"
#include "JBufferConfig.hpp"
#include "JCustomVideoMetadata.hpp"
#include "JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload.hpp"
#include "JLivePlaybackParams.hpp"
#include "JNativeDrmParams.hpp"
@@ -62,6 +64,8 @@ namespace margelo::nitro::video {
jni::local_ref<jni::JMap<jni::JString, jni::JString>> headers = this->getFieldValue(fieldHeaders);
static const auto fieldBufferConfig = clazz->getField<JBufferConfig>("bufferConfig");
jni::local_ref<JBufferConfig> bufferConfig = this->getFieldValue(fieldBufferConfig);
static const auto fieldMetadata = clazz->getField<JCustomVideoMetadata>("metadata");
jni::local_ref<JCustomVideoMetadata> metadata = this->getFieldValue(fieldMetadata);
static const auto fieldInitializeOnCreation = clazz->getField<jni::JBoolean>("initializeOnCreation");
jni::local_ref<jni::JBoolean> initializeOnCreation = this->getFieldValue(fieldInitializeOnCreation);
return NativeVideoConfig(
@@ -86,6 +90,7 @@ namespace margelo::nitro::video {
return __map;
}()) : std::nullopt,
bufferConfig != nullptr ? std::make_optional(bufferConfig->toCpp()) : std::nullopt,
metadata != nullptr ? std::make_optional(metadata->toCpp()) : std::nullopt,
initializeOnCreation != nullptr ? std::make_optional(static_cast<bool>(initializeOnCreation->value())) : std::nullopt
);
}
@@ -116,6 +121,7 @@ namespace margelo::nitro::video {
return __map;
}() : nullptr,
value.bufferConfig.has_value() ? JBufferConfig::fromCpp(value.bufferConfig.value()) : nullptr,
value.metadata.has_value() ? JCustomVideoMetadata::fromCpp(value.metadata.value()) : nullptr,
value.initializeOnCreation.has_value() ? jni::JBoolean::valueOf(value.initializeOnCreation.value()) : nullptr
);
}

View File

@@ -0,0 +1,59 @@
///
/// JSurfaceType.hpp
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © 2025 Marc Rousavy @ Margelo
///
#pragma once
#include <fbjni/fbjni.h>
#include "SurfaceType.hpp"
namespace margelo::nitro::video {
using namespace facebook;
/**
* The C++ JNI bridge between the C++ enum "SurfaceType" and the the Kotlin enum "SurfaceType".
*/
struct JSurfaceType final: public jni::JavaClass<JSurfaceType> {
public:
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/video/SurfaceType;";
public:
/**
* Convert this Java/Kotlin-based enum to the C++ enum SurfaceType.
*/
[[maybe_unused]]
[[nodiscard]]
SurfaceType toCpp() const {
static const auto clazz = javaClassStatic();
static const auto fieldOrdinal = clazz->getField<int>("value");
int ordinal = this->getFieldValue(fieldOrdinal);
return static_cast<SurfaceType>(ordinal);
}
public:
/**
* Create a Java/Kotlin-based enum with the given C++ enum's value.
*/
[[maybe_unused]]
static jni::alias_ref<JSurfaceType> fromCpp(SurfaceType value) {
static const auto clazz = javaClassStatic();
static const auto fieldSURFACE = clazz->getStaticField<JSurfaceType>("SURFACE");
static const auto fieldTEXTURE = clazz->getStaticField<JSurfaceType>("TEXTURE");
switch (value) {
case SurfaceType::SURFACE:
return clazz->getStaticFieldValue(fieldSURFACE);
case SurfaceType::TEXTURE:
return clazz->getStaticFieldValue(fieldTEXTURE);
default:
std::string stringValue = std::to_string(static_cast<int>(value));
throw std::invalid_argument("Invalid enum value (" + stringValue + "!");
}
}
};
} // namespace margelo::nitro::video

View File

@@ -0,0 +1,41 @@
///
/// CustomVideoMetadata.kt
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © 2025 Marc Rousavy @ Margelo
///
package com.margelo.nitro.video
import androidx.annotation.Keep
import com.facebook.proguard.annotations.DoNotStrip
import com.margelo.nitro.core.*
/**
* Represents the JavaScript object/struct "CustomVideoMetadata".
*/
@DoNotStrip
@Keep
data class CustomVideoMetadata
@DoNotStrip
@Keep
constructor(
@DoNotStrip
@Keep
val title: String?,
@DoNotStrip
@Keep
val subtitle: String?,
@DoNotStrip
@Keep
val description: String?,
@DoNotStrip
@Keep
val artist: String?,
@DoNotStrip
@Keep
val imageUri: String?
) {
/* main constructor */
}

View File

@@ -45,6 +45,12 @@ abstract class HybridVideoPlayerSpec: HybridObject() {
@get:Keep
abstract val eventEmitter: HybridVideoPlayerEventEmitterSpec
@get:DoNotStrip
@get:Keep
@set:DoNotStrip
@set:Keep
abstract var showNotificationControls: Boolean
@get:DoNotStrip
@get:Keep
abstract val status: VideoPlayerStatus

View File

@@ -73,6 +73,12 @@ abstract class HybridVideoViewViewManagerSpec: HybridObject() {
@set:Keep
abstract var keepScreenAwake: Boolean
@get:DoNotStrip
@get:Keep
@set:DoNotStrip
@set:Keep
abstract var surfaceType: SurfaceType
abstract var onPictureInPictureChange: ((isInPictureInPicture: Boolean) -> Unit)?
private var onPictureInPictureChange_cxx: Func_void_bool?

View File

@@ -38,6 +38,9 @@ data class NativeVideoConfig
val bufferConfig: BufferConfig?,
@DoNotStrip
@Keep
val metadata: CustomVideoMetadata?,
@DoNotStrip
@Keep
val initializeOnCreation: Boolean?
) {
/* main constructor */

View File

@@ -0,0 +1,21 @@
///
/// SurfaceType.kt
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © 2025 Marc Rousavy @ Margelo
///
package com.margelo.nitro.video
import androidx.annotation.Keep
import com.facebook.proguard.annotations.DoNotStrip
/**
* Represents the JavaScript enum/union "SurfaceType".
*/
@DoNotStrip
@Keep
enum class SurfaceType(@DoNotStrip @Keep val value: Int) {
SURFACE(0),
TEXTURE(1);
}

View File

@@ -20,11 +20,11 @@
namespace margelo::nitro::video::bridge::swift {
// pragma MARK: std::shared_ptr<HybridVideoPlayerSourceSpec>
std::shared_ptr<HybridVideoPlayerSourceSpec> create_std__shared_ptr_HybridVideoPlayerSourceSpec_(void* _Nonnull swiftUnsafePointer) {
std::shared_ptr<HybridVideoPlayerSourceSpec> create_std__shared_ptr_HybridVideoPlayerSourceSpec_(void* NON_NULL swiftUnsafePointer) noexcept {
ReactNativeVideo::HybridVideoPlayerSourceSpec_cxx swiftPart = ReactNativeVideo::HybridVideoPlayerSourceSpec_cxx::fromUnsafe(swiftUnsafePointer);
return std::make_shared<margelo::nitro::video::HybridVideoPlayerSourceSpecSwift>(swiftPart);
}
void* _Nonnull get_std__shared_ptr_HybridVideoPlayerSourceSpec_(std__shared_ptr_HybridVideoPlayerSourceSpec_ cppType) {
void* NON_NULL get_std__shared_ptr_HybridVideoPlayerSourceSpec_(std__shared_ptr_HybridVideoPlayerSourceSpec_ cppType) noexcept {
std::shared_ptr<margelo::nitro::video::HybridVideoPlayerSourceSpecSwift> swiftWrapper = std::dynamic_pointer_cast<margelo::nitro::video::HybridVideoPlayerSourceSpecSwift>(cppType);
#ifdef NITRO_DEBUG
if (swiftWrapper == nullptr) [[unlikely]] {
@@ -36,11 +36,11 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::shared_ptr<HybridVideoPlayerEventEmitterSpec>
std::shared_ptr<HybridVideoPlayerEventEmitterSpec> create_std__shared_ptr_HybridVideoPlayerEventEmitterSpec_(void* _Nonnull swiftUnsafePointer) {
std::shared_ptr<HybridVideoPlayerEventEmitterSpec> create_std__shared_ptr_HybridVideoPlayerEventEmitterSpec_(void* NON_NULL swiftUnsafePointer) noexcept {
ReactNativeVideo::HybridVideoPlayerEventEmitterSpec_cxx swiftPart = ReactNativeVideo::HybridVideoPlayerEventEmitterSpec_cxx::fromUnsafe(swiftUnsafePointer);
return std::make_shared<margelo::nitro::video::HybridVideoPlayerEventEmitterSpecSwift>(swiftPart);
}
void* _Nonnull get_std__shared_ptr_HybridVideoPlayerEventEmitterSpec_(std__shared_ptr_HybridVideoPlayerEventEmitterSpec_ cppType) {
void* NON_NULL get_std__shared_ptr_HybridVideoPlayerEventEmitterSpec_(std__shared_ptr_HybridVideoPlayerEventEmitterSpec_ cppType) noexcept {
std::shared_ptr<margelo::nitro::video::HybridVideoPlayerEventEmitterSpecSwift> swiftWrapper = std::dynamic_pointer_cast<margelo::nitro::video::HybridVideoPlayerEventEmitterSpecSwift>(cppType);
#ifdef NITRO_DEBUG
if (swiftWrapper == nullptr) [[unlikely]] {
@@ -52,7 +52,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void()>
Func_void create_Func_void(void* _Nonnull swiftClosureWrapper) {
Func_void create_Func_void(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)]() mutable -> void {
swiftClosure.call();
@@ -60,7 +60,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const std::exception_ptr& /* error */)>
Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* _Nonnull swiftClosureWrapper) {
Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_std__exception_ptr::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const std::exception_ptr& error) mutable -> void {
swiftClosure.call(error);
@@ -68,11 +68,11 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::shared_ptr<HybridVideoPlayerSpec>
std::shared_ptr<HybridVideoPlayerSpec> create_std__shared_ptr_HybridVideoPlayerSpec_(void* _Nonnull swiftUnsafePointer) {
std::shared_ptr<HybridVideoPlayerSpec> create_std__shared_ptr_HybridVideoPlayerSpec_(void* NON_NULL swiftUnsafePointer) noexcept {
ReactNativeVideo::HybridVideoPlayerSpec_cxx swiftPart = ReactNativeVideo::HybridVideoPlayerSpec_cxx::fromUnsafe(swiftUnsafePointer);
return std::make_shared<margelo::nitro::video::HybridVideoPlayerSpecSwift>(swiftPart);
}
void* _Nonnull get_std__shared_ptr_HybridVideoPlayerSpec_(std__shared_ptr_HybridVideoPlayerSpec_ cppType) {
void* NON_NULL get_std__shared_ptr_HybridVideoPlayerSpec_(std__shared_ptr_HybridVideoPlayerSpec_ cppType) noexcept {
std::shared_ptr<margelo::nitro::video::HybridVideoPlayerSpecSwift> swiftWrapper = std::dynamic_pointer_cast<margelo::nitro::video::HybridVideoPlayerSpecSwift>(cppType);
#ifdef NITRO_DEBUG
if (swiftWrapper == nullptr) [[unlikely]] {
@@ -84,11 +84,11 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::shared_ptr<HybridVideoPlayerFactorySpec>
std::shared_ptr<HybridVideoPlayerFactorySpec> create_std__shared_ptr_HybridVideoPlayerFactorySpec_(void* _Nonnull swiftUnsafePointer) {
std::shared_ptr<HybridVideoPlayerFactorySpec> create_std__shared_ptr_HybridVideoPlayerFactorySpec_(void* NON_NULL swiftUnsafePointer) noexcept {
ReactNativeVideo::HybridVideoPlayerFactorySpec_cxx swiftPart = ReactNativeVideo::HybridVideoPlayerFactorySpec_cxx::fromUnsafe(swiftUnsafePointer);
return std::make_shared<margelo::nitro::video::HybridVideoPlayerFactorySpecSwift>(swiftPart);
}
void* _Nonnull get_std__shared_ptr_HybridVideoPlayerFactorySpec_(std__shared_ptr_HybridVideoPlayerFactorySpec_ cppType) {
void* NON_NULL get_std__shared_ptr_HybridVideoPlayerFactorySpec_(std__shared_ptr_HybridVideoPlayerFactorySpec_ cppType) noexcept {
std::shared_ptr<margelo::nitro::video::HybridVideoPlayerFactorySpecSwift> swiftWrapper = std::dynamic_pointer_cast<margelo::nitro::video::HybridVideoPlayerFactorySpecSwift>(cppType);
#ifdef NITRO_DEBUG
if (swiftWrapper == nullptr) [[unlikely]] {
@@ -100,7 +100,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(bool /* hasAudioFocus */)>
Func_void_bool create_Func_void_bool(void* _Nonnull swiftClosureWrapper) {
Func_void_bool create_Func_void_bool(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_bool::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](bool hasAudioFocus) mutable -> void {
swiftClosure.call(hasAudioFocus);
@@ -108,7 +108,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const BandwidthData& /* data */)>
Func_void_BandwidthData create_Func_void_BandwidthData(void* _Nonnull swiftClosureWrapper) {
Func_void_BandwidthData create_Func_void_BandwidthData(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_BandwidthData::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const BandwidthData& data) mutable -> void {
swiftClosure.call(data);
@@ -116,7 +116,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const onLoadData& /* data */)>
Func_void_onLoadData create_Func_void_onLoadData(void* _Nonnull swiftClosureWrapper) {
Func_void_onLoadData create_Func_void_onLoadData(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_onLoadData::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const onLoadData& data) mutable -> void {
swiftClosure.call(data);
@@ -124,7 +124,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const onLoadStartData& /* data */)>
Func_void_onLoadStartData create_Func_void_onLoadStartData(void* _Nonnull swiftClosureWrapper) {
Func_void_onLoadStartData create_Func_void_onLoadStartData(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_onLoadStartData::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const onLoadStartData& data) mutable -> void {
swiftClosure.call(data);
@@ -132,7 +132,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const onPlaybackStateChangeData& /* data */)>
Func_void_onPlaybackStateChangeData create_Func_void_onPlaybackStateChangeData(void* _Nonnull swiftClosureWrapper) {
Func_void_onPlaybackStateChangeData create_Func_void_onPlaybackStateChangeData(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_onPlaybackStateChangeData::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const onPlaybackStateChangeData& data) mutable -> void {
swiftClosure.call(data);
@@ -140,7 +140,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(double /* rate */)>
Func_void_double create_Func_void_double(void* _Nonnull swiftClosureWrapper) {
Func_void_double create_Func_void_double(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_double::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](double rate) mutable -> void {
swiftClosure.call(rate);
@@ -148,7 +148,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const onProgressData& /* data */)>
Func_void_onProgressData create_Func_void_onProgressData(void* _Nonnull swiftClosureWrapper) {
Func_void_onProgressData create_Func_void_onProgressData(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_onProgressData::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const onProgressData& data) mutable -> void {
swiftClosure.call(data);
@@ -156,7 +156,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const TimedMetadata& /* metadata */)>
Func_void_TimedMetadata create_Func_void_TimedMetadata(void* _Nonnull swiftClosureWrapper) {
Func_void_TimedMetadata create_Func_void_TimedMetadata(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_TimedMetadata::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const TimedMetadata& metadata) mutable -> void {
swiftClosure.call(metadata);
@@ -164,7 +164,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const std::vector<std::string>& /* texts */)>
Func_void_std__vector_std__string_ create_Func_void_std__vector_std__string_(void* _Nonnull swiftClosureWrapper) {
Func_void_std__vector_std__string_ create_Func_void_std__vector_std__string_(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_std__vector_std__string_::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const std::vector<std::string>& texts) mutable -> void {
swiftClosure.call(texts);
@@ -172,7 +172,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const std::optional<TextTrack>& /* track */)>
Func_void_std__optional_TextTrack_ create_Func_void_std__optional_TextTrack_(void* _Nonnull swiftClosureWrapper) {
Func_void_std__optional_TextTrack_ create_Func_void_std__optional_TextTrack_(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_std__optional_TextTrack_::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const std::optional<TextTrack>& track) mutable -> void {
swiftClosure.call(track);
@@ -180,7 +180,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const onVolumeChangeData& /* data */)>
Func_void_onVolumeChangeData create_Func_void_onVolumeChangeData(void* _Nonnull swiftClosureWrapper) {
Func_void_onVolumeChangeData create_Func_void_onVolumeChangeData(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_onVolumeChangeData::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const onVolumeChangeData& data) mutable -> void {
swiftClosure.call(data);
@@ -188,7 +188,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(VideoPlayerStatus /* status */)>
Func_void_VideoPlayerStatus create_Func_void_VideoPlayerStatus(void* _Nonnull swiftClosureWrapper) {
Func_void_VideoPlayerStatus create_Func_void_VideoPlayerStatus(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_VideoPlayerStatus::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](VideoPlayerStatus status) mutable -> void {
swiftClosure.call(static_cast<int>(status));
@@ -196,7 +196,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const std::string& /* result */)>
Func_void_std__string create_Func_void_std__string(void* _Nonnull swiftClosureWrapper) {
Func_void_std__string create_Func_void_std__string(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_std__string::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const std::string& result) mutable -> void {
swiftClosure.call(result);
@@ -204,7 +204,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>
Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload create_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload(void* _Nonnull swiftClosureWrapper) {
Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload create_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const OnGetLicensePayload& payload) mutable -> std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>> {
auto __result = swiftClosure.call(payload);
@@ -213,7 +213,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const std::shared_ptr<Promise<std::string>>& /* result */)>
Func_void_std__shared_ptr_Promise_std__string__ create_Func_void_std__shared_ptr_Promise_std__string__(void* _Nonnull swiftClosureWrapper) {
Func_void_std__shared_ptr_Promise_std__string__ create_Func_void_std__shared_ptr_Promise_std__string__(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_std__shared_ptr_Promise_std__string__::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const std::shared_ptr<Promise<std::string>>& result) mutable -> void {
swiftClosure.call(result);
@@ -221,7 +221,7 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::function<void(const VideoInformation& /* result */)>
Func_void_VideoInformation create_Func_void_VideoInformation(void* _Nonnull swiftClosureWrapper) {
Func_void_VideoInformation create_Func_void_VideoInformation(void* NON_NULL swiftClosureWrapper) noexcept {
auto swiftClosure = ReactNativeVideo::Func_void_VideoInformation::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const VideoInformation& result) mutable -> void {
swiftClosure.call(result);
@@ -229,11 +229,11 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::shared_ptr<HybridVideoPlayerSourceFactorySpec>
std::shared_ptr<HybridVideoPlayerSourceFactorySpec> create_std__shared_ptr_HybridVideoPlayerSourceFactorySpec_(void* _Nonnull swiftUnsafePointer) {
std::shared_ptr<HybridVideoPlayerSourceFactorySpec> create_std__shared_ptr_HybridVideoPlayerSourceFactorySpec_(void* NON_NULL swiftUnsafePointer) noexcept {
ReactNativeVideo::HybridVideoPlayerSourceFactorySpec_cxx swiftPart = ReactNativeVideo::HybridVideoPlayerSourceFactorySpec_cxx::fromUnsafe(swiftUnsafePointer);
return std::make_shared<margelo::nitro::video::HybridVideoPlayerSourceFactorySpecSwift>(swiftPart);
}
void* _Nonnull get_std__shared_ptr_HybridVideoPlayerSourceFactorySpec_(std__shared_ptr_HybridVideoPlayerSourceFactorySpec_ cppType) {
void* NON_NULL get_std__shared_ptr_HybridVideoPlayerSourceFactorySpec_(std__shared_ptr_HybridVideoPlayerSourceFactorySpec_ cppType) noexcept {
std::shared_ptr<margelo::nitro::video::HybridVideoPlayerSourceFactorySpecSwift> swiftWrapper = std::dynamic_pointer_cast<margelo::nitro::video::HybridVideoPlayerSourceFactorySpecSwift>(cppType);
#ifdef NITRO_DEBUG
if (swiftWrapper == nullptr) [[unlikely]] {
@@ -245,11 +245,11 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::shared_ptr<HybridVideoViewViewManagerSpec>
std::shared_ptr<HybridVideoViewViewManagerSpec> create_std__shared_ptr_HybridVideoViewViewManagerSpec_(void* _Nonnull swiftUnsafePointer) {
std::shared_ptr<HybridVideoViewViewManagerSpec> create_std__shared_ptr_HybridVideoViewViewManagerSpec_(void* NON_NULL swiftUnsafePointer) noexcept {
ReactNativeVideo::HybridVideoViewViewManagerSpec_cxx swiftPart = ReactNativeVideo::HybridVideoViewViewManagerSpec_cxx::fromUnsafe(swiftUnsafePointer);
return std::make_shared<margelo::nitro::video::HybridVideoViewViewManagerSpecSwift>(swiftPart);
}
void* _Nonnull get_std__shared_ptr_HybridVideoViewViewManagerSpec_(std__shared_ptr_HybridVideoViewViewManagerSpec_ cppType) {
void* NON_NULL get_std__shared_ptr_HybridVideoViewViewManagerSpec_(std__shared_ptr_HybridVideoViewViewManagerSpec_ cppType) noexcept {
std::shared_ptr<margelo::nitro::video::HybridVideoViewViewManagerSpecSwift> swiftWrapper = std::dynamic_pointer_cast<margelo::nitro::video::HybridVideoViewViewManagerSpecSwift>(cppType);
#ifdef NITRO_DEBUG
if (swiftWrapper == nullptr) [[unlikely]] {
@@ -261,11 +261,11 @@ namespace margelo::nitro::video::bridge::swift {
}
// pragma MARK: std::shared_ptr<HybridVideoViewViewManagerFactorySpec>
std::shared_ptr<HybridVideoViewViewManagerFactorySpec> create_std__shared_ptr_HybridVideoViewViewManagerFactorySpec_(void* _Nonnull swiftUnsafePointer) {
std::shared_ptr<HybridVideoViewViewManagerFactorySpec> create_std__shared_ptr_HybridVideoViewViewManagerFactorySpec_(void* NON_NULL swiftUnsafePointer) noexcept {
ReactNativeVideo::HybridVideoViewViewManagerFactorySpec_cxx swiftPart = ReactNativeVideo::HybridVideoViewViewManagerFactorySpec_cxx::fromUnsafe(swiftUnsafePointer);
return std::make_shared<margelo::nitro::video::HybridVideoViewViewManagerFactorySpecSwift>(swiftPart);
}
void* _Nonnull get_std__shared_ptr_HybridVideoViewViewManagerFactorySpec_(std__shared_ptr_HybridVideoViewViewManagerFactorySpec_ cppType) {
void* NON_NULL get_std__shared_ptr_HybridVideoViewViewManagerFactorySpec_(std__shared_ptr_HybridVideoViewViewManagerFactorySpec_ cppType) noexcept {
std::shared_ptr<margelo::nitro::video::HybridVideoViewViewManagerFactorySpecSwift> swiftWrapper = std::dynamic_pointer_cast<margelo::nitro::video::HybridVideoViewViewManagerFactorySpecSwift>(cppType);
#ifdef NITRO_DEBUG
if (swiftWrapper == nullptr) [[unlikely]] {

View File

@@ -12,6 +12,8 @@
namespace margelo::nitro::video { struct BandwidthData; }
// Forward declaration of `BufferConfig` to properly resolve imports.
namespace margelo::nitro::video { struct BufferConfig; }
// Forward declaration of `CustomVideoMetadata` to properly resolve imports.
namespace margelo::nitro::video { struct CustomVideoMetadata; }
// Forward declaration of `HybridVideoPlayerEventEmitterSpec` to properly resolve imports.
namespace margelo::nitro::video { class HybridVideoPlayerEventEmitterSpec; }
// Forward declaration of `HybridVideoPlayerFactorySpec` to properly resolve imports.
@@ -82,6 +84,7 @@ namespace ReactNativeVideo { class HybridVideoViewViewManagerSpec_cxx; }
// Include C++ defined types
#include "BandwidthData.hpp"
#include "BufferConfig.hpp"
#include "CustomVideoMetadata.hpp"
#include "HybridVideoPlayerEventEmitterSpec.hpp"
#include "HybridVideoPlayerFactorySpec.hpp"
#include "HybridVideoPlayerSourceFactorySpec.hpp"
@@ -107,6 +110,7 @@ namespace ReactNativeVideo { class HybridVideoViewViewManagerSpec_cxx; }
#include "onPlaybackStateChangeData.hpp"
#include "onProgressData.hpp"
#include "onVolumeChangeData.hpp"
#include <NitroModules/FastVectorCopy.hpp>
#include <NitroModules/Promise.hpp>
#include <NitroModules/PromiseHolder.hpp>
#include <NitroModules/Result.hpp>
@@ -129,34 +133,34 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::shared_ptr<HybridVideoPlayerSourceSpec>`.
*/
using std__shared_ptr_HybridVideoPlayerSourceSpec_ = std::shared_ptr<HybridVideoPlayerSourceSpec>;
std::shared_ptr<HybridVideoPlayerSourceSpec> create_std__shared_ptr_HybridVideoPlayerSourceSpec_(void* _Nonnull swiftUnsafePointer);
void* _Nonnull get_std__shared_ptr_HybridVideoPlayerSourceSpec_(std__shared_ptr_HybridVideoPlayerSourceSpec_ cppType);
std::shared_ptr<HybridVideoPlayerSourceSpec> create_std__shared_ptr_HybridVideoPlayerSourceSpec_(void* NON_NULL swiftUnsafePointer) noexcept;
void* NON_NULL get_std__shared_ptr_HybridVideoPlayerSourceSpec_(std__shared_ptr_HybridVideoPlayerSourceSpec_ cppType) noexcept;
// pragma MARK: std::weak_ptr<HybridVideoPlayerSourceSpec>
using std__weak_ptr_HybridVideoPlayerSourceSpec_ = std::weak_ptr<HybridVideoPlayerSourceSpec>;
inline std__weak_ptr_HybridVideoPlayerSourceSpec_ weakify_std__shared_ptr_HybridVideoPlayerSourceSpec_(const std::shared_ptr<HybridVideoPlayerSourceSpec>& strong) { return strong; }
inline std__weak_ptr_HybridVideoPlayerSourceSpec_ weakify_std__shared_ptr_HybridVideoPlayerSourceSpec_(const std::shared_ptr<HybridVideoPlayerSourceSpec>& strong) noexcept { return strong; }
// pragma MARK: std::shared_ptr<HybridVideoPlayerEventEmitterSpec>
/**
* Specialized version of `std::shared_ptr<HybridVideoPlayerEventEmitterSpec>`.
*/
using std__shared_ptr_HybridVideoPlayerEventEmitterSpec_ = std::shared_ptr<HybridVideoPlayerEventEmitterSpec>;
std::shared_ptr<HybridVideoPlayerEventEmitterSpec> create_std__shared_ptr_HybridVideoPlayerEventEmitterSpec_(void* _Nonnull swiftUnsafePointer);
void* _Nonnull get_std__shared_ptr_HybridVideoPlayerEventEmitterSpec_(std__shared_ptr_HybridVideoPlayerEventEmitterSpec_ cppType);
std::shared_ptr<HybridVideoPlayerEventEmitterSpec> create_std__shared_ptr_HybridVideoPlayerEventEmitterSpec_(void* NON_NULL swiftUnsafePointer) noexcept;
void* NON_NULL get_std__shared_ptr_HybridVideoPlayerEventEmitterSpec_(std__shared_ptr_HybridVideoPlayerEventEmitterSpec_ cppType) noexcept;
// pragma MARK: std::weak_ptr<HybridVideoPlayerEventEmitterSpec>
using std__weak_ptr_HybridVideoPlayerEventEmitterSpec_ = std::weak_ptr<HybridVideoPlayerEventEmitterSpec>;
inline std__weak_ptr_HybridVideoPlayerEventEmitterSpec_ weakify_std__shared_ptr_HybridVideoPlayerEventEmitterSpec_(const std::shared_ptr<HybridVideoPlayerEventEmitterSpec>& strong) { return strong; }
inline std__weak_ptr_HybridVideoPlayerEventEmitterSpec_ weakify_std__shared_ptr_HybridVideoPlayerEventEmitterSpec_(const std::shared_ptr<HybridVideoPlayerEventEmitterSpec>& strong) noexcept { return strong; }
// pragma MARK: std::shared_ptr<Promise<void>>
/**
* Specialized version of `std::shared_ptr<Promise<void>>`.
*/
using std__shared_ptr_Promise_void__ = std::shared_ptr<Promise<void>>;
inline std::shared_ptr<Promise<void>> create_std__shared_ptr_Promise_void__() {
inline std::shared_ptr<Promise<void>> create_std__shared_ptr_Promise_void__() noexcept {
return Promise<void>::create();
}
inline PromiseHolder<void> wrap_std__shared_ptr_Promise_void__(std::shared_ptr<Promise<void>> promise) {
inline PromiseHolder<void> wrap_std__shared_ptr_Promise_void__(std::shared_ptr<Promise<void>> promise) noexcept {
return PromiseHolder<void>(std::move(promise));
}
@@ -171,14 +175,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_Wrapper final {
public:
explicit Func_void_Wrapper(std::function<void()>&& func): _function(std::make_unique<std::function<void()>>(std::move(func))) {}
inline void call() const {
inline void call() const noexcept {
_function->operator()();
}
private:
std::unique_ptr<std::function<void()>> _function;
} SWIFT_NONCOPYABLE;
Func_void create_Func_void(void* _Nonnull swiftClosureWrapper);
inline Func_void_Wrapper wrap_Func_void(Func_void value) {
Func_void create_Func_void(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_Wrapper wrap_Func_void(Func_void value) noexcept {
return Func_void_Wrapper(std::move(value));
}
@@ -193,14 +197,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_std__exception_ptr_Wrapper final {
public:
explicit Func_void_std__exception_ptr_Wrapper(std::function<void(const std::exception_ptr& /* error */)>&& func): _function(std::make_unique<std::function<void(const std::exception_ptr& /* error */)>>(std::move(func))) {}
inline void call(std::exception_ptr error) const {
inline void call(std::exception_ptr error) const noexcept {
_function->operator()(error);
}
private:
std::unique_ptr<std::function<void(const std::exception_ptr& /* error */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* _Nonnull swiftClosureWrapper);
inline Func_void_std__exception_ptr_Wrapper wrap_Func_void_std__exception_ptr(Func_void_std__exception_ptr value) {
Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_std__exception_ptr_Wrapper wrap_Func_void_std__exception_ptr(Func_void_std__exception_ptr value) noexcept {
return Func_void_std__exception_ptr_Wrapper(std::move(value));
}
@@ -209,28 +213,41 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::optional<std::shared_ptr<HybridVideoPlayerSourceSpec>>`.
*/
using std__optional_std__shared_ptr_HybridVideoPlayerSourceSpec__ = std::optional<std::shared_ptr<HybridVideoPlayerSourceSpec>>;
inline std::optional<std::shared_ptr<HybridVideoPlayerSourceSpec>> create_std__optional_std__shared_ptr_HybridVideoPlayerSourceSpec__(const std::shared_ptr<HybridVideoPlayerSourceSpec>& value) {
inline std::optional<std::shared_ptr<HybridVideoPlayerSourceSpec>> create_std__optional_std__shared_ptr_HybridVideoPlayerSourceSpec__(const std::shared_ptr<HybridVideoPlayerSourceSpec>& value) noexcept {
return std::optional<std::shared_ptr<HybridVideoPlayerSourceSpec>>(value);
}
inline bool has_value_std__optional_std__shared_ptr_HybridVideoPlayerSourceSpec__(const std::optional<std::shared_ptr<HybridVideoPlayerSourceSpec>>& optional) noexcept {
return optional.has_value();
}
inline std::shared_ptr<HybridVideoPlayerSourceSpec> get_std__optional_std__shared_ptr_HybridVideoPlayerSourceSpec__(const std::optional<std::shared_ptr<HybridVideoPlayerSourceSpec>>& optional) noexcept {
return *optional;
}
// pragma MARK: std::optional<std::string>
/**
* Specialized version of `std::optional<std::string>`.
*/
using std__optional_std__string_ = std::optional<std::string>;
inline std::optional<std::string> create_std__optional_std__string_(const std::string& value) {
inline std::optional<std::string> create_std__optional_std__string_(const std::string& value) noexcept {
return std::optional<std::string>(value);
}
inline bool has_value_std__optional_std__string_(const std::optional<std::string>& optional) noexcept {
return optional.has_value();
}
inline std::string get_std__optional_std__string_(const std::optional<std::string>& optional) noexcept {
return *optional;
}
// pragma MARK: std::vector<TextTrack>
/**
* Specialized version of `std::vector<TextTrack>`.
*/
using std__vector_TextTrack_ = std::vector<TextTrack>;
inline std::vector<TextTrack> create_std__vector_TextTrack_(size_t size) {
std::vector<TextTrack> vector;
vector.reserve(size);
return vector;
inline std::vector<TextTrack> copy_std__vector_TextTrack_(const TextTrack* CONTIGUOUS_MEMORY NON_NULL data, size_t size) noexcept {
return margelo::nitro::FastVectorCopy<TextTrack>(data, size);
}
inline const TextTrack* CONTIGUOUS_MEMORY NON_NULL get_data_std__vector_TextTrack_(const std::vector<TextTrack>& vector) noexcept {
return vector.data();
}
// pragma MARK: std::optional<TextTrack>
@@ -238,46 +255,52 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::optional<TextTrack>`.
*/
using std__optional_TextTrack_ = std::optional<TextTrack>;
inline std::optional<TextTrack> create_std__optional_TextTrack_(const TextTrack& value) {
inline std::optional<TextTrack> create_std__optional_TextTrack_(const TextTrack& value) noexcept {
return std::optional<TextTrack>(value);
}
inline bool has_value_std__optional_TextTrack_(const std::optional<TextTrack>& optional) noexcept {
return optional.has_value();
}
inline TextTrack get_std__optional_TextTrack_(const std::optional<TextTrack>& optional) noexcept {
return *optional;
}
// pragma MARK: std::shared_ptr<HybridVideoPlayerSpec>
/**
* Specialized version of `std::shared_ptr<HybridVideoPlayerSpec>`.
*/
using std__shared_ptr_HybridVideoPlayerSpec_ = std::shared_ptr<HybridVideoPlayerSpec>;
std::shared_ptr<HybridVideoPlayerSpec> create_std__shared_ptr_HybridVideoPlayerSpec_(void* _Nonnull swiftUnsafePointer);
void* _Nonnull get_std__shared_ptr_HybridVideoPlayerSpec_(std__shared_ptr_HybridVideoPlayerSpec_ cppType);
std::shared_ptr<HybridVideoPlayerSpec> create_std__shared_ptr_HybridVideoPlayerSpec_(void* NON_NULL swiftUnsafePointer) noexcept;
void* NON_NULL get_std__shared_ptr_HybridVideoPlayerSpec_(std__shared_ptr_HybridVideoPlayerSpec_ cppType) noexcept;
// pragma MARK: std::weak_ptr<HybridVideoPlayerSpec>
using std__weak_ptr_HybridVideoPlayerSpec_ = std::weak_ptr<HybridVideoPlayerSpec>;
inline std__weak_ptr_HybridVideoPlayerSpec_ weakify_std__shared_ptr_HybridVideoPlayerSpec_(const std::shared_ptr<HybridVideoPlayerSpec>& strong) { return strong; }
inline std__weak_ptr_HybridVideoPlayerSpec_ weakify_std__shared_ptr_HybridVideoPlayerSpec_(const std::shared_ptr<HybridVideoPlayerSpec>& strong) noexcept { return strong; }
// pragma MARK: Result<std::shared_ptr<Promise<void>>>
using Result_std__shared_ptr_Promise_void___ = Result<std::shared_ptr<Promise<void>>>;
inline Result_std__shared_ptr_Promise_void___ create_Result_std__shared_ptr_Promise_void___(const std::shared_ptr<Promise<void>>& value) {
inline Result_std__shared_ptr_Promise_void___ create_Result_std__shared_ptr_Promise_void___(const std::shared_ptr<Promise<void>>& value) noexcept {
return Result<std::shared_ptr<Promise<void>>>::withValue(value);
}
inline Result_std__shared_ptr_Promise_void___ create_Result_std__shared_ptr_Promise_void___(const std::exception_ptr& error) {
inline Result_std__shared_ptr_Promise_void___ create_Result_std__shared_ptr_Promise_void___(const std::exception_ptr& error) noexcept {
return Result<std::shared_ptr<Promise<void>>>::withError(error);
}
// pragma MARK: Result<std::vector<TextTrack>>
using Result_std__vector_TextTrack__ = Result<std::vector<TextTrack>>;
inline Result_std__vector_TextTrack__ create_Result_std__vector_TextTrack__(const std::vector<TextTrack>& value) {
inline Result_std__vector_TextTrack__ create_Result_std__vector_TextTrack__(const std::vector<TextTrack>& value) noexcept {
return Result<std::vector<TextTrack>>::withValue(value);
}
inline Result_std__vector_TextTrack__ create_Result_std__vector_TextTrack__(const std::exception_ptr& error) {
inline Result_std__vector_TextTrack__ create_Result_std__vector_TextTrack__(const std::exception_ptr& error) noexcept {
return Result<std::vector<TextTrack>>::withError(error);
}
// pragma MARK: Result<void>
using Result_void_ = Result<void>;
inline Result_void_ create_Result_void_() {
inline Result_void_ create_Result_void_() noexcept {
return Result<void>::withValue();
}
inline Result_void_ create_Result_void_(const std::exception_ptr& error) {
inline Result_void_ create_Result_void_(const std::exception_ptr& error) noexcept {
return Result<void>::withError(error);
}
@@ -286,19 +309,19 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::shared_ptr<HybridVideoPlayerFactorySpec>`.
*/
using std__shared_ptr_HybridVideoPlayerFactorySpec_ = std::shared_ptr<HybridVideoPlayerFactorySpec>;
std::shared_ptr<HybridVideoPlayerFactorySpec> create_std__shared_ptr_HybridVideoPlayerFactorySpec_(void* _Nonnull swiftUnsafePointer);
void* _Nonnull get_std__shared_ptr_HybridVideoPlayerFactorySpec_(std__shared_ptr_HybridVideoPlayerFactorySpec_ cppType);
std::shared_ptr<HybridVideoPlayerFactorySpec> create_std__shared_ptr_HybridVideoPlayerFactorySpec_(void* NON_NULL swiftUnsafePointer) noexcept;
void* NON_NULL get_std__shared_ptr_HybridVideoPlayerFactorySpec_(std__shared_ptr_HybridVideoPlayerFactorySpec_ cppType) noexcept;
// pragma MARK: std::weak_ptr<HybridVideoPlayerFactorySpec>
using std__weak_ptr_HybridVideoPlayerFactorySpec_ = std::weak_ptr<HybridVideoPlayerFactorySpec>;
inline std__weak_ptr_HybridVideoPlayerFactorySpec_ weakify_std__shared_ptr_HybridVideoPlayerFactorySpec_(const std::shared_ptr<HybridVideoPlayerFactorySpec>& strong) { return strong; }
inline std__weak_ptr_HybridVideoPlayerFactorySpec_ weakify_std__shared_ptr_HybridVideoPlayerFactorySpec_(const std::shared_ptr<HybridVideoPlayerFactorySpec>& strong) noexcept { return strong; }
// pragma MARK: Result<std::shared_ptr<HybridVideoPlayerSpec>>
using Result_std__shared_ptr_HybridVideoPlayerSpec__ = Result<std::shared_ptr<HybridVideoPlayerSpec>>;
inline Result_std__shared_ptr_HybridVideoPlayerSpec__ create_Result_std__shared_ptr_HybridVideoPlayerSpec__(const std::shared_ptr<HybridVideoPlayerSpec>& value) {
inline Result_std__shared_ptr_HybridVideoPlayerSpec__ create_Result_std__shared_ptr_HybridVideoPlayerSpec__(const std::shared_ptr<HybridVideoPlayerSpec>& value) noexcept {
return Result<std::shared_ptr<HybridVideoPlayerSpec>>::withValue(value);
}
inline Result_std__shared_ptr_HybridVideoPlayerSpec__ create_Result_std__shared_ptr_HybridVideoPlayerSpec__(const std::exception_ptr& error) {
inline Result_std__shared_ptr_HybridVideoPlayerSpec__ create_Result_std__shared_ptr_HybridVideoPlayerSpec__(const std::exception_ptr& error) noexcept {
return Result<std::shared_ptr<HybridVideoPlayerSpec>>::withError(error);
}
@@ -313,14 +336,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_bool_Wrapper final {
public:
explicit Func_void_bool_Wrapper(std::function<void(bool /* hasAudioFocus */)>&& func): _function(std::make_unique<std::function<void(bool /* hasAudioFocus */)>>(std::move(func))) {}
inline void call(bool hasAudioFocus) const {
inline void call(bool hasAudioFocus) const noexcept {
_function->operator()(hasAudioFocus);
}
private:
std::unique_ptr<std::function<void(bool /* hasAudioFocus */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_bool create_Func_void_bool(void* _Nonnull swiftClosureWrapper);
inline Func_void_bool_Wrapper wrap_Func_void_bool(Func_void_bool value) {
Func_void_bool create_Func_void_bool(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_bool_Wrapper wrap_Func_void_bool(Func_void_bool value) noexcept {
return Func_void_bool_Wrapper(std::move(value));
}
@@ -329,9 +352,15 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::optional<double>`.
*/
using std__optional_double_ = std::optional<double>;
inline std::optional<double> create_std__optional_double_(const double& value) {
inline std::optional<double> create_std__optional_double_(const double& value) noexcept {
return std::optional<double>(value);
}
inline bool has_value_std__optional_double_(const std::optional<double>& optional) noexcept {
return optional.has_value();
}
inline double get_std__optional_double_(const std::optional<double>& optional) noexcept {
return *optional;
}
// pragma MARK: std::function<void(const BandwidthData& /* data */)>
/**
@@ -344,14 +373,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_BandwidthData_Wrapper final {
public:
explicit Func_void_BandwidthData_Wrapper(std::function<void(const BandwidthData& /* data */)>&& func): _function(std::make_unique<std::function<void(const BandwidthData& /* data */)>>(std::move(func))) {}
inline void call(BandwidthData data) const {
inline void call(BandwidthData data) const noexcept {
_function->operator()(data);
}
private:
std::unique_ptr<std::function<void(const BandwidthData& /* data */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_BandwidthData create_Func_void_BandwidthData(void* _Nonnull swiftClosureWrapper);
inline Func_void_BandwidthData_Wrapper wrap_Func_void_BandwidthData(Func_void_BandwidthData value) {
Func_void_BandwidthData create_Func_void_BandwidthData(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_BandwidthData_Wrapper wrap_Func_void_BandwidthData(Func_void_BandwidthData value) noexcept {
return Func_void_BandwidthData_Wrapper(std::move(value));
}
@@ -366,14 +395,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_onLoadData_Wrapper final {
public:
explicit Func_void_onLoadData_Wrapper(std::function<void(const onLoadData& /* data */)>&& func): _function(std::make_unique<std::function<void(const onLoadData& /* data */)>>(std::move(func))) {}
inline void call(onLoadData data) const {
inline void call(onLoadData data) const noexcept {
_function->operator()(data);
}
private:
std::unique_ptr<std::function<void(const onLoadData& /* data */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_onLoadData create_Func_void_onLoadData(void* _Nonnull swiftClosureWrapper);
inline Func_void_onLoadData_Wrapper wrap_Func_void_onLoadData(Func_void_onLoadData value) {
Func_void_onLoadData create_Func_void_onLoadData(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_onLoadData_Wrapper wrap_Func_void_onLoadData(Func_void_onLoadData value) noexcept {
return Func_void_onLoadData_Wrapper(std::move(value));
}
@@ -388,14 +417,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_onLoadStartData_Wrapper final {
public:
explicit Func_void_onLoadStartData_Wrapper(std::function<void(const onLoadStartData& /* data */)>&& func): _function(std::make_unique<std::function<void(const onLoadStartData& /* data */)>>(std::move(func))) {}
inline void call(onLoadStartData data) const {
inline void call(onLoadStartData data) const noexcept {
_function->operator()(data);
}
private:
std::unique_ptr<std::function<void(const onLoadStartData& /* data */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_onLoadStartData create_Func_void_onLoadStartData(void* _Nonnull swiftClosureWrapper);
inline Func_void_onLoadStartData_Wrapper wrap_Func_void_onLoadStartData(Func_void_onLoadStartData value) {
Func_void_onLoadStartData create_Func_void_onLoadStartData(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_onLoadStartData_Wrapper wrap_Func_void_onLoadStartData(Func_void_onLoadStartData value) noexcept {
return Func_void_onLoadStartData_Wrapper(std::move(value));
}
@@ -410,14 +439,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_onPlaybackStateChangeData_Wrapper final {
public:
explicit Func_void_onPlaybackStateChangeData_Wrapper(std::function<void(const onPlaybackStateChangeData& /* data */)>&& func): _function(std::make_unique<std::function<void(const onPlaybackStateChangeData& /* data */)>>(std::move(func))) {}
inline void call(onPlaybackStateChangeData data) const {
inline void call(onPlaybackStateChangeData data) const noexcept {
_function->operator()(data);
}
private:
std::unique_ptr<std::function<void(const onPlaybackStateChangeData& /* data */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_onPlaybackStateChangeData create_Func_void_onPlaybackStateChangeData(void* _Nonnull swiftClosureWrapper);
inline Func_void_onPlaybackStateChangeData_Wrapper wrap_Func_void_onPlaybackStateChangeData(Func_void_onPlaybackStateChangeData value) {
Func_void_onPlaybackStateChangeData create_Func_void_onPlaybackStateChangeData(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_onPlaybackStateChangeData_Wrapper wrap_Func_void_onPlaybackStateChangeData(Func_void_onPlaybackStateChangeData value) noexcept {
return Func_void_onPlaybackStateChangeData_Wrapper(std::move(value));
}
@@ -432,14 +461,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_double_Wrapper final {
public:
explicit Func_void_double_Wrapper(std::function<void(double /* rate */)>&& func): _function(std::make_unique<std::function<void(double /* rate */)>>(std::move(func))) {}
inline void call(double rate) const {
inline void call(double rate) const noexcept {
_function->operator()(rate);
}
private:
std::unique_ptr<std::function<void(double /* rate */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_double create_Func_void_double(void* _Nonnull swiftClosureWrapper);
inline Func_void_double_Wrapper wrap_Func_void_double(Func_void_double value) {
Func_void_double create_Func_void_double(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_double_Wrapper wrap_Func_void_double(Func_void_double value) noexcept {
return Func_void_double_Wrapper(std::move(value));
}
@@ -454,14 +483,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_onProgressData_Wrapper final {
public:
explicit Func_void_onProgressData_Wrapper(std::function<void(const onProgressData& /* data */)>&& func): _function(std::make_unique<std::function<void(const onProgressData& /* data */)>>(std::move(func))) {}
inline void call(onProgressData data) const {
inline void call(onProgressData data) const noexcept {
_function->operator()(data);
}
private:
std::unique_ptr<std::function<void(const onProgressData& /* data */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_onProgressData create_Func_void_onProgressData(void* _Nonnull swiftClosureWrapper);
inline Func_void_onProgressData_Wrapper wrap_Func_void_onProgressData(Func_void_onProgressData value) {
Func_void_onProgressData create_Func_void_onProgressData(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_onProgressData_Wrapper wrap_Func_void_onProgressData(Func_void_onProgressData value) noexcept {
return Func_void_onProgressData_Wrapper(std::move(value));
}
@@ -470,10 +499,11 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::vector<TimedMetadataObject>`.
*/
using std__vector_TimedMetadataObject_ = std::vector<TimedMetadataObject>;
inline std::vector<TimedMetadataObject> create_std__vector_TimedMetadataObject_(size_t size) {
std::vector<TimedMetadataObject> vector;
vector.reserve(size);
return vector;
inline std::vector<TimedMetadataObject> copy_std__vector_TimedMetadataObject_(const TimedMetadataObject* CONTIGUOUS_MEMORY NON_NULL data, size_t size) noexcept {
return margelo::nitro::FastVectorCopy<TimedMetadataObject>(data, size);
}
inline const TimedMetadataObject* CONTIGUOUS_MEMORY NON_NULL get_data_std__vector_TimedMetadataObject_(const std::vector<TimedMetadataObject>& vector) noexcept {
return vector.data();
}
// pragma MARK: std::function<void(const TimedMetadata& /* metadata */)>
@@ -487,14 +517,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_TimedMetadata_Wrapper final {
public:
explicit Func_void_TimedMetadata_Wrapper(std::function<void(const TimedMetadata& /* metadata */)>&& func): _function(std::make_unique<std::function<void(const TimedMetadata& /* metadata */)>>(std::move(func))) {}
inline void call(TimedMetadata metadata) const {
inline void call(TimedMetadata metadata) const noexcept {
_function->operator()(metadata);
}
private:
std::unique_ptr<std::function<void(const TimedMetadata& /* metadata */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_TimedMetadata create_Func_void_TimedMetadata(void* _Nonnull swiftClosureWrapper);
inline Func_void_TimedMetadata_Wrapper wrap_Func_void_TimedMetadata(Func_void_TimedMetadata value) {
Func_void_TimedMetadata create_Func_void_TimedMetadata(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_TimedMetadata_Wrapper wrap_Func_void_TimedMetadata(Func_void_TimedMetadata value) noexcept {
return Func_void_TimedMetadata_Wrapper(std::move(value));
}
@@ -503,7 +533,7 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::vector<std::string>`.
*/
using std__vector_std__string_ = std::vector<std::string>;
inline std::vector<std::string> create_std__vector_std__string_(size_t size) {
inline std::vector<std::string> create_std__vector_std__string_(size_t size) noexcept {
std::vector<std::string> vector;
vector.reserve(size);
return vector;
@@ -520,14 +550,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_std__vector_std__string__Wrapper final {
public:
explicit Func_void_std__vector_std__string__Wrapper(std::function<void(const std::vector<std::string>& /* texts */)>&& func): _function(std::make_unique<std::function<void(const std::vector<std::string>& /* texts */)>>(std::move(func))) {}
inline void call(std::vector<std::string> texts) const {
inline void call(std::vector<std::string> texts) const noexcept {
_function->operator()(texts);
}
private:
std::unique_ptr<std::function<void(const std::vector<std::string>& /* texts */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_std__vector_std__string_ create_Func_void_std__vector_std__string_(void* _Nonnull swiftClosureWrapper);
inline Func_void_std__vector_std__string__Wrapper wrap_Func_void_std__vector_std__string_(Func_void_std__vector_std__string_ value) {
Func_void_std__vector_std__string_ create_Func_void_std__vector_std__string_(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_std__vector_std__string__Wrapper wrap_Func_void_std__vector_std__string_(Func_void_std__vector_std__string_ value) noexcept {
return Func_void_std__vector_std__string__Wrapper(std::move(value));
}
@@ -542,14 +572,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_std__optional_TextTrack__Wrapper final {
public:
explicit Func_void_std__optional_TextTrack__Wrapper(std::function<void(const std::optional<TextTrack>& /* track */)>&& func): _function(std::make_unique<std::function<void(const std::optional<TextTrack>& /* track */)>>(std::move(func))) {}
inline void call(std::optional<TextTrack> track) const {
inline void call(std::optional<TextTrack> track) const noexcept {
_function->operator()(track);
}
private:
std::unique_ptr<std::function<void(const std::optional<TextTrack>& /* track */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_std__optional_TextTrack_ create_Func_void_std__optional_TextTrack_(void* _Nonnull swiftClosureWrapper);
inline Func_void_std__optional_TextTrack__Wrapper wrap_Func_void_std__optional_TextTrack_(Func_void_std__optional_TextTrack_ value) {
Func_void_std__optional_TextTrack_ create_Func_void_std__optional_TextTrack_(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_std__optional_TextTrack__Wrapper wrap_Func_void_std__optional_TextTrack_(Func_void_std__optional_TextTrack_ value) noexcept {
return Func_void_std__optional_TextTrack__Wrapper(std::move(value));
}
@@ -564,14 +594,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_onVolumeChangeData_Wrapper final {
public:
explicit Func_void_onVolumeChangeData_Wrapper(std::function<void(const onVolumeChangeData& /* data */)>&& func): _function(std::make_unique<std::function<void(const onVolumeChangeData& /* data */)>>(std::move(func))) {}
inline void call(onVolumeChangeData data) const {
inline void call(onVolumeChangeData data) const noexcept {
_function->operator()(data);
}
private:
std::unique_ptr<std::function<void(const onVolumeChangeData& /* data */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_onVolumeChangeData create_Func_void_onVolumeChangeData(void* _Nonnull swiftClosureWrapper);
inline Func_void_onVolumeChangeData_Wrapper wrap_Func_void_onVolumeChangeData(Func_void_onVolumeChangeData value) {
Func_void_onVolumeChangeData create_Func_void_onVolumeChangeData(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_onVolumeChangeData_Wrapper wrap_Func_void_onVolumeChangeData(Func_void_onVolumeChangeData value) noexcept {
return Func_void_onVolumeChangeData_Wrapper(std::move(value));
}
@@ -586,14 +616,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_VideoPlayerStatus_Wrapper final {
public:
explicit Func_void_VideoPlayerStatus_Wrapper(std::function<void(VideoPlayerStatus /* status */)>&& func): _function(std::make_unique<std::function<void(VideoPlayerStatus /* status */)>>(std::move(func))) {}
inline void call(int status) const {
inline void call(int status) const noexcept {
_function->operator()(static_cast<VideoPlayerStatus>(status));
}
private:
std::unique_ptr<std::function<void(VideoPlayerStatus /* status */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_VideoPlayerStatus create_Func_void_VideoPlayerStatus(void* _Nonnull swiftClosureWrapper);
inline Func_void_VideoPlayerStatus_Wrapper wrap_Func_void_VideoPlayerStatus(Func_void_VideoPlayerStatus value) {
Func_void_VideoPlayerStatus create_Func_void_VideoPlayerStatus(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_VideoPlayerStatus_Wrapper wrap_Func_void_VideoPlayerStatus(Func_void_VideoPlayerStatus value) noexcept {
return Func_void_VideoPlayerStatus_Wrapper(std::move(value));
}
@@ -602,10 +632,11 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::vector<NativeExternalSubtitle>`.
*/
using std__vector_NativeExternalSubtitle_ = std::vector<NativeExternalSubtitle>;
inline std::vector<NativeExternalSubtitle> create_std__vector_NativeExternalSubtitle_(size_t size) {
std::vector<NativeExternalSubtitle> vector;
vector.reserve(size);
return vector;
inline std::vector<NativeExternalSubtitle> copy_std__vector_NativeExternalSubtitle_(const NativeExternalSubtitle* CONTIGUOUS_MEMORY NON_NULL data, size_t size) noexcept {
return margelo::nitro::FastVectorCopy<NativeExternalSubtitle>(data, size);
}
inline const NativeExternalSubtitle* CONTIGUOUS_MEMORY NON_NULL get_data_std__vector_NativeExternalSubtitle_(const std::vector<NativeExternalSubtitle>& vector) noexcept {
return vector.data();
}
// pragma MARK: std::optional<std::vector<NativeExternalSubtitle>>
@@ -613,21 +644,27 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::optional<std::vector<NativeExternalSubtitle>>`.
*/
using std__optional_std__vector_NativeExternalSubtitle__ = std::optional<std::vector<NativeExternalSubtitle>>;
inline std::optional<std::vector<NativeExternalSubtitle>> create_std__optional_std__vector_NativeExternalSubtitle__(const std::vector<NativeExternalSubtitle>& value) {
inline std::optional<std::vector<NativeExternalSubtitle>> create_std__optional_std__vector_NativeExternalSubtitle__(const std::vector<NativeExternalSubtitle>& value) noexcept {
return std::optional<std::vector<NativeExternalSubtitle>>(value);
}
inline bool has_value_std__optional_std__vector_NativeExternalSubtitle__(const std::optional<std::vector<NativeExternalSubtitle>>& optional) noexcept {
return optional.has_value();
}
inline std::vector<NativeExternalSubtitle> get_std__optional_std__vector_NativeExternalSubtitle__(const std::optional<std::vector<NativeExternalSubtitle>>& optional) noexcept {
return *optional;
}
// pragma MARK: std::unordered_map<std::string, std::string>
/**
* Specialized version of `std::unordered_map<std::string, std::string>`.
*/
using std__unordered_map_std__string__std__string_ = std::unordered_map<std::string, std::string>;
inline std::unordered_map<std::string, std::string> create_std__unordered_map_std__string__std__string_(size_t size) {
inline std::unordered_map<std::string, std::string> create_std__unordered_map_std__string__std__string_(size_t size) noexcept {
std::unordered_map<std::string, std::string> map;
map.reserve(size);
return map;
}
inline std::vector<std::string> get_std__unordered_map_std__string__std__string__keys(const std__unordered_map_std__string__std__string_& map) {
inline std::vector<std::string> get_std__unordered_map_std__string__std__string__keys(const std__unordered_map_std__string__std__string_& map) noexcept {
std::vector<std::string> keys;
keys.reserve(map.size());
for (const auto& entry : map) {
@@ -635,10 +672,10 @@ namespace margelo::nitro::video::bridge::swift {
}
return keys;
}
inline std::string get_std__unordered_map_std__string__std__string__value(const std__unordered_map_std__string__std__string_& map, const std::string& key) {
return map.at(key);
inline std::string get_std__unordered_map_std__string__std__string__value(const std__unordered_map_std__string__std__string_& map, const std::string& key) noexcept {
return map.find(key)->second;
}
inline void emplace_std__unordered_map_std__string__std__string_(std__unordered_map_std__string__std__string_& map, const std::string& key, const std::string& value) {
inline void emplace_std__unordered_map_std__string__std__string_(std__unordered_map_std__string__std__string_& map, const std::string& key, const std::string& value) noexcept {
map.emplace(key, value);
}
@@ -647,28 +684,40 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::optional<std::unordered_map<std::string, std::string>>`.
*/
using std__optional_std__unordered_map_std__string__std__string__ = std::optional<std::unordered_map<std::string, std::string>>;
inline std::optional<std::unordered_map<std::string, std::string>> create_std__optional_std__unordered_map_std__string__std__string__(const std::unordered_map<std::string, std::string>& value) {
inline std::optional<std::unordered_map<std::string, std::string>> create_std__optional_std__unordered_map_std__string__std__string__(const std::unordered_map<std::string, std::string>& value) noexcept {
return std::optional<std::unordered_map<std::string, std::string>>(value);
}
inline bool has_value_std__optional_std__unordered_map_std__string__std__string__(const std::optional<std::unordered_map<std::string, std::string>>& optional) noexcept {
return optional.has_value();
}
inline std::unordered_map<std::string, std::string> get_std__optional_std__unordered_map_std__string__std__string__(const std::optional<std::unordered_map<std::string, std::string>>& optional) noexcept {
return *optional;
}
// pragma MARK: std::optional<bool>
/**
* Specialized version of `std::optional<bool>`.
*/
using std__optional_bool_ = std::optional<bool>;
inline std::optional<bool> create_std__optional_bool_(const bool& value) {
inline std::optional<bool> create_std__optional_bool_(const bool& value) noexcept {
return std::optional<bool>(value);
}
inline bool has_value_std__optional_bool_(const std::optional<bool>& optional) noexcept {
return optional.has_value();
}
inline bool get_std__optional_bool_(const std::optional<bool>& optional) noexcept {
return *optional;
}
// pragma MARK: std::shared_ptr<Promise<std::string>>
/**
* Specialized version of `std::shared_ptr<Promise<std::string>>`.
*/
using std__shared_ptr_Promise_std__string__ = std::shared_ptr<Promise<std::string>>;
inline std::shared_ptr<Promise<std::string>> create_std__shared_ptr_Promise_std__string__() {
inline std::shared_ptr<Promise<std::string>> create_std__shared_ptr_Promise_std__string__() noexcept {
return Promise<std::string>::create();
}
inline PromiseHolder<std::string> wrap_std__shared_ptr_Promise_std__string__(std::shared_ptr<Promise<std::string>> promise) {
inline PromiseHolder<std::string> wrap_std__shared_ptr_Promise_std__string__(std::shared_ptr<Promise<std::string>> promise) noexcept {
return PromiseHolder<std::string>(std::move(promise));
}
@@ -683,14 +732,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_std__string_Wrapper final {
public:
explicit Func_void_std__string_Wrapper(std::function<void(const std::string& /* result */)>&& func): _function(std::make_unique<std::function<void(const std::string& /* result */)>>(std::move(func))) {}
inline void call(std::string result) const {
inline void call(std::string result) const noexcept {
_function->operator()(result);
}
private:
std::unique_ptr<std::function<void(const std::string& /* result */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_std__string create_Func_void_std__string(void* _Nonnull swiftClosureWrapper);
inline Func_void_std__string_Wrapper wrap_Func_void_std__string(Func_void_std__string value) {
Func_void_std__string create_Func_void_std__string(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_std__string_Wrapper wrap_Func_void_std__string(Func_void_std__string value) noexcept {
return Func_void_std__string_Wrapper(std::move(value));
}
@@ -705,15 +754,15 @@ namespace margelo::nitro::video::bridge::swift {
class Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload_Wrapper final {
public:
explicit Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload_Wrapper(std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>&& func): _function(std::make_unique<std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>>(std::move(func))) {}
inline std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>> call(OnGetLicensePayload payload) const {
inline std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>> call(OnGetLicensePayload payload) const noexcept {
auto __result = _function->operator()(payload);
return __result;
}
private:
std::unique_ptr<std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>> _function;
} SWIFT_NONCOPYABLE;
Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload create_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload(void* _Nonnull swiftClosureWrapper);
inline Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload_Wrapper wrap_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload(Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload value) {
Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload create_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload_Wrapper wrap_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload(Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload value) noexcept {
return Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload_Wrapper(std::move(value));
}
@@ -722,10 +771,10 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>`.
*/
using std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____ = std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>;
inline std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>> create_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____() {
inline std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>> create_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____() noexcept {
return Promise<std::shared_ptr<Promise<std::string>>>::create();
}
inline PromiseHolder<std::shared_ptr<Promise<std::string>>> wrap_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____(std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>> promise) {
inline PromiseHolder<std::shared_ptr<Promise<std::string>>> wrap_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____(std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>> promise) noexcept {
return PromiseHolder<std::shared_ptr<Promise<std::string>>>(std::move(promise));
}
@@ -740,14 +789,14 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_std__shared_ptr_Promise_std__string___Wrapper final {
public:
explicit Func_void_std__shared_ptr_Promise_std__string___Wrapper(std::function<void(const std::shared_ptr<Promise<std::string>>& /* result */)>&& func): _function(std::make_unique<std::function<void(const std::shared_ptr<Promise<std::string>>& /* result */)>>(std::move(func))) {}
inline void call(std::shared_ptr<Promise<std::string>> result) const {
inline void call(std::shared_ptr<Promise<std::string>> result) const noexcept {
_function->operator()(result);
}
private:
std::unique_ptr<std::function<void(const std::shared_ptr<Promise<std::string>>& /* result */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_std__shared_ptr_Promise_std__string__ create_Func_void_std__shared_ptr_Promise_std__string__(void* _Nonnull swiftClosureWrapper);
inline Func_void_std__shared_ptr_Promise_std__string___Wrapper wrap_Func_void_std__shared_ptr_Promise_std__string__(Func_void_std__shared_ptr_Promise_std__string__ value) {
Func_void_std__shared_ptr_Promise_std__string__ create_Func_void_std__shared_ptr_Promise_std__string__(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_std__shared_ptr_Promise_std__string___Wrapper wrap_Func_void_std__shared_ptr_Promise_std__string__(Func_void_std__shared_ptr_Promise_std__string__ value) noexcept {
return Func_void_std__shared_ptr_Promise_std__string___Wrapper(std::move(value));
}
@@ -756,55 +805,94 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::optional<std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& / * payload * /)>>`.
*/
using std__optional_std__function_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____const_OnGetLicensePayload_____payload______ = std::optional<std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>>;
inline std::optional<std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>> create_std__optional_std__function_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____const_OnGetLicensePayload_____payload______(const std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>& value) {
inline std::optional<std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>> create_std__optional_std__function_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____const_OnGetLicensePayload_____payload______(const std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>& value) noexcept {
return std::optional<std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>>(value);
}
inline bool has_value_std__optional_std__function_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____const_OnGetLicensePayload_____payload______(const std::optional<std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>>& optional) noexcept {
return optional.has_value();
}
inline std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)> get_std__optional_std__function_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____const_OnGetLicensePayload_____payload______(const std::optional<std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<std::string>>>>(const OnGetLicensePayload& /* payload */)>>& optional) noexcept {
return *optional;
}
// pragma MARK: std::optional<NativeDrmParams>
/**
* Specialized version of `std::optional<NativeDrmParams>`.
*/
using std__optional_NativeDrmParams_ = std::optional<NativeDrmParams>;
inline std::optional<NativeDrmParams> create_std__optional_NativeDrmParams_(const NativeDrmParams& value) {
inline std::optional<NativeDrmParams> create_std__optional_NativeDrmParams_(const NativeDrmParams& value) noexcept {
return std::optional<NativeDrmParams>(value);
}
inline bool has_value_std__optional_NativeDrmParams_(const std::optional<NativeDrmParams>& optional) noexcept {
return optional.has_value();
}
inline NativeDrmParams get_std__optional_NativeDrmParams_(const std::optional<NativeDrmParams>& optional) noexcept {
return *optional;
}
// pragma MARK: std::optional<LivePlaybackParams>
/**
* Specialized version of `std::optional<LivePlaybackParams>`.
*/
using std__optional_LivePlaybackParams_ = std::optional<LivePlaybackParams>;
inline std::optional<LivePlaybackParams> create_std__optional_LivePlaybackParams_(const LivePlaybackParams& value) {
inline std::optional<LivePlaybackParams> create_std__optional_LivePlaybackParams_(const LivePlaybackParams& value) noexcept {
return std::optional<LivePlaybackParams>(value);
}
inline bool has_value_std__optional_LivePlaybackParams_(const std::optional<LivePlaybackParams>& optional) noexcept {
return optional.has_value();
}
inline LivePlaybackParams get_std__optional_LivePlaybackParams_(const std::optional<LivePlaybackParams>& optional) noexcept {
return *optional;
}
// pragma MARK: std::optional<Resolution>
/**
* Specialized version of `std::optional<Resolution>`.
*/
using std__optional_Resolution_ = std::optional<Resolution>;
inline std::optional<Resolution> create_std__optional_Resolution_(const Resolution& value) {
inline std::optional<Resolution> create_std__optional_Resolution_(const Resolution& value) noexcept {
return std::optional<Resolution>(value);
}
inline bool has_value_std__optional_Resolution_(const std::optional<Resolution>& optional) noexcept {
return optional.has_value();
}
inline Resolution get_std__optional_Resolution_(const std::optional<Resolution>& optional) noexcept {
return *optional;
}
// pragma MARK: std::optional<BufferConfig>
/**
* Specialized version of `std::optional<BufferConfig>`.
*/
using std__optional_BufferConfig_ = std::optional<BufferConfig>;
inline std::optional<BufferConfig> create_std__optional_BufferConfig_(const BufferConfig& value) {
inline std::optional<BufferConfig> create_std__optional_BufferConfig_(const BufferConfig& value) noexcept {
return std::optional<BufferConfig>(value);
}
inline bool has_value_std__optional_BufferConfig_(const std::optional<BufferConfig>& optional) noexcept {
return optional.has_value();
}
inline BufferConfig get_std__optional_BufferConfig_(const std::optional<BufferConfig>& optional) noexcept {
return *optional;
}
// pragma MARK: std::optional<CustomVideoMetadata>
/**
* Specialized version of `std::optional<CustomVideoMetadata>`.
*/
using std__optional_CustomVideoMetadata_ = std::optional<CustomVideoMetadata>;
inline std::optional<CustomVideoMetadata> create_std__optional_CustomVideoMetadata_(const CustomVideoMetadata& value) {
return std::optional<CustomVideoMetadata>(value);
}
// pragma MARK: std::shared_ptr<Promise<VideoInformation>>
/**
* Specialized version of `std::shared_ptr<Promise<VideoInformation>>`.
*/
using std__shared_ptr_Promise_VideoInformation__ = std::shared_ptr<Promise<VideoInformation>>;
inline std::shared_ptr<Promise<VideoInformation>> create_std__shared_ptr_Promise_VideoInformation__() {
inline std::shared_ptr<Promise<VideoInformation>> create_std__shared_ptr_Promise_VideoInformation__() noexcept {
return Promise<VideoInformation>::create();
}
inline PromiseHolder<VideoInformation> wrap_std__shared_ptr_Promise_VideoInformation__(std::shared_ptr<Promise<VideoInformation>> promise) {
inline PromiseHolder<VideoInformation> wrap_std__shared_ptr_Promise_VideoInformation__(std::shared_ptr<Promise<VideoInformation>> promise) noexcept {
return PromiseHolder<VideoInformation>(std::move(promise));
}
@@ -819,23 +907,23 @@ namespace margelo::nitro::video::bridge::swift {
class Func_void_VideoInformation_Wrapper final {
public:
explicit Func_void_VideoInformation_Wrapper(std::function<void(const VideoInformation& /* result */)>&& func): _function(std::make_unique<std::function<void(const VideoInformation& /* result */)>>(std::move(func))) {}
inline void call(VideoInformation result) const {
inline void call(VideoInformation result) const noexcept {
_function->operator()(result);
}
private:
std::unique_ptr<std::function<void(const VideoInformation& /* result */)>> _function;
} SWIFT_NONCOPYABLE;
Func_void_VideoInformation create_Func_void_VideoInformation(void* _Nonnull swiftClosureWrapper);
inline Func_void_VideoInformation_Wrapper wrap_Func_void_VideoInformation(Func_void_VideoInformation value) {
Func_void_VideoInformation create_Func_void_VideoInformation(void* NON_NULL swiftClosureWrapper) noexcept;
inline Func_void_VideoInformation_Wrapper wrap_Func_void_VideoInformation(Func_void_VideoInformation value) noexcept {
return Func_void_VideoInformation_Wrapper(std::move(value));
}
// pragma MARK: Result<std::shared_ptr<Promise<VideoInformation>>>
using Result_std__shared_ptr_Promise_VideoInformation___ = Result<std::shared_ptr<Promise<VideoInformation>>>;
inline Result_std__shared_ptr_Promise_VideoInformation___ create_Result_std__shared_ptr_Promise_VideoInformation___(const std::shared_ptr<Promise<VideoInformation>>& value) {
inline Result_std__shared_ptr_Promise_VideoInformation___ create_Result_std__shared_ptr_Promise_VideoInformation___(const std::shared_ptr<Promise<VideoInformation>>& value) noexcept {
return Result<std::shared_ptr<Promise<VideoInformation>>>::withValue(value);
}
inline Result_std__shared_ptr_Promise_VideoInformation___ create_Result_std__shared_ptr_Promise_VideoInformation___(const std::exception_ptr& error) {
inline Result_std__shared_ptr_Promise_VideoInformation___ create_Result_std__shared_ptr_Promise_VideoInformation___(const std::exception_ptr& error) noexcept {
return Result<std::shared_ptr<Promise<VideoInformation>>>::withError(error);
}
@@ -844,19 +932,19 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::shared_ptr<HybridVideoPlayerSourceFactorySpec>`.
*/
using std__shared_ptr_HybridVideoPlayerSourceFactorySpec_ = std::shared_ptr<HybridVideoPlayerSourceFactorySpec>;
std::shared_ptr<HybridVideoPlayerSourceFactorySpec> create_std__shared_ptr_HybridVideoPlayerSourceFactorySpec_(void* _Nonnull swiftUnsafePointer);
void* _Nonnull get_std__shared_ptr_HybridVideoPlayerSourceFactorySpec_(std__shared_ptr_HybridVideoPlayerSourceFactorySpec_ cppType);
std::shared_ptr<HybridVideoPlayerSourceFactorySpec> create_std__shared_ptr_HybridVideoPlayerSourceFactorySpec_(void* NON_NULL swiftUnsafePointer) noexcept;
void* NON_NULL get_std__shared_ptr_HybridVideoPlayerSourceFactorySpec_(std__shared_ptr_HybridVideoPlayerSourceFactorySpec_ cppType) noexcept;
// pragma MARK: std::weak_ptr<HybridVideoPlayerSourceFactorySpec>
using std__weak_ptr_HybridVideoPlayerSourceFactorySpec_ = std::weak_ptr<HybridVideoPlayerSourceFactorySpec>;
inline std__weak_ptr_HybridVideoPlayerSourceFactorySpec_ weakify_std__shared_ptr_HybridVideoPlayerSourceFactorySpec_(const std::shared_ptr<HybridVideoPlayerSourceFactorySpec>& strong) { return strong; }
inline std__weak_ptr_HybridVideoPlayerSourceFactorySpec_ weakify_std__shared_ptr_HybridVideoPlayerSourceFactorySpec_(const std::shared_ptr<HybridVideoPlayerSourceFactorySpec>& strong) noexcept { return strong; }
// pragma MARK: Result<std::shared_ptr<HybridVideoPlayerSourceSpec>>
using Result_std__shared_ptr_HybridVideoPlayerSourceSpec__ = Result<std::shared_ptr<HybridVideoPlayerSourceSpec>>;
inline Result_std__shared_ptr_HybridVideoPlayerSourceSpec__ create_Result_std__shared_ptr_HybridVideoPlayerSourceSpec__(const std::shared_ptr<HybridVideoPlayerSourceSpec>& value) {
inline Result_std__shared_ptr_HybridVideoPlayerSourceSpec__ create_Result_std__shared_ptr_HybridVideoPlayerSourceSpec__(const std::shared_ptr<HybridVideoPlayerSourceSpec>& value) noexcept {
return Result<std::shared_ptr<HybridVideoPlayerSourceSpec>>::withValue(value);
}
inline Result_std__shared_ptr_HybridVideoPlayerSourceSpec__ create_Result_std__shared_ptr_HybridVideoPlayerSourceSpec__(const std::exception_ptr& error) {
inline Result_std__shared_ptr_HybridVideoPlayerSourceSpec__ create_Result_std__shared_ptr_HybridVideoPlayerSourceSpec__(const std::exception_ptr& error) noexcept {
return Result<std::shared_ptr<HybridVideoPlayerSourceSpec>>::withError(error);
}
@@ -865,55 +953,79 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::optional<std::shared_ptr<HybridVideoPlayerSpec>>`.
*/
using std__optional_std__shared_ptr_HybridVideoPlayerSpec__ = std::optional<std::shared_ptr<HybridVideoPlayerSpec>>;
inline std::optional<std::shared_ptr<HybridVideoPlayerSpec>> create_std__optional_std__shared_ptr_HybridVideoPlayerSpec__(const std::shared_ptr<HybridVideoPlayerSpec>& value) {
inline std::optional<std::shared_ptr<HybridVideoPlayerSpec>> create_std__optional_std__shared_ptr_HybridVideoPlayerSpec__(const std::shared_ptr<HybridVideoPlayerSpec>& value) noexcept {
return std::optional<std::shared_ptr<HybridVideoPlayerSpec>>(value);
}
inline bool has_value_std__optional_std__shared_ptr_HybridVideoPlayerSpec__(const std::optional<std::shared_ptr<HybridVideoPlayerSpec>>& optional) noexcept {
return optional.has_value();
}
inline std::shared_ptr<HybridVideoPlayerSpec> get_std__optional_std__shared_ptr_HybridVideoPlayerSpec__(const std::optional<std::shared_ptr<HybridVideoPlayerSpec>>& optional) noexcept {
return *optional;
}
// pragma MARK: std::optional<std::function<void(bool /* isInPictureInPicture */)>>
/**
* Specialized version of `std::optional<std::function<void(bool / * isInPictureInPicture * /)>>`.
*/
using std__optional_std__function_void_bool____isInPictureInPicture______ = std::optional<std::function<void(bool /* isInPictureInPicture */)>>;
inline std::optional<std::function<void(bool /* isInPictureInPicture */)>> create_std__optional_std__function_void_bool____isInPictureInPicture______(const std::function<void(bool /* isInPictureInPicture */)>& value) {
inline std::optional<std::function<void(bool /* isInPictureInPicture */)>> create_std__optional_std__function_void_bool____isInPictureInPicture______(const std::function<void(bool /* isInPictureInPicture */)>& value) noexcept {
return std::optional<std::function<void(bool /* isInPictureInPicture */)>>(value);
}
inline bool has_value_std__optional_std__function_void_bool____isInPictureInPicture______(const std::optional<std::function<void(bool /* isInPictureInPicture */)>>& optional) noexcept {
return optional.has_value();
}
inline std::function<void(bool /* isInPictureInPicture */)> get_std__optional_std__function_void_bool____isInPictureInPicture______(const std::optional<std::function<void(bool /* isInPictureInPicture */)>>& optional) noexcept {
return *optional;
}
// pragma MARK: std::optional<std::function<void(bool /* fullscreen */)>>
/**
* Specialized version of `std::optional<std::function<void(bool / * fullscreen * /)>>`.
*/
using std__optional_std__function_void_bool____fullscreen______ = std::optional<std::function<void(bool /* fullscreen */)>>;
inline std::optional<std::function<void(bool /* fullscreen */)>> create_std__optional_std__function_void_bool____fullscreen______(const std::function<void(bool /* fullscreen */)>& value) {
inline std::optional<std::function<void(bool /* fullscreen */)>> create_std__optional_std__function_void_bool____fullscreen______(const std::function<void(bool /* fullscreen */)>& value) noexcept {
return std::optional<std::function<void(bool /* fullscreen */)>>(value);
}
inline bool has_value_std__optional_std__function_void_bool____fullscreen______(const std::optional<std::function<void(bool /* fullscreen */)>>& optional) noexcept {
return optional.has_value();
}
inline std::function<void(bool /* fullscreen */)> get_std__optional_std__function_void_bool____fullscreen______(const std::optional<std::function<void(bool /* fullscreen */)>>& optional) noexcept {
return *optional;
}
// pragma MARK: std::optional<std::function<void()>>
/**
* Specialized version of `std::optional<std::function<void()>>`.
*/
using std__optional_std__function_void____ = std::optional<std::function<void()>>;
inline std::optional<std::function<void()>> create_std__optional_std__function_void____(const std::function<void()>& value) {
inline std::optional<std::function<void()>> create_std__optional_std__function_void____(const std::function<void()>& value) noexcept {
return std::optional<std::function<void()>>(value);
}
inline bool has_value_std__optional_std__function_void____(const std::optional<std::function<void()>>& optional) noexcept {
return optional.has_value();
}
inline std::function<void()> get_std__optional_std__function_void____(const std::optional<std::function<void()>>& optional) noexcept {
return *optional;
}
// pragma MARK: std::shared_ptr<HybridVideoViewViewManagerSpec>
/**
* Specialized version of `std::shared_ptr<HybridVideoViewViewManagerSpec>`.
*/
using std__shared_ptr_HybridVideoViewViewManagerSpec_ = std::shared_ptr<HybridVideoViewViewManagerSpec>;
std::shared_ptr<HybridVideoViewViewManagerSpec> create_std__shared_ptr_HybridVideoViewViewManagerSpec_(void* _Nonnull swiftUnsafePointer);
void* _Nonnull get_std__shared_ptr_HybridVideoViewViewManagerSpec_(std__shared_ptr_HybridVideoViewViewManagerSpec_ cppType);
std::shared_ptr<HybridVideoViewViewManagerSpec> create_std__shared_ptr_HybridVideoViewViewManagerSpec_(void* NON_NULL swiftUnsafePointer) noexcept;
void* NON_NULL get_std__shared_ptr_HybridVideoViewViewManagerSpec_(std__shared_ptr_HybridVideoViewViewManagerSpec_ cppType) noexcept;
// pragma MARK: std::weak_ptr<HybridVideoViewViewManagerSpec>
using std__weak_ptr_HybridVideoViewViewManagerSpec_ = std::weak_ptr<HybridVideoViewViewManagerSpec>;
inline std__weak_ptr_HybridVideoViewViewManagerSpec_ weakify_std__shared_ptr_HybridVideoViewViewManagerSpec_(const std::shared_ptr<HybridVideoViewViewManagerSpec>& strong) { return strong; }
inline std__weak_ptr_HybridVideoViewViewManagerSpec_ weakify_std__shared_ptr_HybridVideoViewViewManagerSpec_(const std::shared_ptr<HybridVideoViewViewManagerSpec>& strong) noexcept { return strong; }
// pragma MARK: Result<bool>
using Result_bool_ = Result<bool>;
inline Result_bool_ create_Result_bool_(bool value) {
inline Result_bool_ create_Result_bool_(bool value) noexcept {
return Result<bool>::withValue(std::move(value));
}
inline Result_bool_ create_Result_bool_(const std::exception_ptr& error) {
inline Result_bool_ create_Result_bool_(const std::exception_ptr& error) noexcept {
return Result<bool>::withError(error);
}
@@ -922,19 +1034,19 @@ namespace margelo::nitro::video::bridge::swift {
* Specialized version of `std::shared_ptr<HybridVideoViewViewManagerFactorySpec>`.
*/
using std__shared_ptr_HybridVideoViewViewManagerFactorySpec_ = std::shared_ptr<HybridVideoViewViewManagerFactorySpec>;
std::shared_ptr<HybridVideoViewViewManagerFactorySpec> create_std__shared_ptr_HybridVideoViewViewManagerFactorySpec_(void* _Nonnull swiftUnsafePointer);
void* _Nonnull get_std__shared_ptr_HybridVideoViewViewManagerFactorySpec_(std__shared_ptr_HybridVideoViewViewManagerFactorySpec_ cppType);
std::shared_ptr<HybridVideoViewViewManagerFactorySpec> create_std__shared_ptr_HybridVideoViewViewManagerFactorySpec_(void* NON_NULL swiftUnsafePointer) noexcept;
void* NON_NULL get_std__shared_ptr_HybridVideoViewViewManagerFactorySpec_(std__shared_ptr_HybridVideoViewViewManagerFactorySpec_ cppType) noexcept;
// pragma MARK: std::weak_ptr<HybridVideoViewViewManagerFactorySpec>
using std__weak_ptr_HybridVideoViewViewManagerFactorySpec_ = std::weak_ptr<HybridVideoViewViewManagerFactorySpec>;
inline std__weak_ptr_HybridVideoViewViewManagerFactorySpec_ weakify_std__shared_ptr_HybridVideoViewViewManagerFactorySpec_(const std::shared_ptr<HybridVideoViewViewManagerFactorySpec>& strong) { return strong; }
inline std__weak_ptr_HybridVideoViewViewManagerFactorySpec_ weakify_std__shared_ptr_HybridVideoViewViewManagerFactorySpec_(const std::shared_ptr<HybridVideoViewViewManagerFactorySpec>& strong) noexcept { return strong; }
// pragma MARK: Result<std::shared_ptr<HybridVideoViewViewManagerSpec>>
using Result_std__shared_ptr_HybridVideoViewViewManagerSpec__ = Result<std::shared_ptr<HybridVideoViewViewManagerSpec>>;
inline Result_std__shared_ptr_HybridVideoViewViewManagerSpec__ create_Result_std__shared_ptr_HybridVideoViewViewManagerSpec__(const std::shared_ptr<HybridVideoViewViewManagerSpec>& value) {
inline Result_std__shared_ptr_HybridVideoViewViewManagerSpec__ create_Result_std__shared_ptr_HybridVideoViewViewManagerSpec__(const std::shared_ptr<HybridVideoViewViewManagerSpec>& value) noexcept {
return Result<std::shared_ptr<HybridVideoViewViewManagerSpec>>::withValue(value);
}
inline Result_std__shared_ptr_HybridVideoViewViewManagerSpec__ create_Result_std__shared_ptr_HybridVideoViewViewManagerSpec__(const std::exception_ptr& error) {
inline Result_std__shared_ptr_HybridVideoViewViewManagerSpec__ create_Result_std__shared_ptr_HybridVideoViewViewManagerSpec__(const std::exception_ptr& error) noexcept {
return Result<std::shared_ptr<HybridVideoViewViewManagerSpec>>::withError(error);
}

View File

@@ -12,6 +12,8 @@
namespace margelo::nitro::video { struct BandwidthData; }
// Forward declaration of `BufferConfig` to properly resolve imports.
namespace margelo::nitro::video { struct BufferConfig; }
// Forward declaration of `CustomVideoMetadata` to properly resolve imports.
namespace margelo::nitro::video { struct CustomVideoMetadata; }
// Forward declaration of `HybridVideoPlayerEventEmitterSpec` to properly resolve imports.
namespace margelo::nitro::video { class HybridVideoPlayerEventEmitterSpec; }
// Forward declaration of `HybridVideoPlayerFactorySpec` to properly resolve imports.
@@ -48,6 +50,8 @@ namespace margelo::nitro::video { struct Resolution; }
namespace margelo::nitro::video { enum class SourceType; }
// Forward declaration of `SubtitleType` to properly resolve imports.
namespace margelo::nitro::video { enum class SubtitleType; }
// Forward declaration of `SurfaceType` to properly resolve imports.
namespace margelo::nitro::video { enum class SurfaceType; }
// Forward declaration of `TextTrack` to properly resolve imports.
namespace margelo::nitro::video { struct TextTrack; }
// Forward declaration of `TimedMetadataObject` to properly resolve imports.
@@ -74,6 +78,7 @@ namespace margelo::nitro::video { struct onVolumeChangeData; }
// Include C++ defined types
#include "BandwidthData.hpp"
#include "BufferConfig.hpp"
#include "CustomVideoMetadata.hpp"
#include "HybridVideoPlayerEventEmitterSpec.hpp"
#include "HybridVideoPlayerFactorySpec.hpp"
#include "HybridVideoPlayerSourceFactorySpec.hpp"
@@ -92,6 +97,7 @@ namespace margelo::nitro::video { struct onVolumeChangeData; }
#include "Resolution.hpp"
#include "SourceType.hpp"
#include "SubtitleType.hpp"
#include "SurfaceType.hpp"
#include "TextTrack.hpp"
#include "TimedMetadata.hpp"
#include "TimedMetadataObject.hpp"

View File

@@ -30,6 +30,8 @@ namespace margelo::nitro::video { struct BufferConfig; }
namespace margelo::nitro::video { struct LivePlaybackParams; }
// Forward declaration of `Resolution` to properly resolve imports.
namespace margelo::nitro::video { struct Resolution; }
// Forward declaration of `CustomVideoMetadata` to properly resolve imports.
namespace margelo::nitro::video { struct CustomVideoMetadata; }
#include <memory>
#include "HybridVideoPlayerSourceSpec.hpp"
@@ -47,6 +49,7 @@ namespace margelo::nitro::video { struct Resolution; }
#include "BufferConfig.hpp"
#include "LivePlaybackParams.hpp"
#include "Resolution.hpp"
#include "CustomVideoMetadata.hpp"
#include "ReactNativeVideo-Swift-Cxx-Umbrella.hpp"
@@ -98,7 +101,7 @@ namespace margelo::nitro::video {
return __value;
}
inline std::shared_ptr<HybridVideoPlayerSourceSpec> fromVideoConfig(const NativeVideoConfig& config) override {
auto __result = _swiftPart.fromVideoConfig(config);
auto __result = _swiftPart.fromVideoConfig(std::forward<decltype(config)>(config));
if (__result.hasError()) [[unlikely]] {
std::rethrow_exception(__result.error());
}

View File

@@ -28,6 +28,8 @@ namespace margelo::nitro::video { struct BufferConfig; }
namespace margelo::nitro::video { struct LivePlaybackParams; }
// Forward declaration of `Resolution` to properly resolve imports.
namespace margelo::nitro::video { struct Resolution; }
// Forward declaration of `CustomVideoMetadata` to properly resolve imports.
namespace margelo::nitro::video { struct CustomVideoMetadata; }
// Forward declaration of `VideoInformation` to properly resolve imports.
namespace margelo::nitro::video { struct VideoInformation; }
// Forward declaration of `VideoOrientation` to properly resolve imports.
@@ -47,6 +49,7 @@ namespace margelo::nitro::video { enum class VideoOrientation; }
#include "BufferConfig.hpp"
#include "LivePlaybackParams.hpp"
#include "Resolution.hpp"
#include "CustomVideoMetadata.hpp"
#include "VideoInformation.hpp"
#include "VideoOrientation.hpp"
@@ -92,8 +95,7 @@ namespace margelo::nitro::video {
return __result;
}
inline NativeVideoConfig getConfig() noexcept override {
auto __result = _swiftPart.getConfig();
return __result;
return _swiftPart.getConfig();
}
public:

View File

@@ -82,6 +82,12 @@ namespace margelo::nitro::video {
auto __result = _swiftPart.getEventEmitter();
return __result;
}
inline bool getShowNotificationControls() noexcept override {
return _swiftPart.getShowNotificationControls();
}
inline void setShowNotificationControls(bool showNotificationControls) noexcept override {
_swiftPart.setShowNotificationControls(std::forward<decltype(showNotificationControls)>(showNotificationControls));
}
inline VideoPlayerStatus getStatus() noexcept override {
auto __result = _swiftPart.getStatus();
return static_cast<VideoPlayerStatus>(__result);

View File

@@ -16,11 +16,14 @@ namespace ReactNativeVideo { class HybridVideoViewViewManagerSpec_cxx; }
namespace margelo::nitro::video { class HybridVideoPlayerSpec; }
// Forward declaration of `ResizeMode` to properly resolve imports.
namespace margelo::nitro::video { enum class ResizeMode; }
// Forward declaration of `SurfaceType` to properly resolve imports.
namespace margelo::nitro::video { enum class SurfaceType; }
#include <memory>
#include "HybridVideoPlayerSpec.hpp"
#include <optional>
#include "ResizeMode.hpp"
#include "SurfaceType.hpp"
#include <functional>
#include "ReactNativeVideo-Swift-Cxx-Umbrella.hpp"
@@ -98,6 +101,13 @@ namespace margelo::nitro::video {
inline void setKeepScreenAwake(bool keepScreenAwake) noexcept override {
_swiftPart.setKeepScreenAwake(std::forward<decltype(keepScreenAwake)>(keepScreenAwake));
}
inline SurfaceType getSurfaceType() noexcept override {
auto __result = _swiftPart.getSurfaceType();
return static_cast<SurfaceType>(__result);
}
inline void setSurfaceType(SurfaceType surfaceType) noexcept override {
_swiftPart.setSurfaceType(static_cast<int>(surfaceType));
}
inline std::optional<std::function<void(bool /* isInPictureInPicture */)>> getOnPictureInPictureChange() noexcept override {
auto __result = _swiftPart.getOnPictureInPictureChange();
return __result;

View File

@@ -91,13 +91,7 @@ public extension BufferConfig {
var livePlayback: LivePlaybackParams? {
@inline(__always)
get {
return { () -> LivePlaybackParams? in
if let __unwrapped = self.__livePlayback.value {
return __unwrapped
} else {
return nil
}
}()
return self.__livePlayback.value
}
@inline(__always)
set {
@@ -233,13 +227,7 @@ public extension BufferConfig {
var preferredMaximumResolution: Resolution? {
@inline(__always)
get {
return { () -> Resolution? in
if let __unwrapped = self.__preferredMaximumResolution.value {
return __unwrapped
} else {
return nil
}
}()
return self.__preferredMaximumResolution.value
}
@inline(__always)
set {
@@ -273,13 +261,7 @@ public extension BufferConfig {
var preferredMaximumResolutionForExpensiveNetworks: Resolution? {
@inline(__always)
get {
return { () -> Resolution? in
if let __unwrapped = self.__preferredMaximumResolutionForExpensiveNetworks.value {
return __unwrapped
} else {
return nil
}
}()
return self.__preferredMaximumResolutionForExpensiveNetworks.value
}
@inline(__always)
set {

View File

@@ -0,0 +1,169 @@
///
/// CustomVideoMetadata.swift
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © 2025 Marc Rousavy @ Margelo
///
import NitroModules
/**
* Represents an instance of `CustomVideoMetadata`, backed by a C++ struct.
*/
public typealias CustomVideoMetadata = margelo.nitro.video.CustomVideoMetadata
public extension CustomVideoMetadata {
private typealias bridge = margelo.nitro.video.bridge.swift
/**
* Create a new instance of `CustomVideoMetadata`.
*/
init(title: String?, subtitle: String?, description: String?, artist: String?, imageUri: String?) {
self.init({ () -> bridge.std__optional_std__string_ in
if let __unwrappedValue = title {
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
} else {
return .init()
}
}(), { () -> bridge.std__optional_std__string_ in
if let __unwrappedValue = subtitle {
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
} else {
return .init()
}
}(), { () -> bridge.std__optional_std__string_ in
if let __unwrappedValue = description {
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
} else {
return .init()
}
}(), { () -> bridge.std__optional_std__string_ in
if let __unwrappedValue = artist {
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
} else {
return .init()
}
}(), { () -> bridge.std__optional_std__string_ in
if let __unwrappedValue = imageUri {
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
} else {
return .init()
}
}())
}
var title: String? {
@inline(__always)
get {
return { () -> String? in
if let __unwrapped = self.__title.value {
return String(__unwrapped)
} else {
return nil
}
}()
}
@inline(__always)
set {
self.__title = { () -> bridge.std__optional_std__string_ in
if let __unwrappedValue = newValue {
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
} else {
return .init()
}
}()
}
}
var subtitle: String? {
@inline(__always)
get {
return { () -> String? in
if let __unwrapped = self.__subtitle.value {
return String(__unwrapped)
} else {
return nil
}
}()
}
@inline(__always)
set {
self.__subtitle = { () -> bridge.std__optional_std__string_ in
if let __unwrappedValue = newValue {
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
} else {
return .init()
}
}()
}
}
var description: String? {
@inline(__always)
get {
return { () -> String? in
if let __unwrapped = self.__description.value {
return String(__unwrapped)
} else {
return nil
}
}()
}
@inline(__always)
set {
self.__description = { () -> bridge.std__optional_std__string_ in
if let __unwrappedValue = newValue {
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
} else {
return .init()
}
}()
}
}
var artist: String? {
@inline(__always)
get {
return { () -> String? in
if let __unwrapped = self.__artist.value {
return String(__unwrapped)
} else {
return nil
}
}()
}
@inline(__always)
set {
self.__artist = { () -> bridge.std__optional_std__string_ in
if let __unwrappedValue = newValue {
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
} else {
return .init()
}
}()
}
}
var imageUri: String? {
@inline(__always)
get {
return { () -> String? in
if let __unwrapped = self.__imageUri.value {
return String(__unwrapped)
} else {
return nil
}
}()
}
@inline(__always)
set {
self.__imageUri = { () -> bridge.std__optional_std__string_ in
if let __unwrappedValue = newValue {
return bridge.create_std__optional_std__string_(std.string(__unwrappedValue))
} else {
return .init()
}
}()
}
}
}

View File

@@ -23,13 +23,7 @@ public final class Func_void_std__optional_TextTrack_ {
@inline(__always)
public func call(track: bridge.std__optional_TextTrack_) -> Void {
self.closure({ () -> TextTrack? in
if let __unwrapped = track.value {
return __unwrapped
} else {
return nil
}
}())
self.closure(track.value)
}
/**

View File

@@ -13,6 +13,7 @@ public protocol HybridVideoPlayerSpec_protocol: HybridObject {
// Properties
var source: (any HybridVideoPlayerSourceSpec) { get }
var eventEmitter: (any HybridVideoPlayerEventEmitterSpec) { get }
var showNotificationControls: Bool { get set }
var status: VideoPlayerStatus { get }
var duration: Double { get }
var volume: Double { get set }

View File

@@ -126,6 +126,17 @@ open class HybridVideoPlayerSpec_cxx {
}
}
public final var showNotificationControls: Bool {
@inline(__always)
get {
return self.__implementation.showNotificationControls
}
@inline(__always)
set {
self.__implementation.showNotificationControls = newValue
}
}
public final var status: Int32 {
@inline(__always)
get {
@@ -264,7 +275,8 @@ open class HybridVideoPlayerSpec_cxx {
public final func replaceSourceAsync(source: bridge.std__optional_std__shared_ptr_HybridVideoPlayerSourceSpec__) -> bridge.Result_std__shared_ptr_Promise_void___ {
do {
let __result = try self.__implementation.replaceSourceAsync(source: { () -> (any HybridVideoPlayerSourceSpec)? in
if let __unwrapped = source.value {
if bridge.has_value_std__optional_std__shared_ptr_HybridVideoPlayerSourceSpec__(source) {
let __unwrapped = bridge.get_std__optional_std__shared_ptr_HybridVideoPlayerSourceSpec__(source)
return { () -> HybridVideoPlayerSourceSpec in
let __unsafePointer = bridge.get_std__shared_ptr_HybridVideoPlayerSourceSpec_(__unwrapped)
let __instance = HybridVideoPlayerSourceSpec_cxx.fromUnsafe(__unsafePointer)
@@ -293,13 +305,9 @@ open class HybridVideoPlayerSpec_cxx {
public final func getAvailableTextTracks() -> bridge.Result_std__vector_TextTrack__ {
do {
let __result = try self.__implementation.getAvailableTextTracks()
let __resultCpp = { () -> bridge.std__vector_TextTrack_ in
var __vector = bridge.create_std__vector_TextTrack_(__result.count)
for __item in __result {
__vector.push_back(__item)
}
return __vector
}()
let __resultCpp = __result.withUnsafeBufferPointer { __pointer -> bridge.std__vector_TextTrack_ in
return bridge.copy_std__vector_TextTrack_(__pointer.baseAddress!, __result.count)
}
return bridge.create_Result_std__vector_TextTrack__(__resultCpp)
} catch (let __error) {
let __exceptionPtr = __error.toCpp()
@@ -310,13 +318,7 @@ open class HybridVideoPlayerSpec_cxx {
@inline(__always)
public final func selectTextTrack(textTrack: bridge.std__optional_TextTrack_) -> bridge.Result_void_ {
do {
try self.__implementation.selectTextTrack(textTrack: { () -> TextTrack? in
if let __unwrapped = textTrack.value {
return __unwrapped
} else {
return nil
}
}())
try self.__implementation.selectTextTrack(textTrack: textTrack.value)
return bridge.create_Result_void_()
} catch (let __error) {
let __exceptionPtr = __error.toCpp()

View File

@@ -17,6 +17,7 @@ public protocol HybridVideoViewViewManagerSpec_protocol: HybridObject {
var autoEnterPictureInPicture: Bool { get set }
var resizeMode: ResizeMode { get set }
var keepScreenAwake: Bool { get set }
var surfaceType: SurfaceType { get set }
var onPictureInPictureChange: ((_ isInPictureInPicture: Bool) -> Void)? { get set }
var onFullscreenChange: ((_ fullscreen: Bool) -> Void)? { get set }
var willEnterFullscreen: (() -> Void)? { get set }

View File

@@ -123,7 +123,8 @@ open class HybridVideoViewViewManagerSpec_cxx {
@inline(__always)
set {
self.__implementation.player = { () -> (any HybridVideoPlayerSpec)? in
if let __unwrapped = newValue.value {
if bridge.has_value_std__optional_std__shared_ptr_HybridVideoPlayerSpec__(newValue) {
let __unwrapped = bridge.get_std__optional_std__shared_ptr_HybridVideoPlayerSpec__(newValue)
return { () -> HybridVideoPlayerSpec in
let __unsafePointer = bridge.get_std__shared_ptr_HybridVideoPlayerSpec_(__unwrapped)
let __instance = HybridVideoPlayerSpec_cxx.fromUnsafe(__unsafePointer)
@@ -191,6 +192,17 @@ open class HybridVideoViewViewManagerSpec_cxx {
}
}
public final var surfaceType: Int32 {
@inline(__always)
get {
return self.__implementation.surfaceType.rawValue
}
@inline(__always)
set {
self.__implementation.surfaceType = margelo.nitro.video.SurfaceType(rawValue: newValue)!
}
}
public final var onPictureInPictureChange: bridge.std__optional_std__function_void_bool____isInPictureInPicture______ {
@inline(__always)
get {
@@ -208,7 +220,8 @@ open class HybridVideoViewViewManagerSpec_cxx {
@inline(__always)
set {
self.__implementation.onPictureInPictureChange = { () -> ((_ isInPictureInPicture: Bool) -> Void)? in
if let __unwrapped = newValue.value {
if bridge.has_value_std__optional_std__function_void_bool____isInPictureInPicture______(newValue) {
let __unwrapped = bridge.get_std__optional_std__function_void_bool____isInPictureInPicture______(newValue)
return { () -> (Bool) -> Void in
let __wrappedFunction = bridge.wrap_Func_void_bool(__unwrapped)
return { (__isInPictureInPicture: Bool) -> Void in
@@ -239,7 +252,8 @@ open class HybridVideoViewViewManagerSpec_cxx {
@inline(__always)
set {
self.__implementation.onFullscreenChange = { () -> ((_ fullscreen: Bool) -> Void)? in
if let __unwrapped = newValue.value {
if bridge.has_value_std__optional_std__function_void_bool____fullscreen______(newValue) {
let __unwrapped = bridge.get_std__optional_std__function_void_bool____fullscreen______(newValue)
return { () -> (Bool) -> Void in
let __wrappedFunction = bridge.wrap_Func_void_bool(__unwrapped)
return { (__fullscreen: Bool) -> Void in
@@ -270,7 +284,8 @@ open class HybridVideoViewViewManagerSpec_cxx {
@inline(__always)
set {
self.__implementation.willEnterFullscreen = { () -> (() -> Void)? in
if let __unwrapped = newValue.value {
if bridge.has_value_std__optional_std__function_void____(newValue) {
let __unwrapped = bridge.get_std__optional_std__function_void____(newValue)
return { () -> () -> Void in
let __wrappedFunction = bridge.wrap_Func_void(__unwrapped)
return { () -> Void in
@@ -301,7 +316,8 @@ open class HybridVideoViewViewManagerSpec_cxx {
@inline(__always)
set {
self.__implementation.willExitFullscreen = { () -> (() -> Void)? in
if let __unwrapped = newValue.value {
if bridge.has_value_std__optional_std__function_void____(newValue) {
let __unwrapped = bridge.get_std__optional_std__function_void____(newValue)
return { () -> () -> Void in
let __wrappedFunction = bridge.wrap_Func_void(__unwrapped)
return { () -> Void in
@@ -332,7 +348,8 @@ open class HybridVideoViewViewManagerSpec_cxx {
@inline(__always)
set {
self.__implementation.willEnterPictureInPicture = { () -> (() -> Void)? in
if let __unwrapped = newValue.value {
if bridge.has_value_std__optional_std__function_void____(newValue) {
let __unwrapped = bridge.get_std__optional_std__function_void____(newValue)
return { () -> () -> Void in
let __wrappedFunction = bridge.wrap_Func_void(__unwrapped)
return { () -> Void in
@@ -363,7 +380,8 @@ open class HybridVideoViewViewManagerSpec_cxx {
@inline(__always)
set {
self.__implementation.willExitPictureInPicture = { () -> (() -> Void)? in
if let __unwrapped = newValue.value {
if bridge.has_value_std__optional_std__function_void____(newValue) {
let __unwrapped = bridge.get_std__optional_std__function_void____(newValue)
return { () -> () -> Void in
let __wrappedFunction = bridge.wrap_Func_void(__unwrapped)
return { () -> Void in

View File

@@ -77,7 +77,8 @@ public extension NativeDrmParams {
@inline(__always)
get {
return { () -> String? in
if let __unwrapped = self.__type.value {
if bridge.has_value_std__optional_std__string_(self.__type) {
let __unwrapped = bridge.get_std__optional_std__string_(self.__type)
return String(__unwrapped)
} else {
return nil
@@ -100,7 +101,8 @@ public extension NativeDrmParams {
@inline(__always)
get {
return { () -> String? in
if let __unwrapped = self.__licenseUrl.value {
if bridge.has_value_std__optional_std__string_(self.__licenseUrl) {
let __unwrapped = bridge.get_std__optional_std__string_(self.__licenseUrl)
return String(__unwrapped)
} else {
return nil
@@ -123,7 +125,8 @@ public extension NativeDrmParams {
@inline(__always)
get {
return { () -> String? in
if let __unwrapped = self.__certificateUrl.value {
if bridge.has_value_std__optional_std__string_(self.__certificateUrl) {
let __unwrapped = bridge.get_std__optional_std__string_(self.__certificateUrl)
return String(__unwrapped)
} else {
return nil
@@ -146,7 +149,8 @@ public extension NativeDrmParams {
@inline(__always)
get {
return { () -> String? in
if let __unwrapped = self.__contentId.value {
if bridge.has_value_std__optional_std__string_(self.__contentId) {
let __unwrapped = bridge.get_std__optional_std__string_(self.__contentId)
return String(__unwrapped)
} else {
return nil
@@ -169,7 +173,8 @@ public extension NativeDrmParams {
@inline(__always)
get {
return { () -> Dictionary<String, String>? in
if let __unwrapped = self.__licenseHeaders.value {
if bridge.has_value_std__optional_std__unordered_map_std__string__std__string__(self.__licenseHeaders) {
let __unwrapped = bridge.get_std__optional_std__unordered_map_std__string__std__string__(self.__licenseHeaders)
return { () -> Dictionary<String, String> in
var __dictionary = Dictionary<String, String>(minimumCapacity: __unwrapped.size())
let __keys = bridge.get_std__unordered_map_std__string__std__string__keys(__unwrapped)
@@ -223,7 +228,8 @@ public extension NativeDrmParams {
@inline(__always)
get {
return { () -> ((_ payload: OnGetLicensePayload) -> Promise<Promise<String>>)? in
if let __unwrapped = self.__getLicense.value {
if bridge.has_value_std__optional_std__function_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____const_OnGetLicensePayload_____payload______(self.__getLicense) {
let __unwrapped = bridge.get_std__optional_std__function_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____const_OnGetLicensePayload_____payload______(self.__getLicense)
return { () -> (OnGetLicensePayload) -> Promise<Promise<String>> in
let __wrappedFunction = bridge.wrap_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____OnGetLicensePayload(__unwrapped)
return { (__payload: OnGetLicensePayload) -> Promise<Promise<String>> in

View File

@@ -18,16 +18,12 @@ public extension NativeVideoConfig {
/**
* Create a new instance of `NativeVideoConfig`.
*/
init(uri: String, externalSubtitles: [NativeExternalSubtitle]?, drm: NativeDrmParams?, headers: Dictionary<String, String>?, bufferConfig: BufferConfig?, initializeOnCreation: Bool?) {
init(uri: String, externalSubtitles: [NativeExternalSubtitle]?, drm: NativeDrmParams?, headers: Dictionary<String, String>?, bufferConfig: BufferConfig?, metadata: CustomVideoMetadata?, initializeOnCreation: Bool?) {
self.init(std.string(uri), { () -> bridge.std__optional_std__vector_NativeExternalSubtitle__ in
if let __unwrappedValue = externalSubtitles {
return bridge.create_std__optional_std__vector_NativeExternalSubtitle__({ () -> bridge.std__vector_NativeExternalSubtitle_ in
var __vector = bridge.create_std__vector_NativeExternalSubtitle_(__unwrappedValue.count)
for __item in __unwrappedValue {
__vector.push_back(__item)
}
return __vector
}())
return bridge.create_std__optional_std__vector_NativeExternalSubtitle__(__unwrappedValue.withUnsafeBufferPointer { __pointer -> bridge.std__vector_NativeExternalSubtitle_ in
return bridge.copy_std__vector_NativeExternalSubtitle_(__pointer.baseAddress!, __unwrappedValue.count)
})
} else {
return .init()
}
@@ -55,6 +51,12 @@ public extension NativeVideoConfig {
} else {
return .init()
}
}(), { () -> bridge.std__optional_CustomVideoMetadata_ in
if let __unwrappedValue = metadata {
return bridge.create_std__optional_CustomVideoMetadata_(__unwrappedValue)
} else {
return .init()
}
}(), { () -> bridge.std__optional_bool_ in
if let __unwrappedValue = initializeOnCreation {
return bridge.create_std__optional_bool_(__unwrappedValue)
@@ -79,8 +81,13 @@ public extension NativeVideoConfig {
@inline(__always)
get {
return { () -> [NativeExternalSubtitle]? in
if let __unwrapped = self.__externalSubtitles.value {
return __unwrapped.map({ __item in __item })
if bridge.has_value_std__optional_std__vector_NativeExternalSubtitle__(self.__externalSubtitles) {
let __unwrapped = bridge.get_std__optional_std__vector_NativeExternalSubtitle__(self.__externalSubtitles)
return { () -> [NativeExternalSubtitle] in
let __data = bridge.get_data_std__vector_NativeExternalSubtitle_(__unwrapped)
let __size = __unwrapped.size()
return Array(UnsafeBufferPointer(start: __data, count: __size))
}()
} else {
return nil
}
@@ -90,13 +97,9 @@ public extension NativeVideoConfig {
set {
self.__externalSubtitles = { () -> bridge.std__optional_std__vector_NativeExternalSubtitle__ in
if let __unwrappedValue = newValue {
return bridge.create_std__optional_std__vector_NativeExternalSubtitle__({ () -> bridge.std__vector_NativeExternalSubtitle_ in
var __vector = bridge.create_std__vector_NativeExternalSubtitle_(__unwrappedValue.count)
for __item in __unwrappedValue {
__vector.push_back(__item)
}
return __vector
}())
return bridge.create_std__optional_std__vector_NativeExternalSubtitle__(__unwrappedValue.withUnsafeBufferPointer { __pointer -> bridge.std__vector_NativeExternalSubtitle_ in
return bridge.copy_std__vector_NativeExternalSubtitle_(__pointer.baseAddress!, __unwrappedValue.count)
})
} else {
return .init()
}
@@ -107,13 +110,7 @@ public extension NativeVideoConfig {
var drm: NativeDrmParams? {
@inline(__always)
get {
return { () -> NativeDrmParams? in
if let __unwrapped = self.__drm.value {
return __unwrapped
} else {
return nil
}
}()
return self.__drm.value
}
@inline(__always)
set {
@@ -131,7 +128,8 @@ public extension NativeVideoConfig {
@inline(__always)
get {
return { () -> Dictionary<String, String>? in
if let __unwrapped = self.__headers.value {
if bridge.has_value_std__optional_std__unordered_map_std__string__std__string__(self.__headers) {
let __unwrapped = bridge.get_std__optional_std__unordered_map_std__string__std__string__(self.__headers)
return { () -> Dictionary<String, String> in
var __dictionary = Dictionary<String, String>(minimumCapacity: __unwrapped.size())
let __keys = bridge.get_std__unordered_map_std__string__std__string__keys(__unwrapped)
@@ -167,8 +165,25 @@ public extension NativeVideoConfig {
var bufferConfig: BufferConfig? {
@inline(__always)
get {
return { () -> BufferConfig? in
if let __unwrapped = self.__bufferConfig.value {
return self.__bufferConfig.value
}
@inline(__always)
set {
self.__bufferConfig = { () -> bridge.std__optional_BufferConfig_ in
if let __unwrappedValue = newValue {
return bridge.create_std__optional_BufferConfig_(__unwrappedValue)
} else {
return .init()
}
}()
}
}
var metadata: CustomVideoMetadata? {
@inline(__always)
get {
return { () -> CustomVideoMetadata? in
if let __unwrapped = self.__metadata.value {
return __unwrapped
} else {
return nil
@@ -177,9 +192,9 @@ public extension NativeVideoConfig {
}
@inline(__always)
set {
self.__bufferConfig = { () -> bridge.std__optional_BufferConfig_ in
self.__metadata = { () -> bridge.std__optional_CustomVideoMetadata_ in
if let __unwrappedValue = newValue {
return bridge.create_std__optional_BufferConfig_(__unwrappedValue)
return bridge.create_std__optional_CustomVideoMetadata_(__unwrappedValue)
} else {
return .init()
}

View File

@@ -0,0 +1,40 @@
///
/// SurfaceType.swift
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © 2025 Marc Rousavy @ Margelo
///
/**
* Represents the JS union `SurfaceType`, backed by a C++ enum.
*/
public typealias SurfaceType = margelo.nitro.video.SurfaceType
public extension SurfaceType {
/**
* Get a SurfaceType for the given String value, or
* return `nil` if the given value was invalid/unknown.
*/
init?(fromString string: String) {
switch string {
case "surface":
self = .surface
case "texture":
self = .texture
default:
return nil
}
}
/**
* Get the String value this SurfaceType represents.
*/
var stringValue: String {
switch self {
case .surface:
return "surface"
case .texture:
return "texture"
}
}
}

View File

@@ -54,7 +54,8 @@ public extension TextTrack {
@inline(__always)
get {
return { () -> String? in
if let __unwrapped = self.__language.value {
if bridge.has_value_std__optional_std__string_(self.__language) {
let __unwrapped = bridge.get_std__optional_std__string_(self.__language)
return String(__unwrapped)
} else {
return nil

View File

@@ -19,29 +19,25 @@ public extension TimedMetadata {
* Create a new instance of `TimedMetadata`.
*/
init(metadata: [TimedMetadataObject]) {
self.init({ () -> bridge.std__vector_TimedMetadataObject_ in
var __vector = bridge.create_std__vector_TimedMetadataObject_(metadata.count)
for __item in metadata {
__vector.push_back(__item)
}
return __vector
}())
self.init(metadata.withUnsafeBufferPointer { __pointer -> bridge.std__vector_TimedMetadataObject_ in
return bridge.copy_std__vector_TimedMetadataObject_(__pointer.baseAddress!, metadata.count)
})
}
var metadata: [TimedMetadataObject] {
@inline(__always)
get {
return self.__metadata.map({ __item in __item })
return { () -> [TimedMetadataObject] in
let __data = bridge.get_data_std__vector_TimedMetadataObject_(self.__metadata)
let __size = self.__metadata.size()
return Array(UnsafeBufferPointer(start: __data, count: __size))
}()
}
@inline(__always)
set {
self.__metadata = { () -> bridge.std__vector_TimedMetadataObject_ in
var __vector = bridge.create_std__vector_TimedMetadataObject_(newValue.count)
for __item in newValue {
__vector.push_back(__item)
}
return __vector
}()
self.__metadata = newValue.withUnsafeBufferPointer { __pointer -> bridge.std__vector_TimedMetadataObject_ in
return bridge.copy_std__vector_TimedMetadataObject_(__pointer.baseAddress!, newValue.count)
}
}
}
}

View File

@@ -0,0 +1,84 @@
///
/// CustomVideoMetadata.hpp
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © 2025 Marc Rousavy @ Margelo
///
#pragma once
#if __has_include(<NitroModules/JSIConverter.hpp>)
#include <NitroModules/JSIConverter.hpp>
#else
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
#endif
#if __has_include(<NitroModules/NitroDefines.hpp>)
#include <NitroModules/NitroDefines.hpp>
#else
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
#endif
#include <string>
#include <optional>
namespace margelo::nitro::video {
/**
* A struct which can be represented as a JavaScript object (CustomVideoMetadata).
*/
struct CustomVideoMetadata {
public:
std::optional<std::string> title SWIFT_PRIVATE;
std::optional<std::string> subtitle SWIFT_PRIVATE;
std::optional<std::string> description SWIFT_PRIVATE;
std::optional<std::string> artist SWIFT_PRIVATE;
std::optional<std::string> imageUri SWIFT_PRIVATE;
public:
CustomVideoMetadata() = default;
explicit CustomVideoMetadata(std::optional<std::string> title, std::optional<std::string> subtitle, std::optional<std::string> description, std::optional<std::string> artist, std::optional<std::string> imageUri): title(title), subtitle(subtitle), description(description), artist(artist), imageUri(imageUri) {}
};
} // namespace margelo::nitro::video
namespace margelo::nitro {
// C++ CustomVideoMetadata <> JS CustomVideoMetadata (object)
template <>
struct JSIConverter<margelo::nitro::video::CustomVideoMetadata> final {
static inline margelo::nitro::video::CustomVideoMetadata fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
jsi::Object obj = arg.asObject(runtime);
return margelo::nitro::video::CustomVideoMetadata(
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "title")),
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "subtitle")),
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "description")),
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "artist")),
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "imageUri"))
);
}
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::video::CustomVideoMetadata& arg) {
jsi::Object obj(runtime);
obj.setProperty(runtime, "title", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.title));
obj.setProperty(runtime, "subtitle", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.subtitle));
obj.setProperty(runtime, "description", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.description));
obj.setProperty(runtime, "artist", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.artist));
obj.setProperty(runtime, "imageUri", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.imageUri));
return obj;
}
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
if (!value.isObject()) {
return false;
}
jsi::Object obj = value.getObject(runtime);
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "title"))) return false;
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "subtitle"))) return false;
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "description"))) return false;
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "artist"))) return false;
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "imageUri"))) return false;
return true;
}
};
} // namespace margelo::nitro

View File

@@ -16,6 +16,8 @@ namespace margelo::nitro::video {
registerHybrids(this, [](Prototype& prototype) {
prototype.registerHybridGetter("source", &HybridVideoPlayerSpec::getSource);
prototype.registerHybridGetter("eventEmitter", &HybridVideoPlayerSpec::getEventEmitter);
prototype.registerHybridGetter("showNotificationControls", &HybridVideoPlayerSpec::getShowNotificationControls);
prototype.registerHybridSetter("showNotificationControls", &HybridVideoPlayerSpec::setShowNotificationControls);
prototype.registerHybridGetter("status", &HybridVideoPlayerSpec::getStatus);
prototype.registerHybridGetter("duration", &HybridVideoPlayerSpec::getDuration);
prototype.registerHybridGetter("volume", &HybridVideoPlayerSpec::getVolume);

View File

@@ -66,6 +66,8 @@ namespace margelo::nitro::video {
// Properties
virtual std::shared_ptr<HybridVideoPlayerSourceSpec> getSource() = 0;
virtual std::shared_ptr<HybridVideoPlayerEventEmitterSpec> getEventEmitter() = 0;
virtual bool getShowNotificationControls() = 0;
virtual void setShowNotificationControls(bool showNotificationControls) = 0;
virtual VideoPlayerStatus getStatus() = 0;
virtual double getDuration() = 0;
virtual double getVolume() = 0;

View File

@@ -26,6 +26,8 @@ namespace margelo::nitro::video {
prototype.registerHybridSetter("resizeMode", &HybridVideoViewViewManagerSpec::setResizeMode);
prototype.registerHybridGetter("keepScreenAwake", &HybridVideoViewViewManagerSpec::getKeepScreenAwake);
prototype.registerHybridSetter("keepScreenAwake", &HybridVideoViewViewManagerSpec::setKeepScreenAwake);
prototype.registerHybridGetter("surfaceType", &HybridVideoViewViewManagerSpec::getSurfaceType);
prototype.registerHybridSetter("surfaceType", &HybridVideoViewViewManagerSpec::setSurfaceType);
prototype.registerHybridGetter("onPictureInPictureChange", &HybridVideoViewViewManagerSpec::getOnPictureInPictureChange);
prototype.registerHybridSetter("onPictureInPictureChange", &HybridVideoViewViewManagerSpec::setOnPictureInPictureChange);
prototype.registerHybridGetter("onFullscreenChange", &HybridVideoViewViewManagerSpec::getOnFullscreenChange);

View File

@@ -17,11 +17,14 @@
namespace margelo::nitro::video { class HybridVideoPlayerSpec; }
// Forward declaration of `ResizeMode` to properly resolve imports.
namespace margelo::nitro::video { enum class ResizeMode; }
// Forward declaration of `SurfaceType` to properly resolve imports.
namespace margelo::nitro::video { enum class SurfaceType; }
#include <memory>
#include "HybridVideoPlayerSpec.hpp"
#include <optional>
#include "ResizeMode.hpp"
#include "SurfaceType.hpp"
#include <functional>
namespace margelo::nitro::video {
@@ -63,6 +66,8 @@ namespace margelo::nitro::video {
virtual void setResizeMode(ResizeMode resizeMode) = 0;
virtual bool getKeepScreenAwake() = 0;
virtual void setKeepScreenAwake(bool keepScreenAwake) = 0;
virtual SurfaceType getSurfaceType() = 0;
virtual void setSurfaceType(SurfaceType surfaceType) = 0;
virtual std::optional<std::function<void(bool /* isInPictureInPicture */)>> getOnPictureInPictureChange() = 0;
virtual void setOnPictureInPictureChange(const std::optional<std::function<void(bool /* isInPictureInPicture */)>>& onPictureInPictureChange) = 0;
virtual std::optional<std::function<void(bool /* fullscreen */)>> getOnFullscreenChange() = 0;

View File

@@ -24,6 +24,8 @@ namespace margelo::nitro::video { struct NativeExternalSubtitle; }
namespace margelo::nitro::video { struct NativeDrmParams; }
// Forward declaration of `BufferConfig` to properly resolve imports.
namespace margelo::nitro::video { struct BufferConfig; }
// Forward declaration of `CustomVideoMetadata` to properly resolve imports.
namespace margelo::nitro::video { struct CustomVideoMetadata; }
#include <string>
#include "NativeExternalSubtitle.hpp"
@@ -32,6 +34,7 @@ namespace margelo::nitro::video { struct BufferConfig; }
#include "NativeDrmParams.hpp"
#include <unordered_map>
#include "BufferConfig.hpp"
#include "CustomVideoMetadata.hpp"
namespace margelo::nitro::video {
@@ -45,11 +48,12 @@ namespace margelo::nitro::video {
std::optional<NativeDrmParams> drm SWIFT_PRIVATE;
std::optional<std::unordered_map<std::string, std::string>> headers SWIFT_PRIVATE;
std::optional<BufferConfig> bufferConfig SWIFT_PRIVATE;
std::optional<CustomVideoMetadata> metadata SWIFT_PRIVATE;
std::optional<bool> initializeOnCreation SWIFT_PRIVATE;
public:
NativeVideoConfig() = default;
explicit NativeVideoConfig(std::string uri, std::optional<std::vector<NativeExternalSubtitle>> externalSubtitles, std::optional<NativeDrmParams> drm, std::optional<std::unordered_map<std::string, std::string>> headers, std::optional<BufferConfig> bufferConfig, std::optional<bool> initializeOnCreation): uri(uri), externalSubtitles(externalSubtitles), drm(drm), headers(headers), bufferConfig(bufferConfig), initializeOnCreation(initializeOnCreation) {}
explicit NativeVideoConfig(std::string uri, std::optional<std::vector<NativeExternalSubtitle>> externalSubtitles, std::optional<NativeDrmParams> drm, std::optional<std::unordered_map<std::string, std::string>> headers, std::optional<BufferConfig> bufferConfig, std::optional<CustomVideoMetadata> metadata, std::optional<bool> initializeOnCreation): uri(uri), externalSubtitles(externalSubtitles), drm(drm), headers(headers), bufferConfig(bufferConfig), metadata(metadata), initializeOnCreation(initializeOnCreation) {}
};
} // namespace margelo::nitro::video
@@ -67,6 +71,7 @@ namespace margelo::nitro {
JSIConverter<std::optional<margelo::nitro::video::NativeDrmParams>>::fromJSI(runtime, obj.getProperty(runtime, "drm")),
JSIConverter<std::optional<std::unordered_map<std::string, std::string>>>::fromJSI(runtime, obj.getProperty(runtime, "headers")),
JSIConverter<std::optional<margelo::nitro::video::BufferConfig>>::fromJSI(runtime, obj.getProperty(runtime, "bufferConfig")),
JSIConverter<std::optional<margelo::nitro::video::CustomVideoMetadata>>::fromJSI(runtime, obj.getProperty(runtime, "metadata")),
JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, "initializeOnCreation"))
);
}
@@ -77,6 +82,7 @@ namespace margelo::nitro {
obj.setProperty(runtime, "drm", JSIConverter<std::optional<margelo::nitro::video::NativeDrmParams>>::toJSI(runtime, arg.drm));
obj.setProperty(runtime, "headers", JSIConverter<std::optional<std::unordered_map<std::string, std::string>>>::toJSI(runtime, arg.headers));
obj.setProperty(runtime, "bufferConfig", JSIConverter<std::optional<margelo::nitro::video::BufferConfig>>::toJSI(runtime, arg.bufferConfig));
obj.setProperty(runtime, "metadata", JSIConverter<std::optional<margelo::nitro::video::CustomVideoMetadata>>::toJSI(runtime, arg.metadata));
obj.setProperty(runtime, "initializeOnCreation", JSIConverter<std::optional<bool>>::toJSI(runtime, arg.initializeOnCreation));
return obj;
}
@@ -90,6 +96,7 @@ namespace margelo::nitro {
if (!JSIConverter<std::optional<margelo::nitro::video::NativeDrmParams>>::canConvert(runtime, obj.getProperty(runtime, "drm"))) return false;
if (!JSIConverter<std::optional<std::unordered_map<std::string, std::string>>>::canConvert(runtime, obj.getProperty(runtime, "headers"))) return false;
if (!JSIConverter<std::optional<margelo::nitro::video::BufferConfig>>::canConvert(runtime, obj.getProperty(runtime, "bufferConfig"))) return false;
if (!JSIConverter<std::optional<margelo::nitro::video::CustomVideoMetadata>>::canConvert(runtime, obj.getProperty(runtime, "metadata"))) return false;
if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, "initializeOnCreation"))) return false;
return true;
}

View File

@@ -0,0 +1,76 @@
///
/// SurfaceType.hpp
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © 2025 Marc Rousavy @ Margelo
///
#pragma once
#if __has_include(<NitroModules/NitroHash.hpp>)
#include <NitroModules/NitroHash.hpp>
#else
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
#endif
#if __has_include(<NitroModules/JSIConverter.hpp>)
#include <NitroModules/JSIConverter.hpp>
#else
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
#endif
#if __has_include(<NitroModules/NitroDefines.hpp>)
#include <NitroModules/NitroDefines.hpp>
#else
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
#endif
namespace margelo::nitro::video {
/**
* An enum which can be represented as a JavaScript union (SurfaceType).
*/
enum class SurfaceType {
SURFACE SWIFT_NAME(surface) = 0,
TEXTURE SWIFT_NAME(texture) = 1,
} CLOSED_ENUM;
} // namespace margelo::nitro::video
namespace margelo::nitro {
// C++ SurfaceType <> JS SurfaceType (union)
template <>
struct JSIConverter<margelo::nitro::video::SurfaceType> final {
static inline margelo::nitro::video::SurfaceType fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, arg);
switch (hashString(unionValue.c_str(), unionValue.size())) {
case hashString("surface"): return margelo::nitro::video::SurfaceType::SURFACE;
case hashString("texture"): return margelo::nitro::video::SurfaceType::TEXTURE;
default: [[unlikely]]
throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum SurfaceType - invalid value!");
}
}
static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::video::SurfaceType arg) {
switch (arg) {
case margelo::nitro::video::SurfaceType::SURFACE: return JSIConverter<std::string>::toJSI(runtime, "surface");
case margelo::nitro::video::SurfaceType::TEXTURE: return JSIConverter<std::string>::toJSI(runtime, "texture");
default: [[unlikely]]
throw std::invalid_argument("Cannot convert SurfaceType to JS - invalid value: "
+ std::to_string(static_cast<int>(arg)) + "!");
}
}
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
if (!value.isString()) {
return false;
}
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, value);
switch (hashString(unionValue.c_str(), unionValue.size())) {
case hashString("surface"):
case hashString("texture"):
return true;
default:
return false;
}
}
};
} // namespace margelo::nitro

View File

@@ -1,6 +1,6 @@
{
"name": "react-native-video",
"version": "7.0.0-alpha.4",
"version": "7.0.0-alpha.5",
"description": "<Video /> Component for React Native",
"source": "./src/index.tsx",
"main": "./lib/commonjs/index.js",
@@ -52,7 +52,7 @@
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
"prepare": "bun run build",
"build": "bob build",
"specs": "nitro-codegen",
"specs": "nitrogen",
"release": "release-it --preRelease alpha --npm.tag=next"
},
"keywords": [
@@ -75,19 +75,21 @@
},
"devDependencies": {
"@expo/config-plugins": "^10.0.2",
"@react-native/eslint-config": "^0.77.0",
"@types/react": "^18.2.44",
"@types/react-native-web": "^0.19.2",
"del-cli": "^5.1.0",
"eslint": "^8.51.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"nitro-codegen": "^0.28.0",
"nitrogen": "^0.29.0",
"prettier": "^3.0.3",
"react": "18.3.1",
"react-native": "^0.77.0",
"@react-native/eslint-config": "^0.77.0",
"react-native-builder-bob": "^0.40.0",
"react-native-nitro-modules": "^0.28.0",
"typescript": "^5.2.2"
"react-native-nitro-modules": "^0.29.0",
"typescript": "^5.2.2",
"video.js": "^8.23.4"
},
"peerDependencies": {
"react": "*",

View File

@@ -1,27 +1,28 @@
import { Platform } from 'react-native';
import { NitroModules } from 'react-native-nitro-modules';
import { type VideoPlayer as VideoPlayerImpl } from '../spec/nitro/VideoPlayer.nitro';
import type { VideoPlayerSource } from '../spec/nitro/VideoPlayerSource.nitro';
import type { IgnoreSilentSwitchMode } from './types/IgnoreSilentSwitchMode';
import type { MixAudioMode } from './types/MixAudioMode';
import type { TextTrack } from './types/TextTrack';
import type { NoAutocomplete } from './types/Utils';
import type { VideoConfig, VideoSource } from './types/VideoConfig';
import { Platform } from "react-native";
import { NitroModules } from "react-native-nitro-modules";
import type { VideoPlayer as VideoPlayerImpl } from "../spec/nitro/VideoPlayer.nitro";
import type { VideoPlayerSource } from "../spec/nitro/VideoPlayerSource.nitro";
import type { IgnoreSilentSwitchMode } from "./types/IgnoreSilentSwitchMode";
import type { MixAudioMode } from "./types/MixAudioMode";
import type { TextTrack } from "./types/TextTrack";
import type { NoAutocomplete } from "./types/Utils";
import type { VideoConfig, VideoSource } from "./types/VideoConfig";
import {
tryParseNativeVideoError,
VideoRuntimeError,
} from './types/VideoError';
import type { VideoPlayerBase } from './types/VideoPlayerBase';
import type { VideoPlayerStatus } from './types/VideoPlayerStatus';
import { createPlayer } from './utils/playerFactory';
import { createSource } from './utils/sourceFactory';
import { VideoPlayerEvents } from './VideoPlayerEvents';
} from "./types/VideoError";
import type { VideoPlayerBase } from "./types/VideoPlayerBase";
import type { VideoPlayerStatus } from "./types/VideoPlayerStatus";
import { createPlayer } from "./utils/playerFactory";
import { createSource } from "./utils/sourceFactory";
import { VideoPlayerEvents } from "./VideoPlayerEvents";
import type { AudioTrack } from "./types/AudioTrack";
import type { VideoTrack } from "./types/VideoTrack";
import type { QualityLevel } from "./types/QualityLevel";
class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
protected player: VideoPlayerImpl;
public onError?: (error: VideoRuntimeError) => void = undefined;
constructor(source: VideoSource | VideoConfig | VideoPlayerSource) {
const hybridSource = createSource(source);
const player = createPlayer(hybridSource);
@@ -57,8 +58,10 @@ class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
private throwError(error: unknown) {
const parsedError = tryParseNativeVideoError(error);
if (parsedError instanceof VideoRuntimeError && this.onError) {
this.onError(parsedError);
if (
parsedError instanceof VideoRuntimeError &&
this.triggerEvent("onError", parsedError)
) {
// We don't throw errors if onError is provided
return;
}
@@ -153,9 +156,9 @@ class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
}
set ignoreSilentSwitchMode(value: IgnoreSilentSwitchMode) {
if (__DEV__ && !['ios'].includes(Platform.OS)) {
if (__DEV__ && !["ios"].includes(Platform.OS)) {
console.warn(
'ignoreSilentSwitchMode is not supported on this platform, it wont have any effect'
"ignoreSilentSwitchMode is not supported on this platform, it wont have any effect",
);
}
@@ -185,6 +188,14 @@ class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
return this.player.isPlaying;
}
get showNotificationControls(): boolean {
return this.player.showNotificationControls;
}
set showNotificationControls(value: boolean) {
this.player.showNotificationControls = value;
}
async initialize(): Promise<void> {
await this.wrapPromise(this.player.initialize());
@@ -240,12 +251,16 @@ class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
}
async replaceSourceAsync(
source: VideoSource | VideoConfig | NoAutocomplete<VideoPlayerSource> | null
source:
| VideoSource
| VideoConfig
| NoAutocomplete<VideoPlayerSource>
| null,
): Promise<void> {
await this.wrapPromise(
this.player.replaceSourceAsync(
source === null ? null : createSource(source)
)
source === null ? null : createSource(source),
),
);
NitroModules.updateMemorySize(this.player);
@@ -273,6 +288,43 @@ class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
get selectedTrack(): TextTrack | undefined {
return this.player.selectedTrack;
}
// TODO: implement this
getAvailableAudioTracks(): AudioTrack[] {
return [];
}
selectAudioTrack(_: AudioTrack | null): void {}
get selectedAudioTrack(): AudioTrack | undefined {
return undefined;
}
getAvailableVideoTracks(): VideoTrack[] {
return [];
}
selectVideoTrack(_: VideoTrack | null): void {}
get selectedVideoTrack(): VideoTrack | undefined {
return undefined;
}
// quality
getAvailableQualities(): QualityLevel[] {
return [];
}
selectQuality(_: QualityLevel | null): void {}
get currentQuality(): QualityLevel | undefined {
return undefined;
}
get autoQualityEnabled(): boolean {
return true;
}
}
export { VideoPlayer };

View File

@@ -0,0 +1,413 @@
import videojs from "video.js";
import type { VideoPlayerSource } from "../spec/nitro/VideoPlayerSource.nitro";
import type { AudioTrack } from "./types/AudioTrack";
import type { IgnoreSilentSwitchMode } from "./types/IgnoreSilentSwitchMode";
import type { MixAudioMode } from "./types/MixAudioMode";
import type { TextTrack } from "./types/TextTrack";
import type { NoAutocomplete } from "./types/Utils";
import type {
NativeVideoConfig,
VideoConfig,
VideoSource,
} from "./types/VideoConfig";
import type { VideoPlayerBase } from "./types/VideoPlayerBase";
import type { VideoPlayerSourceBase } from "./types/VideoPlayerSourceBase";
import type { VideoPlayerStatus } from "./types/VideoPlayerStatus";
import { VideoPlayerEvents } from "./VideoPlayerEvents";
import { MediaSessionHandler } from "./web/MediaSession";
import { WebEventEmiter } from "./web/WebEventEmiter";
import type { VideoTrack } from "./types/VideoTrack";
import type { QualityLevel } from "./types/QualityLevel";
type VideoJsPlayer = ReturnType<typeof videojs>;
// declared https://github.com/videojs/video.js/blob/main/src/js/tracks/track-list.js#L58
export type VideoJsTextTracks = {
length: number;
[i: number]: {
// declared: https://github.com/videojs/video.js/blob/main/src/js/tracks/track.js
id: string;
label: string;
language: string;
// declared https://github.com/videojs/video.js/blob/20f8d76cd24325a97ccedf0b013cd1a90ad0bcd7/src/js/tracks/text-track.js
default: boolean;
mode: "showing" | "disabled" | "hidden";
};
};
export type VideoJsTracks = {
length: number;
[i: number]: {
id: string;
label: string;
language: string;
enabled: boolean;
};
};
// declared https://github.com/videojs/videojs-contrib-quality-levels/blob/main/src/quality-level.js#L32
export type VideoJsQualityArray = {
length: number;
selectedIndex: number;
[i: number]: {
id: string;
label: string;
width: number;
height: number;
bitrate: number;
frameRate: number;
enabled: boolean;
};
};
class VideoPlayer extends VideoPlayerEvents implements VideoPlayerBase {
protected video: HTMLVideoElement;
public player: VideoJsPlayer;
private mediaSession: MediaSessionHandler;
private _source: NativeVideoConfig | undefined;
constructor(source: VideoSource | VideoConfig | VideoPlayerSource) {
const video = document.createElement("video");
const player = videojs(video, { qualityLevels: true });
super(new WebEventEmiter(player));
this.video = video;
this.player = player;
this.mediaSession = new MediaSessionHandler(this.player);
this.replaceSourceAsync(source);
}
/**
* Cleans up player's native resources and releases native state.
* After calling this method, the player is no longer usable.
* @internal
*/
__destroy() {
this.player.dispose();
}
__getNativeRef() {
return this.video;
}
// Source
get source(): VideoPlayerSourceBase {
return {
uri: this._source?.uri!,
config: this._source!,
getAssetInformationAsync: async () => {
return {
bitrate: NaN,
width: this.player.videoWidth(),
height: this.player.videoHeight(),
duration: BigInt(this.duration),
fileSize: BigInt(NaN),
isHDR: false,
isLive: false,
orientation: "landscape",
};
},
};
}
// Status
get status(): VideoPlayerStatus {
if (this.video.error) return "error";
if (this.video.readyState === HTMLMediaElement.HAVE_NOTHING) return "idle";
if (
this.video.readyState === HTMLMediaElement.HAVE_ENOUGH_DATA ||
this.video.readyState === HTMLMediaElement.HAVE_FUTURE_DATA
)
return "readyToPlay";
return "loading";
}
// Duration
get duration(): number {
return this.player.duration() ?? NaN;
}
// Volume
get volume(): number {
return this.player.volume() ?? 1;
}
set volume(value: number) {
this.player.volume(value);
}
// Current Time
get currentTime(): number {
return this.player.currentTime() ?? NaN;
}
set currentTime(value: number) {
this.player.currentTime(value);
}
// Muted
get muted(): boolean {
return this.player.muted() ?? false;
}
set muted(value: boolean) {
this.player.muted(value);
}
// Loop
get loop(): boolean {
return this.player.loop() ?? false;
}
set loop(value: boolean) {
this.player.loop(value);
}
// Rate
get rate(): number {
return this.player.playbackRate() ?? 1;
}
set rate(value: number) {
this.player.playbackRate(value);
}
// Mix Audio Mode
get mixAudioMode(): MixAudioMode {
return "auto";
}
set mixAudioMode(_: MixAudioMode) {}
// Ignore Silent Switch Mode
get ignoreSilentSwitchMode(): IgnoreSilentSwitchMode {
return "auto";
}
set ignoreSilentSwitchMode(_: IgnoreSilentSwitchMode) {}
// Play In Background
get playInBackground(): boolean {
return true;
}
set playInBackground(_: boolean) {}
// Play When Inactive
get playWhenInactive(): boolean {
return true;
}
set playWhenInactive(_: boolean) {}
get isPlaying(): boolean {
return !this.player.paused();
}
get showNotificationControls(): boolean {
return this.mediaSession.enabled;
}
set showNotificationControls(value: boolean) {
if (!value) {
this.mediaSession.disable();
return;
}
this.mediaSession.enable();
this.mediaSession.updateMediaSession(this._source?.metadata);
}
async initialize(): Promise<void> {
// noop on web
}
async preload(): Promise<void> {
this.player.load();
}
/**
* Releases the player's native resources and releases native state.
* After calling this method, the player is no longer usable.
* Accessing any properties or methods of the player after calling this method will throw an error.
* If you want to clean player resource use `replaceSourceAsync` with `null` instead.
*/
release(): void {
this.__destroy();
}
play(): void {
// error are already handled by the `onError` callback, no need to catch it here.
this.player.play()?.catch();
}
pause(): void {
this.player.pause();
}
seekBy(time: number): void {
const now = this.player.currentTime() ?? 0;
this.player.currentTime(now + time);
}
seekTo(time: number): void {
this.player.currentTime(time);
}
async replaceSourceAsync(
source:
| VideoSource
| VideoConfig
| NoAutocomplete<VideoPlayerSource>
| null,
): Promise<void> {
if (!source) {
this.player.src([]);
this.player.reset();
return;
}
if (typeof source === "string") {
source = { uri: source };
}
if (typeof source === "number" || typeof source.uri === "number") {
console.error(
"A source uri must be a string. Numbers are only supported on native.",
);
return;
}
this._source = source as VideoPlayerSource;
// TODO: handle start time
this.player.src({
src: source.uri,
type: source.mimeType,
});
if (this.mediaSession.enabled)
this.mediaSession.updateMediaSession(source.metadata);
if (source.initializeOnCreation) await this.preload();
}
// Text Track Management
getAvailableTextTracks(): TextTrack[] {
// @ts-expect-error they define length & index properties via prototype
const tracks: VideoJsTextTracks = this.player.textTracks();
return [...Array(tracks.length)].map((_, i) => ({
id: tracks[i]!.id,
label: tracks[i]!.label,
language: tracks[i]!.language,
selected: tracks[i]!.mode === "showing",
}));
}
selectTextTrack(textTrack: TextTrack | null): void {
// @ts-expect-error they define length & index properties via prototype
const tracks: VideoJsTextTracks = this.player.textTracks();
for (let i = 0; i < tracks.length; i++) {
if (tracks[i]!.mode === "showing") tracks[i]!.mode = "disabled";
if (tracks[i]!.id === textTrack?.id) tracks[i]!.mode = "showing";
}
}
// Selected Text Track
get selectedTrack(): TextTrack | undefined {
return this.getAvailableTextTracks().find((x) => x.selected);
}
// audio tracks
getAvailableAudioTracks(): AudioTrack[] {
// @ts-expect-error they define length & index properties via prototype
const tracks: VideoJsTracks = this.player.audioTracks();
return [...Array(tracks.length)].map((_, i) => ({
id: tracks[i]!.id,
label: tracks[i]!.label,
language: tracks[i]!.language,
selected: tracks[i]!.enabled,
}));
}
selectAudioTrack(track: AudioTrack | null): void {
// @ts-expect-error they define length & index properties via prototype
const tracks: VideoJsTracks = this.player.audioTracks();
for (let i = 0; i < tracks.length; i++) {
tracks[i]!.enabled = tracks[i]!.id === track?.id;
}
}
get selectedAudioTrack(): AudioTrack | undefined {
return this.getAvailableAudioTracks().find((x) => x.selected);
}
// video tracks
getAvailableVideoTracks(): VideoTrack[] {
// @ts-expect-error they define length & index properties via prototype
const tracks: VideoJsTracks = this.player.videoTracks();
return [...Array(tracks.length)].map((_, i) => ({
id: tracks[i]!.id,
label: tracks[i]!.label,
language: tracks[i]!.language,
selected: tracks[i]!.enabled,
}));
}
selectVideoTrack(track: VideoTrack | null): void {
// @ts-expect-error they define length & index properties via prototype
const tracks: VideoJsTracks = this.player.videoTracks();
for (let i = 0; i < tracks.length; i++) {
tracks[i]!.enabled = tracks[i]!.id === track?.id;
}
}
get selectedVideoTrack(): VideoTrack | undefined {
return this.getAvailableVideoTracks().find((x) => x.selected);
}
// quality
getAvailableQualities(): QualityLevel[] {
// @ts-expect-error this isn't typed
const levels: VideoJsQualityArray = this.player.qualityLevels();
return [...Array(levels.length)].map((_, i) => ({
id: levels[i]!.id,
width: levels[i]!.width,
height: levels[i]!.height,
bitrate: levels[i]!.bitrate,
selected: levels.selectedIndex === i,
}));
}
selectQuality(quality: QualityLevel | null): void {
// @ts-expect-error this isn't typed
const levels: VideoJsQualityArray = this.player.qualityLevels();
for (let i = 0; i < levels.length; i++) {
// if quality is null, enable back auto-quality switch (so enable all lvls)
levels[i]!.enabled = !quality || levels[i]!.id === quality.id;
}
}
get currentQuality(): QualityLevel | undefined {
return this.getAvailableQualities().find((x) => x.selected);
}
get autoQualityEnabled(): boolean {
// @ts-expect-error this isn't typed
const levels: VideoJsQualityArray = this.player.qualityLevels();
// if we have a quality disabled that means we manually disabled it & disabled auto quality
for (let i = 0; i < levels.length; i++) {
if (!levels[i]!.enabled) return false;
}
return true;
}
}
export { VideoPlayer };

View File

@@ -1,33 +1,50 @@
import type { VideoPlayerEventEmitter } from '../spec/nitro/VideoPlayerEventEmitter.nitro';
import type { VideoPlayerEvents as VideoPlayerEventsInterface } from './types/Events';
import {
ALL_PLAYER_EVENTS,
type VideoPlayerEvents as NativePlayerEvents,
type AllPlayerEvents as PlayerEvents,
} from "./types/Events";
export class VideoPlayerEvents implements VideoPlayerEventsInterface {
protected eventEmitter: VideoPlayerEventEmitter;
export class VideoPlayerEvents {
protected eventEmitter: NativePlayerEvents;
protected eventListeners: Partial<
Record<keyof PlayerEvents, Set<(...params: any[]) => void>>
> = {};
protected readonly supportedEvents: (keyof VideoPlayerEventsInterface)[] = [
'onAudioBecomingNoisy',
'onAudioFocusChange',
'onBandwidthUpdate',
'onBuffer',
'onControlsVisibleChange',
'onEnd',
'onExternalPlaybackChange',
'onLoad',
'onLoadStart',
'onPlaybackRateChange',
'onPlaybackStateChange',
'onProgress',
'onReadyToDisplay',
'onSeek',
'onStatusChange',
'onTextTrackDataChanged',
'onTimedMetadata',
'onTrackChange',
'onVolumeChange',
];
protected readonly supportedEvents: (keyof PlayerEvents)[] =
ALL_PLAYER_EVENTS;
constructor(eventEmitter: VideoPlayerEventEmitter) {
constructor(eventEmitter: NativePlayerEvents) {
this.eventEmitter = eventEmitter;
for (const event of this.supportedEvents) {
// @ts-expect-error we narrow the type of the event
this.eventEmitter[event] = this.triggerEvent.bind(this, event);
}
}
protected triggerEvent<Event extends keyof PlayerEvents>(
event: Event,
...params: Parameters<PlayerEvents[Event]>
): boolean {
if (!this.eventListeners[event]?.size) return false;
for (const fn of this.eventListeners[event]) {
fn(...params);
}
return true;
}
addEventListener<Event extends keyof PlayerEvents>(
event: Event,
callback: PlayerEvents[Event],
) {
this.eventListeners[event] ??= new Set<PlayerEvents[Event]>();
this.eventListeners[event].add(callback);
}
removeEventListener<Event extends keyof PlayerEvents>(
event: Event,
callback: PlayerEvents[Event],
) {
this.eventListeners[event]?.delete(callback);
}
/**
@@ -43,177 +60,7 @@ export class VideoPlayerEvents implements VideoPlayerEventsInterface {
* Clears a specific event from the event emitter.
* @param event - The name of the event to clear.
*/
clearEvent(event: keyof VideoPlayerEventsInterface) {
this.eventEmitter[event] = VideoPlayerEvents.NOOP;
}
static NOOP = () => {};
set onAudioBecomingNoisy(
value: VideoPlayerEventsInterface['onAudioBecomingNoisy']
) {
this.eventEmitter.onAudioBecomingNoisy = value;
}
get onAudioBecomingNoisy(): VideoPlayerEventsInterface['onAudioBecomingNoisy'] {
return this.eventEmitter.onAudioBecomingNoisy;
}
set onAudioFocusChange(
value: VideoPlayerEventsInterface['onAudioFocusChange']
) {
this.eventEmitter.onAudioFocusChange = value;
}
get onAudioFocusChange(): VideoPlayerEventsInterface['onAudioFocusChange'] {
return this.eventEmitter.onAudioFocusChange;
}
set onBandwidthUpdate(
value: VideoPlayerEventsInterface['onBandwidthUpdate']
) {
this.eventEmitter.onBandwidthUpdate = value;
}
get onBandwidthUpdate(): VideoPlayerEventsInterface['onBandwidthUpdate'] {
return this.eventEmitter.onBandwidthUpdate;
}
set onBuffer(value: VideoPlayerEventsInterface['onBuffer']) {
this.eventEmitter.onBuffer = value;
}
get onBuffer(): VideoPlayerEventsInterface['onBuffer'] {
return this.eventEmitter.onBuffer;
}
set onControlsVisibleChange(
value: VideoPlayerEventsInterface['onControlsVisibleChange']
) {
this.eventEmitter.onControlsVisibleChange = value;
}
get onControlsVisibleChange(): VideoPlayerEventsInterface['onControlsVisibleChange'] {
return this.eventEmitter.onControlsVisibleChange;
}
set onEnd(value: VideoPlayerEventsInterface['onEnd']) {
this.eventEmitter.onEnd = value;
}
get onEnd(): VideoPlayerEventsInterface['onEnd'] {
return this.eventEmitter.onEnd;
}
set onExternalPlaybackChange(
value: VideoPlayerEventsInterface['onExternalPlaybackChange']
) {
this.eventEmitter.onExternalPlaybackChange = value;
}
get onExternalPlaybackChange(): VideoPlayerEventsInterface['onExternalPlaybackChange'] {
return this.eventEmitter.onExternalPlaybackChange;
}
set onLoad(value: VideoPlayerEventsInterface['onLoad']) {
this.eventEmitter.onLoad = value;
}
get onLoad(): VideoPlayerEventsInterface['onLoad'] {
return this.eventEmitter.onLoad;
}
set onLoadStart(value: VideoPlayerEventsInterface['onLoadStart']) {
this.eventEmitter.onLoadStart = value;
}
get onLoadStart(): VideoPlayerEventsInterface['onLoadStart'] {
return this.eventEmitter.onLoadStart;
}
set onPlaybackStateChange(
value: VideoPlayerEventsInterface['onPlaybackStateChange']
) {
this.eventEmitter.onPlaybackStateChange = value;
}
get onPlaybackStateChange(): VideoPlayerEventsInterface['onPlaybackStateChange'] {
return this.eventEmitter.onPlaybackStateChange;
}
set onPlaybackRateChange(
value: VideoPlayerEventsInterface['onPlaybackRateChange']
) {
this.eventEmitter.onPlaybackRateChange = value;
}
get onPlaybackRateChange(): VideoPlayerEventsInterface['onPlaybackRateChange'] {
return this.eventEmitter.onPlaybackRateChange;
}
set onProgress(value: VideoPlayerEventsInterface['onProgress']) {
this.eventEmitter.onProgress = value;
}
get onProgress(): VideoPlayerEventsInterface['onProgress'] {
return this.eventEmitter.onProgress;
}
set onReadyToDisplay(value: VideoPlayerEventsInterface['onReadyToDisplay']) {
this.eventEmitter.onReadyToDisplay = value;
}
get onReadyToDisplay(): VideoPlayerEventsInterface['onReadyToDisplay'] {
return this.eventEmitter.onReadyToDisplay;
}
set onSeek(value: VideoPlayerEventsInterface['onSeek']) {
this.eventEmitter.onSeek = value;
}
get onSeek(): VideoPlayerEventsInterface['onSeek'] {
return this.eventEmitter.onSeek;
}
set onStatusChange(value: VideoPlayerEventsInterface['onStatusChange']) {
this.eventEmitter.onStatusChange = value;
}
get onStatusChange(): VideoPlayerEventsInterface['onStatusChange'] {
return this.eventEmitter.onStatusChange;
}
set onTimedMetadata(value: VideoPlayerEventsInterface['onTimedMetadata']) {
this.eventEmitter.onTimedMetadata = value;
}
get onTimedMetadata(): VideoPlayerEventsInterface['onTimedMetadata'] {
return this.eventEmitter.onTimedMetadata;
}
set onTextTrackDataChanged(
value: VideoPlayerEventsInterface['onTextTrackDataChanged']
) {
this.eventEmitter.onTextTrackDataChanged = value;
}
get onTextTrackDataChanged(): VideoPlayerEventsInterface['onTextTrackDataChanged'] {
return this.eventEmitter.onTextTrackDataChanged;
}
set onTrackChange(value: VideoPlayerEventsInterface['onTrackChange']) {
this.eventEmitter.onTrackChange = value;
}
get onTrackChange(): VideoPlayerEventsInterface['onTrackChange'] {
return this.eventEmitter.onTrackChange;
}
set onVolumeChange(value: VideoPlayerEventsInterface['onVolumeChange']) {
this.eventEmitter.onVolumeChange = value;
}
get onVolumeChange(): VideoPlayerEventsInterface['onVolumeChange'] {
return this.eventEmitter.onVolumeChange;
clearEvent(event: keyof PlayerEvents) {
this.eventListeners[event]?.clear();
}
}

View File

@@ -1,19 +1,6 @@
import { useEffect } from 'react';
import { VideoPlayer } from '../VideoPlayer';
import { type VideoPlayerEvents } from '../types/Events';
// Omit undefined from events
type NonUndefined<T> = T extends undefined ? never : T;
// Valid events names
type Events = keyof VideoPlayerEvents | 'onError';
// Valid events params
type EventsParams<T extends Events> = T extends keyof VideoPlayerEvents
? // (Native) Events from VideoPlayerEvents
Parameters<VideoPlayerEvents[T]>
: // (JS) Events from Video Player
Parameters<NonUndefined<VideoPlayer[T]>>;
import type { AllPlayerEvents } from '../types/Events';
import type { VideoPlayer } from '../VideoPlayer';
/**
* Attaches an event listener to a `VideoPlayer` instance for a specified event.
@@ -22,22 +9,14 @@ type EventsParams<T extends Events> = T extends keyof VideoPlayerEvents
* @param event - The name of the event to attach the callback to
* @param callback - The callback for the event
*/
export const useEvent = <T extends Events>(
export const useEvent = <T extends keyof AllPlayerEvents>(
player: VideoPlayer,
event: T,
callback: (...args: EventsParams<T>) => void
callback: AllPlayerEvents[T]
) => {
useEffect(() => {
// @ts-expect-error we narrow the type of the event
player[event] = callback;
player.addEventListener(event, callback);
return () => {
if (event === 'onError') {
// onError is not native event, so we can set it to undefined
player.onError = undefined;
} else {
player.clearEvent(event);
}
};
return () => player.removeEventListener(event, callback);
}, [player, event, callback]);
};

View File

@@ -1,7 +1,7 @@
import type { VideoPlayerSource } from '../../spec/nitro/VideoPlayerSource.nitro';
import type { NoAutocomplete } from '../types/Utils';
import type { VideoConfig, VideoSource } from '../types/VideoConfig';
import { isVideoPlayerSource } from '../utils/sourceFactory';
import { isVideoPlayerSource } from '../utils/sourceUtils';
import { VideoPlayer } from '../VideoPlayer';
import { useManagedInstance } from './useManagedInstance';

View File

@@ -0,0 +1,22 @@
export interface AudioTrack {
/**
* Unique identifier for the audio track
*/
id: string;
/**
* Display label for the audio track
*/
label: string;
/**
* Language code (ISO 639-1 or ISO 639-2)
* @example "en", "es", "fr"
*/
language?: string;
/**
* Whether this track is currently selected
*/
selected: boolean;
}

View File

@@ -1,7 +1,11 @@
import type { VideoPlayerSource } from '../../spec/nitro/VideoPlayerSource.nitro';
import type { AudioTrack } from './AudioTrack';
import type { QualityLevel } from './QualityLevel';
import type { TextTrack } from './TextTrack';
import type { VideoRuntimeError } from './VideoError';
import type { VideoOrientation } from './VideoOrientation';
import type { VideoPlayerSourceBase } from './VideoPlayerSourceBase';
import type { VideoPlayerStatus } from './VideoPlayerStatus';
import type { VideoTrack } from './VideoTrack';
export interface VideoPlayerEvents {
/**
@@ -15,6 +19,11 @@ export interface VideoPlayerEvents {
* @platform Android
*/
onAudioFocusChange: (hasAudioFocus: boolean) => void;
/**
* Called when the audio track changes
* @param track The new audio track
*/
onAudioTrackChange: (track: AudioTrack | null) => void;
/**
* Called when the bandwidth of the video changes.
*/
@@ -27,6 +36,7 @@ export interface VideoPlayerEvents {
/**
* Called when the video view's controls visibility changes.
* @param visible Whether the video view's controls are visible.
* @platform Android, Ios
*/
onControlsVisibleChange: (visible: boolean) => void;
/**
@@ -61,6 +71,10 @@ export interface VideoPlayerEvents {
* Called when the player progress changes.
*/
onProgress: (data: onProgressData) => void;
/**
* Called when the player quality changes.
*/
onQualityChange: (quality: QualityLevel) => void;
/**
* Called when the video is ready to display.
*/
@@ -71,15 +85,18 @@ export interface VideoPlayerEvents {
onSeek: (seekTime: number) => void;
/**
* Called when player receives timed metadata.
* @platform Android, Ios
*/
onTimedMetadata: (metadata: TimedMetadata) => void;
/**
* Called when the text track (currently displayed subtitle) data changes.
* @platform Android, Ios
*/
onTextTrackDataChanged: (texts: string[]) => void;
/**
* Called when the selected text track changes.
* @param track - The newly selected text track, or null if no track is selected
* @platform Android, Ios
*/
onTrackChange: (track: TextTrack | null) => void;
/**
@@ -90,6 +107,15 @@ export interface VideoPlayerEvents {
* Called when the player status changes.
*/
onStatusChange: (status: VideoPlayerStatus) => void;
/**
* Called when the video track changes
* @param track The new video track
*/
onVideoTrackChange: (track: VideoTrack | null) => void;
}
export interface AllPlayerEvents extends VideoPlayerEvents {
onError: (error: VideoRuntimeError) => void;
}
export interface VideoViewEvents {
@@ -173,7 +199,7 @@ export interface onLoadStartData {
/**
* The source of the video.
*/
source: VideoPlayerSource;
source: VideoPlayerSourceBase;
}
export interface onPlaybackStateChangeData {
@@ -220,3 +246,45 @@ export interface onVolumeChangeData {
*/
muted: boolean;
}
type CheckAllAndOnly<T, A extends readonly (keyof T)[]> =
// Missing keys?
Exclude<keyof T, A[number]> extends never
? // Extra keys?
Exclude<A[number], keyof T> extends never
? A
: ['Extra keys', Exclude<A[number], keyof T>]
: ['Missing keys', Exclude<keyof T, A[number]>];
function allKeysOf<T>() {
return <A extends readonly (keyof T)[]>(...arr: A): CheckAllAndOnly<T, A> => {
return arr as CheckAllAndOnly<T, A>;
};
}
export const ALL_PLAYER_EVENTS: (keyof AllPlayerEvents)[] =
allKeysOf<AllPlayerEvents>()(
'onAudioBecomingNoisy',
'onAudioFocusChange',
'onAudioTrackChange',
'onBandwidthUpdate',
'onBuffer',
'onControlsVisibleChange',
'onEnd',
'onError',
'onExternalPlaybackChange',
'onLoad',
'onLoadStart',
'onPlaybackStateChange',
'onPlaybackRateChange',
'onProgress',
'onQualityChange',
'onReadyToDisplay',
'onSeek',
'onTimedMetadata',
'onTextTrackDataChanged',
'onTrackChange',
'onVolumeChange',
'onVideoTrackChange',
'onStatusChange'
);

View File

@@ -0,0 +1,26 @@
export interface QualityLevel {
/**
* Unique identifier for the quality
*/
id: string;
/**
* Width of the quality
*/
width: number;
/**
* Height of the quality
*/
height: number;
/**
* Bitrate of the quality
*/
bitrate: number;
/**
* Whether this quality is currently selected
*/
selected: boolean;
}

View File

@@ -14,6 +14,11 @@ export type VideoConfig = {
* ```
*/
uri: VideoSource;
/**
* complete mime type, used to select a background for playback.
* if not specified, the extension of the url might be used
*/
mimeType?: string
/**
* The headers to be sent with the request.
*/
@@ -26,6 +31,11 @@ export type VideoConfig = {
* The player buffer configuration.
*/
bufferConfig?: BufferConfig;
/**
* The custom metadata to be associated with the video.
* This metadata can be used by the native player to show information about the video.
*/
metadata?: CustomVideoMetadata;
/**
* The external subtitles to be used.
* @note on iOS, only WebVTT (.vtt) subtitles are supported (for HLS streams and MP4 files).
@@ -135,3 +145,11 @@ interface NativeExternalSubtitle {
interface NativeDrmParams extends DrmParams {
type?: string;
}
export interface CustomVideoMetadata {
title?: string;
subtitle?: string;
description?: string;
artist?: string;
imageUri?: string;
}

View File

@@ -0,0 +1,22 @@
export interface VideoTrack {
/**
* Unique identifier for the video track
*/
id: string;
/**
* Display label for the video track
*/
label: string;
/**
* Language code (ISO 639-1 or ISO 639-2)
* @example "en", "es", "fr"
*/
language?: string;
/**
* Whether this track is currently selected
*/
selected: boolean;
}

View File

@@ -5,8 +5,9 @@ import type {
} from '../../spec/nitro/VideoPlayer.nitro';
import type { VideoPlayerSource } from '../../spec/nitro/VideoPlayerSource.nitro';
import type { VideoConfig, VideoSource } from '../types/VideoConfig';
import { createSource, isVideoPlayerSource } from './sourceFactory';
import { createSource } from './sourceFactory';
import { tryParseNativeVideoError } from '../types/VideoError';
import { isVideoPlayerSource } from './sourceUtils';
const VideoPlayerFactory =
NitroModules.createHybridObject<VideoPlayerFactory>('VideoPlayerFactory');

View File

@@ -12,21 +12,13 @@ import type {
VideoSource,
} from '../types/VideoConfig';
import { tryParseNativeVideoError } from '../types/VideoError';
import { isVideoPlayerSource } from './sourceUtils';
const VideoPlayerSourceFactory =
NitroModules.createHybridObject<VideoPlayerSourceFactory>(
'VideoPlayerSourceFactory'
);
export const isVideoPlayerSource = (obj: any): obj is VideoPlayerSource => {
return (
obj && // obj is not null
typeof obj === 'object' && // obj is an object
'name' in obj && // obj has a name property
obj.name === 'VideoPlayerSource' // obj.name is 'VideoPlayerSource'
);
};
/**
* Creates a `VideoPlayerSource` instance from a URI (string).
*

View File

@@ -0,0 +1,11 @@
import type { VideoPlayerSource } from "../../spec/nitro/VideoPlayerSource.nitro";
export const isVideoPlayerSource = (obj: any): obj is VideoPlayerSource => {
return (
obj && // obj is not null
typeof obj === 'object' && // obj is an object
'name' in obj && // obj has a name property
obj.name === 'VideoPlayerSource' // obj.name is 'VideoPlayerSource'
);
};

View File

@@ -1,74 +1,14 @@
import * as React from 'react';
import type { ViewProps, ViewStyle } from 'react-native';
import type { ViewStyle } from 'react-native';
import { NitroModules } from 'react-native-nitro-modules';
import type {
VideoViewViewManager,
VideoViewViewManagerFactory,
} from '../../spec/nitro/VideoViewViewManager.nitro';
import type { VideoViewEvents } from '../types/Events';
import type { ResizeMode } from '../types/ResizeMode';
import { tryParseNativeVideoError, VideoError } from '../types/VideoError';
import type { VideoPlayer } from '../VideoPlayer';
import { NativeVideoView } from './NativeVideoView';
export interface VideoViewProps extends Partial<VideoViewEvents>, ViewProps {
/**
* The player to play the video - {@link VideoPlayer}
*/
player: VideoPlayer;
/**
* The style of the video view - {@link ViewStyle}
*/
style?: ViewStyle;
/**
* Whether to show the controls. Defaults to false.
*/
controls?: boolean;
/**
* Whether to enable & show the picture in picture button in native controls. Defaults to false.
*/
pictureInPicture?: boolean;
/**
* Whether to automatically enter picture in picture mode when the video is playing. Defaults to false.
*/
autoEnterPictureInPicture?: boolean;
/**
* How the video should be resized to fit the view. Defaults to 'none'.
* - 'contain': Scale the video uniformly (maintain aspect ratio) so that it fits entirely within the view
* - 'cover': Scale the video uniformly (maintain aspect ratio) so that it fills the entire view (may crop)
* - 'stretch': Scale the video to fill the entire view without maintaining aspect ratio
* - 'none': Do not resize the video
*/
resizeMode?: ResizeMode;
/**
* Whether to keep the screen awake while the video view is mounted. Defaults to true.
*/
keepScreenAwake?: boolean;
}
export interface VideoViewRef {
/**
* Enter fullscreen mode
*/
enterFullscreen: () => void;
/**
* Exit fullscreen mode
*/
exitFullscreen: () => void;
/**
* Enter picture in picture mode
*/
enterPictureInPicture: () => void;
/**
* Exit picture in picture mode
*/
exitPictureInPicture: () => void;
/**
* Check if picture in picture mode is supported
* @returns true if picture in picture mode is supported, false otherwise
*/
canEnterPictureInPicture: () => boolean;
}
import type { VideoViewProps, VideoViewRef } from './ViewViewProps';
let nitroIdCounter = 1;
const VideoViewViewManagerFactory =
@@ -104,6 +44,7 @@ const updateProps = (manager: VideoViewViewManager, props: VideoViewProps) => {
manager.willEnterPictureInPicture = props.willEnterPictureInPicture;
manager.willExitPictureInPicture = props.willExitPictureInPicture;
manager.keepScreenAwake = props.keepScreenAwake ?? true;
manager.surfaceType = props.surfaceType ?? 'surface';
};
/**

View File

@@ -0,0 +1,93 @@
import {
forwardRef,
memo,
useEffect,
useImperativeHandle,
useRef,
type CSSProperties,
} from "react";
import { View, type ViewStyle } from "react-native";
import type { VideoPlayer } from "../VideoPlayer.web";
import type { VideoViewProps, VideoViewRef } from "./ViewViewProps";
/**
* VideoView is a component that allows you to display a video from a {@link VideoPlayer}.
*
* @param player - The player to play the video - {@link VideoPlayer}
* @param controls - Whether to show the controls. Defaults to false.
* @param style - The style of the video view - {@link ViewStyle}
* @param pictureInPicture - Whether to show the picture in picture button. Defaults to false.
* @param autoEnterPictureInPicture - Whether to automatically enter picture in picture mode
* when the video is playing. Defaults to false.
* @param resizeMode - How the video should be resized to fit the view. Defaults to 'none'.
*/
const VideoView = forwardRef<VideoViewRef, VideoViewProps>(
(
{
player: nPlayer,
controls = false,
resizeMode = "none",
// auto pip is unsupported
pictureInPicture = false,
autoEnterPictureInPicture = false,
keepScreenAwake = true,
...props
},
ref,
) => {
const player = nPlayer as unknown as VideoPlayer;
const vRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const videoElement = player.__getNativeRef();
vRef.current?.appendChild(videoElement);
return () => vRef.current?.replaceChildren();
}, [player]);
useImperativeHandle(
ref,
() => ({
enterFullscreen: () => {
player.player.requestFullscreen({ navigationUI: "hide" });
},
exitFullscreen: () => {
document.exitFullscreen();
},
enterPictureInPicture: () => {
player.player.requestPictureInPicture();
},
exitPictureInPicture: () => {
document.exitPictureInPicture();
},
canEnterPictureInPicture: () => document.pictureInPictureEnabled,
}),
[player],
);
useEffect(() => {
player.player.controls(controls);
}, [player, controls]);
useEffect(() => {
const vid = player.__getNativeRef();
const objectFit: CSSProperties["objectFit"] =
resizeMode === "stretch" ? "fill" : resizeMode;
vid.style = `position: absolute; inset: 0; width: 100%; height: 100%; object-fit: ${objectFit}`;
}, [player, resizeMode]);
return (
<View {...props}>
<div
ref={vRef}
style={{
position: "absolute",
inset: 0
}}
/>
</View>
);
},
);
VideoView.displayName = "VideoView";
export default memo(VideoView);

View File

@@ -0,0 +1,76 @@
import type { ViewProps, ViewStyle } from "react-native";
import type { SurfaceType } from "../../spec/nitro/VideoViewViewManager.nitro";
import type { VideoViewEvents } from "../types/Events";
import type { ResizeMode } from "../types/ResizeMode";
import type { VideoPlayer } from "../VideoPlayer";
export interface VideoViewProps extends Partial<VideoViewEvents>, ViewProps {
/**
* The player to play the video - {@link VideoPlayer}
*/
player: VideoPlayer;
/**
* The style of the video view - {@link ViewStyle}
*/
style?: ViewStyle;
/**
* Whether to show the controls. Defaults to false.
*/
controls?: boolean;
/**
* Whether to enable & show the picture in picture button in native controls. Defaults to false.
*/
pictureInPicture?: boolean;
/**
* Whether to automatically enter picture in picture mode when the video is playing. Defaults to false.
*/
autoEnterPictureInPicture?: boolean;
/**
* How the video should be resized to fit the view. Defaults to 'none'.
* - 'contain': Scale the video uniformly (maintain aspect ratio) so that it fits entirely within the view
* - 'cover': Scale the video uniformly (maintain aspect ratio) so that it fills the entire view (may crop)
* - 'stretch': Scale the video to fill the entire view without maintaining aspect ratio
* - 'none': Do not resize the video
*/
resizeMode?: ResizeMode;
/**
* Whether to keep the screen awake while the video view is mounted. Defaults to true.
*/
keepScreenAwake?: boolean;
/**
* The type of underlying native view. Defaults to 'surface'.
* - 'surface': Uses a SurfaceView on Android. More performant, but cannot be animated or transformed.
* - 'texture': Uses a TextureView on Android. Less performant, but can be animated and transformed.
*
* Only applicable on Android
*
* @default 'surface'
* @platform android
*/
surfaceType?: SurfaceType;
}
export interface VideoViewRef {
/**
* Enter fullscreen mode
*/
enterFullscreen: () => void;
/**
* Exit fullscreen mode
*/
exitFullscreen: () => void;
/**
* Enter picture in picture mode
*/
enterPictureInPicture: () => void;
/**
* Exit picture in picture mode
*/
exitPictureInPicture: () => void;
/**
* Check if picture in picture mode is supported
* @returns true if picture in picture mode is supported, false otherwise
*/
canEnterPictureInPicture: () => boolean;
}

View File

@@ -0,0 +1,147 @@
import type videojs from "video.js";
import type { CustomVideoMetadata } from "../types/VideoConfig";
type VideoJsPlayer = ReturnType<typeof videojs>;
const mediaSession = window.navigator.mediaSession;
export class MediaSessionHandler {
enabled: boolean = false;
constructor(private player: VideoJsPlayer) {}
enable() {
this.enabled = true;
const defaultSkipTime = 15;
const actionHandlers = [
[
"play",
() => {
this.player.play();
},
],
[
"pause",
() => {
this.player.pause();
},
],
[
"stop",
() => {
this.player.pause();
this.player.currentTime(0);
},
],
// videojs-contrib-ads
[
"seekbackward",
(details: MediaSessionActionDetails) => {
// @ts-expect-error ads is in an optional plugin that isn't typed.
if (this.player.usingPlugin("ads") && this.player.ads.inAdBreak()) {
return;
}
this.player.currentTime(
Math.max(
0,
(this.player.currentTime() ?? 0) -
(details.seekOffset || defaultSkipTime),
),
);
},
],
[
"seekforward",
(details: MediaSessionActionDetails) => {
// @ts-expect-error ads is in an optional plugin that isn't typed.
if (this.player.usingPlugin("ads") && this.player.ads.inAdBreak()) {
return;
}
this.player.currentTime(
Math.min(
this.player.duration() ?? 0,
(this.player.currentTime() ?? 0) +
(details.seekOffset || defaultSkipTime),
),
);
},
],
[
"seekto",
(details: MediaSessionActionDetails) => {
// @ts-expect-error ads is in an optional plugin that isn't typed.
if (this.player.usingPlugin("ads") && this.player.ads.inAdBreak()) {
return;
}
this.player.currentTime(details.seekTime);
},
],
] as const;
for (const [action, handler] of actionHandlers) {
try {
mediaSession.setActionHandler(action, handler);
} catch {
this.player.log.debug(
`Couldn't register media session action "${action}".`,
);
}
}
const onPlaying = () => {
mediaSession.playbackState = "playing";
};
const onPaused = () => {
mediaSession.playbackState = "paused";
};
const onTimeUpdate = () => {
const dur = this.player.duration();
if (Number.isFinite(dur)) {
mediaSession.setPositionState({
duration: dur,
playbackRate: this.player.playbackRate(),
position: this.player.currentTime(),
});
}
};
this.player.on("playing", onPlaying);
this.player.on("paused", onPaused);
if ("setPositionState" in mediaSession) {
this.player.on("timeupdate", onTimeUpdate);
}
this.disable = () => {
this.enabled = false;
this.player.off("playing", onPlaying);
this.player.off("paused", onPaused);
if ("setPositionState" in mediaSession) {
this.player.off("timeupdate", onTimeUpdate);
}
mediaSession.metadata = null;
for (const [action, _] of actionHandlers) {
try {
mediaSession.setActionHandler(action, null);
} catch {}
}
};
}
disable() {}
updateMediaSession(metadata: CustomVideoMetadata | undefined) {
if (!metadata) {
mediaSession.metadata = null;
return;
}
mediaSession.metadata = new window.MediaMetadata({
title: metadata.title,
album: metadata.subtitle,
artist: metadata.artist,
artwork: metadata.imageUri ? [{ src: metadata.imageUri }] : [],
});
}
}

Some files were not shown because too many files have changed in this diff Show More