Skip to content

Commit

Permalink
Merge pull request #452 from THEOplayer/release/v8.9.0
Browse files Browse the repository at this point in the history
Release/v8.9.0
  • Loading branch information
tvanlaerhoven authored Nov 29, 2024
2 parents 70f71f0 + adbee47 commit 5b6c839
Show file tree
Hide file tree
Showing 32 changed files with 551 additions and 161 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/pr_android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@ on:
workflow_dispatch:
pull_request:
types: [opened, reopened, synchronize]
paths:
- .github/workflows/pr_android.yml
- example/**
- e2e/**
- package.json
- src/**
- android/**

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
api-level: [ 34 ]
name: Build for API Level ${{ matrix.api-level }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand Down
14 changes: 12 additions & 2 deletions .github/workflows/pr_ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,22 @@ on:
workflow_dispatch:
pull_request:
types: [opened, reopened, synchronize]
paths:
- .github/workflows/pr_ios.yml
- example/**
- e2e/**
- package.json
- src/**
- ios/**

jobs:
build:
strategy:
matrix:
xcode_version: [ '15.4.0' ]
platform: [iOS, tvOS]
runs-on: macos-latest
name: Build for ${{ matrix.platform }} using XCode version ${{ matrix.xcode_version }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand Down Expand Up @@ -52,12 +61,13 @@ jobs:
- name: Start iOS simulator
uses: futureware-tech/simulator-action@v4
with:
model: 'iPhone 15'
model: ${{ matrix.platform == 'iOS' && 'iPhone 15' || 'Apple TV' }}
os: ${{ matrix.platform }}
os_version: '>=14.0'

- name: Run e2e tests
working-directory: e2e
run: npm run test:e2e:ios
run: npm run test:e2e:${{ matrix.platform == 'iOS' && 'ios' || 'tvos' }}

- name: Summarize results
working-directory: e2e
Expand Down
20 changes: 19 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,27 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [8.9.0] - 24-11-29

### Added

- Added support for the `SURFACE_CONTROL` rendering target on Android, which improves switching from/to fullscreen presentation mode. Rendering target `SURFACE_CONTROL` will be selected instead of `SURFACE_VIEW` on API level 29+.

### Fixed

- Fixed a memory leak on iOS, caused by the wrapping ViewController that was keeping a strong reference to the THEOplayerRCTView.

### Added

- Added support for the experimental media3 player pipeline on Android.

### Changed

- **BREAKING**: Changed the `view` parameter in the `Omid` API from a ref container to a native node handle when registering "friendly" obstructions.

## [8.8.1] - 24-11-20

### Fixed
### Fixed

- Fixed build issue on tvOS caused by HomeIndicatorViewController

Expand Down
16 changes: 14 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def enabledTHEOads = safeExtGet("THEOplayer_extensionTHEOads", 'false').toBoolea
def enabledAds = enabledGoogleIMA || enabledGoogleDAI || enabledTHEOads
def enabledCast = safeExtGet("THEOplayer_extensionCast", 'false').toBoolean()
def enabledMediaSession = safeExtGet("THEOplayer_extensionMediaSession", 'true').toBoolean()
def enabledMedia3 = safeExtGet("THEOplayer_extensionMedia3", 'true').toBoolean()

android {
compileSdk safeExtGet('THEOplayer_compileSdkVersion', 34)
Expand Down Expand Up @@ -66,6 +67,7 @@ android {
buildConfigField "boolean", "EXTENSION_ADS", "${enabledAds}"
buildConfigField "boolean", "EXTENSION_CAST", "${enabledCast}"
buildConfigField "boolean", "EXTENSION_MEDIASESSION", "${enabledMediaSession}"
buildConfigField "boolean", "EXTENSION_MEDIA3", "${enabledMedia3}"

consumerProguardFiles 'proguard-rules.pro'
}
Expand Down Expand Up @@ -93,7 +95,9 @@ android {

rootProject.allprojects {
repositories {
mavenLocal()
maven { url "https://maven.theoplayer.com/releases" }
maven { url "https://maven.theoplayer.com/snapshots" }
maven { url("$rootDir/../node_modules/react-native-theoplayer/android/local") }
}
}
Expand All @@ -110,8 +114,8 @@ repositories {
maven { url "https://maven.theoplayer.com/releases" }
}

// The minimum supported THEOplayer version is 8.3.0
def theoplayer_sdk_version = safeExtGet('THEOplayer_sdk', '[8.3.0, 9.0.0)')
// The minimum supported THEOplayer version is 8.5.1
def theoplayer_sdk_version = safeExtGet('THEOplayer_sdk', '[8.5.1, 9.0.0)')
def theoplayer_mediasession_version = safeExtGet('THEOplayer_mediasession', '[8.0.0, 9.0.0)')

dependencies {
Expand Down Expand Up @@ -158,6 +162,14 @@ dependencies {
println('Disable THEOplayer cast extension.')
compileOnly "com.theoplayer.theoplayer-sdk-android:integration-cast:${theoplayer_sdk_version}"
}

if (enabledMedia3) {
println('Enable THEOplayer media3 extension.')
implementation "com.theoplayer.theoplayer-sdk-android:integration-media3:${theoplayer_sdk_version}"
} else {
println('Disable THEOplayer media3 extension.')
compileOnly "com.theoplayer.theoplayer-sdk-android:integration-media3:${theoplayer_sdk_version}"
}
}

// Make sure to align all ads extension versions
Expand Down
10 changes: 10 additions & 0 deletions android/src/main/java/com/theoplayer/PlayerConfigAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ private const val PROP_UI_ENABLED = "uiEnabled"
private const val PROP_CAST_STRATEGY = "strategy"
private const val PROP_RETRY_CONFIG = "retryConfiguration"
private const val PROP_HLS_DATE_RANGE = "hlsDateRange"
private const val PROP_USE_MEDIA3 = "useMedia3"
private const val PROP_RETRY_MAX_RETRIES = "maxRetries"
private const val PROP_RETRY_MIN_BACKOFF = "minimumBackoff"
private const val PROP_RETRY_MAX_BACKOFF = "maximumBackoff"
Expand All @@ -39,6 +40,12 @@ private const val PROP_ALLOWED_MIMETYPES = "allowedMimeTypes"

class PlayerConfigAdapter(private val configProps: ReadableMap?) {

/**
* Whether the Media3 extension is used for play-out.
*/
var useMedia3: Boolean = false
private set

