Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
9316b4f4
authored
Dec 15, 2021
by
bachinger
Committed by
Ian Baker
Dec 16, 2021
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Add helper method to split the AdPlaybackState
PiperOrigin-RevId: 416543473
parent
66f7657a
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
634 additions
and
0 deletions
extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java
extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaUtilTest.java
extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java
View file @
9316b4f4
...
...
@@ -15,6 +15,9 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
ext
.
ima
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkState
;
import
android.content.Context
;
import
android.os.Looper
;
import
android.view.View
;
...
...
@@ -36,6 +39,8 @@ import com.google.ads.interactivemedia.v3.api.UiElement;
import
com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer
;
import
com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Timeline
;
import
com.google.android.exoplayer2.source.ads.AdPlaybackState
;
import
com.google.android.exoplayer2.ui.AdOverlayInfo
;
import
com.google.android.exoplayer2.ui.AdViewProvider
;
import
com.google.android.exoplayer2.upstream.DataSchemeDataSource
;
...
...
@@ -43,10 +48,13 @@ import com.google.android.exoplayer2.upstream.DataSourceUtil;
import
com.google.android.exoplayer2.upstream.DataSpec
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.common.collect.ImmutableList
;
import
com.google.common.collect.ImmutableMap
;
import
java.io.IOException
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
/** Utilities for working with IMA SDK and IMA extension data types. */
...
...
@@ -255,5 +263,125 @@ import java.util.Set;
}
}
/**
* Splits an {@link AdPlaybackState} into a separate {@link AdPlaybackState} for each period of a
* content timeline. Ad group times are expected to not take previous ad duration into account and
* needs to be translated to the actual position in the {@code contentTimeline} by adding prior ad
* durations.
*
* <p>If a period is enclosed by an ad group, the period is considered an ad period and gets an ad
* playback state assigned with a single ad in a single ad group. The duration of the ad is set to
* the duration of the period. All other periods are considered content periods with an empty ad
* playback state without any ads.
*
* @param adPlaybackState The ad playback state to be split.
* @param contentTimeline The content timeline for each period of which to create an {@link
* AdPlaybackState}.
* @return A map of ad playback states for each period UID in the content timeline.
*/
public
static
ImmutableMap
<
Object
,
AdPlaybackState
>
splitAdPlaybackStateForPeriods
(
AdPlaybackState
adPlaybackState
,
Timeline
contentTimeline
)
{
Timeline
.
Period
period
=
new
Timeline
.
Period
();
if
(
contentTimeline
.
getPeriodCount
()
==
1
)
{
// A single period gets the entire ad playback state that may contain multiple ad groups.
return
ImmutableMap
.
of
(
checkNotNull
(
contentTimeline
.
getPeriod
(
/* periodIndex= */
0
,
period
,
/* setIds= */
true
).
uid
),
adPlaybackState
);
}
int
periodIndex
=
0
;
long
totalElapsedContentDurationUs
=
0
;
Object
adsId
=
checkNotNull
(
adPlaybackState
.
adsId
);
AdPlaybackState
contentOnlyAdPlaybackState
=
new
AdPlaybackState
(
adsId
);
Map
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
new
HashMap
<>();
for
(
int
i
=
adPlaybackState
.
removedAdGroupCount
;
i
<
adPlaybackState
.
adGroupCount
;
i
++)
{
AdPlaybackState
.
AdGroup
adGroup
=
adPlaybackState
.
getAdGroup
(
/* adGroupIndex= */
i
);
if
(
adGroup
.
timeUs
==
C
.
TIME_END_OF_SOURCE
)
{
checkState
(
i
==
adPlaybackState
.
adGroupCount
-
1
);
// The last ad group is a placeholder for a potential post roll. We can just stop here.
break
;
}
// The ad group start timeUs is in content position. We need to add the ad
// duration before the ad group to translate the start time to the position in the period.
long
adGroupDurationUs
=
getTotalDurationUs
(
adGroup
.
durationsUs
);
long
elapsedAdGroupAdDurationUs
=
0
;
for
(
int
j
=
periodIndex
;
j
<
contentTimeline
.
getPeriodCount
();
j
++)
{
contentTimeline
.
getPeriod
(
j
,
period
,
/* setIds= */
true
);
if
(
totalElapsedContentDurationUs
<
adGroup
.
timeUs
)
{
// Period starts before the ad group, so it is a content period.
adPlaybackStates
.
put
(
checkNotNull
(
period
.
uid
),
contentOnlyAdPlaybackState
);
totalElapsedContentDurationUs
+=
period
.
durationUs
;
}
else
{
long
periodStartUs
=
totalElapsedContentDurationUs
+
elapsedAdGroupAdDurationUs
;
if
(
periodStartUs
+
period
.
durationUs
<=
adGroup
.
timeUs
+
adGroupDurationUs
)
{
// The period ends before the end of the ad group, so it is an ad period (Note: An ad
// reported by the IMA SDK may span multiple periods).
adPlaybackStates
.
put
(
checkNotNull
(
period
.
uid
),
splitAdGroupForPeriod
(
adsId
,
adGroup
,
periodStartUs
,
period
.
durationUs
));
elapsedAdGroupAdDurationUs
+=
period
.
durationUs
;
}
else
{
// Period is after the current ad group. Continue with next ad group.
break
;
}
}
// Increment the period index to the next unclassified period.
periodIndex
++;
}
}
// The remaining periods end after the last ad group, so these are content periods.
for
(
int
i
=
periodIndex
;
i
<
contentTimeline
.
getPeriodCount
();
i
++)
{
contentTimeline
.
getPeriod
(
i
,
period
,
/* setIds= */
true
);
adPlaybackStates
.
put
(
checkNotNull
(
period
.
uid
),
contentOnlyAdPlaybackState
);
}
return
ImmutableMap
.
copyOf
(
adPlaybackStates
);
}
private
static
AdPlaybackState
splitAdGroupForPeriod
(
Object
adsId
,
AdPlaybackState
.
AdGroup
adGroup
,
long
periodStartUs
,
long
periodDurationUs
)
{
checkState
(
adGroup
.
timeUs
<=
periodStartUs
);
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
checkNotNull
(
adsId
),
/* adGroupTimesUs...= */
0
)
.
withAdCount
(
/* adGroupIndex= */
0
,
/* adCount= */
1
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
long
periodEndUs
=
periodStartUs
+
periodDurationUs
;
long
adDurationsUs
=
0
;
for
(
int
i
=
0
;
i
<
adGroup
.
count
;
i
++)
{
adDurationsUs
+=
adGroup
.
durationsUs
[
i
];
if
(
periodEndUs
==
adGroup
.
timeUs
+
adDurationsUs
)
{
// Map the state of the global ad state to the period specific ad state.
switch
(
adGroup
.
states
[
i
])
{
case
AdPlaybackState
.
AD_STATE_PLAYED
:
adPlaybackState
=
adPlaybackState
.
withPlayedAd
(
/* adGroupIndex= */
0
,
/* adIndexInAdGroup= */
0
);
break
;
case
AdPlaybackState
.
AD_STATE_SKIPPED
:
adPlaybackState
=
adPlaybackState
.
withSkippedAd
(
/* adGroupIndex= */
0
,
/* adIndexInAdGroup= */
0
);
break
;
case
AdPlaybackState
.
AD_STATE_ERROR
:
adPlaybackState
=
adPlaybackState
.
withAdLoadError
(
/* adGroupIndex= */
0
,
/* adIndexInAdGroup= */
0
);
break
;
default
:
// Do nothing.
break
;
}
break
;
}
}
return
adPlaybackState
;
}
private
static
long
getTotalDurationUs
(
long
[]
durationsUs
)
{
long
totalDurationUs
=
0
;
for
(
long
adDurationUs
:
durationsUs
)
{
totalDurationUs
+=
adDurationUs
;
}
return
totalDurationUs
;
}
private
ImaUtil
()
{}
}
extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaUtilTest.java
0 → 100644
View file @
9316b4f4
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer2
.
ext
.
ima
;
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
FakeTimeline
.
TimelineWindowDefinition
.
DEFAULT_WINDOW_DURATION_US
;
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
FakeTimeline
.
TimelineWindowDefinition
.
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
android.util.Pair
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Timeline
;
import
com.google.android.exoplayer2.source.ads.AdPlaybackState
;
import
com.google.android.exoplayer2.testutil.FakeTimeline
;
import
com.google.common.collect.ImmutableMap
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
/** Tests for {@link ImaUtil}. */
@RunWith
(
AndroidJUnit4
.
class
)
public
class
ImaUtilTest
{
@Test
public
void
splitAdPlaybackStateForPeriods_emptyTimeline_emptyMapOfAdPlaybackStates
()
{
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
""
,
0
,
20_000
,
C
.
TIME_END_OF_SOURCE
);
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
Timeline
.
EMPTY
);
assertThat
(
adPlaybackStates
).
isEmpty
();
}
@Test
public
void
splitAdPlaybackStateForPeriods_singlePeriod_doesNotSplit
()
{
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
""
,
0
,
20_000
,
C
.
TIME_END_OF_SOURCE
);
FakeTimeline
singlePeriodTimeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
1
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
singlePeriodTimeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
1
);
assertThat
(
adPlaybackStates
).
containsEntry
(
new
Pair
<>(
0L
,
0
),
adPlaybackState
);
}
@Test
public
void
splitAdPlaybackStateForPeriods_livePlaceholder_isIgnored
()
{
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
""
,
C
.
TIME_END_OF_SOURCE
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
singlePeriodTimeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
3
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
singlePeriodTimeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
3
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
0
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
1
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
2
)).
adGroupCount
).
isEqualTo
(
0
);
}
@Test
public
void
splitAdPlaybackStateForPeriods_noAds_splitToEmptyAdPlaybackStates
()
{
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
11
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
11
);
for
(
AdPlaybackState
periodAdPlaybackState
:
adPlaybackStates
.
values
())
{
assertThat
(
periodAdPlaybackState
.
adsId
).
isEqualTo
(
"adsId"
);
assertThat
(
periodAdPlaybackState
.
adGroupCount
).
isEqualTo
(
0
);
}
}
@Test
public
void
splitAdPlaybackStateForPeriods_twoPrerollAds_splitToFirstTwoPeriods
()
{
int
periodCount
=
4
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
/* adGroupTimesUs... */
0
)
.
withAdCount
(
/* adGroupIndex= */
0
,
2
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
periodDurationUs
,
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
periodCount
);
for
(
int
i
=
0
;
i
<
2
;
i
++)
{
Pair
<
Long
,
Integer
>
periodUid
=
new
Pair
<>(
0L
,
i
);
AdPlaybackState
periodAdPlaybackState
=
adPlaybackStates
.
get
(
periodUid
);
assertThat
(
periodAdPlaybackState
.
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
periodAdPlaybackState
.
adsId
).
isEqualTo
(
"adsId"
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
timeUs
).
isEqualTo
(
0
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
isServerSideInserted
).
isTrue
();
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
).
hasLength
(
1
);
int
adDurationUs
=
i
==
0
?
125_500_000
:
2_500_000
;
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
[
0
]).
isEqualTo
(
adDurationUs
);
}
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
2
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
3
)).
adGroupCount
).
isEqualTo
(
0
);
}
@Test
public
void
splitAdPlaybackStateForPeriods_onePrerollAdGroup_splitToFirstThreePeriods
()
{
int
periodCount
=
4
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
/* adGroupTimesUs... */
0
)
.
withAdCount
(
/* adGroupIndex= */
0
,
1
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
3
*
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
periodCount
);
for
(
int
i
=
0
;
i
<
3
;
i
++)
{
Pair
<
Long
,
Integer
>
periodUid
=
new
Pair
<>(
0L
,
i
);
AdPlaybackState
periodAdPlaybackState
=
adPlaybackStates
.
get
(
periodUid
);
assertThat
(
periodAdPlaybackState
.
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
).
hasLength
(
1
);
int
adDurationUs
=
i
==
0
?
125_500_000
:
2_500_000
;
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
[
0
]).
isEqualTo
(
adDurationUs
);
}
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
3
)).
adGroupCount
).
isEqualTo
(
0
);
}
@Test
public
void
splitAdPlaybackStateForPeriods_twoMidrollAds_splitToMiddleTwoPeriods
()
{
int
periodCount
=
4
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
periodDurationUs
)
.
withAdCount
(
/* adGroupIndex= */
0
,
2
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
periodDurationUs
,
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
periodCount
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
0
)).
adGroupCount
).
isEqualTo
(
0
);
for
(
int
i
=
1
;
i
<
3
;
i
++)
{
Pair
<
Long
,
Integer
>
periodUid
=
new
Pair
<>(
0L
,
i
);
AdPlaybackState
periodAdPlaybackState
=
adPlaybackStates
.
get
(
periodUid
);
assertThat
(
periodAdPlaybackState
.
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
timeUs
).
isEqualTo
(
0
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
).
hasLength
(
1
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
[
0
]).
isEqualTo
(
2_500_000
);
}
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
3
)).
adGroupCount
).
isEqualTo
(
0
);
}
@Test
public
void
splitAdPlaybackStateForPeriods_oneMidrollAdGroupOneAd_adSpansTwoPeriods
()
{
int
periodCount
=
5
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
periodDurationUs
)
.
withAdCount
(
/* adGroupIndex= */
0
,
1
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
2
*
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
periodCount
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
0
)).
adGroupCount
).
isEqualTo
(
0
);
for
(
int
i
=
1
;
i
<
3
;
i
++)
{
Pair
<
Long
,
Integer
>
periodUid
=
new
Pair
<>(
0L
,
i
);
AdPlaybackState
periodAdPlaybackState
=
adPlaybackStates
.
get
(
periodUid
);
assertThat
(
periodAdPlaybackState
.
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
).
hasLength
(
1
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
[
0
]).
isEqualTo
(
2_000_000
);
}
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
3
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
4
)).
adGroupCount
).
isEqualTo
(
0
);
}
@Test
public
void
splitAdPlaybackStateForPeriods_oneMidrollAdGroupTwoAds_eachAdSplitsToOnePeriod
()
{
int
periodCount
=
5
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
periodDurationUs
)
.
withAdCount
(
/* adGroupIndex= */
0
,
2
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
periodDurationUs
,
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
periodCount
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
0
)).
adGroupCount
).
isEqualTo
(
0
);
for
(
int
i
=
1
;
i
<
3
;
i
++)
{
Pair
<
Long
,
Integer
>
periodUid
=
new
Pair
<>(
0L
,
i
);
AdPlaybackState
periodAdPlaybackState
=
adPlaybackStates
.
get
(
periodUid
);
assertThat
(
periodAdPlaybackState
.
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
).
hasLength
(
1
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
[
0
]).
isEqualTo
(
2_000_000
);
}
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
3
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
4
)).
adGroupCount
).
isEqualTo
(
0
);
}
@Test
public
void
splitAdPlaybackStateForPeriods_twoPostrollAds_splitToLastTwoPeriods
()
{
int
periodCount
=
4
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
2
*
periodDurationUs
)
.
withAdCount
(
/* adGroupIndex= */
0
,
2
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
periodDurationUs
,
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
periodCount
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
0
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
1
)).
adGroupCount
).
isEqualTo
(
0
);
for
(
int
i
=
2
;
i
<
periodCount
;
i
++)
{
Pair
<
Long
,
Integer
>
periodUid
=
new
Pair
<>(
0L
,
i
);
AdPlaybackState
periodAdPlaybackState
=
adPlaybackStates
.
get
(
periodUid
);
assertThat
(
periodAdPlaybackState
.
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
).
hasLength
(
1
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
[
0
]).
isEqualTo
(
2_500_000
);
}
}
@Test
public
void
splitAdPlaybackStateForPeriods_onePostrollAdGroup_splitToLastThreePeriods
()
{
int
periodCount
=
7
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
4
*
periodDurationUs
)
.
withAdCount
(
/* adGroupIndex= */
0
,
1
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
3
*
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
periodCount
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
0
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
1
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
2
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
3
)).
adGroupCount
).
isEqualTo
(
0
);
for
(
int
i
=
4
;
i
<
adPlaybackStates
.
size
();
i
++)
{
Pair
<
Long
,
Integer
>
periodUid
=
new
Pair
<>(
0L
,
i
);
AdPlaybackState
periodAdPlaybackState
=
adPlaybackStates
.
get
(
periodUid
);
assertThat
(
periodAdPlaybackState
.
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
).
hasLength
(
1
);
assertThat
(
periodAdPlaybackState
.
getAdGroup
(
0
).
durationsUs
[
0
]).
isEqualTo
(
periodDurationUs
);
}
}
@Test
public
void
splitAdPlaybackStateForPeriods_preMidAndPostrollAdGroup_splitCorrectly
()
{
int
periodCount
=
11
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
0
,
(
2
*
periodDurationUs
),
(
5
*
periodDurationUs
))
.
withAdCount
(
/* adGroupIndex= */
0
,
2
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
periodDurationUs
,
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
)
.
withAdCount
(
/* adGroupIndex= */
1
,
2
)
.
withAdDurationsUs
(
/* adGroupIndex= */
1
,
periodDurationUs
,
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
1
,
true
)
.
withAdCount
(
/* adGroupIndex= */
2
,
2
)
.
withAdDurationsUs
(
/* adGroupIndex= */
2
,
periodDurationUs
,
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
2
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
periodCount
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
0
)).
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
1
)).
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
2
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
3
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
4
)).
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
5
)).
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
6
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
7
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
8
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
9
)).
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
10
)).
adGroupCount
).
isEqualTo
(
1
);
}
@Test
public
void
splitAdPlaybackStateForPeriods_midAndPostrollAdGroup_splitCorrectly
()
{
int
periodCount
=
9
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
(
2
*
periodDurationUs
),
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
(
5
*
periodDurationUs
))
.
withAdCount
(
/* adGroupIndex= */
0
,
2
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
periodDurationUs
,
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
)
.
withAdCount
(
/* adGroupIndex= */
1
,
2
)
.
withAdDurationsUs
(
/* adGroupIndex= */
1
,
periodDurationUs
,
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
1
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
periodCount
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
0
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
1
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
2
)).
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
3
)).
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
4
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
5
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
6
)).
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
7
)).
adGroupCount
).
isEqualTo
(
1
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
8
)).
adGroupCount
).
isEqualTo
(
1
);
}
@Test
public
void
splitAdPlaybackStateForPeriods_correctAdsIdInSplitPlaybackStates
()
{
int
periodCount
=
4
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
2
*
periodDurationUs
)
.
withAdCount
(
/* adGroupIndex= */
0
,
1
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
2
*
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
for
(
int
i
=
0
;
i
<
adPlaybackStates
.
size
();
i
++)
{
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
i
)).
adsId
).
isEqualTo
(
"adsId"
);
}
}
@Test
public
void
splitAdPlaybackStateForPeriods_correctAdPlaybackStates
()
{
int
periodCount
=
7
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
0
)
.
withAdCount
(
/* adGroupIndex= */
0
,
periodCount
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
/* adDurationsUs...= */
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
periodDurationUs
,
periodDurationUs
,
periodDurationUs
,
periodDurationUs
,
periodDurationUs
,
periodDurationUs
,
periodDurationUs
)
.
withPlayedAd
(
/* adGroupIndex= */
0
,
/* adIndexInAdGroup= */
0
)
.
withSkippedAd
(
/* adGroupIndex= */
0
,
/* adIndexInAdGroup= */
1
)
.
withAdLoadError
(
/* adGroupIndex= */
0
,
/* adIndexInAdGroup= */
2
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
0
)).
getAdGroup
(
/* adGroupIndex= */
0
).
states
[
0
])
.
isEqualTo
(
AdPlaybackState
.
AD_STATE_PLAYED
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
1
)).
getAdGroup
(
/* adGroupIndex= */
0
).
states
[
0
])
.
isEqualTo
(
AdPlaybackState
.
AD_STATE_SKIPPED
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
2
)).
getAdGroup
(
/* adGroupIndex= */
0
).
states
[
0
])
.
isEqualTo
(
AdPlaybackState
.
AD_STATE_ERROR
);
assertThat
(
adPlaybackStates
.
get
(
new
Pair
<>(
0L
,
3
)).
getAdGroup
(
/* adGroupIndex= */
0
).
states
[
0
])
.
isEqualTo
(
AdPlaybackState
.
AD_STATE_UNAVAILABLE
);
}
@Test
public
void
splitAdPlaybackStateForPeriods_lateMidrollAdGroupStartTimeUs_adGroupIgnored
()
{
int
periodCount
=
4
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+
periodDurationUs
+
1
)
.
withAdCount
(
/* adGroupIndex= */
0
,
1
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
/* adDurationsUs...= */
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
periodCount
);
for
(
AdPlaybackState
periodAdPlaybackState
:
adPlaybackStates
.
values
())
{
assertThat
(
periodAdPlaybackState
.
adGroupCount
).
isEqualTo
(
0
);
}
}
@Test
public
void
splitAdPlaybackStateForPeriods_earlyMidrollAdGroupStartTimeUs_adGroupIgnored
()
{
int
periodCount
=
4
;
long
periodDurationUs
=
DEFAULT_WINDOW_DURATION_US
/
periodCount
;
AdPlaybackState
adPlaybackState
=
new
AdPlaybackState
(
/* adsId= */
"adsId"
,
periodDurationUs
-
1
)
.
withAdCount
(
/* adGroupIndex= */
0
,
1
)
.
withAdDurationsUs
(
/* adGroupIndex= */
0
,
/* adDurationsUs...= */
periodDurationUs
)
.
withIsServerSideInserted
(
/* adGroupIndex= */
0
,
true
);
FakeTimeline
timeline
=
new
FakeTimeline
(
new
FakeTimeline
.
TimelineWindowDefinition
(
/* periodCount= */
periodCount
,
/* id= */
0L
));
ImmutableMap
<
Object
,
AdPlaybackState
>
adPlaybackStates
=
ImaUtil
.
splitAdPlaybackStateForPeriods
(
adPlaybackState
,
timeline
);
assertThat
(
adPlaybackStates
).
hasSize
(
periodCount
);
for
(
AdPlaybackState
periodAdPlaybackState
:
adPlaybackStates
.
values
())
{
assertThat
(
periodAdPlaybackState
.
adGroupCount
).
isEqualTo
(
0
);
assertThat
(
periodAdPlaybackState
.
adsId
).
isEqualTo
(
"adsId"
);
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment