unified-video-framework 1.0.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/.github/workflows/ci.yml +253 -0
- package/ANDROID_TV_IMPLEMENTATION.md +313 -0
- package/COMPLETION_STATUS.md +165 -0
- package/CONTRIBUTING.md +376 -0
- package/FINAL_STATUS_REPORT.md +170 -0
- package/FRAMEWORK_REVIEW.md +247 -0
- package/IMPROVEMENTS_SUMMARY.md +168 -0
- package/LICENSE +21 -0
- package/NATIVE_APP_INTEGRATION_GUIDE.md +903 -0
- package/PAYWALL_RENTAL_FLOW.md +499 -0
- package/PLATFORM_SETUP_GUIDE.md +1636 -0
- package/README.md +315 -0
- package/RUN_LOCALLY.md +151 -0
- package/apps/demo/cast-sender-min.html +173 -0
- package/apps/demo/custom-player.html +883 -0
- package/apps/demo/demo.html +990 -0
- package/apps/demo/enhanced-player.html +3556 -0
- package/apps/demo/index.html +159 -0
- package/apps/rental-api/.env.example +24 -0
- package/apps/rental-api/README.md +23 -0
- package/apps/rental-api/migrations/001_init.sql +35 -0
- package/apps/rental-api/migrations/002_videos.sql +10 -0
- package/apps/rental-api/migrations/003_add_gateway_subref.sql +4 -0
- package/apps/rental-api/migrations/004_update_gateways.sql +4 -0
- package/apps/rental-api/migrations/005_seed_demo_video.sql +5 -0
- package/apps/rental-api/package-lock.json +2045 -0
- package/apps/rental-api/package.json +33 -0
- package/apps/rental-api/scripts/run-migration.js +42 -0
- package/apps/rental-api/scripts/update-video-currency.js +21 -0
- package/apps/rental-api/scripts/update-video-price.js +19 -0
- package/apps/rental-api/src/config.ts +14 -0
- package/apps/rental-api/src/db.ts +10 -0
- package/apps/rental-api/src/routes/cashfree.ts +167 -0
- package/apps/rental-api/src/routes/pesapal.ts +92 -0
- package/apps/rental-api/src/routes/rentals.ts +242 -0
- package/apps/rental-api/src/routes/webhooks.ts +73 -0
- package/apps/rental-api/src/server.ts +41 -0
- package/apps/rental-api/src/services/entitlements.ts +45 -0
- package/apps/rental-api/src/services/payments.ts +22 -0
- package/apps/rental-api/tsconfig.json +17 -0
- package/check-urls.ps1 +74 -0
- package/comparison-report.md +181 -0
- package/docs/PAYWALL.md +95 -0
- package/docs/PLAYER_UI_VISIBILITY.md +431 -0
- package/docs/README.md +7 -0
- package/docs/SYSTEM_ARCHITECTURE.md +612 -0
- package/docs/VDOCIPHER_CLONE_REQUIREMENTS.md +403 -0
- package/examples/android/JavaSampleApp/MainActivity.java +641 -0
- package/examples/android/JavaSampleApp/activity_main.xml +226 -0
- package/examples/android/SampleApp/MainActivity.kt +430 -0
- package/examples/ios/SampleApp/ViewController.swift +337 -0
- package/examples/ios/SwiftUISampleApp/ContentView.swift +304 -0
- package/iOS_IMPLEMENTATION_OPTIONS.md +470 -0
- package/ios/UnifiedVideoPlayer/UnifiedVideoPlayer.podspec +33 -0
- package/jest.config.js +33 -0
- package/jitpack.yml +5 -0
- package/lerna.json +35 -0
- package/package.json +69 -0
- package/packages/PLATFORM_STATUS.md +163 -0
- package/packages/android/build.gradle +135 -0
- package/packages/android/src/main/AndroidManifest.xml +36 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/PlayerConfiguration.java +221 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/UnifiedVideoPlayer.java +1037 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/UnifiedVideoPlayer.kt +707 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/analytics/AnalyticsProvider.java +9 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/cast/CastManager.java +141 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/cast/CastOptionsProvider.java +29 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/overlay/WatermarkOverlayView.java +88 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/pip/PipActionReceiver.java +33 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/services/PlaybackService.java +110 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/services/PlayerHolder.java +19 -0
- package/packages/core/package.json +34 -0
- package/packages/core/src/BasePlayer.ts +250 -0
- package/packages/core/src/VideoPlayer.ts +237 -0
- package/packages/core/src/VideoPlayerFactory.ts +145 -0
- package/packages/core/src/index.ts +20 -0
- package/packages/core/src/interfaces/IVideoPlayer.ts +184 -0
- package/packages/core/src/interfaces.ts +240 -0
- package/packages/core/src/utils/EventEmitter.ts +66 -0
- package/packages/core/src/utils/PlatformDetector.ts +300 -0
- package/packages/core/tsconfig.json +20 -0
- package/packages/enact/package.json +51 -0
- package/packages/enact/src/VideoPlayer.js +365 -0
- package/packages/enact/src/adapters/TizenAdapter.js +354 -0
- package/packages/enact/src/index.js +82 -0
- package/packages/ios/BUILD_INSTRUCTIONS.md +108 -0
- package/packages/ios/FIX_EMBED_ISSUE.md +142 -0
- package/packages/ios/GETTING_STARTED.md +100 -0
- package/packages/ios/Package.swift +35 -0
- package/packages/ios/README.md +84 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/Analytics/AnalyticsEmitter.swift +26 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/DRM/FairPlayDRMManager.swift +102 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/Info.plist +24 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/Remote/RemoteCommandCenter.swift +109 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/UnifiedVideoPlayer.swift +811 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/UnifiedVideoPlayerView.swift +640 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/Utilities/Color+Hex.swift +36 -0
- package/packages/ios/UnifiedVideoPlayer.podspec +27 -0
- package/packages/ios/UnifiedVideoPlayer.xcodeproj/project.pbxproj +385 -0
- package/packages/ios/build_framework.sh +55 -0
- package/packages/react-native/android/src/main/java/com/unifiedvideo/UnifiedVideoPlayerModule.kt +482 -0
- package/packages/react-native/ios/UnifiedVideoPlayer.swift +436 -0
- package/packages/react-native/package.json +51 -0
- package/packages/react-native/src/ReactNativePlayer.tsx +423 -0
- package/packages/react-native/src/VideoPlayer.tsx +224 -0
- package/packages/react-native/src/index.ts +28 -0
- package/packages/react-native/src/utils/EventEmitter.ts +66 -0
- package/packages/react-native/tsconfig.json +31 -0
- package/packages/roku/components/UnifiedVideoPlayer.brs +400 -0
- package/packages/roku/package.json +44 -0
- package/packages/roku/source/VideoPlayer.brs +231 -0
- package/packages/roku/source/main.brs +28 -0
- package/packages/web/GETTING_STARTED.md +292 -0
- package/packages/web/jest.config.js +28 -0
- package/packages/web/jest.setup.ts +110 -0
- package/packages/web/package.json +50 -0
- package/packages/web/src/SecureVideoPlayer.ts +1164 -0
- package/packages/web/src/WebPlayer.ts +3110 -0
- package/packages/web/src/__tests__/WebPlayer.test.ts +314 -0
- package/packages/web/src/index.ts +14 -0
- package/packages/web/src/paywall/PaywallController.ts +215 -0
- package/packages/web/src/react/WebPlayerView.tsx +177 -0
- package/packages/web/tsconfig.json +23 -0
- package/packages/web/webpack.config.js +45 -0
- package/server.js +131 -0
- package/server.py +84 -0
- package/test-urls.ps1 +97 -0
- package/test-video-urls.ps1 +87 -0
- package/tsconfig.json +39 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Platform Implementation Status
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
The Unified Video Framework is designed as a modular, extensible system where each platform has its own implementation package that conforms to the core interfaces.
|
|
5
|
+
|
|
6
|
+
## Implementation Status
|
|
7
|
+
|
|
8
|
+
### ✅ Fully Implemented
|
|
9
|
+
|
|
10
|
+
#### 1. **Core** (`packages/core`)
|
|
11
|
+
- **Status**: Complete
|
|
12
|
+
- **Purpose**: Defines interfaces and factory pattern
|
|
13
|
+
- **Files**:
|
|
14
|
+
- `interfaces.ts` - TypeScript interfaces for all platforms
|
|
15
|
+
- `PlayerFactory.ts` - Factory pattern for creating platform-specific players
|
|
16
|
+
- `VideoPlayer.ts` - Base implementation
|
|
17
|
+
|
|
18
|
+
#### 2. **Web** (`packages/web`)
|
|
19
|
+
- **Status**: Complete
|
|
20
|
+
- **Purpose**: Browser-based video playback
|
|
21
|
+
- **Technology**: HTML5 Video API, HLS.js, dash.js
|
|
22
|
+
- **Files**:
|
|
23
|
+
- `HTML5Player.ts` - TypeScript implementation
|
|
24
|
+
- `SimpleHTML5Player.js` - JavaScript implementation
|
|
25
|
+
- **Demo**: Available at `/apps/demo/demo.html`
|
|
26
|
+
|
|
27
|
+
#### 3. **Enact** (`packages/enact`)
|
|
28
|
+
- **Status**: Complete (Adapter layer)
|
|
29
|
+
- **Purpose**: Samsung Tizen and LG webOS Smart TVs
|
|
30
|
+
- **Technology**: Enact framework
|
|
31
|
+
- **Files**:
|
|
32
|
+
- `TizenAdapter.js` - TV-specific adaptations
|
|
33
|
+
- **Note**: Uses web player with TV-specific enhancements
|
|
34
|
+
|
|
35
|
+
### ⏳ Planned Implementations
|
|
36
|
+
|
|
37
|
+
#### 4. **React Native** (`packages/react-native`)
|
|
38
|
+
- **Status**: Placeholder created
|
|
39
|
+
- **Purpose**: iOS and Android mobile apps
|
|
40
|
+
- **Technology Stack**:
|
|
41
|
+
- React Native
|
|
42
|
+
- react-native-video library
|
|
43
|
+
- Native players (AVPlayer for iOS, ExoPlayer for Android)
|
|
44
|
+
- **Why Not Implemented**:
|
|
45
|
+
- Requires React Native development environment
|
|
46
|
+
- Needs platform-specific native code
|
|
47
|
+
- Different build toolchain
|
|
48
|
+
|
|
49
|
+
#### 5. **Roku** (`packages/roku`)
|
|
50
|
+
- **Status**: Placeholder created
|
|
51
|
+
- **Purpose**: Roku streaming devices
|
|
52
|
+
- **Technology Stack**:
|
|
53
|
+
- BrightScript programming language
|
|
54
|
+
- SceneGraph framework
|
|
55
|
+
- Roku SDK
|
|
56
|
+
- **Why Not Implemented**:
|
|
57
|
+
- Completely different programming paradigm
|
|
58
|
+
- Requires Roku developer account
|
|
59
|
+
- Specific deployment process
|
|
60
|
+
|
|
61
|
+
## Why This Architecture?
|
|
62
|
+
|
|
63
|
+
### 1. **Separation of Concerns**
|
|
64
|
+
Each platform has unique requirements:
|
|
65
|
+
- **Web**: Runs in browser sandbox
|
|
66
|
+
- **Mobile**: Native performance requirements
|
|
67
|
+
- **TV**: Remote control navigation
|
|
68
|
+
- **Roku**: BrightScript language
|
|
69
|
+
|
|
70
|
+
### 2. **Maintainability**
|
|
71
|
+
- Platform-specific bugs isolated
|
|
72
|
+
- Teams can work independently
|
|
73
|
+
- Updates don't affect other platforms
|
|
74
|
+
|
|
75
|
+
### 3. **Scalability**
|
|
76
|
+
Easy to add new platforms:
|
|
77
|
+
```
|
|
78
|
+
packages/
|
|
79
|
+
├── apple-tv/ # Future: tvOS support
|
|
80
|
+
├── android-tv/ # Future: Android TV native
|
|
81
|
+
├── xbox/ # Future: Xbox apps
|
|
82
|
+
└── playstation/ # Future: PlayStation apps
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## How to Add a New Platform
|
|
86
|
+
|
|
87
|
+
1. **Create Package Directory**
|
|
88
|
+
```bash
|
|
89
|
+
mkdir packages/[platform-name]
|
|
90
|
+
cd packages/[platform-name]
|
|
91
|
+
npm init
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
2. **Implement Core Interface**
|
|
95
|
+
```typescript
|
|
96
|
+
import { VideoPlayerInterface } from '../core/src/interfaces';
|
|
97
|
+
|
|
98
|
+
export class PlatformVideoPlayer implements VideoPlayerInterface {
|
|
99
|
+
// Implement all required methods
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
3. **Register with Factory**
|
|
104
|
+
```typescript
|
|
105
|
+
// In core/src/PlayerFactory.ts
|
|
106
|
+
import { PlatformVideoPlayer } from '../platform-name';
|
|
107
|
+
|
|
108
|
+
PlayerFactory.register('platform-name', PlatformVideoPlayer);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
4. **Create Demo App**
|
|
112
|
+
```bash
|
|
113
|
+
mkdir apps/platform-demo
|
|
114
|
+
# Add platform-specific demo
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Development Priorities
|
|
118
|
+
|
|
119
|
+
### Phase 1 (Complete) ✅
|
|
120
|
+
- Core architecture
|
|
121
|
+
- Web implementation
|
|
122
|
+
- Basic TV support
|
|
123
|
+
|
|
124
|
+
### Phase 2 (Current) 🚧
|
|
125
|
+
- Enhanced streaming support
|
|
126
|
+
- Demo applications
|
|
127
|
+
- Documentation
|
|
128
|
+
|
|
129
|
+
### Phase 3 (Future) 📅
|
|
130
|
+
- React Native implementation
|
|
131
|
+
- Roku implementation
|
|
132
|
+
- Additional TV platforms
|
|
133
|
+
|
|
134
|
+
### Phase 4 (Long-term) 🔮
|
|
135
|
+
- Gaming consoles
|
|
136
|
+
- Desktop native apps
|
|
137
|
+
- WebRTC support
|
|
138
|
+
|
|
139
|
+
## Required Development Environments
|
|
140
|
+
|
|
141
|
+
### For React Native
|
|
142
|
+
- Node.js 14+
|
|
143
|
+
- React Native CLI
|
|
144
|
+
- Xcode (for iOS)
|
|
145
|
+
- Android Studio (for Android)
|
|
146
|
+
- Physical devices or emulators
|
|
147
|
+
|
|
148
|
+
### For Roku
|
|
149
|
+
- Roku SDK
|
|
150
|
+
- Roku developer account
|
|
151
|
+
- Roku device in developer mode
|
|
152
|
+
- Eclipse IDE (optional)
|
|
153
|
+
|
|
154
|
+
### For Smart TVs
|
|
155
|
+
- Tizen Studio (Samsung)
|
|
156
|
+
- webOS SDK (LG)
|
|
157
|
+
- TV emulators or physical TVs
|
|
158
|
+
|
|
159
|
+
## Conclusion
|
|
160
|
+
|
|
161
|
+
The empty directories represent the framework's extensibility and future growth potential. The architecture is designed to accommodate any video-capable platform while maintaining a consistent API across all implementations.
|
|
162
|
+
|
|
163
|
+
Currently, the **web implementation is fully functional** and serves as the reference implementation for other platforms. The demo at `/apps/demo/demo.html` showcases the complete feature set that other platforms should implement.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.kotlin_version = '1.9.24'
|
|
3
|
+
repositories {
|
|
4
|
+
google()
|
|
5
|
+
mavenCentral()
|
|
6
|
+
gradlePluginPortal()
|
|
7
|
+
}
|
|
8
|
+
dependencies {
|
|
9
|
+
classpath 'com.android.tools.build:gradle:8.2.2'
|
|
10
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
group = project.findProperty('GROUP') ?: System.getenv('GROUP') ?: 'com.github.Webnexs'
|
|
15
|
+
version = project.findProperty('VERSION') ?: System.getenv('VERSION') ?: '1.0.0'
|
|
16
|
+
|
|
17
|
+
apply plugin: 'com.android.library'
|
|
18
|
+
apply plugin: 'kotlin-android'
|
|
19
|
+
apply plugin: 'maven-publish'
|
|
20
|
+
|
|
21
|
+
android {
|
|
22
|
+
compileSdk 34
|
|
23
|
+
|
|
24
|
+
defaultConfig {
|
|
25
|
+
minSdk 21
|
|
26
|
+
targetSdk 34
|
|
27
|
+
versionCode 1
|
|
28
|
+
versionName "1.0.0"
|
|
29
|
+
|
|
30
|
+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
31
|
+
consumerProguardFiles "consumer-rules.pro"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
buildTypes {
|
|
35
|
+
release {
|
|
36
|
+
minifyEnabled false
|
|
37
|
+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
compileOptions {
|
|
42
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
43
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
kotlinOptions {
|
|
47
|
+
jvmTarget = '1.8'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
buildFeatures {
|
|
51
|
+
viewBinding true
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
namespace 'com.unifiedvideo.player'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
repositories {
|
|
58
|
+
google()
|
|
59
|
+
mavenCentral()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
dependencies {
|
|
63
|
+
// ExoPlayer
|
|
64
|
+
implementation 'com.google.android.exoplayer:exoplayer:2.19.1'
|
|
65
|
+
implementation 'com.google.android.exoplayer:exoplayer-hls:2.19.1'
|
|
66
|
+
implementation 'com.google.android.exoplayer:exoplayer-dash:2.19.1'
|
|
67
|
+
implementation 'com.google.android.exoplayer:exoplayer-smoothstreaming:2.19.1'
|
|
68
|
+
implementation 'com.google.android.exoplayer:extension-okhttp:2.19.1'
|
|
69
|
+
|
|
70
|
+
// UI Components
|
|
71
|
+
implementation 'com.google.android.exoplayer:exoplayer-ui:2.19.1'
|
|
72
|
+
|
|
73
|
+
// DRM Support
|
|
74
|
+
implementation 'com.google.android.exoplayer:extension-drm:2.19.1'
|
|
75
|
+
|
|
76
|
+
// Google Cast (sender)
|
|
77
|
+
implementation 'com.google.android.gms:play-services-cast-framework:21.4.0'
|
|
78
|
+
|
|
79
|
+
// Kotlin
|
|
80
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
81
|
+
|
|
82
|
+
// AndroidX
|
|
83
|
+
implementation 'androidx.core:core-ktx:1.12.0'
|
|
84
|
+
implementation 'androidx.appcompat:appcompat:1.6.1'
|
|
85
|
+
implementation 'com.google.android.material:material:1.11.0'
|
|
86
|
+
implementation 'androidx.mediarouter:mediarouter:1.6.0'
|
|
87
|
+
implementation 'androidx.media:media:1.6.0'
|
|
88
|
+
|
|
89
|
+
// Testing
|
|
90
|
+
testImplementation 'junit:junit:4.13.2'
|
|
91
|
+
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
|
92
|
+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Maven Publishing
|
|
96
|
+
afterEvaluate {
|
|
97
|
+
publishing {
|
|
98
|
+
publications {
|
|
99
|
+
release(MavenPublication) {
|
|
100
|
+
from components.release
|
|
101
|
+
|
|
102
|
+
groupId = project.group
|
|
103
|
+
artifactId = 'unifiedvideo-player'
|
|
104
|
+
version = project.version
|
|
105
|
+
|
|
106
|
+
pom {
|
|
107
|
+
name = 'Unified Video Player'
|
|
108
|
+
description = 'Unified video player SDK for Android'
|
|
109
|
+
url = 'https://github.com/Webnexs/unified-video-framework'
|
|
110
|
+
licenses {
|
|
111
|
+
license {
|
|
112
|
+
name = 'MIT License'
|
|
113
|
+
url = 'https://opensource.org/licenses/MIT'
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Optional: Only publish to GitHub Packages if credentials are provided (prevents JitPack failures)
|
|
120
|
+
if (project.hasProperty('github.user') && project.hasProperty('github.token')) {
|
|
121
|
+
repositories {
|
|
122
|
+
maven {
|
|
123
|
+
name = "GitHubPackages"
|
|
124
|
+
url = uri("https://maven.pkg.github.com/yourcompany/unified-video-android")
|
|
125
|
+
credentials {
|
|
126
|
+
username = project.findProperty("github.user")
|
|
127
|
+
password = project.findProperty("github.token")
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
tasks.register('install') { dependsOn('publishToMavenLocal') }
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
package="com.unifiedvideo.player">
|
|
4
|
+
|
|
5
|
+
<!-- Permissions -->
|
|
6
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
7
|
+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
8
|
+
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
9
|
+
|
|
10
|
+
<!-- Optional permissions for background playback -->
|
|
11
|
+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
12
|
+
|
|
13
|
+
<application>
|
|
14
|
+
<!-- Background playback service (optional) -->
|
|
15
|
+
<service
|
|
16
|
+
android:name=".services.PlaybackService"
|
|
17
|
+
android:exported="false"
|
|
18
|
+
android:foregroundServiceType="mediaPlayback" />
|
|
19
|
+
|
|
20
|
+
<!-- PiP Action Receiver -->
|
|
21
|
+
<receiver
|
|
22
|
+
android:name=".pip.PipActionReceiver"
|
|
23
|
+
android:exported="false">
|
|
24
|
+
<intent-filter>
|
|
25
|
+
<action android:name="com.unifiedvideo.player.ACTION_PLAY" />
|
|
26
|
+
<action android:name="com.unifiedvideo.player.ACTION_PAUSE" />
|
|
27
|
+
</intent-filter>
|
|
28
|
+
</receiver>
|
|
29
|
+
|
|
30
|
+
<!-- Google Cast Framework options provider (sender SDK) -->
|
|
31
|
+
<meta-data
|
|
32
|
+
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
|
33
|
+
android:value="com.unifiedvideo.player.cast.CastOptionsProvider" />
|
|
34
|
+
</application>
|
|
35
|
+
|
|
36
|
+
</manifest>
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PlayerConfiguration.java
|
|
3
|
+
* Player configuration for UnifiedVideoPlayer
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
package com.unifiedvideo.player;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Player configuration class
|
|
10
|
+
*/
|
|
11
|
+
public class PlayerConfiguration {
|
|
12
|
+
public final boolean autoPlay;
|
|
13
|
+
public final boolean controls;
|
|
14
|
+
public final boolean muted;
|
|
15
|
+
public final boolean loop;
|
|
16
|
+
public final String preload;
|
|
17
|
+
public final long startTime;
|
|
18
|
+
public final float playbackSpeed;
|
|
19
|
+
public final float volume;
|
|
20
|
+
public final boolean debug;
|
|
21
|
+
public final boolean useStyledControls;
|
|
22
|
+
public final boolean allowBackgroundPlayback;
|
|
23
|
+
|
|
24
|
+
private PlayerConfiguration(Builder builder) {
|
|
25
|
+
this.autoPlay = builder.autoPlay;
|
|
26
|
+
this.controls = builder.controls;
|
|
27
|
+
this.muted = builder.muted;
|
|
28
|
+
this.loop = builder.loop;
|
|
29
|
+
this.preload = builder.preload;
|
|
30
|
+
this.startTime = builder.startTime;
|
|
31
|
+
this.playbackSpeed = builder.playbackSpeed;
|
|
32
|
+
this.volume = builder.volume;
|
|
33
|
+
this.debug = builder.debug;
|
|
34
|
+
this.useStyledControls = builder.useStyledControls;
|
|
35
|
+
this.allowBackgroundPlayback = builder.allowBackgroundPlayback;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Builder class for PlayerConfiguration
|
|
40
|
+
*/
|
|
41
|
+
public static class Builder {
|
|
42
|
+
private boolean autoPlay = false;
|
|
43
|
+
private boolean controls = true;
|
|
44
|
+
private boolean muted = false;
|
|
45
|
+
private boolean loop = false;
|
|
46
|
+
private String preload = "auto";
|
|
47
|
+
private long startTime = 0;
|
|
48
|
+
private float playbackSpeed = 1.0f;
|
|
49
|
+
private float volume = 1.0f;
|
|
50
|
+
private boolean debug = false;
|
|
51
|
+
private boolean useStyledControls = true;
|
|
52
|
+
private boolean allowBackgroundPlayback = false;
|
|
53
|
+
|
|
54
|
+
public Builder() {
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public Builder setAutoPlay(boolean autoPlay) {
|
|
58
|
+
this.autoPlay = autoPlay;
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public Builder setControls(boolean controls) {
|
|
63
|
+
this.controls = controls;
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public Builder setMuted(boolean muted) {
|
|
68
|
+
this.muted = muted;
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public Builder setLoop(boolean loop) {
|
|
73
|
+
this.loop = loop;
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public Builder setPreload(String preload) {
|
|
78
|
+
this.preload = preload;
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public Builder setStartTime(long startTime) {
|
|
83
|
+
this.startTime = startTime;
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public Builder setPlaybackSpeed(float speed) {
|
|
88
|
+
this.playbackSpeed = speed;
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public Builder setVolume(float volume) {
|
|
93
|
+
this.volume = volume;
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public Builder setDebug(boolean debug) {
|
|
98
|
+
this.debug = debug;
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public Builder setUseStyledControls(boolean styled) {
|
|
103
|
+
this.useStyledControls = styled;
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public Builder setAllowBackgroundPlayback(boolean allow) {
|
|
108
|
+
this.allowBackgroundPlayback = allow;
|
|
109
|
+
return this;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public PlayerConfiguration build() {
|
|
113
|
+
return new PlayerConfiguration(this);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@Override
|
|
118
|
+
public String toString() {
|
|
119
|
+
return "PlayerConfiguration{" +
|
|
120
|
+
"autoPlay=" + autoPlay +
|
|
121
|
+
", controls=" + controls +
|
|
122
|
+
", muted=" + muted +
|
|
123
|
+
", loop=" + loop +
|
|
124
|
+
", preload='" + preload + '\'' +
|
|
125
|
+
", startTime=" + startTime +
|
|
126
|
+
", playbackSpeed=" + playbackSpeed +
|
|
127
|
+
", volume=" + volume +
|
|
128
|
+
", debug=" + debug +
|
|
129
|
+
", useStyledControls=" + useStyledControls +
|
|
130
|
+
", allowBackgroundPlayback=" + allowBackgroundPlayback +
|
|
131
|
+
'}';
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Media source information class
|
|
137
|
+
*/
|
|
138
|
+
class MediaSourceInfo {
|
|
139
|
+
public final String url;
|
|
140
|
+
public final String type;
|
|
141
|
+
public final DRMConfiguration drm;
|
|
142
|
+
public final java.util.Map<String, Object> metadata;
|
|
143
|
+
public final java.util.List<SubtitleTrack> subtitles;
|
|
144
|
+
|
|
145
|
+
public MediaSourceInfo(String url) {
|
|
146
|
+
this(url, detectType(url), null, null, null);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public MediaSourceInfo(String url, String type) {
|
|
150
|
+
this(url, type, null, null, null);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public MediaSourceInfo(String url, String type, DRMConfiguration drm,
|
|
154
|
+
java.util.Map<String, Object> metadata,
|
|
155
|
+
java.util.List<SubtitleTrack> subtitles) {
|
|
156
|
+
this.url = url;
|
|
157
|
+
this.type = type;
|
|
158
|
+
this.drm = drm;
|
|
159
|
+
this.metadata = metadata;
|
|
160
|
+
this.subtitles = subtitles;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public static String detectType(String url) {
|
|
164
|
+
if (url.contains(".m3u8")) return "hls";
|
|
165
|
+
if (url.contains(".mpd")) return "dash";
|
|
166
|
+
if (url.contains(".ism")) return "smoothstreaming";
|
|
167
|
+
if (url.contains(".mp4")) return "mp4";
|
|
168
|
+
if (url.contains(".webm")) return "webm";
|
|
169
|
+
if (url.contains(".mkv")) return "mkv";
|
|
170
|
+
return "mp4";
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* DRM configuration class
|
|
176
|
+
*/
|
|
177
|
+
class DRMConfiguration {
|
|
178
|
+
public final String type; // widevine, playready, clearkey
|
|
179
|
+
public final String licenseUrl;
|
|
180
|
+
public final java.util.Map<String, String> headers;
|
|
181
|
+
public final boolean multiSession;
|
|
182
|
+
public final boolean forceDefaultLicenseUri;
|
|
183
|
+
|
|
184
|
+
public DRMConfiguration(String type, String licenseUrl) {
|
|
185
|
+
this(type, licenseUrl, null, false, false);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public DRMConfiguration(String type, String licenseUrl,
|
|
189
|
+
java.util.Map<String, String> headers,
|
|
190
|
+
boolean multiSession,
|
|
191
|
+
boolean forceDefaultLicenseUri) {
|
|
192
|
+
this.type = type;
|
|
193
|
+
this.licenseUrl = licenseUrl;
|
|
194
|
+
this.headers = headers;
|
|
195
|
+
this.multiSession = multiSession;
|
|
196
|
+
this.forceDefaultLicenseUri = forceDefaultLicenseUri;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Subtitle track class
|
|
202
|
+
*/
|
|
203
|
+
class SubtitleTrack {
|
|
204
|
+
public final String url;
|
|
205
|
+
public final String language;
|
|
206
|
+
public final String label;
|
|
207
|
+
public final String kind; // subtitles, captions
|
|
208
|
+
public final String mimeType;
|
|
209
|
+
|
|
210
|
+
public SubtitleTrack(String url, String language, String label) {
|
|
211
|
+
this(url, language, label, "subtitles", "text/vtt");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public SubtitleTrack(String url, String language, String label, String kind, String mimeType) {
|
|
215
|
+
this.url = url;
|
|
216
|
+
this.language = language;
|
|
217
|
+
this.label = label;
|
|
218
|
+
this.kind = kind;
|
|
219
|
+
this.mimeType = mimeType;
|
|
220
|
+
}
|
|
221
|
+
}
|