expo-libvlc-player 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +2 -0
- package/README.md +107 -0
- package/android/.gradle/9.0-milestone-1/checksums/checksums.lock +0 -0
- package/android/.gradle/9.0-milestone-1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/9.0-milestone-1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/9.0-milestone-1/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/config.properties +2 -0
- package/android/.gradle/ideaInitScripts/ijtgtmapper.gradle +3 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/.idea/AndroidProjectSystem.xml +6 -0
- package/android/.idea/android.iml +9 -0
- package/android/.idea/caches/deviceStreaming.xml +835 -0
- package/android/.idea/deviceManager.xml +13 -0
- package/android/.idea/gradle.xml +13 -0
- package/android/.idea/misc.xml +3 -0
- package/android/.idea/modules.xml +8 -0
- package/android/.idea/runConfigurations.xml +17 -0
- package/android/.idea/vcs.xml +6 -0
- package/android/.idea/workspace.xml +72 -0
- package/android/build.gradle +53 -0
- package/android/local.properties +8 -0
- package/android/proguard-rules.pro +19 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/expo/modules/libvlcplayer/AudioFocusManager.kt +210 -0
- package/android/src/main/java/expo/modules/libvlcplayer/VlcPlayerManager.kt +82 -0
- package/android/src/main/java/expo/modules/libvlcplayer/VlcPlayerModule.kt +129 -0
- package/android/src/main/java/expo/modules/libvlcplayer/VlcPlayerView.kt +328 -0
- package/android/src/main/java/expo/modules/libvlcplayer/enums/AudioMixingMode.kt +20 -0
- package/app.plugin.js +1 -0
- package/build/VlcPlayer.types.d.ts +278 -0
- package/build/VlcPlayer.types.d.ts.map +1 -0
- package/build/VlcPlayer.types.js +2 -0
- package/build/VlcPlayer.types.js.map +1 -0
- package/build/VlcPlayerModule.d.ts +6 -0
- package/build/VlcPlayerModule.d.ts.map +1 -0
- package/build/VlcPlayerModule.js +4 -0
- package/build/VlcPlayerModule.js.map +1 -0
- package/build/VlcPlayerView.d.ts +5 -0
- package/build/VlcPlayerView.d.ts.map +1 -0
- package/build/VlcPlayerView.js +36 -0
- package/build/VlcPlayerView.js.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/build/utils/props.d.ts +3 -0
- package/build/utils/props.d.ts.map +1 -0
- package/build/utils/props.js +11 -0
- package/build/utils/props.js.map +1 -0
- package/eslint.config.js +50 -0
- package/expo-module.config.json +16 -0
- package/ios/Enums/AudioMixingMode.swift +35 -0
- package/ios/ExpoLibVlcPlayer.podspec +29 -0
- package/ios/VlcPlayerManager.swift +116 -0
- package/ios/VlcPlayerModule.swift +110 -0
- package/ios/VlcPlayerView.swift +321 -0
- package/package.json +49 -0
- package/plugin/build/withExpoLibVlcPlayer.d.ts +3 -0
- package/plugin/build/withExpoLibVlcPlayer.js +18 -0
- package/plugin/src/withExpoLibVlcPlayer.ts +21 -0
- package/plugin/tsconfig.json +9 -0
- package/plugin/tsconfig.tsbuildinfo +1 -0
- package/src/VlcPlayer.types.ts +291 -0
- package/src/VlcPlayerModule.ts +7 -0
- package/src/VlcPlayerView.tsx +73 -0
- package/src/index.ts +4 -0
- package/src/utils/props.ts +20 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { requireNativeView } from "expo";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { convertNativeProps } from "./utils/props";
|
|
4
|
+
const NativeView = requireNativeView("ExpoLibVlcPlayer");
|
|
5
|
+
let loggedRenderingChildrenWarning = false;
|
|
6
|
+
const VlcPlayerView = React.forwardRef((props, ref) => {
|
|
7
|
+
const nativeProps = convertNativeProps(props);
|
|
8
|
+
// @ts-expect-error
|
|
9
|
+
if (nativeProps.children && !loggedRenderingChildrenWarning) {
|
|
10
|
+
console.warn("The <VLCPlayerView> component does not support children. This may lead to inconsistent behaviour or crashes. If you want to render content on top of the VLCPlayer, consider using absolute positioning.");
|
|
11
|
+
loggedRenderingChildrenWarning = true;
|
|
12
|
+
}
|
|
13
|
+
const onWarn = ({ nativeEvent }) => {
|
|
14
|
+
if (props.onWarn) {
|
|
15
|
+
props.onWarn(nativeEvent);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const onError = ({ nativeEvent }) => {
|
|
19
|
+
if (props.onError) {
|
|
20
|
+
props.onError(nativeEvent);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const onPositionChanged = ({ nativeEvent, }) => {
|
|
24
|
+
if (props.onPositionChanged) {
|
|
25
|
+
props.onPositionChanged(nativeEvent);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const onLoad = ({ nativeEvent }) => {
|
|
29
|
+
if (props.onLoad) {
|
|
30
|
+
props.onLoad(nativeEvent);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
return (<NativeView {...nativeProps} ref={ref} onWarn={onWarn} onError={onError} onPositionChanged={onPositionChanged} onLoad={onLoad}/>);
|
|
34
|
+
});
|
|
35
|
+
export default VlcPlayerView;
|
|
36
|
+
//# sourceMappingURL=VlcPlayerView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VlcPlayerView.js","sourceRoot":"","sources":["../src/VlcPlayerView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,UAAU,GACd,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;AAExC,IAAI,8BAA8B,GAAG,KAAK,CAAC;AAE3C,MAAM,aAAa,GAAG,KAAK,CAAC,UAAU,CACpC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACb,MAAM,WAAW,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAE9C,mBAAmB;IACnB,IAAI,WAAW,CAAC,QAAQ,IAAI,CAAC,8BAA8B,EAAE,CAAC;QAC5D,OAAO,CAAC,IAAI,CACV,0MAA0M,CAC3M,CAAC;QACF,8BAA8B,GAAG,IAAI,CAAC;IACxC,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,EAAE,WAAW,EAAyB,EAAE,EAAE;QACxD,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjB,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,EAAE,WAAW,EAA0B,EAAE,EAAE;QAC1D,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YAClB,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,iBAAiB,GAAG,CAAC,EACzB,WAAW,GAGZ,EAAE,EAAE;QACH,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,CAAC,EAAE,WAAW,EAA8B,EAAE,EAAE;QAC7D,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjB,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,CAAC,UAAU,CACT,IAAI,WAAW,CAAC,CAChB,GAAG,CAAC,CAAC,GAAG,CAAC,CACT,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,OAAO,CAAC,CAAC,OAAO,CAAC,CACjB,iBAAiB,CAAC,CAAC,iBAAiB,CAAC,CACrC,MAAM,CAAC,CAAC,MAAM,CAAC,EACf,CACH,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,eAAe,aAAa,CAAC","sourcesContent":["import { requireNativeView } from \"expo\";\nimport * as React from \"react\";\n\nimport {\n VlcPlayerViewNativeProps,\n VlcPlayerViewProps,\n VLCPlayerViewRef,\n type Warn,\n type Error,\n type PositionChanged,\n type VideoInfo,\n} from \"./VlcPlayer.types\";\nimport { convertNativeProps } from \"./utils/props\";\n\nconst NativeView: React.ComponentType<VlcPlayerViewNativeProps> =\n requireNativeView(\"ExpoLibVlcPlayer\");\n\nlet loggedRenderingChildrenWarning = false;\n\nconst VlcPlayerView = React.forwardRef<VLCPlayerViewRef, VlcPlayerViewProps>(\n (props, ref) => {\n const nativeProps = convertNativeProps(props);\n\n // @ts-expect-error\n if (nativeProps.children && !loggedRenderingChildrenWarning) {\n console.warn(\n \"The <VLCPlayerView> component does not support children. This may lead to inconsistent behaviour or crashes. If you want to render content on top of the VLCPlayer, consider using absolute positioning.\",\n );\n loggedRenderingChildrenWarning = true;\n }\n\n const onWarn = ({ nativeEvent }: { nativeEvent: Warn }) => {\n if (props.onWarn) {\n props.onWarn(nativeEvent);\n }\n };\n\n const onError = ({ nativeEvent }: { nativeEvent: Error }) => {\n if (props.onError) {\n props.onError(nativeEvent);\n }\n };\n\n const onPositionChanged = ({\n nativeEvent,\n }: {\n nativeEvent: PositionChanged;\n }) => {\n if (props.onPositionChanged) {\n props.onPositionChanged(nativeEvent);\n }\n };\n\n const onLoad = ({ nativeEvent }: { nativeEvent: VideoInfo }) => {\n if (props.onLoad) {\n props.onLoad(nativeEvent);\n }\n };\n\n return (\n <NativeView\n {...nativeProps}\n ref={ref}\n onWarn={onWarn}\n onError={onError}\n onPositionChanged={onPositionChanged}\n onLoad={onLoad}\n />\n );\n },\n);\n\nexport default VlcPlayerView;\n"]}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,cAAc,mBAAmB,CAAC"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,cAAc,mBAAmB,CAAC","sourcesContent":["// Reexport the native module. On native platforms, it will be resolved to VlcPlayer.ts\nexport { default } from \"./VlcPlayerModule\";\nexport { default as VLCPlayerView } from \"./VlcPlayerView\";\nexport * from \"./VlcPlayer.types\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../src/utils/props.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAE5B,wBAAgB,kBAAkB,CAChC,KAAK,CAAC,EAAE,kBAAkB,GACzB,wBAAwB,CAY1B"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function convertNativeProps(props) {
|
|
2
|
+
if (!props || typeof props !== "object") {
|
|
3
|
+
return {};
|
|
4
|
+
}
|
|
5
|
+
const nativeProps = {};
|
|
6
|
+
for (const [key, value] of Object.entries(props)) {
|
|
7
|
+
nativeProps[key] = value;
|
|
8
|
+
}
|
|
9
|
+
return nativeProps;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=props.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.js","sourceRoot":"","sources":["../../src/utils/props.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,kBAAkB,CAChC,KAA0B;IAE1B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,WAAW,GAA6B,EAAE,CAAC;IAEjD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,WAAW,CAAC,GAAqC,CAAC,GAAG,KAAK,CAAC;IAC7D,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC","sourcesContent":["import {\n VlcPlayerViewNativeProps,\n VlcPlayerViewProps,\n} from \"../VlcPlayer.types\";\n\nexport function convertNativeProps(\n props?: VlcPlayerViewProps,\n): VlcPlayerViewNativeProps {\n if (!props || typeof props !== \"object\") {\n return {};\n }\n\n const nativeProps: VlcPlayerViewNativeProps = {};\n\n for (const [key, value] of Object.entries(props)) {\n nativeProps[key as keyof VlcPlayerViewNativeProps] = value;\n }\n\n return nativeProps;\n}\n"]}
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const { fixupConfigRules } = require("@eslint/compat");
|
|
2
|
+
const { FlatCompat } = require("@eslint/eslintrc");
|
|
3
|
+
const js = require("@eslint/js");
|
|
4
|
+
const { defineConfig, globalIgnores } = require("eslint/config");
|
|
5
|
+
const globals = require("globals");
|
|
6
|
+
|
|
7
|
+
const compat = new FlatCompat({
|
|
8
|
+
baseDirectory: __dirname,
|
|
9
|
+
recommendedConfig: js.configs.recommended,
|
|
10
|
+
allConfig: js.configs.all,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
module.exports = defineConfig([
|
|
14
|
+
{
|
|
15
|
+
extends: [...fixupConfigRules(compat.extends("universe/native"))],
|
|
16
|
+
rules: {
|
|
17
|
+
"no-restricted-imports": [
|
|
18
|
+
"warn",
|
|
19
|
+
{
|
|
20
|
+
patterns: ["fbjs/*", "fbjs"],
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
languageOptions: {
|
|
25
|
+
globals: {
|
|
26
|
+
...globals.node,
|
|
27
|
+
__DEV__: true,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
files: ["**/__tests__/*"],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
files: ["./*.config.js", "./.*rc.js"],
|
|
36
|
+
extends: [...fixupConfigRules(compat.extends("universe/node"))],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
files: ["**/*.ts", "**/*.tsx", "**/*.d.ts"],
|
|
40
|
+
rules: {
|
|
41
|
+
"no-redeclare": "off",
|
|
42
|
+
"@typescript-eslint/no-redeclare": "off",
|
|
43
|
+
"no-unused-expressions": "off",
|
|
44
|
+
"no-unused-vars": "off",
|
|
45
|
+
"@typescript-eslint/no-unused-expressions": "off",
|
|
46
|
+
"@typescript-eslint/no-unused-vars": "off",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
globalIgnores(["**/build"]),
|
|
50
|
+
]);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import CoreMedia
|
|
2
|
+
import ExpoModulesCore
|
|
3
|
+
|
|
4
|
+
enum AudioMixingMode: String, Enumerable {
|
|
5
|
+
case mixWithOthers
|
|
6
|
+
case duckOthers
|
|
7
|
+
case doNotMix
|
|
8
|
+
case auto
|
|
9
|
+
|
|
10
|
+
func priority() -> Int {
|
|
11
|
+
switch self {
|
|
12
|
+
case .doNotMix:
|
|
13
|
+
return 3
|
|
14
|
+
case .auto:
|
|
15
|
+
return 2
|
|
16
|
+
case .duckOthers:
|
|
17
|
+
return 1
|
|
18
|
+
case .mixWithOthers:
|
|
19
|
+
return 0
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
func toSessionCategoryOption() -> AVAudioSession.CategoryOptions? {
|
|
24
|
+
switch self {
|
|
25
|
+
case .duckOthers:
|
|
26
|
+
return .duckOthers
|
|
27
|
+
case .mixWithOthers:
|
|
28
|
+
return .mixWithOthers
|
|
29
|
+
case .doNotMix:
|
|
30
|
+
return nil
|
|
31
|
+
case .auto:
|
|
32
|
+
return nil
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'ExpoLibVlcPlayer'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.description = package['description']
|
|
10
|
+
s.license = package['license']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.homepage = package['homepage']
|
|
13
|
+
s.platforms = {
|
|
14
|
+
:ios => '15.1'
|
|
15
|
+
}
|
|
16
|
+
s.swift_version = '5.4'
|
|
17
|
+
s.source = { git: 'https://github.com/cornejobarraza/expo-libvlc-player' }
|
|
18
|
+
s.static_framework = true
|
|
19
|
+
|
|
20
|
+
s.dependency 'ExpoModulesCore'
|
|
21
|
+
s.dependency 'MobileVLCKit', '3.6.0'
|
|
22
|
+
|
|
23
|
+
# Swift/Objective-C compatibility
|
|
24
|
+
s.pod_target_xcconfig = {
|
|
25
|
+
'DEFINES_MODULE' => 'YES',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
|
|
29
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import AVFoundation
|
|
2
|
+
import ExpoModulesCore
|
|
3
|
+
import Foundation
|
|
4
|
+
|
|
5
|
+
class VlcPlayerManager {
|
|
6
|
+
static var shared = VlcPlayerManager()
|
|
7
|
+
|
|
8
|
+
private static var managerQueue = DispatchQueue(label: "com.expo.libvlcplayer.manager.managerQueue")
|
|
9
|
+
private var views = NSHashTable<VlcPlayerView>.weakObjects()
|
|
10
|
+
|
|
11
|
+
func registerView(view: VlcPlayerView) {
|
|
12
|
+
views.add(view)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
func unregisterView(view: VlcPlayerView) {
|
|
16
|
+
views.remove(view)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
func onAppDestroyed() {
|
|
20
|
+
for view in views.allObjects {
|
|
21
|
+
view.destroyPlayer()
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func onAppBackgrounded() {
|
|
26
|
+
for view in views.allObjects {
|
|
27
|
+
view.onBackground([:])
|
|
28
|
+
|
|
29
|
+
guard let player = view.mediaPlayer else { continue }
|
|
30
|
+
|
|
31
|
+
if !view.playInBackground, player.isPlaying {
|
|
32
|
+
player.pause()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func setAppropriateAudioSessionOrWarn() {
|
|
38
|
+
Self.managerQueue.async { [weak self] in
|
|
39
|
+
self?.setAudioSession()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private func setAudioSession() {
|
|
44
|
+
let audioSession = AVAudioSession.sharedInstance()
|
|
45
|
+
let audioMixingMode = findAudioMixingMode()
|
|
46
|
+
var audioSessionCategoryOptions: AVAudioSession.CategoryOptions = audioSession.categoryOptions
|
|
47
|
+
|
|
48
|
+
let isOutputtingAudio = views.allObjects.contains { view in
|
|
49
|
+
if let isPlaying = view.mediaPlayer?.isPlaying,
|
|
50
|
+
let isMuted = view.mediaPlayer?.audio?.isMuted
|
|
51
|
+
{
|
|
52
|
+
if isPlaying, !isMuted {
|
|
53
|
+
return true
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let shouldMixOverride = audioMixingMode == .mixWithOthers
|
|
61
|
+
let doNotMixOverride = audioMixingMode == .doNotMix
|
|
62
|
+
let shouldDuckOthers = audioMixingMode == .duckOthers && isOutputtingAudio
|
|
63
|
+
|
|
64
|
+
let shouldMixWithOthers = shouldMixOverride || !isOutputtingAudio
|
|
65
|
+
|
|
66
|
+
if shouldMixWithOthers && !shouldDuckOthers && !doNotMixOverride {
|
|
67
|
+
audioSessionCategoryOptions.insert(.mixWithOthers)
|
|
68
|
+
} else {
|
|
69
|
+
audioSessionCategoryOptions.remove(.mixWithOthers)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if shouldDuckOthers && !doNotMixOverride {
|
|
73
|
+
audioSessionCategoryOptions.insert(.duckOthers)
|
|
74
|
+
} else {
|
|
75
|
+
audioSessionCategoryOptions.remove(.duckOthers)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if audioSession.categoryOptions != audioSessionCategoryOptions || audioSession.category != .playback || audioSession.mode != .moviePlayback {
|
|
79
|
+
do {
|
|
80
|
+
try audioSession.setCategory(.playback, mode: .moviePlayback, options: audioSessionCategoryOptions)
|
|
81
|
+
} catch {
|
|
82
|
+
log.warn("Failed to set audio session category")
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if isOutputtingAudio || doNotMixOverride {
|
|
87
|
+
do {
|
|
88
|
+
try audioSession.setActive(true)
|
|
89
|
+
} catch {
|
|
90
|
+
log.warn("Failed to activate the audio session")
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private func findAudioMixingMode() -> AudioMixingMode? {
|
|
96
|
+
let playingViews = views.allObjects.filter { view in
|
|
97
|
+
if let isPlaying = view.mediaPlayer?.isPlaying, isPlaying {
|
|
98
|
+
return true
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
var audioMixingMode: AudioMixingMode = .mixWithOthers
|
|
105
|
+
|
|
106
|
+
if playingViews.isEmpty {
|
|
107
|
+
return nil
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for playerView in playingViews where (audioMixingMode.priority()) < playerView.audioMixingMode.priority() {
|
|
111
|
+
audioMixingMode = playerView.audioMixingMode
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return audioMixingMode
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import AVFoundation
|
|
2
|
+
import ExpoModulesCore
|
|
3
|
+
|
|
4
|
+
private let bufferingEvent = "onBuffering"
|
|
5
|
+
private let playingEvent = "onPlaying"
|
|
6
|
+
private let pausedEvent = "onPaused"
|
|
7
|
+
private let stoppedEvent = "onStopped"
|
|
8
|
+
private let endedEvent = "onEnded"
|
|
9
|
+
private let repeatEvent = "onRepeat"
|
|
10
|
+
private let warnEvent = "onWarn"
|
|
11
|
+
private let errorEvent = "onError"
|
|
12
|
+
private let positionChangedEvent = "onPositionChanged"
|
|
13
|
+
private let loadEvent = "onLoad"
|
|
14
|
+
private let backgroundEvent = "onBackground"
|
|
15
|
+
|
|
16
|
+
let playerEvents = [
|
|
17
|
+
bufferingEvent,
|
|
18
|
+
playingEvent,
|
|
19
|
+
pausedEvent,
|
|
20
|
+
stoppedEvent,
|
|
21
|
+
endedEvent,
|
|
22
|
+
repeatEvent,
|
|
23
|
+
warnEvent,
|
|
24
|
+
errorEvent,
|
|
25
|
+
positionChangedEvent,
|
|
26
|
+
loadEvent,
|
|
27
|
+
backgroundEvent,
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
public class VlcPlayerModule: Module {
|
|
31
|
+
public func definition() -> ModuleDefinition {
|
|
32
|
+
Name("ExpoLibVlcPlayer")
|
|
33
|
+
|
|
34
|
+
OnDestroy {
|
|
35
|
+
VlcPlayerManager.shared.onAppDestroyed()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
View(VlcPlayerView.self) {
|
|
39
|
+
Events(playerEvents)
|
|
40
|
+
|
|
41
|
+
Prop("uri") { (view: VlcPlayerView, uri: String) in
|
|
42
|
+
view.setUri(uri)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
Prop("subtitle") { (view: VlcPlayerView, subtitle: [String: Any]?) in
|
|
46
|
+
view.setSubtitle(subtitle)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Prop("options") { (view: VlcPlayerView, options: [String]?) in
|
|
50
|
+
view.setOptions(options ?? [String]())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
Prop("volume") { (view: VlcPlayerView, volume: Int?) in
|
|
54
|
+
view.setVolume(volume ?? maxPlayerVolume)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Prop("mute") { (view: VlcPlayerView, mute: Bool?) in
|
|
58
|
+
view.setMute(mute ?? false)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Prop("rate") { (view: VlcPlayerView, rate: Float?) in
|
|
62
|
+
view.setRate(rate ?? defaultPlayerRate)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Prop("tracks") { (view: VlcPlayerView, tracks: [String: Any]?) in
|
|
66
|
+
view.setTracks(tracks)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Prop("repeat") { (view: VlcPlayerView, shouldRepeat: Bool?) in
|
|
70
|
+
view.setRepeat(shouldRepeat ?? false)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Prop("aspectRatio") { (view: VlcPlayerView, aspectRatio: String?) in
|
|
74
|
+
view.setAspectRatio(aspectRatio)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
Prop("audioMixingMode") { (view: VlcPlayerView, audioMixingMode: AudioMixingMode) in
|
|
78
|
+
view.setAudioMixingMode(audioMixingMode)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
Prop("playInBackground") { (view: VlcPlayerView, playInBackground: Bool?) in
|
|
82
|
+
view.setPlayInBackground(playInBackground ?? false)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
Prop("autoplay") { (view: VlcPlayerView, autoplay: Bool?) in
|
|
86
|
+
view.setAutoplay(autoplay ?? true)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
AsyncFunction("play") { (view: VlcPlayerView) in
|
|
90
|
+
view.play()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
AsyncFunction("pause") { (view: VlcPlayerView) in
|
|
94
|
+
view.pause()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
AsyncFunction("stop") { (view: VlcPlayerView) in
|
|
98
|
+
view.stop()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
AsyncFunction("seek") { (view: VlcPlayerView, position: Float) in
|
|
102
|
+
view.seek(position)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
OnAppEntersBackground {
|
|
107
|
+
VlcPlayerManager.shared.onAppBackgrounded()
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|