Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Defer content rendition changes during ads #76

Merged
merged 32 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
fe9fcac
feat: Defer from the content rendition changing during ad breaks
daytime-em Nov 23, 2024
e074a47
ok
daytime-em Nov 23, 2024
f0d9136
yay more
daytime-em Nov 23, 2024
2f9b251
eeee
daytime-em Nov 23, 2024
2245477
Man it would be nice to know what the PlayerListener thinks is going on
daytime-em Nov 23, 2024
9508a54
try doign this while playing
daytime-em Nov 23, 2024
30e85dc
america
daytime-em Nov 25, 2024
bc339db
up
daytime-em Nov 25, 2024
2a046c3
Bop
daytime-em Nov 26, 2024
73c7233
up
daytime-em Nov 26, 2024
521394d
core
daytime-em Nov 26, 2024
e2b0815
walaksdj
daytime-em Nov 26, 2024
6065bb0
asdlkm
daytime-em Nov 26, 2024
a452eb3
cleanup
daytime-em Nov 26, 2024
4c3ce7f
ok
daytime-em Nov 26, 2024
57666d6
ok
daytime-em Nov 26, 2024
8a7eda7
walerij
daytime-em Nov 26, 2024
c2ee6e9
alksfj
daytime-em Nov 27, 2024
1cdf396
sflkj
daytime-em Nov 27, 2024
ddd141b
afsklj
daytime-em Nov 27, 2024
1d3d6d5
SFLkj
daytime-em Nov 27, 2024
3723f40
asdlikj
daytime-em Nov 27, 2024
6e46896
ASFLIhkj
daytime-em Nov 27, 2024
0f0e1d3
alsfkj
daytime-em Nov 27, 2024
dcb16aa
ASLFKJ
daytime-em Nov 27, 2024
b9a53cf
cleaned-up java core
daytime-em Nov 27, 2024
26de48c
cleanup muxnetwork
daytime-em Nov 27, 2024
3f7da77
cleanup 2
daytime-em Nov 27, 2024
5d54686
add tests
daytime-em Nov 27, 2024
408df49
Add test cases for subsequent renditionchanges
daytime-em Dec 5, 2024
436a223
Add test cases for subsequent renditionchanges
daytime-em Dec 5, 2024
1255bc2
Merge branch 'feat/defer-renditionchange-during-events' of github.com…
daytime-em Dec 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ plugins {

android {
namespace = "com.mux.app"
compileSdk = 34
compileSdk = 35

defaultConfig {
applicationId = "com.mux.app"
minSdk = 24
targetSdk = 34
targetSdk = 35
versionCode = 1
versionName = "1.0"

Expand All @@ -36,11 +36,11 @@ dependencies {

project(":library")

implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.core:core-ktx:1.15.0")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("com.google.android.material:material:1.12.0")
implementation("androidx.activity:activity:1.8.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.activity:activity:1.9.3")
implementation("androidx.constraintlayout:constraintlayout:2.2.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
Expand Down
24 changes: 0 additions & 24 deletions app/src/androidTest/java/com/mux/app/ExampleInstrumentedTest.kt

This file was deleted.

17 changes: 0 additions & 17 deletions app/src/test/java/com/mux/app/ExampleUnitTest.kt

This file was deleted.

3 changes: 2 additions & 1 deletion library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ muxDistribution {
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1"

api "com.mux:stats.muxcore:8.1.3"
api "com.mux:stats.muxcore:dev-feat/send-all-on-rc-34eac3b"

testImplementation 'androidx.test.ext:junit-ktx:1.2.1'
testImplementation 'junit:junit:4.13.2'
testImplementation 'androidx.test.ext:junit:1.2.1'
testImplementation "io.mockk:mockk:1.13.9"
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mux.stats.sdk.muxstats

import android.util.Log
import com.mux.android.util.logTag
import com.mux.android.util.noneOf
import com.mux.android.util.oneOf
Expand All @@ -10,6 +11,7 @@ import com.mux.stats.sdk.core.events.InternalErrorEvent
import com.mux.stats.sdk.core.events.playback.*
import com.mux.stats.sdk.core.model.BandwidthMetricData
import com.mux.stats.sdk.core.model.CustomerVideoData
import com.mux.stats.sdk.core.model.PlayerData
import com.mux.stats.sdk.core.model.SessionTag
import com.mux.stats.sdk.core.model.VideoData
import com.mux.stats.sdk.core.util.MuxLogger
Expand Down Expand Up @@ -442,8 +444,18 @@ open class MuxStateCollector(
reset()
}

/**
* Set to true if we get a main-content format change during a period when we shouldn't be getting
* one (eg, during ad breaks). In this case, the rendition info will be sent after the ad break
* ends
*/
private var contentRenditionDeferred: Boolean = false

/**
* Call when the currently-playing rendition changes.
*
* Expects only to be called for changes to the rendition of the main content being played. Ad
* sizes should not be reported, even SSAI ads or segmented CSAI ads
*/
@Suppress("unused")
fun renditionChange(
Expand All @@ -457,6 +469,12 @@ open class MuxStateCollector(
this.sourceWidth = sourceWidth
this.sourceHeight = sourceHeight

if (_playerState == MuxPlayerState.PLAYING_ADS) {
// we have to save this one for after the ad break
contentRenditionDeferred = true
return
}

dispatch(RenditionChangeEvent(null))
}

Expand Down Expand Up @@ -484,6 +502,12 @@ open class MuxStateCollector(
fun finishedPlayingAds() {
_playerState = MuxPlayerState.FINISHED_PLAYING_ADS

if (contentRenditionDeferred) {
MuxLogger.d("MuxStateCollector", "sending deferred content 'renditionchange'")
contentRenditionDeferred = false
dispatch(RenditionChangeEvent(null))
}

// players allow seeking out of ads.
// If playback follows, the data sdk also needs to call playing()
if (seekingInProgress) {
Expand Down Expand Up @@ -547,6 +571,7 @@ open class MuxStateCollector(
allowedHeaders.clear()
droppedFrames = 0
muxStats.setDroppedFramesCount(0)
contentRenditionDeferred = false
}

@JvmSynthetic
Expand Down
102 changes: 102 additions & 0 deletions library/src/test/java/com/mux/core_android/StateCollectorTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Before
import org.junit.Test
import kotlin.math.exp

class StateCollectorTests : AbsRobolectricTest() {

Expand Down Expand Up @@ -352,4 +353,105 @@ class StateCollectorTests : AbsRobolectricTest() {
mockMuxStats.setDroppedFramesCount(0)
}
}

@Test
fun testRenditionChangeDuringAd() {
val expected = 2000;

eventDispatcher.dispatch(AdBreakStartEvent(null))
stateCollector.playingAds()
stateCollector.renditionChange(
daytime-em marked this conversation as resolved.
Show resolved Hide resolved
advertisedBitrate = 1000,
advertisedFrameRate = 1000f,
sourceHeight = 1000,
sourceWidth = 1000
)
stateCollector.renditionChange(
advertisedFrameRate = expected.toFloat(),
advertisedBitrate = expected,
sourceWidth = expected,
sourceHeight = expected,
)
eventDispatcher.dispatch(AdBreakEndEvent(null))
stateCollector.finishedPlayingAds()

eventDispatcher.assertHasExactlyThese(listOf(
AdBreakStartEvent(null), AdBreakEndEvent(null), RenditionChangeEvent(null)
))

assertEquals(
"Values from intermediate rendition changes should be skipped",
expected, stateCollector.sourceAdvertisedBitrate
)
assertEquals(
"Values from intermediate rendition changes should be skipped",
expected.toFloat(), stateCollector.sourceAdvertisedFrameRate.toFloat()
)
assertEquals(
"Values from intermediate rendition changes should be skipped",
expected, stateCollector.sourceWidth
)
assertEquals(
"Values from intermediate rendition changes should be skipped",
expected, stateCollector.sourceHeight
)
}

@Test
fun testRenditionChangeNotDuringAd() {
val finalExpectedValue = 2000;

stateCollector.play()
stateCollector.playing()
// this method under test and should emit one 'renditionchange'
stateCollector.renditionChange(
advertisedBitrate = 1000,
advertisedFrameRate = 1000f,
sourceHeight = 1000,
sourceWidth = 1000
)
// this method under test and should emit no events
stateCollector.finishedPlayingAds()

stateCollector.pause();
stateCollector.playing();

// this method under test and should emit one 'renditionchange'
stateCollector.renditionChange(
advertisedBitrate = 3000,
advertisedFrameRate = 3000f,
sourceHeight = 3000,
sourceWidth = 3000,
)
// this method under test and should emit one 'renditionchange'
stateCollector.renditionChange(
advertisedBitrate = finalExpectedValue,
advertisedFrameRate = finalExpectedValue.toFloat(),
sourceHeight = finalExpectedValue,
sourceWidth = finalExpectedValue,
)

eventDispatcher.assertHasExactlyThese(listOf(
PlayEvent(null), PlayingEvent(null), RenditionChangeEvent(null),
PauseEvent(null), PlayEvent(null), PlayingEvent(null),
RenditionChangeEvent(null), RenditionChangeEvent(null)
))

assertEquals(
"Values from intermediate rendition changes should be skipped",
finalExpectedValue, stateCollector.sourceAdvertisedBitrate
)
assertEquals(
"Values from intermediate rendition changes should be skipped",
finalExpectedValue.toFloat(), stateCollector.sourceAdvertisedFrameRate.toFloat()
)
assertEquals(
"Values from intermediate rendition changes should be skipped",
finalExpectedValue, stateCollector.sourceWidth
)
assertEquals(
"Values from intermediate rendition changes should be skipped",
finalExpectedValue, stateCollector.sourceHeight
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ class FakeEventDispatcher : IEventDispatcher {
}

private fun failAssert(message: String, expected: List<IEvent>, actual: List<IEvent>) {
throw AssertionError("$message:\nActual: $actual\nExpected: $expected")
throw AssertionError("$message:\nActual: ${actual.map { it.type }}" +
"\nExpected: ${expected.map { it.type }}")
}

data class Record(val event: IEvent, val systemTime: Long)
Expand Down