Skip to content

Commit

Permalink
Releases/v3.4.5 (#329)
Browse files Browse the repository at this point in the history
## Improvements

* Add support for ExoPlayer 2.19 (#327)
* Clean out code for old ExoPlayer support (#328)



Co-authored-by: Emily Dixon <edixon@mux.com>
Co-authored-by: GitHub <noreply@github.com>
  • Loading branch information
daytime-em and web-flow authored Sep 19, 2023
1 parent 520ccc2 commit 56425ad
Show file tree
Hide file tree
Showing 182 changed files with 1,308 additions and 34,351 deletions.
17 changes: 7 additions & 10 deletions .github/workflows/saucelabs-tests-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@ name: Test with Sauce Labs (Only Latest)

on:
push:
branches:
- '!releases/**'
- '!master'

env:
SAUCE_USERNAME: ${{secrets.SAUCE_USERNAME}}
SAUCE_ACCESS_KEY: ${{secrets.SAUCE_ACCESS_KEY}}

concurrency:
group: sauce-labs
cancel-in-progress: true
#concurrency:
# group: sauce-labs
# cancel-in-progress: true

jobs:
build:
Expand All @@ -29,7 +26,7 @@ jobs:
- name: Build automated tests
uses: gradle/gradle-build-action@v2.3.3
with:
arguments: automatedtests:assembleR2_18_1Debug :automatedtests:assembleR2_18_1DebugAndroidTest
arguments: automatedtests:assembleR2_19_1Debug :automatedtests:assembleR2_19_1DebugAndroidTest
- name: Upload Test APKs
uses: actions/upload-artifact@v3
with:
Expand All @@ -38,15 +35,15 @@ jobs:
automatedtests/buildout/outputs/apk/androidTest/**/*.apk
automatedtests/buildout/outputs/apk/*/debug/automatedtests-*-debug.apk
test-18:
test:
name: Run Sauce Labs Tests
runs-on: ubuntu-latest
needs: build

strategy:
max-parallel: 2
matrix:
exo: ['r2_18_1']
exo: ['r2_19_1']

env:
app_artifact: automatedtests\/buildout\/outputs\/apk\/${{ matrix.exo }}\/debug\/automatedtests-${{ matrix.exo }}-debug.apk
Expand All @@ -69,7 +66,7 @@ jobs:
.sauce/template.yml > .sauce/conf.yml
- name: Dump Generated Sauce Conf
run: cat .sauce/conf.yml
- name: Run Saucelabs Test (2.18.1)
- name: Run Saucelabs Test
uses: saucelabs/saucectl-run-action@v3
env:
GITHUB_TOKEN: ${{ github.token }}
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/saucelabs-tests-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ env:
SAUCE_USERNAME: ${{secrets.SAUCE_USERNAME}}
SAUCE_ACCESS_KEY: ${{secrets.SAUCE_ACCESS_KEY}}

concurrency:
group: sauce-labs
cancel-in-progress: true
#concurrency:
# group: sauce-labs
# cancel-in-progress: true

jobs:
build:
Expand Down Expand Up @@ -47,7 +47,7 @@ jobs:
max-parallel: 1
#max-parallel: 2
matrix:
exo: ['r2_18_1','r2_17_1','r2_16_1','r2_15_1','r2_14_1',]
exo: ['r2_18_1','r2_17_1','r2_16_1','r2_15_1','r2_14_1']

env:
app_artifact: automatedtests\/buildout\/outputs\/apk\/${{ matrix.exo }}\/debug\/automatedtests-${{ matrix.exo }}-debug.apk
Expand Down
24 changes: 18 additions & 6 deletions ExoPlayerAdapter/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,25 @@ android {
just2_15 { dimension 'source' }
just2_16 { dimension 'source' }
just2_17 { dimension 'source' }
from2_18toNow { dimension 'source' }
just2_18 { dimension 'source' }
just2_19 { dimension 'source' }
// Exoplayer version for testing/variant matching
r2_14_1 { dimension 'exoplayer' }
r2_15_1 { dimension 'exoplayer' }
r2_16_1 { dimension 'exoplayer' }
amznPort { dimension 'exoplayer' }
r2_17_1 { dimension 'exoplayer' }
r2_18_1 { dimension 'exoplayer' }
r2_19_1 { dimension 'exoplayer' }
}
// We only want the variants where the sourceSet and exoplayer version agree
def realVariants = [
"just2_14" : ["r2_14_1"],
"just2_15" : ["r2_15_1"],
"just2_16" : ["r2_16_1", "amznPort"],
"just2_17" : ["r2_17_1"],
"from2_18toNow" : ["r2_18_1"]
"just2_18" : ["r2_18_1"],
"just2_19" : ["r2_19_1"],
]
variantFilter { variant ->
def exoPlayerFlavor = variant.flavors.findAll { it.dimension == "exoplayer" }[0]
Expand Down Expand Up @@ -77,7 +80,7 @@ android {
just2_16 {
java.srcDirs += 'src/exo-analytics-listener-2_13-2_16/java'
java.srcDirs += 'src/exo-collector-2_10-now/java'
java.srcDirs += 'src/exo-analytics-2_16-now/java'
java.srcDirs += 'src/exo-analytics-just2_16/java'
java.srcDirs += 'src/exo-error-2_15-now/java'
java.srcDirs += 'src/exo-mediaitem-2_14-now/java'
java.srcDirs += 'src/exo-player-2_16-now/java'
Expand All @@ -86,21 +89,29 @@ android {
just2_17 {
java.srcDirs += 'src/exo-analytics-listener-just-2_17/java'
java.srcDirs += 'src/exo-collector-2_10-now/java'
java.srcDirs += 'src/exo-analytics-2_16-now/java'
java.srcDirs += 'src/exo-analytics-just2_16/java'
java.srcDirs += 'src/exo-error-2_15-now/java'
java.srcDirs += 'src/exo-mediaitem-2_14-now/java'
java.srcDirs += 'src/exo-player-2_16-now/java'
// From 2.16 onward, we don't need exo-event
}
from2_18toNow {
just2_18 {
java.srcDirs += 'src/exo-analytics-listener-2_18-now/java'
java.srcDirs += 'src/exo-collector-2_10-now/java'
java.srcDirs += 'src/exo-analytics-2_16-now/java'
java.srcDirs += 'src/exo-analytics-just2_16/java'
java.srcDirs += 'src/exo-error-2_15-now/java'
java.srcDirs += 'src/exo-mediaitem-2_14-now/java'
java.srcDirs += 'src/exo-player-2_16-now/java'
// From 2.16 onward, we don't need exo-event
}
just2_19 {
java.srcDirs += 'src/exo-analytics-listener-2_18-now/java'
java.srcDirs += 'src/exo-collector-2_10-now/java'
java.srcDirs += 'src/exo-analytics-2_19-now/java'
java.srcDirs += 'src/exo-error-2_15-now/java'
java.srcDirs += 'src/exo-mediaitem-2_14-now/java'
java.srcDirs += 'src/exo-player-2_16-now/java'
}
}

compileOptions {
Expand Down Expand Up @@ -144,6 +155,7 @@ dependencies {
r2_17_1Api 'com.google.android.exoplayer:exoplayer:2.17.1'
//noinspection GradleDynamicVersion,GradleDependency
r2_18_1Api 'com.google.android.exoplayer:exoplayer:2.18.1'
r2_19_1Api 'com.google.android.exoplayer:exoplayer:2.19.1'

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${project.ext.kotlinxCoroutinesVersion}"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package com.mux.stats.sdk.muxstats

import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.analytics.AnalyticsListener
import com.google.android.exoplayer2.source.hls.HlsManifest
import com.mux.stats.sdk.core.model.SessionTag
import com.mux.stats.sdk.core.util.MuxLogger
import com.mux.stats.sdk.muxstats.internal.isHlsExtensionAvailable
import com.mux.stats.sdk.muxstats.internal.weak
import java.util.regex.Matcher
import java.util.regex.Pattern

private class SessionDataPlayerBinding : MuxPlayerAdapter.PlayerBinding<ExoPlayer> {

private var listener: AnalyticsListener? by weak(null)

override fun bindPlayer(player: ExoPlayer, collector: MuxStateCollector) {
if (isHlsExtensionAvailable()) {
listener = SessionDataListener(player, collector).also { player.addAnalyticsListener(it) }
}
}

override fun unbindPlayer(player: ExoPlayer, collector: MuxStateCollector) {
listener?.let { player.removeAnalyticsListener(it) }
}

/**
* Listens for timeline changes and updates HLS session data if we're on an HLS stream.
* This class should only be instantiated if ExoPlayer's HLS extension is available at runtime
* @see [.isHlsExtensionAvailable]
*/
private class SessionDataListener(player: ExoPlayer, val collector: MuxStateCollector) :
AnalyticsListener {

private val player by weak(player)

companion object {
val RX_SESSION_TAG_DATA_ID by lazy { Pattern.compile("DATA-ID=\"(.*)\",") }
val RX_SESSION_TAG_VALUES by lazy { Pattern.compile("VALUE=\"(.*)\"") }

/** HLS session data tags with this Data ID will be sent to Mux Data */
const val HLS_SESSION_LITIX_PREFIX = "io.litix.data."
const val LOG_TAG = "SessionDataListener"
}

override fun onTimelineChanged(eventTime: AnalyticsListener.EventTime, reason: Int) {
player?.let { safePlayer ->
val manifest = safePlayer.currentManifest
if (manifest is HlsManifest) {
collector.onMainPlaylistTags(parseHlsSessionData(manifest.multivariantPlaylist.tags))
}
}
}

private fun parseHlsSessionData(hlsTags: List<String>): List<SessionTag> {
val data: MutableList<SessionTag> = ArrayList()
for (tag in filterHlsSessionTags(hlsTags)) {
val st: SessionTag = parseHlsSessionTag(tag)
if (st.key != null && st.key.contains(HLS_SESSION_LITIX_PREFIX)) {
data.add(parseHlsSessionTag(tag))
}
}
return data
}

private fun filterHlsSessionTags(rawTags: List<String>) =
rawTags.filter { it.substring(1).startsWith("EXT-X-SESSION-DATA") }

private fun parseHlsSessionTag(line: String): SessionTag {
val dataId: Matcher = RX_SESSION_TAG_DATA_ID.matcher(line)
val value: Matcher = RX_SESSION_TAG_VALUES.matcher(line)
var parsedDataId: String? = ""
var parsedValue: String? = ""
if (dataId.find()) {
parsedDataId = dataId.group(1)?.replace(HLS_SESSION_LITIX_PREFIX, "")
} else {
MuxLogger.d(LOG_TAG, "Data-ID not found in session data: $line")
}
if (value.find()) {
parsedValue = value.group(1)
} else {
MuxLogger.d(LOG_TAG, "Value not found in session data: $line")
}
return SessionTag(parsedDataId, parsedValue)
}
}
}

/**
* Creates a listener that listens for timeline changes and updates HLS session data if we're on an
* HLS stream.
* This class should only be instantiated if ExoPlayer's HLS extension is available at runtime
* @see [.isHlsExtensionAvailable]
*/
@Suppress("unused") // using the receiver to avoid polluting customers' namespace
fun MuxStateCollector.createExoSessionDataBinding(): MuxPlayerAdapter.PlayerBinding<ExoPlayer> =
SessionDataPlayerBinding()
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.mux.stats.sdk.muxstats

import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.analytics.AnalyticsListener
import com.mux.stats.sdk.core.util.MuxLogger
import com.mux.stats.sdk.muxstats.internal.exoAnalyticsListener
import com.mux.stats.sdk.muxstats.internal.logTag
import com.mux.stats.sdk.muxstats.internal.watchContentPosition

/**
* Binding to an ExoPlayer using AnalyticsListener
*/
private class AnalyticsListenerBinding216ToNow : MuxPlayerAdapter.PlayerBinding<ExoPlayer> {

private var listener: AnalyticsListener? = null//by weak(null)

init {
MuxLogger.d(logTag(), "created");
}

override fun bindPlayer(player: ExoPlayer, collector: MuxStateCollector) {
listener = exoAnalyticsListener(player, collector).also {
player.addAnalyticsListener(it)
player.watchContentPosition(collector)
}
}

override fun unbindPlayer(player: ExoPlayer, collector: MuxStateCollector) {
listener?.let { player.removeAnalyticsListener(it) }
collector.positionWatcher?.stop("unbound")
}

}


@JvmSynthetic // Hides from java callers outside the module
internal fun analyticsListenerMetrics()
: MuxPlayerAdapter.PlayerBinding<ExoPlayer> = AnalyticsListenerBinding216ToNow()
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,6 @@ private class ExoAnalyticsListener(player: ExoPlayer, val collector: MuxStateCol
collector.seeking()
}

@Suppress("OVERRIDE_DEPRECATION") // Not worth making a new variant over (deprecated 2.12)
override fun onSeekProcessed(eventTime: EventTime) {
// TODO: This the new way (over position discontinuity or guessing) so figure out how to use it
//collector.seeked(false)
}

override fun onTimelineChanged(eventTime: EventTime, reason: Int) {
val player = player // strong reference during the listener call
if (player != null && eventTime.timeline.windowCount > 0) {
Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit 56425ad

Please sign in to comment.