/**
* Get general THEOplayerConfig object; these properties apply:
* - license: The license for the player.
Expand All @@ -63,6 +70,9 @@ class PlayerConfigAdapter(private val configProps: ReadableMap?) {
if (hasKey(PROP_HLS_DATE_RANGE)) {
hlsDateRange(getBoolean(PROP_HLS_DATE_RANGE))
}
if (hasKey(PROP_USE_MEDIA3)) {
useMedia3 = getBoolean(PROP_USE_MEDIA3)
}
pipConfiguration(PipConfiguration.Builder().build())
}
}.build()
Expand Down
30 changes: 30 additions & 0 deletions android/src/main/java/com/theoplayer/ReactTHEOplayerContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.res.Configuration
import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.os.Looper
Expand All @@ -24,7 +25,10 @@ import com.theoplayer.android.api.cast.CastIntegration
import com.theoplayer.android.api.cast.CastIntegrationFactory
import com.theoplayer.android.api.event.EventListener
import com.theoplayer.android.api.event.player.*
import com.theoplayer.android.api.media3.Media3PlayerIntegration
import com.theoplayer.android.api.media3.Media3PlayerIntegrationFactory
import com.theoplayer.android.api.player.Player
import com.theoplayer.android.api.player.RenderingTarget
import com.theoplayer.android.connector.mediasession.MediaSessionConnector
import com.theoplayer.audio.AudioBecomingNoisyManager
import com.theoplayer.audio.AudioFocusManager
Expand Down Expand Up @@ -84,6 +88,8 @@ class ReactTHEOplayerContext private constructor(
var imaIntegration: GoogleImaIntegration? = null
private var theoAdsIntegration: TheoAdsIntegration? = null
var castIntegration: CastIntegration? = null
@Suppress("UnstableApiUsage")
private var media3Integration: Media3PlayerIntegration? = null
var wasPlayingOnHostPause: Boolean = false
private var isHostPaused: Boolean = false

Expand Down Expand Up @@ -216,6 +222,13 @@ class ReactTHEOplayerContext private constructor(
}
}

// By default, choose SURFACE_CONTROL/SURFACE_VIEW rendering target, based on API level.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
player.setRenderingTarget(RenderingTarget.SURFACE_CONTROL)
} else {
player.setRenderingTarget(RenderingTarget.SURFACE_VIEW)
}

// By default, the screen should remain on.
playerView.keepScreenOn = true

Expand Down Expand Up @@ -321,6 +334,23 @@ class ReactTHEOplayerContext private constructor(
} catch (e: Exception) {
Log.w(TAG, "Failed to configure Cast integration ${e.message}")
}
try {
if (BuildConfig.EXTENSION_MEDIA3) {
@Suppress("UnstableApiUsage")
media3Integration =
Media3PlayerIntegrationFactory.createMedia3PlayerIntegration { _, _ ->
// selectedSource -> represents the TypedSource the player picked to play.
// source -> represents the SourceDescription passed to the player.
// return true -> the Media3 integration pipeline will be used to play the selected source.
// return false -> the default pipeline will be used to play the selected source.
configAdapter.useMedia3
}
playerView.player.addIntegration(media3Integration)
}
} catch (e: Exception) {
Log.w(TAG, "Failed to configure Cast integration ${e.message}")
}

// Add other future integrations here.
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.theoplayer.latency

import com.theoplayer.android.api.latency.LatencyConfiguration
import org.json.JSONObject

private const val PROP_MINIMUM_OFFSET = "minimumOffset"
private const val PROP_MAXIMUM_OFFSET = "maximumOffset"
private const val PROP_TARGET_OFFSET = "targetOffset"
private const val PROP_FORCE_SEEK_OFFSET = "forceSeekOffset"
private const val PROP_MINIMUM_PLAYBACK_RATE = "minimumPlaybackRate"
private const val PROP_MAXIMUM_PLAYBACK_RATE = "maximumPlaybackRate"

fun parseLatencyConfiguration(jsonLatency: JSONObject): LatencyConfiguration {
return LatencyConfiguration.Builder().apply {
setMinimumOffset(jsonLatency.optDouble(PROP_MINIMUM_OFFSET))
setMaximumOffset(jsonLatency.optDouble(PROP_MAXIMUM_OFFSET))
setTargetOffset(jsonLatency.optDouble(PROP_TARGET_OFFSET))
setForceSeekOffset(jsonLatency.optDouble(PROP_FORCE_SEEK_OFFSET))
setMinimumPlaybackRate(jsonLatency.optDouble(PROP_MINIMUM_PLAYBACK_RATE))
setMaximumPlaybackRate(jsonLatency.optDouble(PROP_MAXIMUM_PLAYBACK_RATE))
}.build()
}
42 changes: 28 additions & 14 deletions android/src/main/java/com/theoplayer/player/PlayerModule.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.theoplayer.player

import android.os.Build
import com.facebook.react.bridge.*
import com.theoplayer.*
import com.theoplayer.abr.ABRConfigurationAdapter
Expand Down Expand Up @@ -184,11 +185,13 @@ class PlayerModule(context: ReactApplicationContext) : ReactContextBaseJavaModul
@ReactMethod
fun setPresentationMode(tag: Int, type: String?) {
viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? ->
view?.presentationManager?.setPresentation(when (type) {
"picture-in-picture" -> PresentationMode.PICTURE_IN_PICTURE
"fullscreen" -> PresentationMode.FULLSCREEN
else -> PresentationMode.INLINE
})
view?.presentationManager?.setPresentation(
when (type) {
"picture-in-picture" -> PresentationMode.PICTURE_IN_PICTURE
"fullscreen" -> PresentationMode.FULLSCREEN
else -> PresentationMode.INLINE
}
)
}
}

Expand All @@ -209,11 +212,13 @@ class PlayerModule(context: ReactApplicationContext) : ReactContextBaseJavaModul
@ReactMethod
fun setAspectRatio(tag: Int, ratio: String) {
viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? ->
view?.player?.setAspectRatio(when (ratio) {
"fill" -> AspectRatio.FILL
"aspectFill" -> AspectRatio.ASPECT_FILL
else -> AspectRatio.FIT
})
view?.player?.setAspectRatio(
when (ratio) {
"fill" -> AspectRatio.FILL
"aspectFill" -> AspectRatio.ASPECT_FILL
else -> AspectRatio.FIT
}
)
}
}

Expand All @@ -236,10 +241,19 @@ class PlayerModule(context: ReactApplicationContext) : ReactContextBaseJavaModul
@ReactMethod
fun setRenderingTarget(tag: Int, target: String) {
viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? ->
view?.player?.setRenderingTarget(when (target) {
"textureView" -> RenderingTarget.TEXTURE_VIEW
else -> RenderingTarget.SURFACE_VIEW
})
view?.player?.setRenderingTarget(
when (target) {
"textureView" -> RenderingTarget.TEXTURE_VIEW
else -> {
// Prefer SURFACE_CONTROL
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
RenderingTarget.SURFACE_CONTROL
} else {
RenderingTarget.SURFACE_VIEW
}
}
}
)
}
}
}
Loading

0 comments on commit 5b6c839

Please sign in to comment.