From 55a86b8a00aa8bd57881a94bc98d71a97b7ff08d Mon Sep 17 00:00:00 2001 From: Kasem SAEED Date: Tue, 5 Oct 2021 10:35:07 -0700 Subject: [PATCH 001/497] Add support for RF64 wave files --- .../android/exoplayer2/audio/WavUtil.java | 4 ++++ .../extractor/wav/WavHeaderReader.java | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/audio/WavUtil.java b/library/extractor/src/main/java/com/google/android/exoplayer2/audio/WavUtil.java index 208989124a..ff8f5175bf 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/audio/WavUtil.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/audio/WavUtil.java @@ -22,6 +22,10 @@ import com.google.android.exoplayer2.util.Util; /** Utilities for handling WAVE files. */ public final class WavUtil { + /** Four character code for "RF64". */ + public static final int RF64_FOURCC = 0x52463634; + /** Four character code for "ds64". */ + public static final int DS64_FOURCC = 0x64733634; /** Four character code for "RIFF". */ public static final int RIFF_FOURCC = 0x52494646; /** Four character code for "WAVE". */ diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java index f794933d16..b5813ae2c2 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java @@ -50,7 +50,7 @@ import java.io.IOException; // Attempt to read the RIFF chunk. ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch); - if (chunkHeader.id != WavUtil.RIFF_FOURCC) { + if (chunkHeader.id != WavUtil.RIFF_FOURCC && chunkHeader.id != WavUtil.RF64_FOURCC) { return null; } @@ -117,14 +117,23 @@ import java.io.IOException; ParsableByteArray scratch = new ParsableByteArray(ChunkHeader.SIZE_IN_BYTES); // Skip all chunks until we find the data header. ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch); + long dataSize = -1; while (chunkHeader.id != WavUtil.DATA_FOURCC) { if (chunkHeader.id != WavUtil.RIFF_FOURCC && chunkHeader.id != WavUtil.FMT_FOURCC) { Log.w(TAG, "Ignoring unknown WAV chunk: " + chunkHeader.id); } long bytesToSkip = ChunkHeader.SIZE_IN_BYTES + chunkHeader.size; // Override size of RIFF chunk, since it describes its size as the entire file. - if (chunkHeader.id == WavUtil.RIFF_FOURCC) { + // Also, ignore the size of RF64 chunk, since its always going to be 0xFFFFFFFF + if (chunkHeader.id == WavUtil.RIFF_FOURCC || chunkHeader.id == WavUtil.RF64_FOURCC) { bytesToSkip = ChunkHeader.SIZE_IN_BYTES + 4; + } else if (chunkHeader.id == WavUtil.DS64_FOURCC) { + int ds64Size = (int) chunkHeader.size; + ParsableByteArray ds64Bytes = new ParsableByteArray(ds64Size); + input.peekFully(ds64Bytes.getData(), 0, ds64Size); + // ds64 chunk contains 64bit sizes. From position 12 to 20 is the data size + ds64Bytes.setPosition(12); + dataSize = ds64Bytes.readLong(); } if (bytesToSkip > Integer.MAX_VALUE) { throw ParserException.createForUnsupportedContainerFeature( @@ -133,11 +142,15 @@ import java.io.IOException; input.skipFully((int) bytesToSkip); chunkHeader = ChunkHeader.peek(input, scratch); } + // Use size from data chunk if it wasn't determined from ds64 chunk + if (dataSize == -1) { + dataSize = chunkHeader.size; + } // Skip past the "data" header. input.skipFully(ChunkHeader.SIZE_IN_BYTES); long dataStartPosition = input.getPosition(); - long dataEndPosition = dataStartPosition + chunkHeader.size; + long dataEndPosition = dataStartPosition + dataSize; long inputLength = input.getLength(); if (inputLength != C.LENGTH_UNSET && dataEndPosition > inputLength) { Log.w(TAG, "Data exceeds input length: " + dataEndPosition + ", " + inputLength); From 8501e997e036c99e128781e6d1658d0326dcd1a1 Mon Sep 17 00:00:00 2001 From: Kasem Date: Thu, 14 Oct 2021 19:21:30 -0700 Subject: [PATCH 002/497] Fix wrong RF64 data size and add unit test --- .../extractor/wav/WavHeaderReader.java | 11 +++++++---- .../extractor/wav/WavExtractorTest.java | 6 ++++++ .../src/test/assets/media/wav/sample_rf64.wav | Bin 0 -> 67016 bytes 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 testdata/src/test/assets/media/wav/sample_rf64.wav diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java index b5813ae2c2..a004b808d3 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java @@ -48,7 +48,7 @@ import java.io.IOException; // Allocate a scratch buffer large enough to store the format chunk. ParsableByteArray scratch = new ParsableByteArray(16); - // Attempt to read the RIFF chunk. + // Attempt to read the RIFF or RF64 chunk. ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch); if (chunkHeader.id != WavUtil.RIFF_FOURCC && chunkHeader.id != WavUtil.RF64_FOURCC) { return null; @@ -117,7 +117,10 @@ import java.io.IOException; ParsableByteArray scratch = new ParsableByteArray(ChunkHeader.SIZE_IN_BYTES); // Skip all chunks until we find the data header. ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch); + + // Data size holder. To be determined from data chunk or ds64 chunk in case of RF64. long dataSize = -1; + while (chunkHeader.id != WavUtil.DATA_FOURCC) { if (chunkHeader.id != WavUtil.RIFF_FOURCC && chunkHeader.id != WavUtil.FMT_FOURCC) { Log.w(TAG, "Ignoring unknown WAV chunk: " + chunkHeader.id); @@ -131,9 +134,9 @@ import java.io.IOException; int ds64Size = (int) chunkHeader.size; ParsableByteArray ds64Bytes = new ParsableByteArray(ds64Size); input.peekFully(ds64Bytes.getData(), 0, ds64Size); - // ds64 chunk contains 64bit sizes. From position 12 to 20 is the data size - ds64Bytes.setPosition(12); - dataSize = ds64Bytes.readLong(); + // ds64 chunk contains 64bit sizes. From position 8 to 16 is the data size + ds64Bytes.setPosition(8); + dataSize = ds64Bytes.readLittleEndianLong(); } if (bytesToSkip > Integer.MAX_VALUE) { throw ParserException.createForUnsupportedContainerFeature( diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java index 4217a1528a..211380463d 100644 --- a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java +++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java @@ -53,4 +53,10 @@ public final class WavExtractorTest { ExtractorAsserts.assertBehavior( WavExtractor::new, "media/wav/sample_ima_adpcm.wav", simulationConfig); } + + @Test + public void sample_RF64() throws Exception { + ExtractorAsserts + .assertBehavior(WavExtractor::new, "media/wav/sample_rf64.wav", simulationConfig); + } } diff --git a/testdata/src/test/assets/media/wav/sample_rf64.wav b/testdata/src/test/assets/media/wav/sample_rf64.wav new file mode 100644 index 0000000000000000000000000000000000000000..b2dd53c687267d970199d63cba3aa6df98b7e9f0 GIT binary patch literal 67016 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

$*;Exa$j;#{{pW=2 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

N!H@pSCpG2buDxf5k z1EwE(A5yG9eQ7U3?^B8wY{v$yhGGWOp`HZFEmL2D&S;GoD6gOrUW48z3E8^+F2D8u zdEIs0m5u*kH!`62TfOh9er^)zz9^Q=`gAL``d97KjRQ~A|0uikIyg~gV7D` z5DVokyn&)n?4EJI_6N9zvp9%t_!dhs2cKXR6ocr31SqGWDqaW8LF~#yWcg~lgY!6s zJxIqYBtvHpV=xptk7$n;s1L;@N}(XMR#2ZMon>6YNhm&%0j)9S<8zFH@*uPpX^R*{ zAp)iF3f!O}Rp2fzL3x?`u@&DzF$w z-#LIEpg6`-%)uuZ1+CY5p%dC522lvdYfv*BLQYmsN1ZKQ#%UaY)`yC1EXQ1^*MrWb z)bF7eIwAp$pnTU#D1}1cEy*A71yt7T`whS17=DEMYi)q~LMSI=HZ+gnBP5|8wEk^{ zCWwM^aNmIPaSKB0X4+nQ|G^z77LpC+Zs=@I`5T+D9;>k!>MuD3<1idL*XxN6XbqkB z)rHRfDxx%sLT7@iHPHf4djQp(+`%!kCZBR7{4>UbPQP!u!y9><}o9GXSce>4P5ViY|B; zs;N>8;HPxQ~Jkq*-HJS0I+gca(pxfUtr-5}}w2#%j zYX;p{-FL;hMAt;uMmn<3?Tl{dozsh}*w4DAgL4L3d*9()>)}YEm+451g<@!vcubTp zr1S9EJYMs2lC8%uHD?vsL|+%Bk>-XZ8Yq1>a>IE!rPIdcoDtyljP zJ+BngGjjaY+S_x3c+TZVA^PMO&n-q5zS7onvm&|pRXA&}!9-H!t^A@P0rgz(VgD?^@n9(wG4A z4IKmL@+%AJO|zBRFo(TAVkZ+~P7-;&2})S3z5E~EKjuiCzH?C+bBZ`Rw_$Jd3rw=vkj9GcIW{n`p$p}aKtiY|l~nRmb0mq|~;VZH*? z(M6IUFpC&KE;R<{`Q3`XO1>c8W9J}08d7sN#y^^!e+7SJlb0A7>gh3HskoV%SIh$NAq;{@kxj1l-N+oFxBZV%op^Z~H@y zP~%Obn%Y${6|k^TkpC~nY{3512I_yI{Ja)<2q{d(J#Cyd_Vao48Ad}r4{91U`1I*) zd~a+Z%AR5jH4>R*@WAL4=w$UD4iJ<7%lMltg`0eOEjJ1U3I`$rl>_>UdImm4l6gK27RnAp#cg) z>%cH)nDcXLVeiuKO7*aN&>elz6@)$Q^{9_!pp%u~I+F9@}AqFhn*5TEXP4?6Eteu$DNwdU`QHgF-`mCi)3pIi;x4Xm&KcKz*Y>TXKk zvf@^6a^)H83{m?CojspRvxp&OO{SoQ@ksJa&*?;Q5xb zP~G29W|AF*_B=|6ReYr<4!94v%2Ltn=7Wo>5j@rh})0 z=O_11R=v$U_dIK_bc)Fz;hu2M2N(dwc9g?i8LA0ajd&ScVg{$at_|JC*QgcOY>@3x z|2W-l8&aTsUpaI~)1an7S)MFUDdw4vf%b^{9_`)jtsETX*-VA<%3F~;qdN6wXbcAl z*e94fqWz!Fj&+~(*s2yNh2C~cnDwS>w*qI}XWXU9HxIZ2?!(aE8wA~_h@gm|x}Lfo z?F+R(O$tg1Qe5ng>yAtRPLZG@K|0UYpFIfuJw48U;fUvm$4L-SzyCV5^d*?)e$sW) zRg0P?ooio!a)gxMu4|A1#ks~pU+eMG^JRf+fptb5?}?{}{wLP&>%PuK1O`LbU3*#; z@9OsFxO1#LrjOhoxg7*Gx1tGXJM8`epJN;nu-3EIqhgpw%!lW=(5YJgbI>(WeZS&( zTbQ4!GxTfFb0MCZEIse_U&Zn&Lb1Ygu5w4+As+geeo8pMt6RURX zsOPAsB{^4w@10?;Fc)oBtk*(+=GiO1YNC6hTQST(q3iaQ>nrQ^ID`qWdX6t)8o)nL zj8U=6Q_fRP)rxIHOJ_^xSn|#Enoo2mT6_C;u6C}r^d8i;OJ#vWt0QQ&vgc~viW=W^_G?Q=!ABi#MSVLRhEJ*u>Oh|*R(&6_W_@qP1lHTvTc0{sj~kY&rV&9%?9&Is1gpGk3s9`t-jgw7)>v%bl1<~P5xe`Vi< z+2(BPJfk9Wm;Qs6^mf*{M?7ZJ3*t}pY(f}y92e>Hq#Dr0=3-O5p%gEuz#2p67k$mX zW>np`D(rjrqozW<^(1m{4@pQNRhWXHgnT2(XoQ!*cdjXw$jb#Q`mXT#NW$ja% zDHiVr-VO9a52J?_?@;e7tyh%`JB|*Rz0sQKS?}Qv{>EefW9w`y)krl)G7mDJk$F_3xwdH&(Xa6_?}`>a?q{h9tL#uOvcj5J#sEsfj0 z+rG)HqZRM?6#Cw?{j-^?-Pf;J%xX}E=3j+4dV?z#GXwfsu@9~Fb*5L0nHh?Uw7@C< zDStC8@h$NwZ}*eHCxLbTb^iNI)Ce|$t$g1bz8gNBEvk2>nQP{j@|E%_|D_-OI(46P z9d+A2Lkea>`6Iff`{`Pq&Uu|;GWxz3p>s*q->6PU=c>x3P;5te$C1qH$VQz&oj`jg zmK7x)qFB(cbYxd-Vq9QcU=cIUbPgNM6!H<|AhQkgO+cq z)K{%B%J|FpbrxEM9i+$W@wV}|vGyQGn3*<)bJT@QQPY{^NbgAR+1#_aZ_}r}IY#D= z%-#2F-?L)W;bi->{klI}5o^R6SE;RT4Atwzqbq&eb^fZK)2`aet7*wB&zDiuU(`Pg zEur7j<6qTZ)vq&J?JLW(gG~3O`))FyEekH6%a=u+Pb^*Ii?It*UUy~AmbEWc%xVZb zOXalWq0sIly2UHcMLFYnD2~S}ccb(JfO;+d7HQ9gb8oWUdR_${` z=xwSEyz1Wf`1bf_lHXK;{b6DO;R zz5TQXy+KMc|9v{LpJiM5{Cp(&6g$-iMH}|}!^wFc>K*FcP50NZKv+Qg$4q9tCvD^G`8{zP`S` z;%0I4EE0?aVbAfq~X+2^7Fe@ib&t<(n^;*+&RPj%} zFaBfvW5s;8F#Sibf5odaj11!(9SyaQo#dG0(0g$?Z#l2N_s_WNyX(_+)O)<*xIWJG zJ2E*if%ygBd%yQ8?<>+CY1g@KgfGGuNxag=k4NmaSJLZ1dt|K0N;`)5m z^R0-jh^@S{yz@=^F{crmnS^6>PY$z%S^X2|m~%{hK5d2iCe*gqw%4%LuqiK5=jM~# zlicm-m#o)dd3$+#JF}fhP|7>mm~0GWQo}U+G^@UW5W*3FEHi@MQCd$Z*Ro)sU|^&% z(r9RFXw&+Nws$t=SG-3*2CXmjSlq-6Iyf@G+%cAZ(TXvI+r#Z==?VD@`)k!nDF0Ho zb-Z)Db0}8P!y(C*WZOsHf!133KKpI^ZEKhbsknk>QYc6COUIXvMrI@P8u5pX&W+A3 z_AShhtYg=?&u;r}`!7(u;DGIbHOuNl$A^ylw)?ie^t#;0s-ytTg-2r|8|@M<~nj6&F#(YA0dw;k3(nwTGRIO z_44WSSbIC|J1;seI;wJRq%)&XGt|@??R9c*buCmYyU4M~vCX;7Ii8*oPJYaQ`boUZ z&^PV*-JA`ja>jMVeZ{S~gw~XL?W}`xFO-L|hFO-Ah&|{U6?GMLX)QU#F~pJTPIW5| zQI(k+PP~N5uF6(_ii(bkj>+a^Gu#$#JMK8{ctWw)adIgXUuZ;a@L2m;`(KW~9Ew|L zeXG64eeyrPw0~*;omye7zvGyxsa)M*c<6ZOSmRvdR1D!J{m&NJ7uoyJN4%1w62J4% ju?u?K>O1Q@Q`{+To!Jes4YBFpDZ+HJwf41E-Oc|1w8(7H literal 0 HcmV?d00001 From 69b2dd0fbf10930a0d567b892e5e53a07189e46b Mon Sep 17 00:00:00 2001 From: Kasem SAEED Date: Fri, 15 Oct 2021 08:48:41 -0700 Subject: [PATCH 003/497] Change condition to not log warning for RF64 files --- .../android/exoplayer2/extractor/wav/WavHeaderReader.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java index a004b808d3..27bd28ad5e 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java @@ -122,7 +122,8 @@ import java.io.IOException; long dataSize = -1; while (chunkHeader.id != WavUtil.DATA_FOURCC) { - if (chunkHeader.id != WavUtil.RIFF_FOURCC && chunkHeader.id != WavUtil.FMT_FOURCC) { + if (chunkHeader.id != WavUtil.RIFF_FOURCC && chunkHeader.id != WavUtil.FMT_FOURCC + && chunkHeader.id != WavUtil. RF64_FOURCC && chunkHeader.id != WavUtil. DS64_FOURCC) { Log.w(TAG, "Ignoring unknown WAV chunk: " + chunkHeader.id); } long bytesToSkip = ChunkHeader.SIZE_IN_BYTES + chunkHeader.size; From 5b05d640c6b6ebaa9a8b85d64f94e4a5eba4612c Mon Sep 17 00:00:00 2001 From: Kasem SAEED Date: Fri, 15 Oct 2021 09:00:07 -0700 Subject: [PATCH 004/497] Add RF64 dump files for testing --- .../extractordumps/wav/sample_rf64.wav.0.dump | 36 +++++++++++++++++++ .../extractordumps/wav/sample_rf64.wav.1.dump | 32 +++++++++++++++++ .../extractordumps/wav/sample_rf64.wav.2.dump | 28 +++++++++++++++ .../extractordumps/wav/sample_rf64.wav.3.dump | 24 +++++++++++++ .../wav/sample_rf64.wav.unknown_length.dump | 36 +++++++++++++++++++ 5 files changed, 156 insertions(+) create mode 100644 testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.0.dump create mode 100644 testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.1.dump create mode 100644 testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.2.dump create mode 100644 testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.3.dump create mode 100644 testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.unknown_length.dump diff --git a/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.0.dump b/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.0.dump new file mode 100644 index 0000000000..1e129acd70 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.0.dump @@ -0,0 +1,36 @@ +seekMap: + isSeekable = true + duration = 348625 + getPosition(0) = [[timeUs=0, position=80]] + getPosition(1) = [[timeUs=0, position=80], [timeUs=20, position=84]] + getPosition(174312) = [[timeUs=174291, position=33544], [timeUs=174312, position=33548]] + getPosition(348625) = [[timeUs=348604, position=67012]] +numberOfTracks = 1 +track 0: + total output bytes = 66936 + sample count = 4 + format 0: + averageBitrate = 1536000 + peakBitrate = 1536000 + sampleMimeType = audio/raw + maxInputSize = 19200 + channelCount = 2 + sampleRate = 48000 + pcmEncoding = 2 + sample 0: + time = 0 + flags = 1 + data = length 19200, hash EF6C7C27 + sample 1: + time = 100000 + flags = 1 + data = length 19200, hash 5AB97AFC + sample 2: + time = 200000 + flags = 1 + data = length 19200, hash 37920F33 + sample 3: + time = 300000 + flags = 1 + data = length 9336, hash 135F1C30 +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.1.dump b/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.1.dump new file mode 100644 index 0000000000..f4d925bad3 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.1.dump @@ -0,0 +1,32 @@ +seekMap: + isSeekable = true + duration = 348625 + getPosition(0) = [[timeUs=0, position=80]] + getPosition(1) = [[timeUs=0, position=80], [timeUs=20, position=84]] + getPosition(174312) = [[timeUs=174291, position=33544], [timeUs=174312, position=33548]] + getPosition(348625) = [[timeUs=348604, position=67012]] +numberOfTracks = 1 +track 0: + total output bytes = 44628 + sample count = 3 + format 0: + averageBitrate = 1536000 + peakBitrate = 1536000 + sampleMimeType = audio/raw + maxInputSize = 19200 + channelCount = 2 + sampleRate = 48000 + pcmEncoding = 2 + sample 0: + time = 116208 + flags = 1 + data = length 19200, hash E4B962ED + sample 1: + time = 216208 + flags = 1 + data = length 19200, hash 4F13D6CF + sample 2: + time = 316208 + flags = 1 + data = length 6228, hash 3FB5F446 +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.2.dump b/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.2.dump new file mode 100644 index 0000000000..2b42e93b5a --- /dev/null +++ b/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.2.dump @@ -0,0 +1,28 @@ +seekMap: + isSeekable = true + duration = 348625 + getPosition(0) = [[timeUs=0, position=80]] + getPosition(1) = [[timeUs=0, position=80], [timeUs=20, position=84]] + getPosition(174312) = [[timeUs=174291, position=33544], [timeUs=174312, position=33548]] + getPosition(348625) = [[timeUs=348604, position=67012]] +numberOfTracks = 1 +track 0: + total output bytes = 22316 + sample count = 2 + format 0: + averageBitrate = 1536000 + peakBitrate = 1536000 + sampleMimeType = audio/raw + maxInputSize = 19200 + channelCount = 2 + sampleRate = 48000 + pcmEncoding = 2 + sample 0: + time = 232416 + flags = 1 + data = length 19200, hash F82E494B + sample 1: + time = 332416 + flags = 1 + data = length 3116, hash 93C99CFD +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.3.dump b/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.3.dump new file mode 100644 index 0000000000..2a6345d4a8 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.3.dump @@ -0,0 +1,24 @@ +seekMap: + isSeekable = true + duration = 348625 + getPosition(0) = [[timeUs=0, position=80]] + getPosition(1) = [[timeUs=0, position=80], [timeUs=20, position=84]] + getPosition(174312) = [[timeUs=174291, position=33544], [timeUs=174312, position=33548]] + getPosition(348625) = [[timeUs=348604, position=67012]] +numberOfTracks = 1 +track 0: + total output bytes = 4 + sample count = 1 + format 0: + averageBitrate = 1536000 + peakBitrate = 1536000 + sampleMimeType = audio/raw + maxInputSize = 19200 + channelCount = 2 + sampleRate = 48000 + pcmEncoding = 2 + sample 0: + time = 348625 + flags = 1 + data = length 4, hash FFD4C53F +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.unknown_length.dump b/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.unknown_length.dump new file mode 100644 index 0000000000..1e129acd70 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/wav/sample_rf64.wav.unknown_length.dump @@ -0,0 +1,36 @@ +seekMap: + isSeekable = true + duration = 348625 + getPosition(0) = [[timeUs=0, position=80]] + getPosition(1) = [[timeUs=0, position=80], [timeUs=20, position=84]] + getPosition(174312) = [[timeUs=174291, position=33544], [timeUs=174312, position=33548]] + getPosition(348625) = [[timeUs=348604, position=67012]] +numberOfTracks = 1 +track 0: + total output bytes = 66936 + sample count = 4 + format 0: + averageBitrate = 1536000 + peakBitrate = 1536000 + sampleMimeType = audio/raw + maxInputSize = 19200 + channelCount = 2 + sampleRate = 48000 + pcmEncoding = 2 + sample 0: + time = 0 + flags = 1 + data = length 19200, hash EF6C7C27 + sample 1: + time = 100000 + flags = 1 + data = length 19200, hash 5AB97AFC + sample 2: + time = 200000 + flags = 1 + data = length 19200, hash 37920F33 + sample 3: + time = 300000 + flags = 1 + data = length 9336, hash 135F1C30 +tracksEnded = true From d3bba3b0e6a70b1ad49c9445e43f5ca6dba792af Mon Sep 17 00:00:00 2001 From: Steve Mayhew Date: Fri, 10 Sep 2021 13:20:04 -0700 Subject: [PATCH 005/497] Implements SeekParameters.*_SYNC variants for HLS The HLS implementation of `getAdjustedSeekPositionUs()` now completely supports `SeekParameters.CLOSEST_SYNC` and it's brotheran, assuming the HLS stream indicates segments all start with an IDR (that is EXT-X-INDEPENDENT-SEGMENTS is specified). This fixes issue #2882 and improves (but does not completely solve #8592 --- .../exoplayer2/source/hls/HlsChunkSource.java | 38 ++++ .../exoplayer2/source/hls/HlsMediaPeriod.java | 9 +- .../source/hls/HlsSampleStreamWrapper.java | 26 +++ .../source/hls/HlsChunkSourceTest.java | 197 ++++++++++++++++++ 4 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsChunkSourceTest.java diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index fa1dfb48ad..ee8fe4c2d0 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -26,6 +26,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator; @@ -237,6 +238,43 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; this.isTimestampMaster = isTimestampMaster; } + /** + * Adjusts a seek position given the specified {@link SeekParameters}. The HLS Segment start times + * are used as the sync points iff the playlist declares {@link HlsMediaPlaylist#hasIndependentSegments} + * indicating each segment starts with an IDR. + * + * @param positionUs The seek position in microseconds. + * @param seekParameters Parameters that control how the seek is performed. + * @return The adjusted seek position, in microseconds. + */ + public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { + long adjustedPositionUs = positionUs; + + int selectedIndex = trackSelection.getSelectedIndex(); + boolean haveTrackSelection = selectedIndex < playlistUrls.length && selectedIndex != C.INDEX_UNSET; + @Nullable HlsMediaPlaylist mediaPlaylist = null; + if (haveTrackSelection) { + mediaPlaylist = playlistTracker.getPlaylistSnapshot(playlistUrls[selectedIndex], /* isForPlayback= */ true); + } + + // Resolve to a segment boundary, current track is fine (all should be same). + // and, segments must start with sync (EXT-X-INDEPENDENT-SEGMENTS must be present) + if (mediaPlaylist != null && mediaPlaylist.hasIndependentSegments && !mediaPlaylist.segments.isEmpty()) { + long startOfPlaylistInPeriodUs = mediaPlaylist.startTimeUs - playlistTracker.getInitialStartTimeUs(); + long targetPositionInPlaylistUs = positionUs - startOfPlaylistInPeriodUs; + + int segIndex = Util.binarySearchFloor(mediaPlaylist.segments, targetPositionInPlaylistUs, true, true); + long firstSyncUs = mediaPlaylist.segments.get(segIndex).relativeStartTimeUs + startOfPlaylistInPeriodUs; + long secondSyncUs = firstSyncUs; + if (segIndex != mediaPlaylist.segments.size() - 1) { + secondSyncUs = mediaPlaylist.segments.get(segIndex + 1).relativeStartTimeUs + startOfPlaylistInPeriodUs; + } + adjustedPositionUs = seekParameters.resolveSeekPositionUs(positionUs, firstSyncUs, secondSyncUs); + } + + return adjustedPositionUs; + } + /** * Returns the publication state of the given chunk. * diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index 6e4430923e..f064bc0436 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -417,7 +417,14 @@ public final class HlsMediaPeriod @Override public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { - return positionUs; + long seekTargetUs = positionUs; + for (HlsSampleStreamWrapper sampleStreamWrapper : enabledSampleStreamWrappers) { + if (sampleStreamWrapper.isVideoSampleStream()) { + seekTargetUs = sampleStreamWrapper.getAdjustedSeekPositionUs(positionUs, seekParameters); + break; + } + } + return seekTargetUs; } // HlsSampleStreamWrapper.Callback implementation. diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index ca72c5516d..5b1db5bf1d 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -30,6 +30,7 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmSession; @@ -585,6 +586,31 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; && exclusionDurationMs != C.TIME_UNSET; } + /** + * Check if the primary sample stream is video, {@link C#TRACK_TYPE_VIDEO}. This + * HlsSampleStreamWrapper may managed audio and other streams muxed in the same + * container, but as long as it has a video stream this method returns true. + * + * @return true if there is a video SampleStream managed by this object. + */ + public boolean isVideoSampleStream() { + return primarySampleQueueType == C.TRACK_TYPE_VIDEO; + } + + + /** + * Adjusts a seek position given the specified {@link SeekParameters}. Method delegates to + * the associated {@link HlsChunkSource#getAdjustedSeekPositionUs(long, SeekParameters)}. + * + * @param positionUs The seek position in microseconds. + * @param seekParameters Parameters that control how the seek is performed. + * @return The adjusted seek position, in microseconds. + */ + public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { + return chunkSource.getAdjustedSeekPositionUs(positionUs, seekParameters); + } + + // SampleStream implementation. public boolean isReady(int sampleQueueIndex) { diff --git a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsChunkSourceTest.java b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsChunkSourceTest.java new file mode 100644 index 0000000000..74e5afe866 --- /dev/null +++ b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsChunkSourceTest.java @@ -0,0 +1,197 @@ +package com.google.android.exoplayer2.source.hls; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import android.net.Uri; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; + +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker; +import com.google.android.exoplayer2.testutil.ExoPlayerTestRunner; +import com.google.android.exoplayer2.util.Util; + + +@RunWith(AndroidJUnit4.class) +public class HlsChunkSourceTest { + + public static final String TEST_PLAYLIST = "#EXTM3U\n" + + "#EXT-X-MEDIA-SEQUENCE:1606273114\n" + + "#EXT-X-VERSION:6\n" + + "#EXT-X-PLAYLIST-TYPE:VOD\n" + + "#EXT-X-I-FRAMES-ONLY\n" + + "#EXT-X-INDEPENDENT-SEGMENTS\n" + + "#EXT-X-MAP:URI=\"init-CCUR_iframe.tsv\"\n" + + "#EXT-X-PROGRAM-DATE-TIME:2020-11-25T02:58:34+00:00\n" + + "#EXTINF:4,\n" + + "#EXT-X-BYTERANGE:52640@19965036\n" + + "1606272900-CCUR_iframe.tsv\n" + + "#EXTINF:4,\n" + + "#EXT-X-BYTERANGE:77832@20253992\n" + + "1606272900-CCUR_iframe.tsv\n" + + "#EXTINF:4,\n" + + "#EXT-X-BYTERANGE:168824@21007496\n" + + "1606272900-CCUR_iframe.tsv\n" + + "#EXTINF:4,\n" + + "#EXT-X-BYTERANGE:177848@21888840\n" + + "1606272900-CCUR_iframe.tsv\n" + + "#EXTINF:4,\n" + + "#EXT-X-BYTERANGE:69560@22496456\n" + + "1606272900-CCUR_iframe.tsv\n" + + "#EXTINF:4,\n" + + "#EXT-X-BYTERANGE:41360@22830156\n" + + "1606272900-CCUR_iframe.tsv\n" + + "#EXT-X-ENDLIST\n" + + "\n"; + public static final Uri PLAYLIST_URI = Uri.parse("http://example.com/"); + + // simulate the playlist has reloaded since the period start. + private static final long PLAYLIST_START_PERIOD_OFFSET = 8_000_000L; + + private final HlsExtractorFactory mockExtractorFactory = HlsExtractorFactory.DEFAULT; + + @Mock + private HlsPlaylistTracker mockPlaylistTracker; + + @Mock + private HlsDataSourceFactory mockDataSourceFactory; + private HlsChunkSource testee; + private HlsMediaPlaylist playlist; + + @Before + public void setup() throws IOException { + // sadly, auto mock does not work, you get NoClassDefFoundError: com/android/dx/rop/type/Type +// MockitoAnnotations.initMocks(this); + mockPlaylistTracker = Mockito.mock(HlsPlaylistTracker.class); + mockDataSourceFactory = Mockito.mock(HlsDataSourceFactory.class); + InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(TEST_PLAYLIST)); + playlist = (HlsMediaPlaylist) new HlsPlaylistParser().parse(PLAYLIST_URI, inputStream); + + when(mockPlaylistTracker.getPlaylistSnapshot(eq(PLAYLIST_URI), anyBoolean())).thenReturn(playlist); + + testee = new HlsChunkSource( + mockExtractorFactory, + mockPlaylistTracker, + new Uri[] {PLAYLIST_URI}, + new Format[] { ExoPlayerTestRunner.VIDEO_FORMAT }, + mockDataSourceFactory, + null, + new TimestampAdjusterProvider(), + null); + + when(mockPlaylistTracker.isSnapshotValid(eq(PLAYLIST_URI))).thenReturn(true); + + // mock a couple of target duration (4s) updates to the playlist since period starts + when(mockPlaylistTracker.getInitialStartTimeUs()).thenReturn(playlist.startTimeUs - PLAYLIST_START_PERIOD_OFFSET); + } + + @Test + public void getAdjustedSeekPositionUs_PreviousSync() { + long adjusted = testee.getAdjustedSeekPositionUs(playlistTimeToPeriodTimeUs(17_000_000), SeekParameters.PREVIOUS_SYNC); + assertThat(periodTimeToPlaylistTime(adjusted)).isEqualTo(16_000_000); + } + + @Test + public void getAdjustedSeekPositionUs_NextSync() { + long adjusted = testee.getAdjustedSeekPositionUs(playlistTimeToPeriodTimeUs(17_000_000), SeekParameters.NEXT_SYNC); + assertThat(periodTimeToPlaylistTime(adjusted)).isEqualTo(20_000_000); + } + + @Test + public void getAdjustedSeekPositionUs_NextSyncAtEnd() { + long adjusted = testee.getAdjustedSeekPositionUs(playlistTimeToPeriodTimeUs(24_000_000), SeekParameters.NEXT_SYNC); + assertThat(periodTimeToPlaylistTime(adjusted)).isEqualTo(24_000_000); + } + + @Test + public void getAdjustedSeekPositionUs_ClosestSync() { + long adjusted = testee.getAdjustedSeekPositionUs(playlistTimeToPeriodTimeUs(17_000_000), SeekParameters.CLOSEST_SYNC); + assertThat(periodTimeToPlaylistTime(adjusted)).isEqualTo(16_000_000); + + adjusted = testee.getAdjustedSeekPositionUs(playlistTimeToPeriodTimeUs(19_000_000), SeekParameters.CLOSEST_SYNC); + assertThat(periodTimeToPlaylistTime(adjusted)).isEqualTo(20_000_000); + } + + @Test + public void getAdjustedSeekPositionUs_Exact() { + long adjusted = testee.getAdjustedSeekPositionUs(playlistTimeToPeriodTimeUs(17_000_000), SeekParameters.EXACT); + assertThat(periodTimeToPlaylistTime(adjusted)).isEqualTo(17_000_000); + } + + @Test + public void getAdjustedSeekPositionUs_NoIndependedSegments() { + HlsMediaPlaylist mockPlaylist = getMockEmptyPlaylist(false); + when(mockPlaylistTracker.getPlaylistSnapshot(eq(PLAYLIST_URI), anyBoolean())).thenReturn(mockPlaylist); + long adjusted = testee.getAdjustedSeekPositionUs(playlistTimeToPeriodTimeUs(100_000_000), SeekParameters.EXACT); + assertThat(periodTimeToPlaylistTime(adjusted)).isEqualTo(100_000_000); + } + + + @Test + public void getAdjustedSeekPositionUs_EmptyPlaylist() { + HlsMediaPlaylist mockPlaylist = getMockEmptyPlaylist(true); + when(mockPlaylistTracker.getPlaylistSnapshot(eq(PLAYLIST_URI), anyBoolean())).thenReturn(mockPlaylist); + long adjusted = testee.getAdjustedSeekPositionUs(playlistTimeToPeriodTimeUs(100_000_000), SeekParameters.EXACT); + assertThat(periodTimeToPlaylistTime(adjusted)).isEqualTo(100_000_000); + } + + + + /** + * Convert playlist start relative time to {@link MediaPeriod} relative time. + * + * It is easier to express test case values relative to the playlist. + * + * @param playlistTimeUs - playlist time (first segment start is time 0) + * @return period time, offset of the playlist update (the Window) from start of period + */ + private long playlistTimeToPeriodTimeUs(long playlistTimeUs) { + return playlistTimeUs + PLAYLIST_START_PERIOD_OFFSET; + } + + private long periodTimeToPlaylistTime(long periodTimeUs) { + return periodTimeUs - PLAYLIST_START_PERIOD_OFFSET; + } + + + private HlsMediaPlaylist getMockEmptyPlaylist(boolean hasIndependentSegments) { + return new HlsMediaPlaylist( + HlsMediaPlaylist.PLAYLIST_TYPE_UNKNOWN, + PLAYLIST_URI.toString(), + Collections.emptyList(), + 0, + false, + 0, + false, + 0, + 0, + 8, + 6, + 2, + hasIndependentSegments, + false, + true, + null, + Collections.emptyList(), + Collections.emptyList(), + new HlsMediaPlaylist.ServerControl(0, true, 0, 0, true), + Collections.emptyMap() + ); + } +} From 701f343ee5fb65111afb7a87211ae9b03482cb9c Mon Sep 17 00:00:00 2001 From: Steve Mayhew Date: Mon, 18 Oct 2021 17:04:29 -0700 Subject: [PATCH 006/497] Fixes issues with EXTINF duration conversion to microseconds The HLS Parser converts from a string decimal duration in seconds into long microseconds. Because the conversion passes through a java double type it can result in representation errors. For example: `#EXTINF:4.004` -> `Segment.durationUs` of 4003999 This matters because the first sample (which is the IDR) for a segment will be discarded following a seek because of the logic in the `SampleQueue`: ````java buffer.timeUs = timesUs[relativeReadIndex]; if (buffer.timeUs < startTimeUs) { buffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY); } ```` --- .../source/hls/playlist/HlsPlaylistParser.java | 10 ++++++++-- .../hls/playlist/HlsMediaPlaylistParserTest.java | 8 +++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index ac8bf1e5a8..022b9f1b2b 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -48,6 +48,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.math.BigDecimal; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; @@ -759,8 +760,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser segments = mediaPlaylist.segments; assertThat(segments).isNotNull(); - assertThat(segments).hasSize(5); + assertThat(segments).hasSize(6); Segment segment = segments.get(0); assertThat(mediaPlaylist.discontinuitySequence + segment.relativeDiscontinuitySequence) @@ -152,6 +155,9 @@ public class HlsMediaPlaylistParserTest { assertThat(segment.byteRangeLength).isEqualTo(C.LENGTH_UNSET); assertThat(segment.byteRangeOffset).isEqualTo(0); assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2683.ts"); + + segment = segments.get(5); + assertThat(segment.durationUs).isEqualTo(2002000); } @Test From 8e24d290405cd5c10e772eccbe0ed6b11ada1206 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 25 Oct 2021 13:13:08 +0100 Subject: [PATCH 007/497] Make the RTSP SocketFactory configurable --- .../exoplayer2/source/rtsp/RtspClient.java | 13 +++++++-- .../source/rtsp/RtspMediaPeriod.java | 12 +++++--- .../source/rtsp/RtspMediaSource.java | 28 +++++++++++++++++-- .../source/rtsp/RtspClientTest.java | 15 ++++++---- .../source/rtsp/RtspMediaPeriodTest.java | 3 +- .../source/rtsp/RtspPlaybackTest.java | 3 +- 6 files changed, 57 insertions(+), 17 deletions(-) diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java index 715212d211..c1b982634a 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java @@ -124,6 +124,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private final PlaybackEventListener playbackEventListener; private final String userAgent; private final boolean debugLoggingEnabled; + @Nullable private final SocketFactory socketFactory; private final ArrayDeque pendingSetupRtpLoadInfos; // TODO(b/172331505) Add a timeout monitor for pending requests. private final SparseArray pendingRequests; @@ -161,11 +162,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; PlaybackEventListener playbackEventListener, String userAgent, Uri uri, - boolean debugLoggingEnabled) { + boolean debugLoggingEnabled, + @Nullable SocketFactory socketFactory) { this.sessionInfoListener = sessionInfoListener; this.playbackEventListener = playbackEventListener; this.userAgent = userAgent; this.debugLoggingEnabled = debugLoggingEnabled; + this.socketFactory = socketFactory; this.pendingSetupRtpLoadInfos = new ArrayDeque<>(); this.pendingRequests = new SparseArray<>(); this.messageSender = new MessageSender(); @@ -286,10 +289,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } /** Returns a {@link Socket} that is connected to the {@code uri}. */ - private static Socket getSocket(Uri uri) throws IOException { + private Socket getSocket(Uri uri) throws IOException { checkArgument(uri.getHost() != null); int rtspPort = uri.getPort() > 0 ? uri.getPort() : DEFAULT_RTSP_PORT; - return SocketFactory.getDefault().createSocket(checkNotNull(uri.getHost()), rtspPort); + + SocketFactory socketFactory = + this.socketFactory != null ? this.socketFactory : SocketFactory.getDefault(); + + return socketFactory.createSocket(checkNotNull(uri.getHost()), rtspPort); } private void dispatchRtspError(Throwable error) { diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java index 435bb59a30..e71f4d72a3 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java @@ -55,6 +55,7 @@ import java.io.IOException; import java.net.BindException; import java.util.ArrayList; import java.util.List; +import javax.net.SocketFactory; import org.checkerframework.checker.nullness.compatqual.NullableType; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -96,12 +97,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** * Creates an RTSP media period. - * - * @param allocator An {@link Allocator} from which to obtain media buffer allocations. + * @param allocator An {@link Allocator} from which to obtain media buffer allocations. * @param rtpDataChannelFactory A {@link RtpDataChannel.Factory} for {@link RtpDataChannel}. * @param uri The RTSP playback {@link Uri}. * @param listener A {@link Listener} to receive session information updates. * @param userAgent The user agent. + * @param debugLoggingEnabled Whether to log RTSP messages. + * @param socketFactory A socket factory. */ public RtspMediaPeriod( Allocator allocator, @@ -109,7 +111,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; Uri uri, Listener listener, String userAgent, - boolean debugLoggingEnabled) { + boolean debugLoggingEnabled, + @Nullable SocketFactory socketFactory) { this.allocator = allocator; this.rtpDataChannelFactory = rtpDataChannelFactory; this.listener = listener; @@ -122,7 +125,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /* playbackEventListener= */ internalListener, /* userAgent= */ userAgent, /* uri= */ uri, - debugLoggingEnabled); + debugLoggingEnabled, + socketFactory); rtspLoaderWrappers = new ArrayList<>(); selectedLoadInfos = new ArrayList<>(); diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java index 63bbeed35c..54145cad9b 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java @@ -40,6 +40,7 @@ import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.TransferListener; import java.io.IOException; +import javax.net.SocketFactory; /** An Rtsp {@link MediaSource} */ public final class RtspMediaSource extends BaseMediaSource { @@ -70,6 +71,7 @@ public final class RtspMediaSource extends BaseMediaSource { private String userAgent; private boolean forceUseRtpTcp; private boolean debugLoggingEnabled; + private SocketFactory socketFactory; public Factory() { timeoutMs = DEFAULT_TIMEOUT_MS; @@ -117,6 +119,19 @@ public final class RtspMediaSource extends BaseMediaSource { return this; } + /** + * Configures a socket factory to be used for client connections. + * + * When unspecified, {@link SocketFactory#getDefault()} is used. + * + * @param socketFactory A socket factory. + * @return This Factory, for convenience. + */ + public Factory setSocketFactory(SocketFactory socketFactory) { + this.socketFactory = socketFactory; + return this; + } + /** * Sets the timeout in milliseconds, the default value is {@link #DEFAULT_TIMEOUT_MS}. * @@ -202,7 +217,8 @@ public final class RtspMediaSource extends BaseMediaSource { ? new TransferRtpDataChannelFactory(timeoutMs) : new UdpDataSourceRtpDataChannelFactory(timeoutMs), userAgent, - debugLoggingEnabled); + debugLoggingEnabled, + socketFactory); } } @@ -227,6 +243,9 @@ public final class RtspMediaSource extends BaseMediaSource { private final Uri uri; private final boolean debugLoggingEnabled; + @Nullable + private final SocketFactory socketFactory; + private long timelineDurationUs; private boolean timelineIsSeekable; private boolean timelineIsLive; @@ -237,12 +256,14 @@ public final class RtspMediaSource extends BaseMediaSource { MediaItem mediaItem, RtpDataChannel.Factory rtpDataChannelFactory, String userAgent, - boolean debugLoggingEnabled) { + boolean debugLoggingEnabled, + @Nullable SocketFactory socketFactory) { this.mediaItem = mediaItem; this.rtpDataChannelFactory = rtpDataChannelFactory; this.userAgent = userAgent; this.uri = checkNotNull(this.mediaItem.localConfiguration).uri; this.debugLoggingEnabled = debugLoggingEnabled; + this.socketFactory = socketFactory; this.timelineDurationUs = C.TIME_UNSET; this.timelineIsPlaceholder = true; } @@ -281,7 +302,8 @@ public final class RtspMediaSource extends BaseMediaSource { notifySourceInfoRefreshed(); }, userAgent, - debugLoggingEnabled); + debugLoggingEnabled, + socketFactory); } @Override diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java index 0018c8a9e4..ca239695ad 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java @@ -113,7 +113,8 @@ public final class RtspClientTest { EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + /* socketFactory */ null); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -164,7 +165,8 @@ public final class RtspClientTest { EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + /* socketFactory */ null); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -207,7 +209,8 @@ public final class RtspClientTest { EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + /* socketFactory */ null); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -253,7 +256,8 @@ public final class RtspClientTest { EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + /* socketFactory */ null); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> failureMessage.get() != null); @@ -299,7 +303,8 @@ public final class RtspClientTest { EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + /* socketFactory */ null); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> failureCause.get() != null); diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java index da7da55d8e..90594f6ca1 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java @@ -84,7 +84,8 @@ public final class RtspMediaPeriodTest { RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), /* listener= */ timing -> refreshedSourceDurationMs.set(timing.getDurationMs()), /* userAgent= */ "ExoPlayer:RtspPeriodTest", - /* debugLoggingEnabled= */ false); + /* debugLoggingEnabled= */ false, + null); mediaPeriod.prepare( new MediaPeriod.Callback() { diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java index c82f68c0a3..8ebcbbe36d 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java @@ -156,7 +156,8 @@ public final class RtspPlaybackTest { MediaItem.fromUri(RtspTestUtils.getTestUri(serverRtspPortNumber)), rtpDataChannelFactory, "ExoPlayer:PlaybackTest", - /* debugLoggingEnabled= */ false), + /* debugLoggingEnabled= */ false, + null), false); return player; } From c14a9c09b324caa819386690e582f16a640b15c9 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 25 Oct 2021 16:11:38 +0100 Subject: [PATCH 008/497] docs --- .../google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java | 2 +- .../android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java | 2 +- .../google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java index e71f4d72a3..8d0347138b 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java @@ -97,7 +97,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** * Creates an RTSP media period. - * @param allocator An {@link Allocator} from which to obtain media buffer allocations. + * @param allocator An {@link Allocator} from which to obtain media buffer allocations. * @param rtpDataChannelFactory A {@link RtpDataChannel.Factory} for {@link RtpDataChannel}. * @param uri The RTSP playback {@link Uri}. * @param listener A {@link Listener} to receive session information updates. diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java index 90594f6ca1..9c77d5406e 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java @@ -85,7 +85,7 @@ public final class RtspMediaPeriodTest { /* listener= */ timing -> refreshedSourceDurationMs.set(timing.getDurationMs()), /* userAgent= */ "ExoPlayer:RtspPeriodTest", /* debugLoggingEnabled= */ false, - null); + /* socketFactory */ null); mediaPeriod.prepare( new MediaPeriod.Callback() { diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java index 8ebcbbe36d..625f310387 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java @@ -157,7 +157,7 @@ public final class RtspPlaybackTest { rtpDataChannelFactory, "ExoPlayer:PlaybackTest", /* debugLoggingEnabled= */ false, - null), + /* socketFactory */ null), false); return player; } From 4001592c93b411aca2a47f84091b85493bf16095 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 26 Oct 2021 12:58:03 +0100 Subject: [PATCH 009/497] Add a test --- .../source/rtsp/RtspClientTest.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java index ca239695ad..2ffb507de2 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java @@ -27,8 +27,12 @@ import com.google.android.exoplayer2.source.rtsp.RtspClient.SessionInfoListener; import com.google.android.exoplayer2.source.rtsp.RtspMediaSource.RtspPlaybackException; import com.google.android.exoplayer2.util.Util; import com.google.common.collect.ImmutableList; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import javax.net.SocketFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -77,6 +81,79 @@ public final class RtspClientTest { Util.closeQuietly(rtspClient); } + @Test + public void connectServerAndClient_usesCustomSocketFactory() throws Exception { + class ResponseProvider implements RtspServer.ResponseProvider { + @Override + public RtspResponse getOptionsResponse() { + return new RtspResponse( + /* status= */ 200, + new RtspHeaders.Builder().add(RtspHeaders.PUBLIC, "OPTIONS, DESCRIBE").build()); + } + + @Override + public RtspResponse getDescribeResponse(Uri requestedUri) { + return RtspTestUtils.newDescribeResponseWithSdpMessage( + SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri); + } + } + rtspServer = new RtspServer(new ResponseProvider()); + + final AtomicReference didCallCreateSocket = new AtomicReference<>(); + + final SocketFactory socketFactory = + new SocketFactory() { + + @Override + public Socket createSocket(String host, int port) throws IOException { + didCallCreateSocket.set(true); + + return SocketFactory.getDefault().createSocket(host, port); + } + + @Override + public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) + throws IOException { + return SocketFactory.getDefault().createSocket(s, i, inetAddress, i1); + } + + @Override + public Socket createSocket(InetAddress inetAddress, int i) throws IOException { + return SocketFactory.getDefault().createSocket(inetAddress, i); + } + + @Override + public Socket createSocket( + InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException { + return SocketFactory.getDefault().createSocket(inetAddress, i, inetAddress1, i1); + } + }; + + AtomicReference> tracksInSession = new AtomicReference<>(); + rtspClient = + new RtspClient( + new SessionInfoListener() { + @Override + public void onSessionTimelineUpdated( + RtspSessionTiming timing, ImmutableList tracks) { + tracksInSession.set(tracks); + } + + @Override + public void onSessionTimelineRequestFailed( + String message, @Nullable Throwable cause) {} + }, + EMPTY_PLAYBACK_LISTENER, + /* userAgent= */ "ExoPlayer:RtspClientTest", + RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), + /* debugLoggingEnabled= */ false, + socketFactory); + rtspClient.start(); + RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); + + assertThat(didCallCreateSocket.get()).isTrue(); + } + @Test public void connectServerAndClient_serverSupportsDescribe_updatesSessionTimeline() throws Exception { From 6dd2177a85cbef092502608a7b45c16e9ff963b9 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 26 Oct 2021 12:58:08 +0100 Subject: [PATCH 010/497] Add release notes --- RELEASENOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2ace17dc48..5e3a4aa675 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -73,6 +73,8 @@ * RTSP: * Support RFC4566 SDP attribute field grammar ([#9430](https://github.com/google/ExoPlayer/issues/9430)). + * Provide a client API to override the `SocketFactory` used for any server + connection ([#9606](https://github.com/google/ExoPlayer/pull/9606)). * DASH: * Populate `Format.sampleMimeType`, `width` and `height` for image `AdaptationSet` elements From 1ecbdb8d9ceade788930da73bc0cb4d292b1047f Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 26 Oct 2021 12:58:49 +0100 Subject: [PATCH 011/497] formatting --- RELEASENOTES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5e3a4aa675..17a41a0618 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -73,8 +73,8 @@ * RTSP: * Support RFC4566 SDP attribute field grammar ([#9430](https://github.com/google/ExoPlayer/issues/9430)). - * Provide a client API to override the `SocketFactory` used for any server - connection ([#9606](https://github.com/google/ExoPlayer/pull/9606)). + * Provide a client API to override the `SocketFactory` used for any server + connection ([#9606](https://github.com/google/ExoPlayer/pull/9606)). * DASH: * Populate `Format.sampleMimeType`, `width` and `height` for image `AdaptationSet` elements From 42f9ddb54ed6ce8d6f42302c8542028fff6345a6 Mon Sep 17 00:00:00 2001 From: ibaker Date: Mon, 1 Nov 2021 10:06:02 +0000 Subject: [PATCH 012/497] Remove unecessary warning suppression in PlaybackException PiperOrigin-RevId: 406783965 --- .../java/com/google/android/exoplayer2/PlaybackException.java | 1 - 1 file changed, 1 deletion(-) diff --git a/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java b/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java index 335dcf2612..b643530678 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java @@ -423,7 +423,6 @@ public class PlaybackException extends Exception implements Bundleable { protected static final int FIELD_CUSTOM_ID_BASE = 1000; /** Object that can create a {@link PlaybackException} from a {@link Bundle}. */ - @SuppressWarnings("unchecked") public static final Creator CREATOR = PlaybackException::new; @CallSuper From 9f352434c72da527d1fa7963447c3cf680db884f Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 1 Nov 2021 10:23:58 +0000 Subject: [PATCH 013/497] Add large renderer position offset. This helps to prevent issues where decoders can't handle negative timestamps. In particular it avoids issues when the media accidentally or intentionally starts with small negative timestamps. But it also helps to prevent other renderer resets at a later point, for example if a live stream with a large start offset is enqueued in the playlist. #minor-release PiperOrigin-RevId: 406786977 --- .../exoplayer2/ExoPlayerImplInternal.java | 9 +-- .../android/exoplayer2/MediaPeriodQueue.java | 24 +++++++- .../exoplayer2/MediaPeriodQueueTest.java | 47 ++++++++++----- .../transformer/TransformerAudioRenderer.java | 1 + .../transformer/TransformerBaseRenderer.java | 7 +++ .../TransformerMuxingVideoRenderer.java | 1 + .../TransformerTranscodingVideoRenderer.java | 1 + .../mka/bear-flac-16bit.mka.audiosink.dump | 58 +++++++++---------- .../mka/bear-flac-24bit.mka.audiosink.dump | 58 +++++++++---------- 9 files changed, 127 insertions(+), 79 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 30085aeb9a..9fadb56a79 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -1266,7 +1266,8 @@ import java.util.concurrent.atomic.AtomicBoolean; queue.advancePlayingPeriod(); } queue.removeAfter(newPlayingPeriodHolder); - newPlayingPeriodHolder.setRendererOffset(/* rendererPositionOffsetUs= */ 0); + newPlayingPeriodHolder.setRendererOffset( + MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US); enableRenderers(); } } @@ -1299,7 +1300,7 @@ import java.util.concurrent.atomic.AtomicBoolean; MediaPeriodHolder playingMediaPeriod = queue.getPlayingPeriod(); rendererPositionUs = playingMediaPeriod == null - ? periodPositionUs + ? MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + periodPositionUs : playingMediaPeriod.toRendererTime(periodPositionUs); mediaClock.resetPosition(rendererPositionUs); for (Renderer renderer : renderers) { @@ -1375,7 +1376,7 @@ import java.util.concurrent.atomic.AtomicBoolean; pendingRecoverableRendererError = null; isRebuffering = false; mediaClock.stop(); - rendererPositionUs = 0; + rendererPositionUs = MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US; for (Renderer renderer : renderers) { try { disableRenderer(renderer); @@ -1963,7 +1964,7 @@ import java.util.concurrent.atomic.AtomicBoolean; emptyTrackSelectorResult); mediaPeriodHolder.mediaPeriod.prepare(this, info.startPositionUs); if (queue.getPlayingPeriod() == mediaPeriodHolder) { - resetRendererPosition(mediaPeriodHolder.getStartPositionRendererTime()); + resetRendererPosition(info.startPositionUs); } handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ false); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java index 18b258d779..f00ca859f1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java @@ -37,6 +37,26 @@ import com.google.common.collect.ImmutableList; */ /* package */ final class MediaPeriodQueue { + /** + * Initial renderer position offset used for the first item in the queue, in microseconds. + * + *

Choosing a positive value, larger than any reasonable single media duration, ensures three + * things: + * + *

    + *
  • Media that accidentally or intentionally starts with small negative timestamps doesn't + * send samples with negative timestamps to decoders. This makes rendering more robust as + * many decoders are known to have problems with negative timestamps. + *
  • Enqueueing media after the initial item with a non-zero start offset (e.g. content after + * ad breaks or live streams) is virtually guaranteed to stay in the positive timestamp + * range even when seeking back. This prevents renderer resets that are required if the + * allowed timestamp range may become negative. + *
  • Choosing a large value with zeros at all relevant digits simplifies debugging as the + * original timestamp of the media is still visible. + *
+ */ + public static final long INITIAL_RENDERER_POSITION_OFFSET_US = 1_000_000_000_000L; + /** * Limits the maximum number of periods to buffer ahead of the current playing period. The * buffering policy normally prevents buffering too far ahead, but the policy could allow too many @@ -163,9 +183,7 @@ import com.google.common.collect.ImmutableList; TrackSelectorResult emptyTrackSelectorResult) { long rendererPositionOffsetUs = loading == null - ? (info.id.isAd() && info.requestedContentPositionUs != C.TIME_UNSET - ? info.requestedContentPositionUs - : 0) + ? INITIAL_RENDERER_POSITION_OFFSET_US : (loading.getRendererOffset() + loading.info.durationUs - info.startPositionUs); MediaPeriodHolder newPeriodHolder = new MediaPeriodHolder( diff --git a/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java b/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java index 635167e658..53bc87e5e6 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java @@ -493,10 +493,13 @@ public final class MediaPeriodQueueTest { // Change position of first ad (= change duration of playing content before first ad). updateAdPlaybackStateAndTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US - 2000); setAdGroupLoaded(/* adGroupIndex= */ 0); - long maxRendererReadPositionUs = FIRST_AD_START_TIME_US - 3000; + long maxRendererReadPositionUs = + MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + FIRST_AD_START_TIME_US - 3000; boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( - playbackInfo.timeline, /* rendererPositionUs= */ 0, maxRendererReadPositionUs); + playbackInfo.timeline, + /* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US, + maxRendererReadPositionUs); assertThat(changeHandled).isTrue(); assertThat(getQueueLength()).isEqualTo(1); @@ -518,10 +521,13 @@ public final class MediaPeriodQueueTest { // Change position of first ad (= change duration of playing content before first ad). updateAdPlaybackStateAndTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US - 2000); setAdGroupLoaded(/* adGroupIndex= */ 0); - long maxRendererReadPositionUs = FIRST_AD_START_TIME_US - 1000; + long maxRendererReadPositionUs = + MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + FIRST_AD_START_TIME_US - 1000; boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( - playbackInfo.timeline, /* rendererPositionUs= */ 0, maxRendererReadPositionUs); + playbackInfo.timeline, + /* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US, + maxRendererReadPositionUs); assertThat(changeHandled).isFalse(); assertThat(getQueueLength()).isEqualTo(1); @@ -552,10 +558,13 @@ public final class MediaPeriodQueueTest { .withIsServerSideInserted(/* adGroupIndex= */ 0, /* isServerSideInserted= */ true); updateTimeline(); setAdGroupLoaded(/* adGroupIndex= */ 0); - long maxRendererReadPositionUs = FIRST_AD_START_TIME_US - 1000; + long maxRendererReadPositionUs = + MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + FIRST_AD_START_TIME_US - 1000; boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( - playbackInfo.timeline, /* rendererPositionUs= */ 0, maxRendererReadPositionUs); + playbackInfo.timeline, + /* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US, + maxRendererReadPositionUs); assertThat(changeHandled).isTrue(); assertThat(getQueueLength()).isEqualTo(1); @@ -583,7 +592,9 @@ public final class MediaPeriodQueueTest { setAdGroupLoaded(/* adGroupIndex= */ 1); boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( - playbackInfo.timeline, /* rendererPositionUs= */ 0, /* maxRendererReadPositionUs= */ 0); + playbackInfo.timeline, + /* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US, + /* maxRendererReadPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US); assertThat(changeHandled).isTrue(); assertThat(getQueueLength()).isEqualTo(3); @@ -608,11 +619,13 @@ public final class MediaPeriodQueueTest { /* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000); setAdGroupLoaded(/* adGroupIndex= */ 0); setAdGroupLoaded(/* adGroupIndex= */ 1); + long maxRendererReadPositionUs = + MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + FIRST_AD_START_TIME_US; boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( playbackInfo.timeline, - /* rendererPositionUs= */ 0, - /* maxRendererReadPositionUs= */ FIRST_AD_START_TIME_US); + /* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US, + maxRendererReadPositionUs); assertThat(changeHandled).isFalse(); assertThat(getQueueLength()).isEqualTo(3); @@ -636,11 +649,14 @@ public final class MediaPeriodQueueTest { /* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000); setAdGroupLoaded(/* adGroupIndex= */ 0); setAdGroupLoaded(/* adGroupIndex= */ 1); - long readingPositionAtStartOfContentBetweenAds = FIRST_AD_START_TIME_US + AD_DURATION_US; + long readingPositionAtStartOfContentBetweenAds = + MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + + FIRST_AD_START_TIME_US + + AD_DURATION_US; boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( playbackInfo.timeline, - /* rendererPositionUs= */ 0, + /* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US, /* maxRendererReadPositionUs= */ readingPositionAtStartOfContentBetweenAds); assertThat(changeHandled).isTrue(); @@ -665,11 +681,14 @@ public final class MediaPeriodQueueTest { /* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000); setAdGroupLoaded(/* adGroupIndex= */ 0); setAdGroupLoaded(/* adGroupIndex= */ 1); - long readingPositionAtEndOfContentBetweenAds = SECOND_AD_START_TIME_US + AD_DURATION_US; + long readingPositionAtEndOfContentBetweenAds = + MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + + SECOND_AD_START_TIME_US + + AD_DURATION_US; boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( playbackInfo.timeline, - /* rendererPositionUs= */ 0, + /* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US, /* maxRendererReadPositionUs= */ readingPositionAtEndOfContentBetweenAds); assertThat(changeHandled).isFalse(); @@ -697,7 +716,7 @@ public final class MediaPeriodQueueTest { boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( playbackInfo.timeline, - /* rendererPositionUs= */ 0, + /* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US, /* maxRendererReadPositionUs= */ C.TIME_END_OF_SOURCE); assertThat(changeHandled).isFalse(); diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java index 02248296d0..8da9dcd2e1 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java @@ -279,6 +279,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; int result = readSource(getFormatHolder(), decoderInputBuffer, /* readFlags= */ 0); switch (result) { case C.RESULT_BUFFER_READ: + decoderInputBuffer.timeUs -= streamOffsetUs; mediaClock.updateTimeForTrackType(getTrackType(), decoderInputBuffer.timeUs); decoderInputBuffer.flip(); decoder.queueInputBuffer(decoderInputBuffer); diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java index e0ceb945fc..6e19f0b9f9 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java @@ -34,6 +34,7 @@ import com.google.android.exoplayer2.util.MimeTypes; protected final Transformation transformation; protected boolean isRendererStarted; + protected long streamOffsetUs; public TransformerBaseRenderer( int trackType, @@ -46,6 +47,12 @@ import com.google.android.exoplayer2.util.MimeTypes; this.transformation = transformation; } + @Override + protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) + throws ExoPlaybackException { + this.streamOffsetUs = offsetUs; + } + @Override @C.FormatSupport public final int supportsFormat(Format format) { diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerMuxingVideoRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerMuxingVideoRenderer.java index 0be02ecdee..d14378754e 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerMuxingVideoRenderer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerMuxingVideoRenderer.java @@ -117,6 +117,7 @@ import java.nio.ByteBuffer; muxerWrapper.endTrack(getTrackType()); return false; } + buffer.timeUs -= streamOffsetUs; mediaClock.updateTimeForTrackType(getTrackType(), buffer.timeUs); ByteBuffer data = checkNotNull(buffer.data); data.flip(); diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerTranscodingVideoRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerTranscodingVideoRenderer.java index b04490152b..931e985a5d 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerTranscodingVideoRenderer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerTranscodingVideoRenderer.java @@ -320,6 +320,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; case C.RESULT_FORMAT_READ: throw new IllegalStateException("Format changes are not supported."); case C.RESULT_BUFFER_READ: + decoderInputBuffer.timeUs -= streamOffsetUs; mediaClock.updateTimeForTrackType(getTrackType(), decoderInputBuffer.timeUs); ByteBuffer data = checkNotNull(decoderInputBuffer.data); data.flip(); diff --git a/testdata/src/test/assets/audiosinkdumps/mka/bear-flac-16bit.mka.audiosink.dump b/testdata/src/test/assets/audiosinkdumps/mka/bear-flac-16bit.mka.audiosink.dump index 044cde306c..b7319b872b 100644 --- a/testdata/src/test/assets/audiosinkdumps/mka/bear-flac-16bit.mka.audiosink.dump +++ b/testdata/src/test/assets/audiosinkdumps/mka/bear-flac-16bit.mka.audiosink.dump @@ -3,89 +3,89 @@ config: channelCount = 2 sampleRate = 48000 buffer: - time = 1000 + time = 1000000001000 data = 1217833679 buffer: - time = 97000 + time = 1000000097000 data = 558614672 buffer: - time = 193000 + time = 1000000193000 data = -709714787 buffer: - time = 289000 + time = 1000000289000 data = 1367870571 buffer: - time = 385000 + time = 1000000385000 data = -141229457 buffer: - time = 481000 + time = 1000000481000 data = 1287758361 buffer: - time = 577000 + time = 1000000577000 data = 1125289147 buffer: - time = 673000 + time = 1000000673000 data = -1677383475 buffer: - time = 769000 + time = 1000000769000 data = 2130742861 buffer: - time = 865000 + time = 1000000865000 data = -1292320253 buffer: - time = 961000 + time = 1000000961000 data = -456587163 buffer: - time = 1057000 + time = 1000001057000 data = 748981534 buffer: - time = 1153000 + time = 1000001153000 data = 1550456016 buffer: - time = 1249000 + time = 1000001249000 data = 1657906039 buffer: - time = 1345000 + time = 1000001345000 data = -762677083 buffer: - time = 1441000 + time = 1000001441000 data = -1343810763 buffer: - time = 1537000 + time = 1000001537000 data = 1137318783 buffer: - time = 1633000 + time = 1000001633000 data = -1891318229 buffer: - time = 1729000 + time = 1000001729000 data = -472068495 buffer: - time = 1825000 + time = 1000001825000 data = 832315001 buffer: - time = 1921000 + time = 1000001921000 data = 2054935175 buffer: - time = 2017000 + time = 1000002017000 data = 57921641 buffer: - time = 2113000 + time = 1000002113000 data = 2132759067 buffer: - time = 2209000 + time = 1000002209000 data = -1742540521 buffer: - time = 2305000 + time = 1000002305000 data = 1657024301 buffer: - time = 2401000 + time = 1000002401000 data = -585080145 buffer: - time = 2497000 + time = 1000002497000 data = 427271397 buffer: - time = 2593000 + time = 1000002593000 data = -364201340 buffer: - time = 2689000 + time = 1000002689000 data = -627965287 diff --git a/testdata/src/test/assets/audiosinkdumps/mka/bear-flac-24bit.mka.audiosink.dump b/testdata/src/test/assets/audiosinkdumps/mka/bear-flac-24bit.mka.audiosink.dump index 319ee311f0..f425e7e2f2 100644 --- a/testdata/src/test/assets/audiosinkdumps/mka/bear-flac-24bit.mka.audiosink.dump +++ b/testdata/src/test/assets/audiosinkdumps/mka/bear-flac-24bit.mka.audiosink.dump @@ -3,89 +3,89 @@ config: channelCount = 2 sampleRate = 48000 buffer: - time = 0 + time = 1000000000000 data = 225023649 buffer: - time = 96000 + time = 1000000096000 data = 455106306 buffer: - time = 192000 + time = 1000000192000 data = 2025727297 buffer: - time = 288000 + time = 1000000288000 data = 758514657 buffer: - time = 384000 + time = 1000000384000 data = 1044986473 buffer: - time = 480000 + time = 1000000480000 data = -2030029695 buffer: - time = 576000 + time = 1000000576000 data = 1907053281 buffer: - time = 672000 + time = 1000000672000 data = -1974954431 buffer: - time = 768000 + time = 1000000768000 data = -206248383 buffer: - time = 864000 + time = 1000000864000 data = 1484984417 buffer: - time = 960000 + time = 1000000960000 data = -1306117439 buffer: - time = 1056000 + time = 1000001056000 data = 692829792 buffer: - time = 1152000 + time = 1000001152000 data = 1070563058 buffer: - time = 1248000 + time = 1000001248000 data = -1444096479 buffer: - time = 1344000 + time = 1000001344000 data = 1753016419 buffer: - time = 1440000 + time = 1000001440000 data = 1947797953 buffer: - time = 1536000 + time = 1000001536000 data = 266121411 buffer: - time = 1632000 + time = 1000001632000 data = 1275494369 buffer: - time = 1728000 + time = 1000001728000 data = 372077825 buffer: - time = 1824000 + time = 1000001824000 data = -993079679 buffer: - time = 1920000 + time = 1000001920000 data = 177307937 buffer: - time = 2016000 + time = 1000002016000 data = 2037083009 buffer: - time = 2112000 + time = 1000002112000 data = -435776287 buffer: - time = 2208000 + time = 1000002208000 data = 1867447329 buffer: - time = 2304000 + time = 1000002304000 data = 1884495937 buffer: - time = 2400000 + time = 1000002400000 data = -804673375 buffer: - time = 2496000 + time = 1000002496000 data = -588531007 buffer: - time = 2592000 + time = 1000002592000 data = -1064642970 buffer: - time = 2688000 + time = 1000002688000 data = -1771406207 From e1494398a039acd209c731ec1d0c1356ccf997cc Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 1 Nov 2021 10:42:22 +0000 Subject: [PATCH 014/497] Upgrade gradle plugin version PiperOrigin-RevId: 406789671 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 055e3cdaff..d362ff785b 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.0.0' + classpath 'com.android.tools.build:gradle:7.0.3' classpath 'com.google.android.gms:strict-version-matcher-plugin:1.2.2' } } From 8829c45d3265cbd298e167a0457720f54af2a985 Mon Sep 17 00:00:00 2001 From: ibaker Date: Mon, 1 Nov 2021 11:13:15 +0000 Subject: [PATCH 015/497] Add TYPE_USE to IntDefs used in the media3 stable API This allows the use of the intdef in parameterized types, e.g. List<@MyIntDef Integer> For IntDefs that are already released in ExoPlayer 2.15.1 we add TYPE_USE in addition to all other reasonable targets, to maintain backwards compatibility with Kotlin code (where an incorrectly positioned annotation is a compilation failure). 'reasonable targets' includes FIELD, METHOD, PARAMETER and LOCAL_VARIABLE but not TYPE, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE or MODULE. TYPE_PARAMETER is implied by TYPE_USE. For not-yet-released IntDefs we just add TYPE_USE. #minor-release PiperOrigin-RevId: 406793413 --- .../java/com/google/android/exoplayer2/C.java | 17 +++++++++++++++-- .../android/exoplayer2/MediaMetadata.java | 9 +++++++++ .../android/exoplayer2/PlaybackException.java | 8 ++++++++ .../com/google/android/exoplayer2/Player.java | 16 ++++++++++++++++ .../com/google/android/exoplayer2/text/Cue.java | 11 +++++++++++ 5 files changed, 59 insertions(+), 2 deletions(-) diff --git a/library/common/src/main/java/com/google/android/exoplayer2/C.java b/library/common/src/main/java/com/google/android/exoplayer2/C.java index a779729bd9..7c26b57600 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/C.java @@ -15,6 +15,12 @@ */ package com.google.android.exoplayer2; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; + import android.content.Context; import android.media.AudioAttributes; import android.media.AudioFormat; @@ -29,7 +35,6 @@ import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; import com.google.errorprone.annotations.InlineMe; import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -126,6 +131,7 @@ public final class C { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target(TYPE_USE) @IntDef( open = true, value = { @@ -306,6 +312,7 @@ public final class C { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ CONTENT_TYPE_MOVIE, CONTENT_TYPE_MUSIC, @@ -334,6 +341,7 @@ public final class C { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef( flag = true, value = {FLAG_AUDIBILITY_ENFORCED}) @@ -354,6 +362,7 @@ public final class C { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ USAGE_ALARM, USAGE_ASSISTANCE_ACCESSIBILITY, @@ -422,6 +431,7 @@ public final class C { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ALLOW_CAPTURE_BY_ALL, ALLOW_CAPTURE_BY_NONE, ALLOW_CAPTURE_BY_SYSTEM}) public @interface AudioAllowedCapturePolicy {} /** See {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_ALL}. */ @@ -565,6 +575,7 @@ public final class C { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef( flag = true, value = {SELECTION_FLAG_DEFAULT, SELECTION_FLAG_FORCED, SELECTION_FLAG_AUTOSELECT}) @@ -680,7 +691,7 @@ public final class C { */ @Documented @Retention(RetentionPolicy.SOURCE) - @Target({ElementType.TYPE_USE}) + @Target(TYPE_USE) @IntDef( open = true, value = { @@ -976,6 +987,7 @@ public final class C { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({WAKE_MODE_NONE, WAKE_MODE_LOCAL, WAKE_MODE_NETWORK}) public @interface WakeMode {} /** @@ -1012,6 +1024,7 @@ public final class C { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef( flag = true, value = { diff --git a/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java b/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java index 4dad2da4c3..3df88a5aa9 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java @@ -15,6 +15,12 @@ */ package com.google.android.exoplayer2; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; + import android.net.Uri; import android.os.Bundle; import androidx.annotation.IntDef; @@ -26,6 +32,7 @@ import com.google.common.base.Objects; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.Arrays; import java.util.List; @@ -500,6 +507,7 @@ public final class MediaMetadata implements Bundleable { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ FOLDER_TYPE_NONE, FOLDER_TYPE_MIXED, @@ -537,6 +545,7 @@ public final class MediaMetadata implements Bundleable { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ PICTURE_TYPE_OTHER, PICTURE_TYPE_FILE_ICON, diff --git a/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java b/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java index b643530678..0adea0535a 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java @@ -15,6 +15,12 @@ */ package com.google.android.exoplayer2; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; + import android.net.ConnectivityManager; import android.os.Bundle; import android.os.RemoteException; @@ -28,6 +34,7 @@ import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; /** Thrown when a non locally recoverable playback failure occurs. */ public class PlaybackException extends Exception implements Bundleable { @@ -40,6 +47,7 @@ public class PlaybackException extends Exception implements Bundleable { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef( open = true, value = { diff --git a/library/common/src/main/java/com/google/android/exoplayer2/Player.java b/library/common/src/main/java/com/google/android/exoplayer2/Player.java index 5c60097eb0..08bfbe9016 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/Player.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/Player.java @@ -15,6 +15,12 @@ */ package com.google.android.exoplayer2; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; + import android.os.Bundle; import android.os.Looper; import android.view.Surface; @@ -40,6 +46,7 @@ import com.google.common.base.Objects; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.ArrayList; import java.util.List; @@ -1079,6 +1086,7 @@ public interface Player { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({STATE_IDLE, STATE_BUFFERING, STATE_READY, STATE_ENDED}) @interface State {} /** The player is idle, and must be {@link #prepare() prepared} before it will play the media. */ @@ -1107,6 +1115,7 @@ public interface Player { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS, @@ -1133,6 +1142,7 @@ public interface Player { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ PLAYBACK_SUPPRESSION_REASON_NONE, PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS @@ -1149,6 +1159,7 @@ public interface Player { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({REPEAT_MODE_OFF, REPEAT_MODE_ONE, REPEAT_MODE_ALL}) @interface RepeatMode {} /** @@ -1180,6 +1191,7 @@ public interface Player { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ DISCONTINUITY_REASON_AUTO_TRANSITION, DISCONTINUITY_REASON_SEEK, @@ -1218,6 +1230,7 @@ public interface Player { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED, TIMELINE_CHANGE_REASON_SOURCE_UPDATE}) @interface TimelineChangeReason {} /** Timeline changed as a result of a change of the playlist items or the order of the items. */ @@ -1238,6 +1251,7 @@ public interface Player { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ MEDIA_ITEM_TRANSITION_REASON_REPEAT, MEDIA_ITEM_TRANSITION_REASON_AUTO, @@ -1270,6 +1284,7 @@ public interface Player { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ EVENT_TIMELINE_CHANGED, EVENT_MEDIA_ITEM_TRANSITION, @@ -1355,6 +1370,7 @@ public interface Player { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ COMMAND_INVALID, COMMAND_PLAY_PAUSE, diff --git a/library/common/src/main/java/com/google/android/exoplayer2/text/Cue.java b/library/common/src/main/java/com/google/android/exoplayer2/text/Cue.java index 66ab2f3682..0ef89f9b0b 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/text/Cue.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/text/Cue.java @@ -15,6 +15,12 @@ */ package com.google.android.exoplayer2.text; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; + import android.graphics.Bitmap; import android.graphics.Color; import android.os.Bundle; @@ -32,6 +38,7 @@ import com.google.common.base.Objects; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import org.checkerframework.dataflow.qual.Pure; /** Contains information about a specific cue, including textual content and formatting data. */ @@ -53,6 +60,7 @@ public final class Cue implements Bundleable { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({TYPE_UNSET, ANCHOR_TYPE_START, ANCHOR_TYPE_MIDDLE, ANCHOR_TYPE_END}) public @interface AnchorType {} @@ -80,6 +88,7 @@ public final class Cue implements Bundleable { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({TYPE_UNSET, LINE_TYPE_FRACTION, LINE_TYPE_NUMBER}) public @interface LineType {} @@ -96,6 +105,7 @@ public final class Cue implements Bundleable { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ TYPE_UNSET, TEXT_SIZE_TYPE_FRACTIONAL, @@ -119,6 +129,7 @@ public final class Cue implements Bundleable { */ @Documented @Retention(RetentionPolicy.SOURCE) + @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ TYPE_UNSET, VERTICAL_TYPE_RL, From 23de0be4c992ed8b213a18f6e8b878669e08fae8 Mon Sep 17 00:00:00 2001 From: ibaker Date: Mon, 1 Nov 2021 12:29:21 +0000 Subject: [PATCH 016/497] Re-position IntDefs in media3 stable API These IntDefs are now annotated with TYPE_USE [1], so they can be moved to directly before the type (int). [1] Since PiperOrigin-RevId: 406803555 --- .../main/java/com/google/android/exoplayer2/Format.java | 8 ++++---- .../java/com/google/android/exoplayer2/MediaItem.java | 8 ++++---- .../java/com/google/android/exoplayer2/MediaMetadata.java | 4 ++-- .../com/google/android/exoplayer2/PlaybackException.java | 2 +- .../main/java/com/google/android/exoplayer2/Player.java | 6 ++---- .../main/java/com/google/android/exoplayer2/text/Cue.java | 8 ++++---- .../trackselection/TrackSelectionParameters.java | 8 ++++---- 7 files changed, 21 insertions(+), 23 deletions(-) diff --git a/library/common/src/main/java/com/google/android/exoplayer2/Format.java b/library/common/src/main/java/com/google/android/exoplayer2/Format.java index 909c759c85..c21e68c886 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/Format.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/Format.java @@ -128,8 +128,8 @@ public final class Format implements Bundleable { @Nullable private String id; @Nullable private String label; @Nullable private String language; - @C.SelectionFlags private int selectionFlags; - @C.RoleFlags private int roleFlags; + private @C.SelectionFlags int selectionFlags; + private @C.RoleFlags int roleFlags; private int averageBitrate; private int peakBitrate; @Nullable private String codecs; @@ -620,9 +620,9 @@ public final class Format implements Bundleable { /** The language as an IETF BCP 47 conformant tag, or null if unknown or not applicable. */ @Nullable public final String language; /** Track selection flags. */ - @C.SelectionFlags public final int selectionFlags; + public final @C.SelectionFlags int selectionFlags; /** Track role flags. */ - @C.RoleFlags public final int roleFlags; + public final @C.RoleFlags int roleFlags; /** * The average bitrate in bits per second, or {@link #NO_VALUE} if unknown or not applicable. The * way in which this field is populated depends on the type of media to which the format diff --git a/library/common/src/main/java/com/google/android/exoplayer2/MediaItem.java b/library/common/src/main/java/com/google/android/exoplayer2/MediaItem.java index 7b4ed43d38..b18c52018e 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/MediaItem.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/MediaItem.java @@ -1235,8 +1235,8 @@ public final class MediaItem implements Bundleable { private Uri uri; @Nullable private String mimeType; @Nullable private String language; - @C.SelectionFlags private int selectionFlags; - @C.RoleFlags private int roleFlags; + private @C.SelectionFlags int selectionFlags; + private @C.RoleFlags int roleFlags; @Nullable private String label; /** @@ -1310,9 +1310,9 @@ public final class MediaItem implements Bundleable { /** The language. */ @Nullable public final String language; /** The selection flags. */ - @C.SelectionFlags public final int selectionFlags; + public final @C.SelectionFlags int selectionFlags; /** The role flags. */ - @C.RoleFlags public final int roleFlags; + public final @C.RoleFlags int roleFlags; /** The label. */ @Nullable public final String label; diff --git a/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java b/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java index 3df88a5aa9..f0c1243e09 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java @@ -623,7 +623,7 @@ public final class MediaMetadata implements Bundleable { /** Optional artwork data as a compressed byte array. */ @Nullable public final byte[] artworkData; /** Optional {@link PictureType} of the artwork data. */ - @Nullable @PictureType public final Integer artworkDataType; + @Nullable public final @PictureType Integer artworkDataType; /** Optional artwork {@link Uri}. */ @Nullable public final Uri artworkUri; /** Optional track number. */ @@ -631,7 +631,7 @@ public final class MediaMetadata implements Bundleable { /** Optional total number of tracks. */ @Nullable public final Integer totalTrackCount; /** Optional {@link FolderType}. */ - @Nullable @FolderType public final Integer folderType; + @Nullable public final @FolderType Integer folderType; /** Optional boolean for media playability. */ @Nullable public final Boolean isPlayable; /** @deprecated Use {@link #recordingYear} instead. */ diff --git a/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java b/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java index 0adea0535a..febb938fdb 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/PlaybackException.java @@ -320,7 +320,7 @@ public class PlaybackException extends Exception implements Bundleable { } /** An error code which identifies the cause of the playback failure. */ - @ErrorCode public final int errorCode; + public final @ErrorCode int errorCode; /** The value of {@link SystemClock#elapsedRealtime()} when this exception was created. */ public final long timestampMs; diff --git a/library/common/src/main/java/com/google/android/exoplayer2/Player.java b/library/common/src/main/java/com/google/android/exoplayer2/Player.java index 08bfbe9016..b6222596a7 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/Player.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/Player.java @@ -454,8 +454,7 @@ public interface Player { * @return The {@link Event} at the given index. * @throws IndexOutOfBoundsException If index is outside the allowed range. */ - @Event - public int get(int index) { + public @Event int get(int index) { return flags.get(index); } @@ -870,8 +869,7 @@ public interface Player { * @return The {@link Command} at the given index. * @throws IndexOutOfBoundsException If index is outside the allowed range. */ - @Command - public int get(int index) { + public @Command int get(int index) { return flags.get(index); } diff --git a/library/common/src/main/java/com/google/android/exoplayer2/text/Cue.java b/library/common/src/main/java/com/google/android/exoplayer2/text/Cue.java index 0ef89f9b0b..a386580f3d 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/text/Cue.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/text/Cue.java @@ -556,16 +556,16 @@ public final class Cue implements Bundleable { @Nullable private Alignment multiRowAlignment; private float line; @LineType private int lineType; - @AnchorType private int lineAnchor; + private @AnchorType int lineAnchor; private float position; - @AnchorType private int positionAnchor; - @TextSizeType private int textSizeType; + private @AnchorType int positionAnchor; + private @TextSizeType int textSizeType; private float textSize; private float size; private float bitmapHeight; private boolean windowColorSet; @ColorInt private int windowColor; - @VerticalType private int verticalType; + private @VerticalType int verticalType; private float shearDegrees; public Builder() { diff --git a/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java b/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java index 738cf74e2b..8080451246 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java @@ -82,13 +82,13 @@ public class TrackSelectionParameters implements Bundleable { private ImmutableList preferredVideoMimeTypes; // Audio private ImmutableList preferredAudioLanguages; - @C.RoleFlags private int preferredAudioRoleFlags; + private @C.RoleFlags int preferredAudioRoleFlags; private int maxAudioChannelCount; private int maxAudioBitrate; private ImmutableList preferredAudioMimeTypes; // Text private ImmutableList preferredTextLanguages; - @C.RoleFlags private int preferredTextRoleFlags; + private @C.RoleFlags int preferredTextRoleFlags; private boolean selectUndeterminedTextLanguage; // General private boolean forceLowestBitrate; @@ -781,7 +781,7 @@ public class TrackSelectionParameters implements Bundleable { * The preferred {@link C.RoleFlags} for audio tracks. {@code 0} selects the default track if * there is one, or the first track if there's no default. The default value is {@code 0}. */ - @C.RoleFlags public final int preferredAudioRoleFlags; + public final @C.RoleFlags int preferredAudioRoleFlags; /** * Maximum allowed audio channel count. The default value is {@link Integer#MAX_VALUE} (i.e. no * constraint). @@ -811,7 +811,7 @@ public class TrackSelectionParameters implements Bundleable { * | {@link C#ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND} if the accessibility {@link CaptioningManager} * is enabled. */ - @C.RoleFlags public final int preferredTextRoleFlags; + public final @C.RoleFlags int preferredTextRoleFlags; /** * Whether a text track with undetermined language should be selected if no track with {@link * #preferredTextLanguages} is available, or if {@link #preferredTextLanguages} is unset. The From 69d6f84159072bcaf465bae4ca9b52e59fa690ef Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 1 Nov 2021 13:18:48 +0000 Subject: [PATCH 017/497] Throw pending clipping errors created during period preparation. Currently, clipping errors are never thrown if we already have a MediaPeriod. This may happen for example for ProgressiveMediaSource where we need to create a MediaPeriod before knowing whether clipping is supported. Playback will still fail, but with unrelated assertion errors that are hard to understand for users. Fix this by setting the pending error on the ClippingMediaPeriod. #minor-release Issue: Issue: google/ExoPlayer#9580 PiperOrigin-RevId: 406809737 --- .../exoplayer2/source/ClippingMediaPeriod.java | 18 ++++++++++++++++++ .../exoplayer2/source/ClippingMediaSource.java | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java index 464bf497fe..10cc75de32 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java @@ -21,6 +21,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.source.ClippingMediaSource.IllegalClippingException; import com.google.android.exoplayer2.trackselection.ExoTrackSelection; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.MimeTypes; @@ -42,6 +43,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb private long pendingInitialDiscontinuityPositionUs; /* package */ long startUs; /* package */ long endUs; + @Nullable private IllegalClippingException clippingError; /** * Creates a new clipping media period that provides a clipped view of the specified {@link @@ -78,6 +80,16 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb this.endUs = endUs; } + /** + * Sets a clipping error detected by the media source so that it can be thrown as a period error + * at the next opportunity. + * + * @param clippingError The clipping error. + */ + public void setClippingError(IllegalClippingException clippingError) { + this.clippingError = clippingError; + } + @Override public void prepare(MediaPeriod.Callback callback, long positionUs) { this.callback = callback; @@ -86,6 +98,9 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb @Override public void maybeThrowPrepareError() throws IOException { + if (clippingError != null) { + throw clippingError; + } mediaPeriod.maybeThrowPrepareError(); } @@ -218,6 +233,9 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb @Override public void onPrepared(MediaPeriod mediaPeriod) { + if (clippingError != null) { + return; + } Assertions.checkNotNull(callback).onPrepared(this); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java index f86b81760d..ab62cca0c5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java @@ -276,6 +276,11 @@ public final class ClippingMediaSource extends CompositeMediaSource { clippingTimeline = new ClippingTimeline(timeline, windowStartUs, windowEndUs); } catch (IllegalClippingException e) { clippingError = e; + // The clipping error won't be propagated while we have existing MediaPeriods. Setting the + // error at the MediaPeriods ensures it will be thrown as soon as possible. + for (int i = 0; i < mediaPeriods.size(); i++) { + mediaPeriods.get(i).setClippingError(clippingError); + } return; } refreshSourceInfo(clippingTimeline); From c05a5a162f28700b36d9e882880740445f4d8d92 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 1 Nov 2021 13:19:35 +0000 Subject: [PATCH 018/497] Fix rounding error in fMP4 presentation time calculation The presentation time in fMP4 is calculated by adding and subtracting 3 values. All 3 values are currently converted to microseconds first before the calculation, leading to rounding errors. The rounding errors can be avoided by doing the conversion to microseconds as the last step. For example: In timescale 96000: 8008+8008-16016 = 0 Rounding to us first: 83416+83416-166833=-1 #minor-release PiperOrigin-RevId: 406809844 --- .../extractor/mp4/FragmentedMp4Extractor.java | 23 ++++++++----------- .../extractor/mp4/TrackFragment.java | 14 ++++------- .../mp4/sample_fragmented.mp4.0.dump | 20 ++++++++-------- .../sample_fragmented.mp4.unknown_length.dump | 20 ++++++++-------- .../mp4/sample_fragmented_seekable.mp4.0.dump | 20 ++++++++-------- .../mp4/sample_fragmented_seekable.mp4.1.dump | 20 ++++++++-------- .../mp4/sample_fragmented_seekable.mp4.2.dump | 20 ++++++++-------- .../mp4/sample_fragmented_seekable.mp4.3.dump | 20 ++++++++-------- ...ragmented_seekable.mp4.unknown_length.dump | 20 ++++++++-------- .../mp4/sample_fragmented_sei.mp4.0.dump | 20 ++++++++-------- ...ple_fragmented_sei.mp4.unknown_length.dump | 20 ++++++++-------- ...ple_fragmented_sideloaded_track.mp4.0.dump | 20 ++++++++-------- ...d_sideloaded_track.mp4.unknown_length.dump | 20 ++++++++-------- .../sample_partially_fragmented.mp4.0.dump | 18 +++++++-------- ...rtially_fragmented.mp4.unknown_length.dump | 18 +++++++-------- 15 files changed, 142 insertions(+), 151 deletions(-) diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index b72159be1d..df05019f9b 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -999,21 +999,18 @@ public class FragmentedMp4Extractor implements Extractor { // Offset to the entire video timeline. In the presence of B-frames this is usually used to // ensure that the first frame's presentation timestamp is zero. - long edtsOffsetUs = 0; + long edtsOffset = 0; // Currently we only support a single edit that moves the entire media timeline (indicated by // duration == 0). Other uses of edit lists are uncommon and unsupported. if (track.editListDurations != null && track.editListDurations.length == 1 && track.editListDurations[0] == 0) { - edtsOffsetUs = - Util.scaleLargeTimestamp( - castNonNull(track.editListMediaTimes)[0], C.MICROS_PER_SECOND, track.timescale); + edtsOffset = castNonNull(track.editListMediaTimes)[0]; } int[] sampleSizeTable = fragment.sampleSizeTable; - int[] sampleCompositionTimeOffsetUsTable = fragment.sampleCompositionTimeOffsetUsTable; - long[] sampleDecodingTimeUsTable = fragment.sampleDecodingTimeUsTable; + long[] samplePresentationTimesUs = fragment.samplePresentationTimesUs; boolean[] sampleIsSyncFrameTable = fragment.sampleIsSyncFrameTable; boolean workaroundEveryVideoFrameIsSyncFrame = @@ -1033,22 +1030,20 @@ public class FragmentedMp4Extractor implements Extractor { sampleFlagsPresent ? trun.readInt() : (i == 0 && firstSampleFlagsPresent) ? firstSampleFlags : defaultSampleValues.flags; + int sampleCompositionTimeOffset = 0; if (sampleCompositionTimeOffsetsPresent) { // The BMFF spec (ISO 14496-12) states that sample offsets should be unsigned integers in // version 0 trun boxes, however a significant number of streams violate the spec and use // signed integers instead. It's safe to always decode sample offsets as signed integers // here, because unsigned integers will still be parsed correctly (unless their top bit is // set, which is never true in practice because sample offsets are always small). - int sampleOffset = trun.readInt(); - sampleCompositionTimeOffsetUsTable[i] = - (int) ((sampleOffset * C.MICROS_PER_SECOND) / timescale); - } else { - sampleCompositionTimeOffsetUsTable[i] = 0; + sampleCompositionTimeOffset = trun.readInt(); } - sampleDecodingTimeUsTable[i] = - Util.scaleLargeTimestamp(cumulativeTime, C.MICROS_PER_SECOND, timescale) - edtsOffsetUs; + long samplePresentationTime = cumulativeTime + sampleCompositionTimeOffset - edtsOffset; + samplePresentationTimesUs[i] = + Util.scaleLargeTimestamp(samplePresentationTime, C.MICROS_PER_SECOND, timescale); if (!fragment.nextFragmentDecodeTimeIncludesMoov) { - sampleDecodingTimeUsTable[i] += trackBundle.moovSampleTable.durationUs; + samplePresentationTimesUs[i] += trackBundle.moovSampleTable.durationUs; } sampleSizeTable[i] = sampleSize; sampleIsSyncFrameTable[i] = diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackFragment.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackFragment.java index 5a1fc6e0d8..d87f7ba443 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackFragment.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackFragment.java @@ -42,10 +42,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; public int[] trunLength; /** The size of each sample in the fragment. */ public int[] sampleSizeTable; - /** The composition time offset of each sample in the fragment, in microseconds. */ - public int[] sampleCompositionTimeOffsetUsTable; - /** The decoding time of each sample in the fragment, in microseconds. */ - public long[] sampleDecodingTimeUsTable; + /** The presentation time of each sample in the fragment, in microseconds. */ + public long[] samplePresentationTimesUs; /** Indicates which samples are sync frames. */ public boolean[] sampleIsSyncFrameTable; /** Whether the fragment defines encryption data. */ @@ -80,8 +78,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; trunDataPosition = new long[0]; trunLength = new int[0]; sampleSizeTable = new int[0]; - sampleCompositionTimeOffsetUsTable = new int[0]; - sampleDecodingTimeUsTable = new long[0]; + samplePresentationTimesUs = new long[0]; sampleIsSyncFrameTable = new boolean[0]; sampleHasSubsampleEncryptionTable = new boolean[0]; sampleEncryptionData = new ParsableByteArray(); @@ -123,8 +120,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; // likely. The choice of 25% is relatively arbitrary. int tableSize = (sampleCount * 125) / 100; sampleSizeTable = new int[tableSize]; - sampleCompositionTimeOffsetUsTable = new int[tableSize]; - sampleDecodingTimeUsTable = new long[tableSize]; + samplePresentationTimesUs = new long[tableSize]; sampleIsSyncFrameTable = new boolean[tableSize]; sampleHasSubsampleEncryptionTable = new boolean[tableSize]; } @@ -173,7 +169,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * @return The presentation timestamps of this sample in microseconds. */ public long getSamplePresentationTimeUs(int index) { - return sampleDecodingTimeUsTable[index] + sampleCompositionTimeOffsetUsTable[index]; + return samplePresentationTimesUs[index]; } /** Returns whether the sample at the given index has a subsample encryption table. */ diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented.mp4.0.dump b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented.mp4.0.dump index 3bb4239d8f..1fca581047 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented.mp4.0.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented.mp4.0.dump @@ -20,7 +20,7 @@ track 0: flags = 1 data = length 38070, hash B58E1AEE sample 1: - time = 200199 + time = 200200 flags = 0 data = length 8340, hash 8AC449FF sample 2: @@ -32,7 +32,7 @@ track 0: flags = 0 data = length 469, hash D6E0A200 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 564, hash E5F56C5B sample 5: @@ -48,7 +48,7 @@ track 0: flags = 0 data = length 455, hash B9CCE047 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 467, hash 69806D94 sample 9: @@ -56,7 +56,7 @@ track 0: flags = 0 data = length 4549, hash 3944F501 sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1087, hash 491BF106 sample 11: @@ -68,7 +68,7 @@ track 0: flags = 0 data = length 455, hash 8A0610 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5190, hash B9031D8 sample 14: @@ -80,7 +80,7 @@ track 0: flags = 0 data = length 653, hash 8494F326 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 485, hash 2CCC85F4 sample 17: @@ -96,7 +96,7 @@ track 0: flags = 0 data = length 640, hash F664125B sample 20: - time = 700699 + time = 700700 flags = 0 data = length 491, hash B5930C7C sample 21: @@ -104,7 +104,7 @@ track 0: flags = 0 data = length 2989, hash 92CF4FCF sample 22: - time = 800799 + time = 800800 flags = 0 data = length 838, hash 294A3451 sample 23: @@ -116,7 +116,7 @@ track 0: flags = 0 data = length 329, hash A654FFA1 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1517, hash 5F7EBF8B sample 26: @@ -128,7 +128,7 @@ track 0: flags = 0 data = length 415, hash B31BBC3B sample 28: - time = 967632 + time = 967633 flags = 0 data = length 415, hash 850DFEA3 sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented.mp4.unknown_length.dump b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented.mp4.unknown_length.dump index 3bb4239d8f..1fca581047 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented.mp4.unknown_length.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented.mp4.unknown_length.dump @@ -20,7 +20,7 @@ track 0: flags = 1 data = length 38070, hash B58E1AEE sample 1: - time = 200199 + time = 200200 flags = 0 data = length 8340, hash 8AC449FF sample 2: @@ -32,7 +32,7 @@ track 0: flags = 0 data = length 469, hash D6E0A200 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 564, hash E5F56C5B sample 5: @@ -48,7 +48,7 @@ track 0: flags = 0 data = length 455, hash B9CCE047 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 467, hash 69806D94 sample 9: @@ -56,7 +56,7 @@ track 0: flags = 0 data = length 4549, hash 3944F501 sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1087, hash 491BF106 sample 11: @@ -68,7 +68,7 @@ track 0: flags = 0 data = length 455, hash 8A0610 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5190, hash B9031D8 sample 14: @@ -80,7 +80,7 @@ track 0: flags = 0 data = length 653, hash 8494F326 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 485, hash 2CCC85F4 sample 17: @@ -96,7 +96,7 @@ track 0: flags = 0 data = length 640, hash F664125B sample 20: - time = 700699 + time = 700700 flags = 0 data = length 491, hash B5930C7C sample 21: @@ -104,7 +104,7 @@ track 0: flags = 0 data = length 2989, hash 92CF4FCF sample 22: - time = 800799 + time = 800800 flags = 0 data = length 838, hash 294A3451 sample 23: @@ -116,7 +116,7 @@ track 0: flags = 0 data = length 329, hash A654FFA1 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1517, hash 5F7EBF8B sample 26: @@ -128,7 +128,7 @@ track 0: flags = 0 data = length 415, hash B31BBC3B sample 28: - time = 967632 + time = 967633 flags = 0 data = length 415, hash 850DFEA3 sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.0.dump b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.0.dump index d6ff4a544c..b96cd5335f 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.0.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.0.dump @@ -23,7 +23,7 @@ track 0: flags = 1 data = length 38070, hash B58E1AEE sample 1: - time = 200199 + time = 200200 flags = 0 data = length 8340, hash 8AC449FF sample 2: @@ -35,7 +35,7 @@ track 0: flags = 0 data = length 469, hash D6E0A200 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 564, hash E5F56C5B sample 5: @@ -51,7 +51,7 @@ track 0: flags = 0 data = length 455, hash B9CCE047 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 467, hash 69806D94 sample 9: @@ -59,7 +59,7 @@ track 0: flags = 0 data = length 4549, hash 3944F501 sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1087, hash 491BF106 sample 11: @@ -71,7 +71,7 @@ track 0: flags = 0 data = length 455, hash 8A0610 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5190, hash B9031D8 sample 14: @@ -83,7 +83,7 @@ track 0: flags = 0 data = length 653, hash 8494F326 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 485, hash 2CCC85F4 sample 17: @@ -99,7 +99,7 @@ track 0: flags = 0 data = length 640, hash F664125B sample 20: - time = 700699 + time = 700700 flags = 0 data = length 491, hash B5930C7C sample 21: @@ -107,7 +107,7 @@ track 0: flags = 0 data = length 2989, hash 92CF4FCF sample 22: - time = 800799 + time = 800800 flags = 0 data = length 838, hash 294A3451 sample 23: @@ -119,7 +119,7 @@ track 0: flags = 0 data = length 329, hash A654FFA1 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1517, hash 5F7EBF8B sample 26: @@ -131,7 +131,7 @@ track 0: flags = 0 data = length 415, hash B31BBC3B sample 28: - time = 967632 + time = 967633 flags = 0 data = length 415, hash 850DFEA3 sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.1.dump b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.1.dump index 4d5f324b4a..508eb65d16 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.1.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.1.dump @@ -23,7 +23,7 @@ track 0: flags = 1 data = length 38070, hash B58E1AEE sample 1: - time = 200199 + time = 200200 flags = 0 data = length 8340, hash 8AC449FF sample 2: @@ -35,7 +35,7 @@ track 0: flags = 0 data = length 469, hash D6E0A200 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 564, hash E5F56C5B sample 5: @@ -51,7 +51,7 @@ track 0: flags = 0 data = length 455, hash B9CCE047 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 467, hash 69806D94 sample 9: @@ -59,7 +59,7 @@ track 0: flags = 0 data = length 4549, hash 3944F501 sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1087, hash 491BF106 sample 11: @@ -71,7 +71,7 @@ track 0: flags = 0 data = length 455, hash 8A0610 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5190, hash B9031D8 sample 14: @@ -83,7 +83,7 @@ track 0: flags = 0 data = length 653, hash 8494F326 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 485, hash 2CCC85F4 sample 17: @@ -99,7 +99,7 @@ track 0: flags = 0 data = length 640, hash F664125B sample 20: - time = 700699 + time = 700700 flags = 0 data = length 491, hash B5930C7C sample 21: @@ -107,7 +107,7 @@ track 0: flags = 0 data = length 2989, hash 92CF4FCF sample 22: - time = 800799 + time = 800800 flags = 0 data = length 838, hash 294A3451 sample 23: @@ -119,7 +119,7 @@ track 0: flags = 0 data = length 329, hash A654FFA1 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1517, hash 5F7EBF8B sample 26: @@ -131,7 +131,7 @@ track 0: flags = 0 data = length 415, hash B31BBC3B sample 28: - time = 967632 + time = 967633 flags = 0 data = length 415, hash 850DFEA3 sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.2.dump b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.2.dump index 4b23814b0a..4aa40d6145 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.2.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.2.dump @@ -23,7 +23,7 @@ track 0: flags = 1 data = length 38070, hash B58E1AEE sample 1: - time = 200199 + time = 200200 flags = 0 data = length 8340, hash 8AC449FF sample 2: @@ -35,7 +35,7 @@ track 0: flags = 0 data = length 469, hash D6E0A200 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 564, hash E5F56C5B sample 5: @@ -51,7 +51,7 @@ track 0: flags = 0 data = length 455, hash B9CCE047 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 467, hash 69806D94 sample 9: @@ -59,7 +59,7 @@ track 0: flags = 0 data = length 4549, hash 3944F501 sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1087, hash 491BF106 sample 11: @@ -71,7 +71,7 @@ track 0: flags = 0 data = length 455, hash 8A0610 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5190, hash B9031D8 sample 14: @@ -83,7 +83,7 @@ track 0: flags = 0 data = length 653, hash 8494F326 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 485, hash 2CCC85F4 sample 17: @@ -99,7 +99,7 @@ track 0: flags = 0 data = length 640, hash F664125B sample 20: - time = 700699 + time = 700700 flags = 0 data = length 491, hash B5930C7C sample 21: @@ -107,7 +107,7 @@ track 0: flags = 0 data = length 2989, hash 92CF4FCF sample 22: - time = 800799 + time = 800800 flags = 0 data = length 838, hash 294A3451 sample 23: @@ -119,7 +119,7 @@ track 0: flags = 0 data = length 329, hash A654FFA1 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1517, hash 5F7EBF8B sample 26: @@ -131,7 +131,7 @@ track 0: flags = 0 data = length 415, hash B31BBC3B sample 28: - time = 967632 + time = 967633 flags = 0 data = length 415, hash 850DFEA3 sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.3.dump b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.3.dump index d234a0f03f..5196703b22 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.3.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.3.dump @@ -23,7 +23,7 @@ track 0: flags = 1 data = length 38070, hash B58E1AEE sample 1: - time = 200199 + time = 200200 flags = 0 data = length 8340, hash 8AC449FF sample 2: @@ -35,7 +35,7 @@ track 0: flags = 0 data = length 469, hash D6E0A200 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 564, hash E5F56C5B sample 5: @@ -51,7 +51,7 @@ track 0: flags = 0 data = length 455, hash B9CCE047 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 467, hash 69806D94 sample 9: @@ -59,7 +59,7 @@ track 0: flags = 0 data = length 4549, hash 3944F501 sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1087, hash 491BF106 sample 11: @@ -71,7 +71,7 @@ track 0: flags = 0 data = length 455, hash 8A0610 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5190, hash B9031D8 sample 14: @@ -83,7 +83,7 @@ track 0: flags = 0 data = length 653, hash 8494F326 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 485, hash 2CCC85F4 sample 17: @@ -99,7 +99,7 @@ track 0: flags = 0 data = length 640, hash F664125B sample 20: - time = 700699 + time = 700700 flags = 0 data = length 491, hash B5930C7C sample 21: @@ -107,7 +107,7 @@ track 0: flags = 0 data = length 2989, hash 92CF4FCF sample 22: - time = 800799 + time = 800800 flags = 0 data = length 838, hash 294A3451 sample 23: @@ -119,7 +119,7 @@ track 0: flags = 0 data = length 329, hash A654FFA1 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1517, hash 5F7EBF8B sample 26: @@ -131,7 +131,7 @@ track 0: flags = 0 data = length 415, hash B31BBC3B sample 28: - time = 967632 + time = 967633 flags = 0 data = length 415, hash 850DFEA3 sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.unknown_length.dump b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.unknown_length.dump index d6ff4a544c..b96cd5335f 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.unknown_length.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_seekable.mp4.unknown_length.dump @@ -23,7 +23,7 @@ track 0: flags = 1 data = length 38070, hash B58E1AEE sample 1: - time = 200199 + time = 200200 flags = 0 data = length 8340, hash 8AC449FF sample 2: @@ -35,7 +35,7 @@ track 0: flags = 0 data = length 469, hash D6E0A200 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 564, hash E5F56C5B sample 5: @@ -51,7 +51,7 @@ track 0: flags = 0 data = length 455, hash B9CCE047 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 467, hash 69806D94 sample 9: @@ -59,7 +59,7 @@ track 0: flags = 0 data = length 4549, hash 3944F501 sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1087, hash 491BF106 sample 11: @@ -71,7 +71,7 @@ track 0: flags = 0 data = length 455, hash 8A0610 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5190, hash B9031D8 sample 14: @@ -83,7 +83,7 @@ track 0: flags = 0 data = length 653, hash 8494F326 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 485, hash 2CCC85F4 sample 17: @@ -99,7 +99,7 @@ track 0: flags = 0 data = length 640, hash F664125B sample 20: - time = 700699 + time = 700700 flags = 0 data = length 491, hash B5930C7C sample 21: @@ -107,7 +107,7 @@ track 0: flags = 0 data = length 2989, hash 92CF4FCF sample 22: - time = 800799 + time = 800800 flags = 0 data = length 838, hash 294A3451 sample 23: @@ -119,7 +119,7 @@ track 0: flags = 0 data = length 329, hash A654FFA1 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1517, hash 5F7EBF8B sample 26: @@ -131,7 +131,7 @@ track 0: flags = 0 data = length 415, hash B31BBC3B sample 28: - time = 967632 + time = 967633 flags = 0 data = length 415, hash 850DFEA3 sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sei.mp4.0.dump b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sei.mp4.0.dump index dbcfe75f35..91376322a8 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sei.mp4.0.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sei.mp4.0.dump @@ -20,7 +20,7 @@ track 0: flags = 1 data = length 38070, hash B58E1AEE sample 1: - time = 200199 + time = 200200 flags = 0 data = length 8340, hash 8AC449FF sample 2: @@ -32,7 +32,7 @@ track 0: flags = 0 data = length 469, hash D6E0A200 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 564, hash E5F56C5B sample 5: @@ -48,7 +48,7 @@ track 0: flags = 0 data = length 455, hash B9CCE047 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 467, hash 69806D94 sample 9: @@ -56,7 +56,7 @@ track 0: flags = 0 data = length 4549, hash 3944F501 sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1087, hash 491BF106 sample 11: @@ -68,7 +68,7 @@ track 0: flags = 0 data = length 455, hash 8A0610 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5190, hash B9031D8 sample 14: @@ -80,7 +80,7 @@ track 0: flags = 0 data = length 653, hash 8494F326 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 485, hash 2CCC85F4 sample 17: @@ -96,7 +96,7 @@ track 0: flags = 0 data = length 640, hash F664125B sample 20: - time = 700699 + time = 700700 flags = 0 data = length 491, hash B5930C7C sample 21: @@ -104,7 +104,7 @@ track 0: flags = 0 data = length 2989, hash 92CF4FCF sample 22: - time = 800799 + time = 800800 flags = 0 data = length 838, hash 294A3451 sample 23: @@ -116,7 +116,7 @@ track 0: flags = 0 data = length 329, hash A654FFA1 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1517, hash 5F7EBF8B sample 26: @@ -128,7 +128,7 @@ track 0: flags = 0 data = length 415, hash B31BBC3B sample 28: - time = 967632 + time = 967633 flags = 0 data = length 415, hash 850DFEA3 sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sei.mp4.unknown_length.dump b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sei.mp4.unknown_length.dump index dbcfe75f35..91376322a8 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sei.mp4.unknown_length.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sei.mp4.unknown_length.dump @@ -20,7 +20,7 @@ track 0: flags = 1 data = length 38070, hash B58E1AEE sample 1: - time = 200199 + time = 200200 flags = 0 data = length 8340, hash 8AC449FF sample 2: @@ -32,7 +32,7 @@ track 0: flags = 0 data = length 469, hash D6E0A200 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 564, hash E5F56C5B sample 5: @@ -48,7 +48,7 @@ track 0: flags = 0 data = length 455, hash B9CCE047 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 467, hash 69806D94 sample 9: @@ -56,7 +56,7 @@ track 0: flags = 0 data = length 4549, hash 3944F501 sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1087, hash 491BF106 sample 11: @@ -68,7 +68,7 @@ track 0: flags = 0 data = length 455, hash 8A0610 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5190, hash B9031D8 sample 14: @@ -80,7 +80,7 @@ track 0: flags = 0 data = length 653, hash 8494F326 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 485, hash 2CCC85F4 sample 17: @@ -96,7 +96,7 @@ track 0: flags = 0 data = length 640, hash F664125B sample 20: - time = 700699 + time = 700700 flags = 0 data = length 491, hash B5930C7C sample 21: @@ -104,7 +104,7 @@ track 0: flags = 0 data = length 2989, hash 92CF4FCF sample 22: - time = 800799 + time = 800800 flags = 0 data = length 838, hash 294A3451 sample 23: @@ -116,7 +116,7 @@ track 0: flags = 0 data = length 329, hash A654FFA1 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1517, hash 5F7EBF8B sample 26: @@ -128,7 +128,7 @@ track 0: flags = 0 data = length 415, hash B31BBC3B sample 28: - time = 967632 + time = 967633 flags = 0 data = length 415, hash 850DFEA3 sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sideloaded_track.mp4.0.dump b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sideloaded_track.mp4.0.dump index f90492cfa1..c1b45465ee 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sideloaded_track.mp4.0.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sideloaded_track.mp4.0.dump @@ -13,7 +13,7 @@ track 0: flags = 1 data = length 38070, hash B58E1AEE sample 1: - time = 200199 + time = 200200 flags = 0 data = length 8340, hash 8AC449FF sample 2: @@ -25,7 +25,7 @@ track 0: flags = 0 data = length 469, hash D6E0A200 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 564, hash E5F56C5B sample 5: @@ -41,7 +41,7 @@ track 0: flags = 0 data = length 455, hash B9CCE047 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 467, hash 69806D94 sample 9: @@ -49,7 +49,7 @@ track 0: flags = 0 data = length 4549, hash 3944F501 sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1087, hash 491BF106 sample 11: @@ -61,7 +61,7 @@ track 0: flags = 0 data = length 455, hash 8A0610 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5190, hash B9031D8 sample 14: @@ -73,7 +73,7 @@ track 0: flags = 0 data = length 653, hash 8494F326 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 485, hash 2CCC85F4 sample 17: @@ -89,7 +89,7 @@ track 0: flags = 0 data = length 640, hash F664125B sample 20: - time = 700699 + time = 700700 flags = 0 data = length 491, hash B5930C7C sample 21: @@ -97,7 +97,7 @@ track 0: flags = 0 data = length 2989, hash 92CF4FCF sample 22: - time = 800799 + time = 800800 flags = 0 data = length 838, hash 294A3451 sample 23: @@ -109,7 +109,7 @@ track 0: flags = 0 data = length 329, hash A654FFA1 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1517, hash 5F7EBF8B sample 26: @@ -121,7 +121,7 @@ track 0: flags = 0 data = length 415, hash B31BBC3B sample 28: - time = 967632 + time = 967633 flags = 0 data = length 415, hash 850DFEA3 sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sideloaded_track.mp4.unknown_length.dump b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sideloaded_track.mp4.unknown_length.dump index f90492cfa1..c1b45465ee 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sideloaded_track.mp4.unknown_length.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_fragmented_sideloaded_track.mp4.unknown_length.dump @@ -13,7 +13,7 @@ track 0: flags = 1 data = length 38070, hash B58E1AEE sample 1: - time = 200199 + time = 200200 flags = 0 data = length 8340, hash 8AC449FF sample 2: @@ -25,7 +25,7 @@ track 0: flags = 0 data = length 469, hash D6E0A200 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 564, hash E5F56C5B sample 5: @@ -41,7 +41,7 @@ track 0: flags = 0 data = length 455, hash B9CCE047 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 467, hash 69806D94 sample 9: @@ -49,7 +49,7 @@ track 0: flags = 0 data = length 4549, hash 3944F501 sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1087, hash 491BF106 sample 11: @@ -61,7 +61,7 @@ track 0: flags = 0 data = length 455, hash 8A0610 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5190, hash B9031D8 sample 14: @@ -73,7 +73,7 @@ track 0: flags = 0 data = length 653, hash 8494F326 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 485, hash 2CCC85F4 sample 17: @@ -89,7 +89,7 @@ track 0: flags = 0 data = length 640, hash F664125B sample 20: - time = 700699 + time = 700700 flags = 0 data = length 491, hash B5930C7C sample 21: @@ -97,7 +97,7 @@ track 0: flags = 0 data = length 2989, hash 92CF4FCF sample 22: - time = 800799 + time = 800800 flags = 0 data = length 838, hash 294A3451 sample 23: @@ -109,7 +109,7 @@ track 0: flags = 0 data = length 329, hash A654FFA1 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1517, hash 5F7EBF8B sample 26: @@ -121,7 +121,7 @@ track 0: flags = 0 data = length 415, hash B31BBC3B sample 28: - time = 967632 + time = 967633 flags = 0 data = length 415, hash 850DFEA3 sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_partially_fragmented.mp4.0.dump b/testdata/src/test/assets/extractordumps/mp4/sample_partially_fragmented.mp4.0.dump index 5bb4411a69..9e58eea933 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_partially_fragmented.mp4.0.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_partially_fragmented.mp4.0.dump @@ -32,7 +32,7 @@ track 0: flags = 536870912 data = length 5867, hash 56F9EE87 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 570, hash 984421BD sample 5: @@ -48,7 +48,7 @@ track 0: flags = 0 data = length 4310, hash 291E6161 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 497, hash 398CBFAA sample 9: @@ -56,7 +56,7 @@ track 0: flags = 0 data = length 4449, hash 322CAA2B sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1076, hash B479B634 sample 11: @@ -68,7 +68,7 @@ track 0: flags = 0 data = length 463, hash A85F9769 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5339, hash F232195D sample 14: @@ -80,7 +80,7 @@ track 0: flags = 0 data = length 689, hash 3EB753A3 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 516, hash E6DF9C1C sample 17: @@ -96,7 +96,7 @@ track 0: flags = 0 data = length 625, hash ED1C8EF1 sample 20: - time = 700699 + time = 700700 flags = 0 data = length 492, hash E6E066EA sample 21: @@ -104,7 +104,7 @@ track 0: flags = 0 data = length 2973, hash A3C54C3B sample 22: - time = 800799 + time = 800800 flags = 0 data = length 833, hash 41CA807D sample 23: @@ -116,7 +116,7 @@ track 0: flags = 0 data = length 384, hash A0E8FA50 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1450, hash 92741C3B sample 26: @@ -128,7 +128,7 @@ track 0: flags = 0 data = length 413, hash 886904C sample 28: - time = 967632 + time = 967633 flags = 0 data = length 427, hash FC2FA8CC sample 29: diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_partially_fragmented.mp4.unknown_length.dump b/testdata/src/test/assets/extractordumps/mp4/sample_partially_fragmented.mp4.unknown_length.dump index 5bb4411a69..9e58eea933 100644 --- a/testdata/src/test/assets/extractordumps/mp4/sample_partially_fragmented.mp4.unknown_length.dump +++ b/testdata/src/test/assets/extractordumps/mp4/sample_partially_fragmented.mp4.unknown_length.dump @@ -32,7 +32,7 @@ track 0: flags = 536870912 data = length 5867, hash 56F9EE87 sample 4: - time = 166832 + time = 166833 flags = 0 data = length 570, hash 984421BD sample 5: @@ -48,7 +48,7 @@ track 0: flags = 0 data = length 4310, hash 291E6161 sample 8: - time = 300299 + time = 300300 flags = 0 data = length 497, hash 398CBFAA sample 9: @@ -56,7 +56,7 @@ track 0: flags = 0 data = length 4449, hash 322CAA2B sample 10: - time = 400399 + time = 400400 flags = 0 data = length 1076, hash B479B634 sample 11: @@ -68,7 +68,7 @@ track 0: flags = 0 data = length 463, hash A85F9769 sample 13: - time = 600599 + time = 600600 flags = 0 data = length 5339, hash F232195D sample 14: @@ -80,7 +80,7 @@ track 0: flags = 0 data = length 689, hash 3EB753A3 sample 16: - time = 567232 + time = 567233 flags = 0 data = length 516, hash E6DF9C1C sample 17: @@ -96,7 +96,7 @@ track 0: flags = 0 data = length 625, hash ED1C8EF1 sample 20: - time = 700699 + time = 700700 flags = 0 data = length 492, hash E6E066EA sample 21: @@ -104,7 +104,7 @@ track 0: flags = 0 data = length 2973, hash A3C54C3B sample 22: - time = 800799 + time = 800800 flags = 0 data = length 833, hash 41CA807D sample 23: @@ -116,7 +116,7 @@ track 0: flags = 0 data = length 384, hash A0E8FA50 sample 25: - time = 1000999 + time = 1001000 flags = 0 data = length 1450, hash 92741C3B sample 26: @@ -128,7 +128,7 @@ track 0: flags = 0 data = length 413, hash 886904C sample 28: - time = 967632 + time = 967633 flags = 0 data = length 427, hash FC2FA8CC sample 29: From 8e03a0653a3d4b2d7c43945c7b75d694c6f50ad2 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 1 Nov 2021 13:57:42 +0000 Subject: [PATCH 019/497] Suppress lint warning about wrong IntDef usage in media2 Utils AudioAttributesCompat.AttributeUsage and C.AudioUsage use equivalent values and can be directly assigned. PiperOrigin-RevId: 406815447 --- .../java/com/google/android/exoplayer2/ext/media2/Utils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/Utils.java b/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/Utils.java index 87b52f3598..70f984016e 100644 --- a/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/Utils.java +++ b/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/Utils.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.ext.media2; +import android.annotation.SuppressLint; import androidx.media.AudioAttributesCompat; import androidx.media2.common.SessionPlayer; import com.google.android.exoplayer2.Player; @@ -24,6 +25,7 @@ import com.google.android.exoplayer2.audio.AudioAttributes; /* package */ final class Utils { /** Returns ExoPlayer audio attributes for the given audio attributes. */ + @SuppressLint("WrongConstant") // AudioAttributesCompat.AttributeUsage is equal to C.AudioUsage public static AudioAttributes getAudioAttributes(AudioAttributesCompat audioAttributesCompat) { return new AudioAttributes.Builder() .setContentType(audioAttributesCompat.getContentType()) From e039e335cd22583ff1b8a2e6cb696ec20817bb46 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 1 Nov 2021 14:00:45 +0000 Subject: [PATCH 020/497] Rename MediaFormatUtil constants PiperOrigin-RevId: 406816023 --- .../exoplayer2/util/MediaFormatUtil.java | 18 ++++++++++-------- .../exoplayer2/util/MediaFormatUtilTest.java | 10 +++++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/MediaFormatUtil.java b/library/common/src/main/java/com/google/android/exoplayer2/util/MediaFormatUtil.java index 653a1e3a99..45b2293c24 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/util/MediaFormatUtil.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/util/MediaFormatUtil.java @@ -32,17 +32,19 @@ public final class MediaFormatUtil { * Custom {@link MediaFormat} key associated with a float representing the ratio between a pixel's * width and height. */ - public static final String KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT = + // The constant value must not be changed, because it's also set by the framework MediaParser API. + public static final String KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT = "exo-pixel-width-height-ratio-float"; /** * Custom {@link MediaFormat} key associated with an integer representing the PCM encoding. * - *

Equivalent to {@link MediaFormat#KEY_PCM_ENCODING}, except it allows additional - * ExoPlayer-specific values including {@link C#ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link + *

Equivalent to {@link MediaFormat#KEY_PCM_ENCODING}, except it allows additional values + * defined by {@link C.PcmEncoding}, including {@link C#ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link * C#ENCODING_PCM_24BIT}, and {@link C#ENCODING_PCM_32BIT}. */ - public static final String KEY_EXO_PCM_ENCODING = "exo-pcm-encoding-int"; + // The constant value must not be changed, because it's also set by the framework MediaParser API. + public static final String KEY_PCM_ENCODING_EXTENDED = "exo-pcm-encoding-int"; private static final int MAX_POWER_OF_TWO_INT = 1 << 30; @@ -52,8 +54,8 @@ public final class MediaFormatUtil { *

May include the following custom keys: * *

    - *
  • {@link #KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT}. - *
  • {@link #KEY_EXO_PCM_ENCODING}. + *
  • {@link #KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT}. + *
  • {@link #KEY_PCM_ENCODING_EXTENDED}. *
*/ @SuppressLint("InlinedApi") // Inlined MediaFormat keys. @@ -184,7 +186,7 @@ public final class MediaFormatUtil { @SuppressLint("InlinedApi") private static void maybeSetPixelAspectRatio( MediaFormat mediaFormat, float pixelWidthHeightRatio) { - mediaFormat.setFloat(KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT, pixelWidthHeightRatio); + mediaFormat.setFloat(KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT, pixelWidthHeightRatio); int pixelAspectRatioWidth = 1; int pixelAspectRatioHeight = 1; // ExoPlayer extractors output the pixel aspect ratio as a float. Do our best to recreate the @@ -207,7 +209,7 @@ public final class MediaFormatUtil { return; } int mediaFormatPcmEncoding; - maybeSetInteger(mediaFormat, KEY_EXO_PCM_ENCODING, exoPcmEncoding); + maybeSetInteger(mediaFormat, KEY_PCM_ENCODING_EXTENDED, exoPcmEncoding); switch (exoPcmEncoding) { case C.ENCODING_PCM_8BIT: mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_8BIT; diff --git a/library/common/src/test/java/com/google/android/exoplayer2/util/MediaFormatUtilTest.java b/library/common/src/test/java/com/google/android/exoplayer2/util/MediaFormatUtilTest.java index 959b1279a0..d35cbe5853 100644 --- a/library/common/src/test/java/com/google/android/exoplayer2/util/MediaFormatUtilTest.java +++ b/library/common/src/test/java/com/google/android/exoplayer2/util/MediaFormatUtilTest.java @@ -37,7 +37,7 @@ public class MediaFormatUtilTest { // Assert that no invalid keys are accidentally being populated. assertThat(mediaFormat.getKeys()) .containsExactly( - MediaFormatUtil.KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT, + MediaFormatUtil.KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT, MediaFormat.KEY_ENCODER_DELAY, MediaFormat.KEY_ENCODER_PADDING, MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH, @@ -46,7 +46,7 @@ public class MediaFormatUtilTest { MediaFormat.KEY_IS_FORCED_SUBTITLE, MediaFormat.KEY_IS_AUTOSELECT, MediaFormat.KEY_ROTATION); - assertThat(mediaFormat.getFloat(MediaFormatUtil.KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT)) + assertThat(mediaFormat.getFloat(MediaFormatUtil.KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT)) .isEqualTo(1.f); assertThat(mediaFormat.getInteger(MediaFormat.KEY_ENCODER_DELAY)).isEqualTo(0); assertThat(mediaFormat.getInteger(MediaFormat.KEY_ENCODER_PADDING)).isEqualTo(0); @@ -116,7 +116,7 @@ public class MediaFormatUtilTest { .isEqualTo(format.initializationData.get(1)); assertThat(mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING)).isEqualTo(format.pcmEncoding); - assertThat(mediaFormat.getInteger(MediaFormatUtil.KEY_EXO_PCM_ENCODING)) + assertThat(mediaFormat.getInteger(MediaFormatUtil.KEY_PCM_ENCODING_EXTENDED)) .isEqualTo(format.pcmEncoding); assertThat(mediaFormat.getString(MediaFormat.KEY_LANGUAGE)).isEqualTo(format.language); @@ -140,7 +140,7 @@ public class MediaFormatUtilTest { (float) mediaFormat.getInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH) / mediaFormat.getInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT); assertThat(calculatedPixelAspectRatio).isWithin(.0001f).of(format.pixelWidthHeightRatio); - assertThat(mediaFormat.getFloat(MediaFormatUtil.KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT)) + assertThat(mediaFormat.getFloat(MediaFormatUtil.KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT)) .isEqualTo(format.pixelWidthHeightRatio); } @@ -148,7 +148,7 @@ public class MediaFormatUtilTest { public void createMediaFormatFromFormat_withPcmEncoding_setsCustomPcmEncodingEntry() { Format format = new Format.Builder().setPcmEncoding(C.ENCODING_PCM_32BIT).build(); MediaFormat mediaFormat = MediaFormatUtil.createMediaFormatFromFormat(format); - assertThat(mediaFormat.getInteger(MediaFormatUtil.KEY_EXO_PCM_ENCODING)) + assertThat(mediaFormat.getInteger(MediaFormatUtil.KEY_PCM_ENCODING_EXTENDED)) .isEqualTo(C.ENCODING_PCM_32BIT); assertThat(mediaFormat.containsKey(MediaFormat.KEY_PCM_ENCODING)).isFalse(); } From bf29d5248bb99522fce34aad5b2eceaefee900d2 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 1 Nov 2021 14:08:07 +0000 Subject: [PATCH 021/497] Suppress lint warning about wrong IntDef assignment. The return values of AudioManager.getPlaybackOffloadSupport are the same as the values defined in C.AudioManagerOffloadMode. PiperOrigin-RevId: 406817413 --- .../com/google/android/exoplayer2/audio/DefaultAudioSink.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java index 5687282fae..5d2c7947d0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.audio; import static java.lang.Math.max; import static java.lang.Math.min; +import android.annotation.SuppressLint; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; @@ -1634,6 +1635,8 @@ public final class DefaultAudioSink implements AudioSink { } @RequiresApi(29) + // Return values of AudioManager.getPlaybackOffloadSupport are equal to C.AudioManagerOffloadMode. + @SuppressLint("WrongConstant") @C.AudioManagerOffloadMode private int getOffloadedPlaybackSupport( AudioFormat audioFormat, android.media.AudioAttributes audioAttributes) { From 5823ffeec0a9690bfd42b648ab60a059ca1057ba Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 1 Nov 2021 14:28:22 +0000 Subject: [PATCH 022/497] Remove wrong IntDef usage. The variable is storing OpenGL's draw mode, which is different from Projection.DrawMode. PiperOrigin-RevId: 406820812 --- .../android/exoplayer2/video/spherical/ProjectionRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/spherical/ProjectionRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/spherical/ProjectionRenderer.java index 692b7e687e..c52e5ddd57 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/spherical/ProjectionRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/spherical/ProjectionRenderer.java @@ -207,7 +207,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private final int vertexCount; private final FloatBuffer vertexBuffer; private final FloatBuffer textureBuffer; - @Projection.DrawMode private final int drawMode; + private final int drawMode; public MeshData(Projection.SubMesh subMesh) { vertexCount = subMesh.getVertexCount(); From 2702501783ad7a5c1c68c2866590b462f3b30455 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 1 Nov 2021 15:09:25 +0000 Subject: [PATCH 023/497] Add missing import for gradle build PiperOrigin-RevId: 406827799 --- .../exoplayer2/trackselection/TrackSelectionOverridesTest.java | 1 + .../exoplayer2/trackselection/TrackSelectionParametersTest.java | 1 + 2 files changed, 2 insertions(+) diff --git a/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionOverridesTest.java b/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionOverridesTest.java index ba04f73429..d96e497b1f 100644 --- a/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionOverridesTest.java +++ b/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionOverridesTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertThrows; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride; import com.google.android.exoplayer2.util.MimeTypes; import com.google.common.collect.ImmutableList; diff --git a/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionParametersTest.java b/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionParametersTest.java index 7fab202421..f1271ecf7a 100644 --- a/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionParametersTest.java +++ b/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionParametersTest.java @@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride; import com.google.android.exoplayer2.util.MimeTypes; import com.google.common.collect.ImmutableList; From 861474f6f9d53323bcb4085bcef9652832a147ac Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 1 Nov 2021 15:46:37 +0000 Subject: [PATCH 024/497] Add missing IntDef constant. The video scaling mode and stream type defines a default constant that needs to be added to the IntDef definition to be assignable. PiperOrigin-RevId: 406835696 --- .../java/com/google/android/exoplayer2/C.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/library/common/src/main/java/com/google/android/exoplayer2/C.java b/library/common/src/main/java/com/google/android/exoplayer2/C.java index 7c26b57600..2c2548468b 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/C.java @@ -21,6 +21,7 @@ import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE_USE; +import android.annotation.SuppressLint; import android.content.Context; import android.media.AudioAttributes; import android.media.AudioFormat; @@ -274,8 +275,10 @@ public final class C { /** * Stream types for an {@link android.media.AudioTrack}. One of {@link #STREAM_TYPE_ALARM}, {@link * #STREAM_TYPE_DTMF}, {@link #STREAM_TYPE_MUSIC}, {@link #STREAM_TYPE_NOTIFICATION}, {@link - * #STREAM_TYPE_RING}, {@link #STREAM_TYPE_SYSTEM} or {@link #STREAM_TYPE_VOICE_CALL}. + * #STREAM_TYPE_RING}, {@link #STREAM_TYPE_SYSTEM}, {@link #STREAM_TYPE_VOICE_CALL} or {@link + * #STREAM_TYPE_DEFAULT}. */ + @SuppressLint("UniqueConstants") // Intentional duplication to set STREAM_TYPE_DEFAULT. @Documented @Retention(RetentionPolicy.SOURCE) @IntDef({ @@ -285,7 +288,8 @@ public final class C { STREAM_TYPE_NOTIFICATION, STREAM_TYPE_RING, STREAM_TYPE_SYSTEM, - STREAM_TYPE_VOICE_CALL + STREAM_TYPE_VOICE_CALL, + STREAM_TYPE_DEFAULT }) public @interface StreamType {} /** @see AudioManager#STREAM_ALARM */ @@ -537,11 +541,17 @@ public final class C { /** * Video scaling modes for {@link MediaCodec}-based renderers. One of {@link - * #VIDEO_SCALING_MODE_SCALE_TO_FIT} or {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING}. + * #VIDEO_SCALING_MODE_SCALE_TO_FIT}, {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING} or + * {@link #VIDEO_SCALING_MODE_DEFAULT}. */ + @SuppressLint("UniqueConstants") // Intentional duplication to set VIDEO_SCALING_MODE_DEFAULT. @Documented @Retention(RetentionPolicy.SOURCE) - @IntDef(value = {VIDEO_SCALING_MODE_SCALE_TO_FIT, VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING}) + @IntDef({ + VIDEO_SCALING_MODE_SCALE_TO_FIT, + VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING, + VIDEO_SCALING_MODE_DEFAULT + }) public @interface VideoScalingMode {} /** See {@link MediaCodec#VIDEO_SCALING_MODE_SCALE_TO_FIT}. */ public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = From 0d01cae27082aae73f8e6b500bf124dc3cd9d6b1 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 1 Nov 2021 16:03:06 +0000 Subject: [PATCH 025/497] Suppress lint warning about wrong IntDef in FrameworkMuxer The values are equivalent and we can suppress the warning. PiperOrigin-RevId: 406839242 --- .../google/android/exoplayer2/transformer/FrameworkMuxer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameworkMuxer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameworkMuxer.java index fc5b65891d..182f34e114 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameworkMuxer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FrameworkMuxer.java @@ -19,6 +19,7 @@ import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import static com.google.android.exoplayer2.util.Util.SDK_INT; import static com.google.android.exoplayer2.util.Util.castNonNull; +import android.annotation.SuppressLint; import android.media.MediaCodec; import android.media.MediaFormat; import android.media.MediaMuxer; @@ -122,6 +123,7 @@ import java.nio.ByteBuffer; return mediaMuxer.addTrack(mediaFormat); } + @SuppressLint("WrongConstant") // C.BUFFER_FLAG_KEY_FRAME equals MediaCodec.BUFFER_FLAG_KEY_FRAME. @Override public void writeSampleData( int trackIndex, ByteBuffer data, boolean isKeyFrame, long presentationTimeUs) { From 70713c84584b699332f2d8905aa2b9925ca07fd6 Mon Sep 17 00:00:00 2001 From: bachinger Date: Mon, 1 Nov 2021 16:07:05 +0000 Subject: [PATCH 026/497] Fix rewriting upstream/crypto package in lib-datasource PiperOrigin-RevId: 406840246 --- .../exoplayer2/upstream/{ => crypto}/AesCipherDataSink.java | 4 +++- .../upstream/{ => crypto}/AesCipherDataSource.java | 5 ++++- .../exoplayer2/upstream/{ => crypto}/AesFlushingCipher.java | 2 +- .../android/exoplayer2/upstream/crypto/package-info.java | 0 .../upstream/{ => crypto}/AesFlushingCipherTest.java | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) rename library/datasource/src/main/java/com/google/android/exoplayer2/upstream/{ => crypto}/AesCipherDataSink.java (95%) rename library/datasource/src/main/java/com/google/android/exoplayer2/upstream/{ => crypto}/AesCipherDataSource.java (91%) rename library/datasource/src/main/java/com/google/android/exoplayer2/upstream/{ => crypto}/AesFlushingCipher.java (99%) rename library/{common => datasource}/src/main/java/com/google/android/exoplayer2/upstream/crypto/package-info.java (100%) rename library/datasource/src/test/java/com/google/android/exoplayer2/upstream/{ => crypto}/AesFlushingCipherTest.java (99%) diff --git a/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/AesCipherDataSink.java b/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSink.java similarity index 95% rename from library/datasource/src/main/java/com/google/android/exoplayer2/upstream/AesCipherDataSink.java rename to library/datasource/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSink.java index 5d84485e24..4e5b9f2b8e 100644 --- a/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/AesCipherDataSink.java +++ b/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSink.java @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream.crypto; import static com.google.android.exoplayer2.util.Util.castNonNull; import static java.lang.Math.min; import androidx.annotation.Nullable; +import com.google.android.exoplayer2.upstream.DataSink; +import com.google.android.exoplayer2.upstream.DataSpec; import java.io.IOException; import javax.crypto.Cipher; diff --git a/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/AesCipherDataSource.java b/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSource.java similarity index 91% rename from library/datasource/src/main/java/com/google/android/exoplayer2/upstream/AesCipherDataSource.java rename to library/datasource/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSource.java index 77126904bb..98ec914fa0 100644 --- a/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/AesCipherDataSource.java +++ b/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSource.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream.crypto; import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import static com.google.android.exoplayer2.util.Util.castNonNull; @@ -21,6 +21,9 @@ import static com.google.android.exoplayer2.util.Util.castNonNull; import android.net.Uri; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.TransferListener; import java.io.IOException; import java.util.List; import java.util.Map; diff --git a/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/AesFlushingCipher.java b/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesFlushingCipher.java similarity index 99% rename from library/datasource/src/main/java/com/google/android/exoplayer2/upstream/AesFlushingCipher.java rename to library/datasource/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesFlushingCipher.java index 5a60a985db..96cb13604e 100644 --- a/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/AesFlushingCipher.java +++ b/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesFlushingCipher.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream.crypto; import androidx.annotation.Nullable; import com.google.android.exoplayer2.util.Assertions; diff --git a/library/common/src/main/java/com/google/android/exoplayer2/upstream/crypto/package-info.java b/library/datasource/src/main/java/com/google/android/exoplayer2/upstream/crypto/package-info.java similarity index 100% rename from library/common/src/main/java/com/google/android/exoplayer2/upstream/crypto/package-info.java rename to library/datasource/src/main/java/com/google/android/exoplayer2/upstream/crypto/package-info.java diff --git a/library/datasource/src/test/java/com/google/android/exoplayer2/upstream/AesFlushingCipherTest.java b/library/datasource/src/test/java/com/google/android/exoplayer2/upstream/crypto/AesFlushingCipherTest.java similarity index 99% rename from library/datasource/src/test/java/com/google/android/exoplayer2/upstream/AesFlushingCipherTest.java rename to library/datasource/src/test/java/com/google/android/exoplayer2/upstream/crypto/AesFlushingCipherTest.java index b6cdb61ba0..2811b0eada 100644 --- a/library/datasource/src/test/java/com/google/android/exoplayer2/upstream/AesFlushingCipherTest.java +++ b/library/datasource/src/test/java/com/google/android/exoplayer2/upstream/crypto/AesFlushingCipherTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.upstream; +package com.google.android.exoplayer2.upstream.crypto; import static com.google.common.truth.Truth.assertThat; import static java.lang.Math.min; From 18e8ebe0f867aa82a07fcc0a7e050c853a7bf455 Mon Sep 17 00:00:00 2001 From: samrobinson Date: Mon, 1 Nov 2021 16:49:44 +0000 Subject: [PATCH 027/497] Allow remove video transformer option. PiperOrigin-RevId: 406849436 --- .../android/exoplayer2/transformer/TranscodingTransformer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java index 348f3dac04..4b01c191a7 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java @@ -481,7 +481,6 @@ public final class TranscodingTransformer { checkState( !transformation.removeAudio || !transformation.removeVideo, "Audio and video cannot both be removed."); - checkState(!(transformation.removeVideo)); this.context = context; this.mediaSourceFactory = mediaSourceFactory; this.muxerFactory = muxerFactory; From c5f4843de29c0c6cefeb769f72619cb08716950c Mon Sep 17 00:00:00 2001 From: huangdarwin Date: Mon, 1 Nov 2021 17:26:35 +0000 Subject: [PATCH 028/497] Transformer GL: Undo accidental setResolution changes(). Accidental changes were introduced in http://https://github.com/google/ExoPlayer/commit/c53924326dd100874d080c55812659a3cb9e843a PiperOrigin-RevId: 406858888 --- .../transformer/TranscodingTransformer.java | 28 ------------------- .../transformer/Transformation.java | 3 -- .../exoplayer2/transformer/Transformer.java | 2 -- 3 files changed, 33 deletions(-) diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java index 4b01c191a7..6f58812be4 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TranscodingTransformer.java @@ -55,7 +55,6 @@ import com.google.android.exoplayer2.source.MediaSourceFactory; import com.google.android.exoplayer2.text.TextOutput; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.util.Clock; -import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.VideoRendererEventListener; @@ -92,16 +91,12 @@ public final class TranscodingTransformer { /** A builder for {@link TranscodingTransformer} instances. */ public static final class Builder { - // Mandatory field. private @MonotonicNonNull Context context; - - // Optional fields. private @MonotonicNonNull MediaSourceFactory mediaSourceFactory; private Muxer.Factory muxerFactory; private boolean removeAudio; private boolean removeVideo; private boolean flattenForSlowMotion; - private int outputHeight; private String outputMimeType; @Nullable private String audioMimeType; @Nullable private String videoMimeType; @@ -126,7 +121,6 @@ public final class TranscodingTransformer { this.removeAudio = transcodingTransformer.transformation.removeAudio; this.removeVideo = transcodingTransformer.transformation.removeVideo; this.flattenForSlowMotion = transcodingTransformer.transformation.flattenForSlowMotion; - this.outputHeight = transcodingTransformer.transformation.outputHeight; this.outputMimeType = transcodingTransformer.transformation.outputMimeType; this.audioMimeType = transcodingTransformer.transformation.audioMimeType; this.videoMimeType = transcodingTransformer.transformation.videoMimeType; @@ -219,21 +213,6 @@ public final class TranscodingTransformer { return this; } - /** - * Sets the output resolution for the video, using the output height. The default value is to - * use the same height as the input. Output width will scale to preserve the input video's - * aspect ratio. - * - *

For example, a 1920x1440 video can be scaled to 640x480 by calling setResolution(480). - * - * @param outputHeight The output height for the video, in pixels. - * @return This builder. - */ - public Builder setResolution(int outputHeight) { - this.outputHeight = outputHeight; - return this; - } - /** * Sets the MIME type of the output. The default value is {@link MimeTypes#VIDEO_MP4}. Supported * values are: @@ -377,12 +356,6 @@ public final class TranscodingTransformer { checkState( muxerFactory.supportsOutputMimeType(outputMimeType), "Unsupported output MIME type: " + outputMimeType); - // TODO(ME): Test with values of 10, 100, 1000). - Log.e("TranscodingTransformer", "outputHeight = " + outputHeight); - if (outputHeight == 0) { - // TODO(ME): get output height from input video. - outputHeight = 480; - } if (audioMimeType != null) { checkSampleMimeType(audioMimeType); } @@ -394,7 +367,6 @@ public final class TranscodingTransformer { removeAudio, removeVideo, flattenForSlowMotion, - outputHeight, outputMimeType, audioMimeType, videoMimeType); diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformation.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformation.java index ed8bf64bf3..e273c1fde5 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformation.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformation.java @@ -24,7 +24,6 @@ import androidx.annotation.Nullable; public final boolean removeAudio; public final boolean removeVideo; public final boolean flattenForSlowMotion; - public final int outputHeight; public final String outputMimeType; @Nullable public final String audioMimeType; @Nullable public final String videoMimeType; @@ -33,14 +32,12 @@ import androidx.annotation.Nullable; boolean removeAudio, boolean removeVideo, boolean flattenForSlowMotion, - int outputHeight, String outputMimeType, @Nullable String audioMimeType, @Nullable String videoMimeType) { this.removeAudio = removeAudio; this.removeVideo = removeVideo; this.flattenForSlowMotion = flattenForSlowMotion; - this.outputHeight = outputHeight; this.outputMimeType = outputMimeType; this.audioMimeType = audioMimeType; this.videoMimeType = videoMimeType; diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java index 093f63caeb..0fd763ad26 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java @@ -297,13 +297,11 @@ public final class Transformer { checkState( muxerFactory.supportsOutputMimeType(outputMimeType), "Unsupported output MIME type: " + outputMimeType); - int outputHeight = 0; // TODO(ME): How do we get the input height here? Transformation transformation = new Transformation( removeAudio, removeVideo, flattenForSlowMotion, - outputHeight, outputMimeType, /* audioMimeType= */ null, /* videoMimeType= */ null); From 7de079493cf039b529c526b105d9289747660c90 Mon Sep 17 00:00:00 2001 From: ibaker Date: Tue, 2 Nov 2021 10:27:56 +0000 Subject: [PATCH 029/497] Migrate usages of Window-based Player methods Where this introduced an inconsistency (e.g. assigning to something called `windowIndex`), I generally renamed the transitive closure of identifiers to maintain consistency (meaning this change is quite large). The exception is code that interacts with Timeline and Window directly, where sometimes I kept the 'window' nomenclature. #minor-release PiperOrigin-RevId: 407040052 --- RELEASENOTES.md | 4 + .../exoplayer2/castdemo/PlayerManager.java | 12 +- .../exoplayer2/demo/PlayerActivity.java | 16 +- .../exoplayer2/ext/cast/CastPlayer.java | 18 +- .../exoplayer2/ext/ima/FakeExoPlayer.java | 2 +- .../ext/leanback/LeanbackPlayerAdapter.java | 2 +- .../exoplayer2/ext/media2/PlayerWrapper.java | 16 +- .../mediasession/MediaSessionConnector.java | 29 +- .../mediasession/TimelineQueueNavigator.java | 38 +- .../google/android/exoplayer2/BasePlayer.java | 49 +- .../google/android/exoplayer2/ExoPlayer.java | 23 +- .../android/exoplayer2/ExoPlayerImpl.java | 43 +- .../exoplayer2/ExoPlayerImplInternal.java | 2 +- .../android/exoplayer2/PlayerMessage.java | 49 +- .../android/exoplayer2/SimpleExoPlayer.java | 6 +- .../analytics/AnalyticsCollector.java | 6 +- .../analytics/AnalyticsListener.java | 10 +- .../exoplayer2/util/DebugTextViewHelper.java | 4 +- .../android/exoplayer2/ExoPlayerTest.java | 1003 +++++++++-------- .../exoplayer2/ui/PlayerControlView.java | 6 +- .../ui/PlayerNotificationManager.java | 10 +- .../android/exoplayer2/ui/PlayerView.java | 4 +- .../ui/StyledPlayerControlView.java | 7 +- .../exoplayer2/ui/StyledPlayerView.java | 4 +- .../robolectric/TestPlayerRunHelper.java | 17 +- .../android/exoplayer2/testutil/Action.java | 61 +- .../exoplayer2/testutil/ActionSchedule.java | 67 +- .../testutil/ExoPlayerTestRunner.java | 22 +- .../exoplayer2/testutil/StubExoPlayer.java | 2 +- 29 files changed, 788 insertions(+), 744 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index bf708bfa32..0d8bf3fdb5 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -85,6 +85,10 @@ * RTMP extension: * Upgrade to `io.antmedia:rtmp_client`, which does not rely on `jcenter()` ([#9591](https://github.com/google/ExoPlayer/issues/9591)). +* MediaSession extension: + * Rename + `MediaSessionConnector.QueueNavigator#onCurrentWindowIndexChanged` to + `onCurrentMediaItemIndexChanged`. * Remove deprecated symbols: * Remove `Renderer.VIDEO_SCALING_MODE_*` constants. Use identically named constants in `C` instead. diff --git a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java index 9e66c823a0..54174b0c53 100644 --- a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java +++ b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java @@ -261,7 +261,7 @@ import java.util.ArrayList; int playbackState = currentPlayer.getPlaybackState(); maybeSetCurrentItemAndNotify( playbackState != Player.STATE_IDLE && playbackState != Player.STATE_ENDED - ? currentPlayer.getCurrentWindowIndex() + ? currentPlayer.getCurrentMediaItemIndex() : C.INDEX_UNSET); } @@ -281,7 +281,7 @@ import java.util.ArrayList; // Player state management. long playbackPositionMs = C.TIME_UNSET; - int windowIndex = C.INDEX_UNSET; + int currentItemIndex = C.INDEX_UNSET; boolean playWhenReady = false; Player previousPlayer = this.currentPlayer; @@ -291,10 +291,10 @@ import java.util.ArrayList; if (playbackState != Player.STATE_ENDED) { playbackPositionMs = previousPlayer.getCurrentPosition(); playWhenReady = previousPlayer.getPlayWhenReady(); - windowIndex = previousPlayer.getCurrentWindowIndex(); - if (windowIndex != currentItemIndex) { + currentItemIndex = previousPlayer.getCurrentMediaItemIndex(); + if (currentItemIndex != this.currentItemIndex) { playbackPositionMs = C.TIME_UNSET; - windowIndex = currentItemIndex; + currentItemIndex = this.currentItemIndex; } } previousPlayer.stop(); @@ -304,7 +304,7 @@ import java.util.ArrayList; this.currentPlayer = currentPlayer; // Media queue management. - currentPlayer.setMediaItems(mediaQueue, windowIndex, playbackPositionMs); + currentPlayer.setMediaItems(mediaQueue, currentItemIndex, playbackPositionMs); currentPlayer.setPlayWhenReady(playWhenReady); currentPlayer.prepare(); } diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index e080c23f99..ca9fd45d42 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -65,7 +65,7 @@ public class PlayerActivity extends AppCompatActivity // Saved instance state keys. private static final String KEY_TRACK_SELECTION_PARAMETERS = "track_selection_parameters"; - private static final String KEY_WINDOW = "window"; + private static final String KEY_ITEM_INDEX = "item_index"; private static final String KEY_POSITION = "position"; private static final String KEY_AUTO_PLAY = "auto_play"; @@ -83,7 +83,7 @@ public class PlayerActivity extends AppCompatActivity private DebugTextViewHelper debugViewHelper; private TracksInfo lastSeenTracksInfo; private boolean startAutoPlay; - private int startWindow; + private int startItemIndex; private long startPosition; // For ad playback only. @@ -114,7 +114,7 @@ public class PlayerActivity extends AppCompatActivity DefaultTrackSelector.Parameters.CREATOR.fromBundle( savedInstanceState.getBundle(KEY_TRACK_SELECTION_PARAMETERS)); startAutoPlay = savedInstanceState.getBoolean(KEY_AUTO_PLAY); - startWindow = savedInstanceState.getInt(KEY_WINDOW); + startItemIndex = savedInstanceState.getInt(KEY_ITEM_INDEX); startPosition = savedInstanceState.getLong(KEY_POSITION); } else { trackSelectionParameters = @@ -206,7 +206,7 @@ public class PlayerActivity extends AppCompatActivity updateStartPosition(); outState.putBundle(KEY_TRACK_SELECTION_PARAMETERS, trackSelectionParameters.toBundle()); outState.putBoolean(KEY_AUTO_PLAY, startAutoPlay); - outState.putInt(KEY_WINDOW, startWindow); + outState.putInt(KEY_ITEM_INDEX, startItemIndex); outState.putLong(KEY_POSITION, startPosition); } @@ -282,9 +282,9 @@ public class PlayerActivity extends AppCompatActivity debugViewHelper = new DebugTextViewHelper(player, debugTextView); debugViewHelper.start(); } - boolean haveStartPosition = startWindow != C.INDEX_UNSET; + boolean haveStartPosition = startItemIndex != C.INDEX_UNSET; if (haveStartPosition) { - player.seekTo(startWindow, startPosition); + player.seekTo(startItemIndex, startPosition); } player.setMediaItems(mediaItems, /* resetPosition= */ !haveStartPosition); player.prepare(); @@ -382,14 +382,14 @@ public class PlayerActivity extends AppCompatActivity private void updateStartPosition() { if (player != null) { startAutoPlay = player.getPlayWhenReady(); - startWindow = player.getCurrentWindowIndex(); + startItemIndex = player.getCurrentMediaItemIndex(); startPosition = Math.max(0, player.getContentPosition()); } } protected void clearStartPosition() { startAutoPlay = true; - startWindow = C.INDEX_UNSET; + startItemIndex = C.INDEX_UNSET; startPosition = C.TIME_UNSET; } diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java index 1bf2cd410b..0054378727 100644 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java +++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java @@ -318,9 +318,9 @@ public final class CastPlayer extends BasePlayer { @Override public void setMediaItems(List mediaItems, boolean resetPosition) { - int windowIndex = resetPosition ? 0 : getCurrentWindowIndex(); + int mediaItemIndex = resetPosition ? 0 : getCurrentMediaItemIndex(); long startPositionMs = resetPosition ? C.TIME_UNSET : getContentPosition(); - setMediaItems(mediaItems, windowIndex, startPositionMs); + setMediaItems(mediaItems, mediaItemIndex, startPositionMs); } @Override @@ -443,7 +443,7 @@ public final class CastPlayer extends BasePlayer { // in RemoteMediaClient. positionMs = positionMs != C.TIME_UNSET ? positionMs : 0; if (mediaStatus != null) { - if (getCurrentWindowIndex() != mediaItemIndex) { + if (getCurrentMediaItemIndex() != mediaItemIndex) { remoteMediaClient .queueJumpToItem( (int) currentTimeline.getPeriod(mediaItemIndex, period).uid, positionMs, null) @@ -636,7 +636,7 @@ public final class CastPlayer extends BasePlayer { @Override public int getCurrentPeriodIndex() { - return getCurrentWindowIndex(); + return getCurrentMediaItemIndex(); } @Override @@ -1103,15 +1103,15 @@ public final class CastPlayer extends BasePlayer { @Nullable private PendingResult setMediaItemsInternal( MediaQueueItem[] mediaQueueItems, - int startWindowIndex, + int startIndex, long startPositionMs, @RepeatMode int repeatMode) { if (remoteMediaClient == null || mediaQueueItems.length == 0) { return null; } startPositionMs = startPositionMs == C.TIME_UNSET ? 0 : startPositionMs; - if (startWindowIndex == C.INDEX_UNSET) { - startWindowIndex = getCurrentWindowIndex(); + if (startIndex == C.INDEX_UNSET) { + startIndex = getCurrentMediaItemIndex(); startPositionMs = getCurrentPosition(); } Timeline currentTimeline = getCurrentTimeline(); @@ -1120,7 +1120,7 @@ public final class CastPlayer extends BasePlayer { } return remoteMediaClient.queueLoad( mediaQueueItems, - min(startWindowIndex, mediaQueueItems.length - 1), + min(startIndex, mediaQueueItems.length - 1), getCastRepeatMode(repeatMode), startPositionMs, /* customData= */ null); @@ -1180,7 +1180,7 @@ public final class CastPlayer extends BasePlayer { } return new PositionInfo( newWindowUid, - getCurrentWindowIndex(), + getCurrentMediaItemIndex(), newMediaItem, newPeriodUid, getCurrentPeriodIndex(), diff --git a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/FakeExoPlayer.java b/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/FakeExoPlayer.java index fb2975920d..90e2087389 100644 --- a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/FakeExoPlayer.java +++ b/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/FakeExoPlayer.java @@ -279,7 +279,7 @@ import com.google.android.exoplayer2.util.Util; timeline.getPeriod(0, period).getAdDurationUs(adGroupIndex, adIndexInAdGroup); return Util.usToMs(adDurationUs); } else { - return timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); + return timeline.getWindow(getCurrentMediaItemIndex(), window).getDurationMs(); } } diff --git a/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java b/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java index a914869f8f..bd70d14394 100644 --- a/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java +++ b/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java @@ -141,7 +141,7 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter implements Runnab if (player.getPlaybackState() == Player.STATE_IDLE) { player.prepare(); } else if (player.getPlaybackState() == Player.STATE_ENDED) { - player.seekToDefaultPosition(player.getCurrentWindowIndex()); + player.seekToDefaultPosition(player.getCurrentMediaItemIndex()); } if (player.isCommandAvailable(Player.COMMAND_PLAY_PAUSE)) { player.play(); diff --git a/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java b/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java index 7891bc47f3..f69f725edb 100644 --- a/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java +++ b/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java @@ -253,8 +253,8 @@ import java.util.List; // checkIndex() throws IndexOutOfBoundsException which maps the RESULT_ERROR_BAD_VALUE // but RESULT_ERROR_INVALID_STATE with IllegalStateException is expected here. Assertions.checkState(0 <= index && index < timeline.getWindowCount()); - int windowIndex = player.getCurrentWindowIndex(); - if (windowIndex == index || !player.isCommandAvailable(COMMAND_SEEK_TO_MEDIA_ITEM)) { + int currentIndex = player.getCurrentMediaItemIndex(); + if (currentIndex == index || !player.isCommandAvailable(COMMAND_SEEK_TO_MEDIA_ITEM)) { return false; } player.seekToDefaultPosition(index); @@ -301,7 +301,7 @@ import java.util.List; } public int getCurrentMediaItemIndex() { - return media2Playlist.isEmpty() ? C.INDEX_UNSET : player.getCurrentWindowIndex(); + return media2Playlist.isEmpty() ? C.INDEX_UNSET : player.getCurrentMediaItemIndex(); } public int getPreviousMediaItemIndex() { @@ -331,7 +331,7 @@ import java.util.List; if (!player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)) { return false; } - player.seekTo(player.getCurrentWindowIndex(), /* positionMs= */ 0); + player.seekTo(player.getCurrentMediaItemIndex(), /* positionMs= */ 0); } boolean playWhenReady = player.getPlayWhenReady(); int suppressReason = player.getPlaybackSuppressionReason(); @@ -358,7 +358,7 @@ import java.util.List; if (!player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)) { return false; } - player.seekTo(player.getCurrentWindowIndex(), position); + player.seekTo(player.getCurrentMediaItemIndex(), position); return true; } @@ -493,7 +493,7 @@ import java.util.List; public boolean isCurrentMediaItemSeekable() { return getCurrentMediaItem() != null && !player.isPlayingAd() - && player.isCurrentWindowSeekable(); + && player.isCurrentMediaItemSeekable(); } public boolean canSkipToPlaylistItem() { @@ -502,11 +502,11 @@ import java.util.List; } public boolean canSkipToPreviousPlaylistItem() { - return player.hasPreviousWindow(); + return player.hasPreviousMediaItem(); } public boolean canSkipToNextPlaylistItem() { - return player.hasNextWindow(); + return player.hasNextMediaItem(); } public boolean hasError() { diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index b823d0f90f..cfda09ff0a 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -263,12 +263,13 @@ public final class MediaSessionConnector { * @param player The player connected to the media session. */ void onTimelineChanged(Player player); + /** - * Called when the current window index changed. + * Called when the current media item index changed. * * @param player The player connected to the media session. */ - void onCurrentWindowIndexChanged(Player player); + default void onCurrentMediaItemIndexChanged(Player player) {} /** * Gets the id of the currently active queue item, or {@link * MediaSessionCompat.QueueItem#UNKNOWN_ID} if the active item is unknown. @@ -969,8 +970,8 @@ public final class MediaSessionConnector { return player != null && mediaButtonEventHandler != null; } - private void seekTo(Player player, int windowIndex, long positionMs) { - player.seekTo(windowIndex, positionMs); + private void seekTo(Player player, int mediaItemIndex, long positionMs) { + player.seekTo(mediaItemIndex, positionMs); } private static int getMediaSessionPlaybackState( @@ -1023,7 +1024,7 @@ public final class MediaSessionConnector { } builder.putLong( MediaMetadataCompat.METADATA_KEY_DURATION, - player.isCurrentWindowDynamic() || player.getDuration() == C.TIME_UNSET + player.isCurrentMediaItemDynamic() || player.getDuration() == C.TIME_UNSET ? -1 : player.getDuration()); long activeQueueItemId = mediaController.getPlaybackState().getActiveQueueItemId(); @@ -1097,7 +1098,7 @@ public final class MediaSessionConnector { private class ComponentListener extends MediaSessionCompat.Callback implements Player.Listener { - private int currentWindowIndex; + private int currentMediaItemIndex; private int currentWindowCount; // Player.Listener implementation. @@ -1107,9 +1108,9 @@ public final class MediaSessionConnector { boolean invalidatePlaybackState = false; boolean invalidateMetadata = false; if (events.contains(Player.EVENT_POSITION_DISCONTINUITY)) { - if (currentWindowIndex != player.getCurrentWindowIndex()) { + if (currentMediaItemIndex != player.getCurrentMediaItemIndex()) { if (queueNavigator != null) { - queueNavigator.onCurrentWindowIndexChanged(player); + queueNavigator.onCurrentMediaItemIndexChanged(player); } invalidateMetadata = true; } @@ -1118,11 +1119,11 @@ public final class MediaSessionConnector { if (events.contains(Player.EVENT_TIMELINE_CHANGED)) { int windowCount = player.getCurrentTimeline().getWindowCount(); - int windowIndex = player.getCurrentWindowIndex(); + int mediaItemIndex = player.getCurrentMediaItemIndex(); if (queueNavigator != null) { queueNavigator.onTimelineChanged(player); invalidatePlaybackState = true; - } else if (currentWindowCount != windowCount || currentWindowIndex != windowIndex) { + } else if (currentWindowCount != windowCount || currentMediaItemIndex != mediaItemIndex) { // active queue item and queue navigation actions may need to be updated invalidatePlaybackState = true; } @@ -1130,8 +1131,8 @@ public final class MediaSessionConnector { invalidateMetadata = true; } - // Update currentWindowIndex after comparisons above. - currentWindowIndex = player.getCurrentWindowIndex(); + // Update currentMediaItemIndex after comparisons above. + currentMediaItemIndex = player.getCurrentMediaItemIndex(); if (events.containsAny( EVENT_PLAYBACK_STATE_CHANGED, @@ -1170,7 +1171,7 @@ public final class MediaSessionConnector { player.prepare(); } } else if (player.getPlaybackState() == Player.STATE_ENDED) { - seekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET); + seekTo(player, player.getCurrentMediaItemIndex(), C.TIME_UNSET); } Assertions.checkNotNull(player).play(); } @@ -1186,7 +1187,7 @@ public final class MediaSessionConnector { @Override public void onSeekTo(long positionMs) { if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_SEEK_TO)) { - seekTo(player, player.getCurrentWindowIndex(), positionMs); + seekTo(player, player.getCurrentMediaItemIndex(), positionMs); } } diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java index 90db27e458..4277de3c32 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java @@ -98,7 +98,7 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu boolean enableNext = false; Timeline timeline = player.getCurrentTimeline(); if (!timeline.isEmpty() && !player.isPlayingAd()) { - timeline.getWindow(player.getCurrentWindowIndex(), window); + timeline.getWindow(player.getCurrentMediaItemIndex(), window); enableSkipTo = timeline.getWindowCount() > 1; enablePrevious = player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM) @@ -128,12 +128,12 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu } @Override - public final void onCurrentWindowIndexChanged(Player player) { + public final void onCurrentMediaItemIndexChanged(Player player) { if (activeQueueItemId == MediaSessionCompat.QueueItem.UNKNOWN_ID || player.getCurrentTimeline().getWindowCount() > maxQueueSize) { publishFloatingQueueWindow(player); } else if (!player.getCurrentTimeline().isEmpty()) { - activeQueueItemId = player.getCurrentWindowIndex(); + activeQueueItemId = player.getCurrentMediaItemIndex(); } } @@ -185,40 +185,40 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu int queueSize = min(maxQueueSize, timeline.getWindowCount()); // Add the active queue item. - int currentWindowIndex = player.getCurrentWindowIndex(); + int currentMediaItemIndex = player.getCurrentMediaItemIndex(); queue.add( new MediaSessionCompat.QueueItem( - getMediaDescription(player, currentWindowIndex), currentWindowIndex)); + getMediaDescription(player, currentMediaItemIndex), currentMediaItemIndex)); // Fill queue alternating with next and/or previous queue items. - int firstWindowIndex = currentWindowIndex; - int lastWindowIndex = currentWindowIndex; + int firstMediaItemIndex = currentMediaItemIndex; + int lastMediaItemIndex = currentMediaItemIndex; boolean shuffleModeEnabled = player.getShuffleModeEnabled(); - while ((firstWindowIndex != C.INDEX_UNSET || lastWindowIndex != C.INDEX_UNSET) + while ((firstMediaItemIndex != C.INDEX_UNSET || lastMediaItemIndex != C.INDEX_UNSET) && queue.size() < queueSize) { // Begin with next to have a longer tail than head if an even sized queue needs to be trimmed. - if (lastWindowIndex != C.INDEX_UNSET) { - lastWindowIndex = + if (lastMediaItemIndex != C.INDEX_UNSET) { + lastMediaItemIndex = timeline.getNextWindowIndex( - lastWindowIndex, Player.REPEAT_MODE_OFF, shuffleModeEnabled); - if (lastWindowIndex != C.INDEX_UNSET) { + lastMediaItemIndex, Player.REPEAT_MODE_OFF, shuffleModeEnabled); + if (lastMediaItemIndex != C.INDEX_UNSET) { queue.add( new MediaSessionCompat.QueueItem( - getMediaDescription(player, lastWindowIndex), lastWindowIndex)); + getMediaDescription(player, lastMediaItemIndex), lastMediaItemIndex)); } } - if (firstWindowIndex != C.INDEX_UNSET && queue.size() < queueSize) { - firstWindowIndex = + if (firstMediaItemIndex != C.INDEX_UNSET && queue.size() < queueSize) { + firstMediaItemIndex = timeline.getPreviousWindowIndex( - firstWindowIndex, Player.REPEAT_MODE_OFF, shuffleModeEnabled); - if (firstWindowIndex != C.INDEX_UNSET) { + firstMediaItemIndex, Player.REPEAT_MODE_OFF, shuffleModeEnabled); + if (firstMediaItemIndex != C.INDEX_UNSET) { queue.addFirst( new MediaSessionCompat.QueueItem( - getMediaDescription(player, firstWindowIndex), firstWindowIndex)); + getMediaDescription(player, firstMediaItemIndex), firstMediaItemIndex)); } } } mediaSession.setQueue(new ArrayList<>(queue)); - activeQueueItemId = currentWindowIndex; + activeQueueItemId = currentMediaItemIndex; } } diff --git a/library/common/src/main/java/com/google/android/exoplayer2/BasePlayer.java b/library/common/src/main/java/com/google/android/exoplayer2/BasePlayer.java index b60e4a3a7e..2209803f3e 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/BasePlayer.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/BasePlayer.java @@ -118,7 +118,7 @@ public abstract class BasePlayer implements Player { @Override public final void seekToDefaultPosition() { - seekToDefaultPosition(getCurrentWindowIndex()); + seekToDefaultPosition(getCurrentMediaItemIndex()); } @Override @@ -128,7 +128,7 @@ public abstract class BasePlayer implements Player { @Override public final void seekTo(long positionMs) { - seekTo(getCurrentWindowIndex(), positionMs); + seekTo(getCurrentMediaItemIndex(), positionMs); } @Override @@ -184,13 +184,13 @@ public abstract class BasePlayer implements Player { if (timeline.isEmpty() || isPlayingAd()) { return; } - boolean hasPreviousWindow = hasPreviousWindow(); - if (isCurrentWindowLive() && !isCurrentWindowSeekable()) { - if (hasPreviousWindow) { - seekToPreviousWindow(); + boolean hasPreviousMediaItem = hasPreviousMediaItem(); + if (isCurrentMediaItemLive() && !isCurrentMediaItemSeekable()) { + if (hasPreviousMediaItem) { + seekToPreviousMediaItem(); } - } else if (hasPreviousWindow && getCurrentPosition() <= getMaxSeekToPreviousPosition()) { - seekToPreviousWindow(); + } else if (hasPreviousMediaItem && getCurrentPosition() <= getMaxSeekToPreviousPosition()) { + seekToPreviousMediaItem(); } else { seekTo(/* positionMs= */ 0); } @@ -239,9 +239,9 @@ public abstract class BasePlayer implements Player { if (timeline.isEmpty() || isPlayingAd()) { return; } - if (hasNextWindow()) { - seekToNextWindow(); - } else if (isCurrentWindowLive() && isCurrentWindowDynamic()) { + if (hasNextMediaItem()) { + seekToNextMediaItem(); + } else if (isCurrentMediaItemLive() && isCurrentMediaItemDynamic()) { seekToDefaultPosition(); } } @@ -293,7 +293,7 @@ public abstract class BasePlayer implements Player { Timeline timeline = getCurrentTimeline(); return timeline.isEmpty() ? null - : timeline.getWindow(getCurrentWindowIndex(), window).mediaItem; + : timeline.getWindow(getCurrentMediaItemIndex(), window).mediaItem; } @Override @@ -310,7 +310,9 @@ public abstract class BasePlayer implements Player { @Nullable public final Object getCurrentManifest() { Timeline timeline = getCurrentTimeline(); - return timeline.isEmpty() ? null : timeline.getWindow(getCurrentWindowIndex(), window).manifest; + return timeline.isEmpty() + ? null + : timeline.getWindow(getCurrentMediaItemIndex(), window).manifest; } @Override @@ -352,7 +354,8 @@ public abstract class BasePlayer implements Player { if (timeline.isEmpty()) { return C.TIME_UNSET; } - long windowStartTimeMs = timeline.getWindow(getCurrentWindowIndex(), window).windowStartTimeMs; + long windowStartTimeMs = + timeline.getWindow(getCurrentMediaItemIndex(), window).windowStartTimeMs; if (windowStartTimeMs == C.TIME_UNSET) { return C.TIME_UNSET; } @@ -376,7 +379,7 @@ public abstract class BasePlayer implements Player { Timeline timeline = getCurrentTimeline(); return timeline.isEmpty() ? C.TIME_UNSET - : timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); + : timeline.getWindow(getCurrentMediaItemIndex(), window).getDurationMs(); } /** @@ -389,22 +392,24 @@ public abstract class BasePlayer implements Player { return new Commands.Builder() .addAll(permanentAvailableCommands) .addIf(COMMAND_SEEK_TO_DEFAULT_POSITION, !isPlayingAd()) - .addIf(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, isCurrentWindowSeekable() && !isPlayingAd()) - .addIf(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, hasPreviousWindow() && !isPlayingAd()) + .addIf(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, isCurrentMediaItemSeekable() && !isPlayingAd()) + .addIf(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, hasPreviousMediaItem() && !isPlayingAd()) .addIf( COMMAND_SEEK_TO_PREVIOUS, !getCurrentTimeline().isEmpty() - && (hasPreviousWindow() || !isCurrentWindowLive() || isCurrentWindowSeekable()) + && (hasPreviousMediaItem() + || !isCurrentMediaItemLive() + || isCurrentMediaItemSeekable()) && !isPlayingAd()) - .addIf(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, hasNextWindow() && !isPlayingAd()) + .addIf(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, hasNextMediaItem() && !isPlayingAd()) .addIf( COMMAND_SEEK_TO_NEXT, !getCurrentTimeline().isEmpty() - && (hasNextWindow() || (isCurrentWindowLive() && isCurrentWindowDynamic())) + && (hasNextMediaItem() || (isCurrentMediaItemLive() && isCurrentMediaItemDynamic())) && !isPlayingAd()) .addIf(COMMAND_SEEK_TO_MEDIA_ITEM, !isPlayingAd()) - .addIf(COMMAND_SEEK_BACK, isCurrentWindowSeekable() && !isPlayingAd()) - .addIf(COMMAND_SEEK_FORWARD, isCurrentWindowSeekable() && !isPlayingAd()) + .addIf(COMMAND_SEEK_BACK, isCurrentMediaItemSeekable() && !isPlayingAd()) + .addIf(COMMAND_SEEK_FORWARD, isCurrentMediaItemSeekable() && !isPlayingAd()) .build(); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index e594883c72..2143d2a1fb 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -1126,7 +1126,7 @@ public interface ExoPlayer extends Player { * @param mediaSources The new {@link MediaSource MediaSources}. * @param resetPosition Whether the playback position should be reset to the default position in * the first {@link Timeline.Window}. If false, playback will start from the position defined - * by {@link #getCurrentWindowIndex()} and {@link #getCurrentPosition()}. + * by {@link #getCurrentMediaItemIndex()} and {@link #getCurrentPosition()}. */ void setMediaSources(List mediaSources, boolean resetPosition); @@ -1134,14 +1134,15 @@ public interface ExoPlayer extends Player { * Clears the playlist and adds the specified {@link MediaSource MediaSources}. * * @param mediaSources The new {@link MediaSource MediaSources}. - * @param startWindowIndex The window index to start playback from. If {@link C#INDEX_UNSET} is - * passed, the current position is not reset. + * @param startMediaItemIndex The media item index to start playback from. If {@link + * C#INDEX_UNSET} is passed, the current position is not reset. * @param startPositionMs The position in milliseconds to start playback from. If {@link - * C#TIME_UNSET} is passed, the default position of the given window is used. In any case, if - * {@code startWindowIndex} is set to {@link C#INDEX_UNSET}, this parameter is ignored and the - * position is not reset at all. + * C#TIME_UNSET} is passed, the default position of the given media item is used. In any case, + * if {@code startMediaItemIndex} is set to {@link C#INDEX_UNSET}, this parameter is ignored + * and the position is not reset at all. */ - void setMediaSources(List mediaSources, int startWindowIndex, long startPositionMs); + void setMediaSources( + List mediaSources, int startMediaItemIndex, long startPositionMs); /** * Clears the playlist, adds the specified {@link MediaSource} and resets the position to the @@ -1164,7 +1165,7 @@ public interface ExoPlayer extends Player { * * @param mediaSource The new {@link MediaSource}. * @param resetPosition Whether the playback position should be reset to the default position. If - * false, playback will start from the position defined by {@link #getCurrentWindowIndex()} + * false, playback will start from the position defined by {@link #getCurrentMediaItemIndex()} * and {@link #getCurrentPosition()}. */ void setMediaSource(MediaSource mediaSource, boolean resetPosition); @@ -1331,9 +1332,9 @@ public interface ExoPlayer extends Player { * will be delivered immediately without blocking on the playback thread. The default {@link * PlayerMessage#getType()} is 0 and the default {@link PlayerMessage#getPayload()} is null. If a * position is specified with {@link PlayerMessage#setPosition(long)}, the message will be - * delivered at this position in the current window defined by {@link #getCurrentWindowIndex()}. - * Alternatively, the message can be sent at a specific window using {@link - * PlayerMessage#setPosition(int, long)}. + * delivered at this position in the current media item defined by {@link + * #getCurrentMediaItemIndex()}. Alternatively, the message can be sent at a specific mediaItem + * using {@link PlayerMessage#setPosition(int, long)}. */ PlayerMessage createMessage(PlayerMessage.Target target); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 653135e59c..61a1d41b82 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -537,7 +537,7 @@ import java.util.concurrent.CopyOnWriteArraySet; playbackInfo, timeline, getPeriodPositionOrMaskWindowPosition( - timeline, getCurrentWindowIndex(), getCurrentPosition())); + timeline, getCurrentMediaItemIndex(), getCurrentPosition())); pendingOperationAcks++; this.shuffleOrder = shuffleOrder; internalPlayer.setShuffleOrder(shuffleOrder); @@ -662,7 +662,7 @@ import java.util.concurrent.CopyOnWriteArraySet; @Player.State int newPlaybackState = getPlaybackState() == Player.STATE_IDLE ? Player.STATE_IDLE : Player.STATE_BUFFERING; - int oldMaskingWindowIndex = getCurrentWindowIndex(); + int oldMaskingMediaItemIndex = getCurrentMediaItemIndex(); PlaybackInfo newPlaybackInfo = playbackInfo.copyWithPlaybackState(newPlaybackState); newPlaybackInfo = maskTimelineAndPosition( @@ -678,7 +678,7 @@ import java.util.concurrent.CopyOnWriteArraySet; /* positionDiscontinuity= */ true, /* positionDiscontinuityReason= */ DISCONTINUITY_REASON_SEEK, /* discontinuityWindowStartPositionUs= */ getCurrentPositionUsInternal(newPlaybackInfo), - oldMaskingWindowIndex); + oldMaskingMediaItemIndex); } @Override @@ -839,7 +839,7 @@ import java.util.concurrent.CopyOnWriteArraySet; internalPlayer, target, playbackInfo.timeline, - getCurrentWindowIndex(), + getCurrentMediaItemIndex(), clock, internalPlayer.getPlaybackLooper()); } @@ -910,7 +910,10 @@ import java.util.concurrent.CopyOnWriteArraySet; if (isPlayingAd()) { playbackInfo.timeline.getPeriodByUid(playbackInfo.periodId.periodUid, period); return playbackInfo.requestedContentPositionUs == C.TIME_UNSET - ? playbackInfo.timeline.getWindow(getCurrentWindowIndex(), window).getDefaultPositionMs() + ? playbackInfo + .timeline + .getWindow(getCurrentMediaItemIndex(), window) + .getDefaultPositionMs() : period.getPositionInWindowMs() + Util.usToMs(playbackInfo.requestedContentPositionUs); } else { return getCurrentPosition(); @@ -924,7 +927,7 @@ import java.util.concurrent.CopyOnWriteArraySet; } if (playbackInfo.loadingMediaPeriodId.windowSequenceNumber != playbackInfo.periodId.windowSequenceNumber) { - return playbackInfo.timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); + return playbackInfo.timeline.getWindow(getCurrentMediaItemIndex(), window).getDurationMs(); } long contentBufferedPositionUs = playbackInfo.bufferedPositionUs; if (playbackInfo.loadingMediaPeriodId.isAd()) { @@ -1218,7 +1221,7 @@ import java.util.concurrent.CopyOnWriteArraySet; boolean positionDiscontinuity, @DiscontinuityReason int positionDiscontinuityReason, long discontinuityWindowStartPositionUs, - int oldMaskingWindowIndex) { + int oldMaskingMediaItemIndex) { // Assign playback info immediately such that all getters return the right values, but keep // snapshot of previous and new state so that listener invocations are triggered correctly. @@ -1267,7 +1270,7 @@ import java.util.concurrent.CopyOnWriteArraySet; if (positionDiscontinuity) { PositionInfo previousPositionInfo = getPreviousPositionInfo( - positionDiscontinuityReason, previousPlaybackInfo, oldMaskingWindowIndex); + positionDiscontinuityReason, previousPlaybackInfo, oldMaskingMediaItemIndex); PositionInfo positionInfo = getPositionInfo(discontinuityWindowStartPositionUs); listeners.queueEvent( Player.EVENT_POSITION_DISCONTINUITY, @@ -1378,19 +1381,19 @@ import java.util.concurrent.CopyOnWriteArraySet; private PositionInfo getPreviousPositionInfo( @DiscontinuityReason int positionDiscontinuityReason, PlaybackInfo oldPlaybackInfo, - int oldMaskingWindowIndex) { + int oldMaskingMediaItemIndex) { @Nullable Object oldWindowUid = null; @Nullable Object oldPeriodUid = null; - int oldWindowIndex = oldMaskingWindowIndex; + int oldMediaItemIndex = oldMaskingMediaItemIndex; int oldPeriodIndex = C.INDEX_UNSET; @Nullable MediaItem oldMediaItem = null; Timeline.Period oldPeriod = new Timeline.Period(); if (!oldPlaybackInfo.timeline.isEmpty()) { oldPeriodUid = oldPlaybackInfo.periodId.periodUid; oldPlaybackInfo.timeline.getPeriodByUid(oldPeriodUid, oldPeriod); - oldWindowIndex = oldPeriod.windowIndex; + oldMediaItemIndex = oldPeriod.windowIndex; oldPeriodIndex = oldPlaybackInfo.timeline.getIndexOfPeriod(oldPeriodUid); - oldWindowUid = oldPlaybackInfo.timeline.getWindow(oldWindowIndex, window).uid; + oldWindowUid = oldPlaybackInfo.timeline.getWindow(oldMediaItemIndex, window).uid; oldMediaItem = window.mediaItem; } long oldPositionUs; @@ -1421,7 +1424,7 @@ import java.util.concurrent.CopyOnWriteArraySet; } return new PositionInfo( oldWindowUid, - oldWindowIndex, + oldMediaItemIndex, oldMediaItem, oldPeriodUid, oldPeriodIndex, @@ -1434,20 +1437,20 @@ import java.util.concurrent.CopyOnWriteArraySet; private PositionInfo getPositionInfo(long discontinuityWindowStartPositionUs) { @Nullable Object newWindowUid = null; @Nullable Object newPeriodUid = null; - int newWindowIndex = getCurrentWindowIndex(); + int newMediaItemIndex = getCurrentMediaItemIndex(); int newPeriodIndex = C.INDEX_UNSET; @Nullable MediaItem newMediaItem = null; if (!playbackInfo.timeline.isEmpty()) { newPeriodUid = playbackInfo.periodId.periodUid; playbackInfo.timeline.getPeriodByUid(newPeriodUid, period); newPeriodIndex = playbackInfo.timeline.getIndexOfPeriod(newPeriodUid); - newWindowUid = playbackInfo.timeline.getWindow(newWindowIndex, window).uid; + newWindowUid = playbackInfo.timeline.getWindow(newMediaItemIndex, window).uid; newMediaItem = window.mediaItem; } long positionMs = Util.usToMs(discontinuityWindowStartPositionUs); return new PositionInfo( newWindowUid, - newWindowIndex, + newMediaItemIndex, newMediaItem, newPeriodUid, newPeriodIndex, @@ -1601,7 +1604,7 @@ import java.util.concurrent.CopyOnWriteArraySet; private PlaybackInfo removeMediaItemsInternal(int fromIndex, int toIndex) { Assertions.checkArgument( fromIndex >= 0 && toIndex >= fromIndex && toIndex <= mediaSourceHolderSnapshots.size()); - int currentWindowIndex = getCurrentWindowIndex(); + int currentIndex = getCurrentMediaItemIndex(); Timeline oldTimeline = getCurrentTimeline(); int currentMediaSourceCount = mediaSourceHolderSnapshots.size(); pendingOperationAcks++; @@ -1618,7 +1621,7 @@ import java.util.concurrent.CopyOnWriteArraySet; && newPlaybackInfo.playbackState != STATE_ENDED && fromIndex < toIndex && toIndex == currentMediaSourceCount - && currentWindowIndex >= newPlaybackInfo.timeline.getWindowCount(); + && currentIndex >= newPlaybackInfo.timeline.getWindowCount(); if (transitionsToEnded) { newPlaybackInfo = newPlaybackInfo.copyWithPlaybackState(STATE_ENDED); } @@ -1753,11 +1756,11 @@ import java.util.concurrent.CopyOnWriteArraySet; isCleared ? C.INDEX_UNSET : getCurrentWindowIndexInternal(), isCleared ? C.TIME_UNSET : currentPositionMs); } - int currentWindowIndex = getCurrentWindowIndex(); + int currentMediaItemIndex = getCurrentMediaItemIndex(); @Nullable Pair oldPeriodPosition = oldTimeline.getPeriodPosition( - window, period, currentWindowIndex, Util.msToUs(currentPositionMs)); + window, period, currentMediaItemIndex, Util.msToUs(currentPositionMs)); Object periodUid = castNonNull(oldPeriodPosition).first; if (newTimeline.getIndexOfPeriod(periodUid) != C.INDEX_UNSET) { // The old period position is still available in the new timeline. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 9fadb56a79..d6f1e1f73a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -2718,7 +2718,7 @@ import java.util.concurrent.atomic.AtomicBoolean; newTimeline, new SeekPosition( pendingMessageInfo.message.getTimeline(), - pendingMessageInfo.message.getWindowIndex(), + pendingMessageInfo.message.getMediaItemIndex(), requestPositionUs), /* trySubsequentPeriods= */ false, repeatMode, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/PlayerMessage.java b/library/core/src/main/java/com/google/android/exoplayer2/PlayerMessage.java index 0d591ee9f6..cc7e749fa0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/PlayerMessage.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/PlayerMessage.java @@ -63,7 +63,7 @@ public final class PlayerMessage { private int type; @Nullable private Object payload; private Looper looper; - private int windowIndex; + private int mediaItemIndex; private long positionMs; private boolean deleteAfterDelivery; private boolean isSent; @@ -78,8 +78,8 @@ public final class PlayerMessage { * @param target The {@link Target} the message is sent to. * @param timeline The timeline used when setting the position with {@link #setPosition(long)}. If * set to {@link Timeline#EMPTY}, any position can be specified. - * @param defaultWindowIndex The default window index in the {@code timeline} when no other window - * index is specified. + * @param defaultMediaItemIndex The default media item index in the {@code timeline} when no other + * media item index is specified. * @param clock The {@link Clock}. * @param defaultLooper The default {@link Looper} to send the message on when no other looper is * specified. @@ -88,7 +88,7 @@ public final class PlayerMessage { Sender sender, Target target, Timeline timeline, - int defaultWindowIndex, + int defaultMediaItemIndex, Clock clock, Looper defaultLooper) { this.sender = sender; @@ -96,7 +96,7 @@ public final class PlayerMessage { this.timeline = timeline; this.looper = defaultLooper; this.clock = clock; - this.windowIndex = defaultWindowIndex; + this.mediaItemIndex = defaultMediaItemIndex; this.positionMs = C.TIME_UNSET; this.deleteAfterDelivery = true; } @@ -173,21 +173,21 @@ public final class PlayerMessage { } /** - * Returns position in window at {@link #getWindowIndex()} at which the message will be delivered, - * in milliseconds. If {@link C#TIME_UNSET}, the message will be delivered immediately. If {@link - * C#TIME_END_OF_SOURCE}, the message will be delivered at the end of the window at {@link - * #getWindowIndex()}. + * Returns position in the media item at {@link #getMediaItemIndex()} at which the message will be + * delivered, in milliseconds. If {@link C#TIME_UNSET}, the message will be delivered immediately. + * If {@link C#TIME_END_OF_SOURCE}, the message will be delivered at the end of the media item at + * {@link #getMediaItemIndex()}. */ public long getPositionMs() { return positionMs; } /** - * Sets a position in the current window at which the message will be delivered. + * Sets a position in the current media item at which the message will be delivered. * - * @param positionMs The position in the current window at which the message will be sent, in + * @param positionMs The position in the current media item at which the message will be sent, in * milliseconds, or {@link C#TIME_END_OF_SOURCE} to deliver the message at the end of the - * current window. + * current media item. * @return This message. * @throws IllegalStateException If {@link #send()} has already been called. */ @@ -198,31 +198,32 @@ public final class PlayerMessage { } /** - * Sets a position in a window at which the message will be delivered. + * Sets a position in a media item at which the message will be delivered. * - * @param windowIndex The index of the window at which the message will be sent. - * @param positionMs The position in the window with index {@code windowIndex} at which the + * @param mediaItemIndex The index of the media item at which the message will be sent. + * @param positionMs The position in the media item with index {@code mediaItemIndex} at which the * message will be sent, in milliseconds, or {@link C#TIME_END_OF_SOURCE} to deliver the - * message at the end of the window with index {@code windowIndex}. + * message at the end of the media item with index {@code mediaItemIndex}. * @return This message. * @throws IllegalSeekPositionException If the timeline returned by {@link #getTimeline()} is not - * empty and the provided window index is not within the bounds of the timeline. + * empty and the provided media item index is not within the bounds of the timeline. * @throws IllegalStateException If {@link #send()} has already been called. */ - public PlayerMessage setPosition(int windowIndex, long positionMs) { + public PlayerMessage setPosition(int mediaItemIndex, long positionMs) { Assertions.checkState(!isSent); Assertions.checkArgument(positionMs != C.TIME_UNSET); - if (windowIndex < 0 || (!timeline.isEmpty() && windowIndex >= timeline.getWindowCount())) { - throw new IllegalSeekPositionException(timeline, windowIndex, positionMs); + if (mediaItemIndex < 0 + || (!timeline.isEmpty() && mediaItemIndex >= timeline.getWindowCount())) { + throw new IllegalSeekPositionException(timeline, mediaItemIndex, positionMs); } - this.windowIndex = windowIndex; + this.mediaItemIndex = mediaItemIndex; this.positionMs = positionMs; return this; } - /** Returns window index at which the message will be delivered. */ - public int getWindowIndex() { - return windowIndex; + /** Returns media item index at which the message will be delivered. */ + public int getMediaItemIndex() { + return mediaItemIndex; } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 3c6607611e..83067a500c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -1110,9 +1110,9 @@ public class SimpleExoPlayer extends BasePlayer @Override public void setMediaSources( - List mediaSources, int startWindowIndex, long startPositionMs) { + List mediaSources, int startMediaItemIndex, long startPositionMs) { verifyApplicationThread(); - player.setMediaSources(mediaSources, startWindowIndex, startPositionMs); + player.setMediaSources(mediaSources, startMediaItemIndex, startPositionMs); } @Override @@ -1419,7 +1419,7 @@ public class SimpleExoPlayer extends BasePlayer @Override public int getCurrentMediaItemIndex() { verifyApplicationThread(); - return player.getCurrentWindowIndex(); + return player.getCurrentMediaItemIndex(); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java index ae22609e29..63e87a5539 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java @@ -914,7 +914,7 @@ public class AnalyticsCollector long eventPositionMs; boolean isInCurrentWindow = timeline.equals(player.getCurrentTimeline()) - && windowIndex == player.getCurrentWindowIndex(); + && windowIndex == player.getCurrentMediaItemIndex(); if (mediaPeriodId != null && mediaPeriodId.isAd()) { boolean isCurrentAd = isInCurrentWindow @@ -939,7 +939,7 @@ public class AnalyticsCollector mediaPeriodId, eventPositionMs, player.getCurrentTimeline(), - player.getCurrentWindowIndex(), + player.getCurrentMediaItemIndex(), currentMediaPeriodId, player.getCurrentPosition(), player.getTotalBufferedDuration()); @@ -962,7 +962,7 @@ public class AnalyticsCollector ? null : mediaPeriodQueueTracker.getMediaPeriodIdTimeline(mediaPeriodId); if (mediaPeriodId == null || knownTimeline == null) { - int windowIndex = player.getCurrentWindowIndex(); + int windowIndex = player.getCurrentMediaItemIndex(); Timeline timeline = player.getCurrentTimeline(); boolean windowIsInTimeline = windowIndex < timeline.getWindowCount(); return generateEventTime( diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java index 9887f397ea..df73a1f7f4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java @@ -382,7 +382,7 @@ public interface AnalyticsListener { /** * The current window index in {@link #currentTimeline} at the time of the event, or the * prospective window index if the timeline is not yet known and empty (equivalent to {@link - * Player#getCurrentWindowIndex()}). + * Player#getCurrentMediaItemIndex()}). */ public final int currentWindowIndex; @@ -419,7 +419,7 @@ public interface AnalyticsListener { * {@link Player#getCurrentTimeline()}). * @param currentWindowIndex The current window index in {@code currentTimeline} at the time of * the event, or the prospective window index if the timeline is not yet known and empty - * (equivalent to {@link Player#getCurrentWindowIndex()}). + * (equivalent to {@link Player#getCurrentMediaItemIndex()}). * @param currentMediaPeriodId {@link MediaPeriodId Media period identifier} for the currently * playing media period at the time of the event, or {@code null} if no current media period * identifier is available. @@ -1204,9 +1204,9 @@ public interface AnalyticsListener { * {@link Player#seekTo(long)} after a {@link * AnalyticsListener#onMediaItemTransition(EventTime, MediaItem, int)}). *

  • They intend to use multiple state values together or in combination with {@link Player} - * getter methods. For example using {@link Player#getCurrentWindowIndex()} with the {@code - * timeline} provided in {@link #onTimelineChanged(EventTime, int)} is only safe from within - * this method. + * getter methods. For example using {@link Player#getCurrentMediaItemIndex()} with the + * {@code timeline} provided in {@link #onTimelineChanged(EventTime, int)} is only safe from + * within this method. *
  • They are interested in events that logically happened together (e.g {@link * #onPlaybackStateChanged(EventTime, int)} to {@link Player#STATE_BUFFERING} because of * {@link #onMediaItemTransition(EventTime, MediaItem, int)}). diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/DebugTextViewHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/util/DebugTextViewHelper.java index 5eeaa060bc..77fb5c048e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/DebugTextViewHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/DebugTextViewHelper.java @@ -138,8 +138,8 @@ public class DebugTextViewHelper implements Player.Listener, Runnable { break; } return String.format( - "playWhenReady:%s playbackState:%s window:%s", - player.getPlayWhenReady(), playbackStateString, player.getCurrentWindowIndex()); + "playWhenReady:%s playbackState:%s item:%s", + player.getPlayWhenReady(), playbackStateString, player.getCurrentMediaItemIndex()); } /** Returns a string containing video debugging information. */ diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java index 64044b2a3f..886d3c8ed9 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -48,7 +48,7 @@ import static com.google.android.exoplayer2.Player.COMMAND_STOP; import static com.google.android.exoplayer2.Player.STATE_ENDED; import static com.google.android.exoplayer2.robolectric.RobolectricUtil.runMainLooperUntil; import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.playUntilPosition; -import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.playUntilStartOfWindow; +import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.playUntilStartOfMediaItem; import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.runUntilPendingCommandsAreFullyHandled; import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.runUntilPlaybackState; import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.runUntilPositionDiscontinuity; @@ -381,7 +381,7 @@ public final class ExoPlayerTest { player.play(); runUntilPositionDiscontinuity(player, Player.DISCONTINUITY_REASON_AUTO_TRANSITION); player.setForegroundMode(/* foregroundMode= */ true); - // Only the video renderer that is disabled in the second window has been reset. + // Only the video renderer that is disabled in the second media item has been reset. assertThat(audioRenderer.resetCount).isEqualTo(0); assertThat(videoRenderer.resetCount).isEqualTo(1); @@ -460,7 +460,7 @@ public final class ExoPlayerTest { // Disable text renderer by selecting a language that is not available. player.setTrackSelectionParameters( player.getTrackSelectionParameters().buildUpon().setPreferredTextLanguage("de").build()); - player.seekTo(/* windowIndex= */ 0, /* positionMs= */ 1000); + player.seekTo(/* mediaItemIndex= */ 0, /* positionMs= */ 1000); runUntilPlaybackState(player, Player.STATE_READY); // Expect formerly enabled renderers to be reset after seek. assertThat(textRenderer.resetCount).isEqualTo(1); @@ -647,21 +647,21 @@ public final class ExoPlayerTest { player.setMediaSource(new FakeMediaSource(timeline, ExoPlayerTestRunner.VIDEO_FORMAT)); player.prepare(); runUntilTimelineChanged(player); - playUntilStartOfWindow(player, /* windowIndex= */ 1); + playUntilStartOfMediaItem(player, /* mediaItemIndex= */ 1); player.setRepeatMode(Player.REPEAT_MODE_ONE); - playUntilStartOfWindow(player, /* windowIndex= */ 1); + playUntilStartOfMediaItem(player, /* mediaItemIndex= */ 1); player.setRepeatMode(Player.REPEAT_MODE_OFF); - playUntilStartOfWindow(player, /* windowIndex= */ 2); + playUntilStartOfMediaItem(player, /* mediaItemIndex= */ 2); player.setRepeatMode(Player.REPEAT_MODE_ONE); - playUntilStartOfWindow(player, /* windowIndex= */ 2); + playUntilStartOfMediaItem(player, /* mediaItemIndex= */ 2); player.setRepeatMode(Player.REPEAT_MODE_ALL); - playUntilStartOfWindow(player, /* windowIndex= */ 0); + playUntilStartOfMediaItem(player, /* mediaItemIndex= */ 0); player.setRepeatMode(Player.REPEAT_MODE_ONE); - playUntilStartOfWindow(player, /* windowIndex= */ 0); - playUntilStartOfWindow(player, /* windowIndex= */ 0); + playUntilStartOfMediaItem(player, /* mediaItemIndex= */ 0); + playUntilStartOfMediaItem(player, /* mediaItemIndex= */ 0); player.setRepeatMode(Player.REPEAT_MODE_OFF); - playUntilStartOfWindow(player, /* windowIndex= */ 1); - playUntilStartOfWindow(player, /* windowIndex= */ 2); + playUntilStartOfMediaItem(player, /* mediaItemIndex= */ 1); + playUntilStartOfMediaItem(player, /* mediaItemIndex= */ 2); player.play(); runUntilPlaybackState(player, Player.STATE_ENDED); @@ -694,9 +694,9 @@ public final class ExoPlayerTest { .pause() .waitForPlaybackState(Player.STATE_READY) .setRepeatMode(Player.REPEAT_MODE_ALL) - .playUntilStartOfWindow(/* windowIndex= */ 1) + .playUntilStartOfMediaItem(/* mediaItemIndex= */ 1) .setShuffleModeEnabled(true) - .playUntilStartOfWindow(/* windowIndex= */ 1) + .playUntilStartOfMediaItem(/* mediaItemIndex= */ 1) .setShuffleModeEnabled(false) .setRepeatMode(Player.REPEAT_MODE_OFF) .play() @@ -806,7 +806,7 @@ public final class ExoPlayerTest { @Override public void run(ExoPlayer player) { try { - player.seekTo(/* windowIndex= */ 100, /* positionMs= */ 0); + player.seekTo(/* mediaItemIndex= */ 100, /* positionMs= */ 0); } catch (IllegalSeekPositionException e) { exception[0] = e; } @@ -1281,7 +1281,7 @@ public final class ExoPlayerTest { .play() .build(); new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 0, /* positionMs= */ 2000) + .initialSeek(/* mediaItemIndex= */ 0, /* positionMs= */ 2000) .setMediaSources(mediaSource) .setActionSchedule(actionSchedule) .build() @@ -1293,7 +1293,7 @@ public final class ExoPlayerTest { @Test public void stop_withoutReset_doesNotResetPosition_correctMasking() throws Exception { - int[] currentWindowIndex = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + int[] currentMediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; long[] currentPosition = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; long[] bufferedPosition = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; long[] totalBufferedDuration = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; @@ -1302,18 +1302,18 @@ public final class ExoPlayerTest { ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .pause() - .seek(/* windowIndex= */ 1, /* positionMs= */ 1000) + .seek(/* mediaItemIndex= */ 1, /* positionMs= */ 1000) .waitForPlaybackState(Player.STATE_READY) .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndex[0] = player.getCurrentWindowIndex(); + currentMediaItemIndex[0] = player.getCurrentMediaItemIndex(); currentPosition[0] = player.getCurrentPosition(); bufferedPosition[0] = player.getBufferedPosition(); totalBufferedDuration[0] = player.getTotalBufferedDuration(); player.stop(/* reset= */ false); - currentWindowIndex[1] = player.getCurrentWindowIndex(); + currentMediaItemIndex[1] = player.getCurrentMediaItemIndex(); currentPosition[1] = player.getCurrentPosition(); bufferedPosition[1] = player.getBufferedPosition(); totalBufferedDuration[1] = player.getTotalBufferedDuration(); @@ -1324,7 +1324,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndex[2] = player.getCurrentWindowIndex(); + currentMediaItemIndex[2] = player.getCurrentMediaItemIndex(); currentPosition[2] = player.getCurrentPosition(); bufferedPosition[2] = player.getBufferedPosition(); totalBufferedDuration[2] = player.getTotalBufferedDuration(); @@ -1345,17 +1345,17 @@ public final class ExoPlayerTest { Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE); testRunner.assertPositionDiscontinuityReasonsEqual(Player.DISCONTINUITY_REASON_SEEK); - assertThat(currentWindowIndex[0]).isEqualTo(1); + assertThat(currentMediaItemIndex[0]).isEqualTo(1); assertThat(currentPosition[0]).isEqualTo(1000); assertThat(bufferedPosition[0]).isEqualTo(10000); assertThat(totalBufferedDuration[0]).isEqualTo(9000); - assertThat(currentWindowIndex[1]).isEqualTo(1); + assertThat(currentMediaItemIndex[1]).isEqualTo(1); assertThat(currentPosition[1]).isEqualTo(1000); assertThat(bufferedPosition[1]).isEqualTo(1000); assertThat(totalBufferedDuration[1]).isEqualTo(0); - assertThat(currentWindowIndex[2]).isEqualTo(1); + assertThat(currentMediaItemIndex[2]).isEqualTo(1); assertThat(currentPosition[2]).isEqualTo(1000); assertThat(bufferedPosition[2]).isEqualTo(1000); assertThat(totalBufferedDuration[2]).isEqualTo(0); @@ -1385,7 +1385,7 @@ public final class ExoPlayerTest { @Test public void stop_withReset_doesResetPosition_correctMasking() throws Exception { - int[] currentWindowIndex = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + int[] currentMediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; long[] currentPosition = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; long[] bufferedPosition = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; long[] totalBufferedDuration = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; @@ -1394,18 +1394,18 @@ public final class ExoPlayerTest { ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .pause() - .seek(/* windowIndex= */ 1, /* positionMs= */ 1000) + .seek(/* mediaItemIndex= */ 1, /* positionMs= */ 1000) .waitForPlaybackState(Player.STATE_READY) .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndex[0] = player.getCurrentWindowIndex(); + currentMediaItemIndex[0] = player.getCurrentMediaItemIndex(); currentPosition[0] = player.getCurrentPosition(); bufferedPosition[0] = player.getBufferedPosition(); totalBufferedDuration[0] = player.getTotalBufferedDuration(); player.stop(/* reset= */ true); - currentWindowIndex[1] = player.getCurrentWindowIndex(); + currentMediaItemIndex[1] = player.getCurrentMediaItemIndex(); currentPosition[1] = player.getCurrentPosition(); bufferedPosition[1] = player.getBufferedPosition(); totalBufferedDuration[1] = player.getTotalBufferedDuration(); @@ -1416,7 +1416,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndex[2] = player.getCurrentWindowIndex(); + currentMediaItemIndex[2] = player.getCurrentMediaItemIndex(); currentPosition[2] = player.getCurrentPosition(); bufferedPosition[2] = player.getBufferedPosition(); totalBufferedDuration[2] = player.getTotalBufferedDuration(); @@ -1439,17 +1439,17 @@ public final class ExoPlayerTest { testRunner.assertPositionDiscontinuityReasonsEqual( Player.DISCONTINUITY_REASON_SEEK, Player.DISCONTINUITY_REASON_REMOVE); - assertThat(currentWindowIndex[0]).isEqualTo(1); + assertThat(currentMediaItemIndex[0]).isEqualTo(1); assertThat(currentPosition[0]).isGreaterThan(0); assertThat(bufferedPosition[0]).isEqualTo(10000); assertThat(totalBufferedDuration[0]).isEqualTo(10000 - currentPosition[0]); - assertThat(currentWindowIndex[1]).isEqualTo(0); + assertThat(currentMediaItemIndex[1]).isEqualTo(0); assertThat(currentPosition[1]).isEqualTo(0); assertThat(bufferedPosition[1]).isEqualTo(0); assertThat(totalBufferedDuration[1]).isEqualTo(0); - assertThat(currentWindowIndex[2]).isEqualTo(0); + assertThat(currentMediaItemIndex[2]).isEqualTo(0); assertThat(currentPosition[2]).isEqualTo(0); assertThat(bufferedPosition[2]).isEqualTo(0); assertThat(totalBufferedDuration[2]).isEqualTo(0); @@ -1479,7 +1479,7 @@ public final class ExoPlayerTest { @Test public void release_correctMasking() throws Exception { - int[] currentWindowIndex = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + int[] currentMediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; long[] currentPosition = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; long[] bufferedPosition = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; long[] totalBufferedDuration = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; @@ -1488,18 +1488,18 @@ public final class ExoPlayerTest { ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .pause() - .seek(/* windowIndex= */ 1, /* positionMs= */ 1000) + .seek(/* mediaItemIndex= */ 1, /* positionMs= */ 1000) .waitForPlaybackState(Player.STATE_READY) .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndex[0] = player.getCurrentWindowIndex(); + currentMediaItemIndex[0] = player.getCurrentMediaItemIndex(); currentPosition[0] = player.getCurrentPosition(); bufferedPosition[0] = player.getBufferedPosition(); totalBufferedDuration[0] = player.getTotalBufferedDuration(); player.release(); - currentWindowIndex[1] = player.getCurrentWindowIndex(); + currentMediaItemIndex[1] = player.getCurrentMediaItemIndex(); currentPosition[1] = player.getCurrentPosition(); bufferedPosition[1] = player.getBufferedPosition(); totalBufferedDuration[1] = player.getTotalBufferedDuration(); @@ -1510,7 +1510,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndex[2] = player.getCurrentWindowIndex(); + currentMediaItemIndex[2] = player.getCurrentMediaItemIndex(); currentPosition[2] = player.getCurrentPosition(); bufferedPosition[2] = player.getBufferedPosition(); totalBufferedDuration[2] = player.getTotalBufferedDuration(); @@ -1525,17 +1525,17 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS); - assertThat(currentWindowIndex[0]).isEqualTo(1); + assertThat(currentMediaItemIndex[0]).isEqualTo(1); assertThat(currentPosition[0]).isGreaterThan(0); assertThat(bufferedPosition[0]).isEqualTo(10000); assertThat(totalBufferedDuration[0]).isEqualTo(10000 - currentPosition[0]); - assertThat(currentWindowIndex[1]).isEqualTo(1); + assertThat(currentMediaItemIndex[1]).isEqualTo(1); assertThat(currentPosition[1]).isEqualTo(currentPosition[0]); assertThat(bufferedPosition[1]).isEqualTo(1000); assertThat(totalBufferedDuration[1]).isEqualTo(0); - assertThat(currentWindowIndex[2]).isEqualTo(1); + assertThat(currentMediaItemIndex[2]).isEqualTo(1); assertThat(currentPosition[2]).isEqualTo(currentPosition[0]); assertThat(bufferedPosition[2]).isEqualTo(1000); assertThat(totalBufferedDuration[2]).isEqualTo(0); @@ -1547,21 +1547,21 @@ public final class ExoPlayerTest { Timeline secondTimeline = new FakeTimeline(/* windowCount= */ 2); MediaSource secondSource = new FakeMediaSource(secondTimeline, ExoPlayerTestRunner.VIDEO_FORMAT); - AtomicInteger windowIndexAfterStop = new AtomicInteger(); + AtomicInteger mediaItemIndexAfterStop = new AtomicInteger(); AtomicLong positionAfterStop = new AtomicLong(); ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForPlaybackState(Player.STATE_READY) .stop(/* reset= */ true) .waitForPlaybackState(Player.STATE_IDLE) - .seek(/* windowIndex= */ 1, /* positionMs= */ 1000) + .seek(/* mediaItemIndex= */ 1, /* positionMs= */ 1000) .setMediaSources(secondSource) .prepare() .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { - windowIndexAfterStop.set(player.getCurrentWindowIndex()); + mediaItemIndexAfterStop.set(player.getCurrentMediaItemIndex()); positionAfterStop.set(player.getCurrentPosition()); } }) @@ -1594,7 +1594,7 @@ public final class ExoPlayerTest { Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED, // stop(true) Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED, Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE); - assertThat(windowIndexAfterStop.get()).isEqualTo(1); + assertThat(mediaItemIndexAfterStop.get()).isEqualTo(1); assertThat(positionAfterStop.get()).isAtLeast(1000L); testRunner.assertPlayedPeriodIndices(0, 1); } @@ -1621,8 +1621,8 @@ public final class ExoPlayerTest { new ActionSchedule.Builder(TAG) .pause() .waitForPlaybackState(Player.STATE_READY) - .playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 2000) - .setMediaSources(/* windowIndex= */ 0, /* positionMs= */ 2000, secondSource) + .playUntilPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 2000) + .setMediaSources(/* mediaItemIndex= */ 0, /* positionMs= */ 2000, secondSource) .waitForTimelineChanged( secondTimeline, /* expectedReason */ Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) .executeRunnable( @@ -1675,7 +1675,7 @@ public final class ExoPlayerTest { new ActionSchedule.Builder(TAG) .pause() .waitForPlaybackState(Player.STATE_READY) - .playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 2000) + .playUntilPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 2000) .setMediaSources(/* resetPosition= */ true, secondSource) .waitForTimelineChanged( secondTimeline, /* expectedReason */ Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) @@ -1732,7 +1732,7 @@ public final class ExoPlayerTest { new ActionSchedule.Builder(TAG) .pause() .waitForPlaybackState(Player.STATE_READY) - .playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 2000) + .playUntilPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 2000) .setMediaSources(secondSource) .waitForTimelineChanged( secondTimeline, /* expectedReason */ Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) @@ -1892,7 +1892,7 @@ public final class ExoPlayerTest { throws Exception { ConcatenatingMediaSource concatenatingMediaSource = new ConcatenatingMediaSource(/* isAtomic= */ false, new FakeShuffleOrder(0)); - AtomicInteger windowIndexAfterAddingSources = new AtomicInteger(); + AtomicInteger mediaItemIndexAfterAddingSources = new AtomicInteger(); ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .setShuffleModeEnabled(true) @@ -1909,7 +1909,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - windowIndexAfterAddingSources.set(player.getCurrentWindowIndex()); + mediaItemIndexAfterAddingSources.set(player.getCurrentMediaItemIndex()); } }) .build(); @@ -1920,20 +1920,20 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertThat(windowIndexAfterAddingSources.get()).isEqualTo(1); + assertThat(mediaItemIndexAfterAddingSources.get()).isEqualTo(1); } @Test public void playbackErrorAndReprepareDoesNotResetPosition() throws Exception { final Timeline timeline = new FakeTimeline(/* windowCount= */ 2); final long[] positionHolder = new long[3]; - final int[] windowIndexHolder = new int[3]; + final int[] mediaItemIndexHolder = new int[3]; final FakeMediaSource firstMediaSource = new FakeMediaSource(timeline); ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .pause() .waitForPlaybackState(Player.STATE_READY) - .playUntilPosition(/* windowIndex= */ 1, /* positionMs= */ 500) + .playUntilPosition(/* mediaItemIndex= */ 1, /* positionMs= */ 500) .throwPlaybackException( ExoPlaybackException.createForSource( new IOException(), PlaybackException.ERROR_CODE_IO_UNSPECIFIED)) @@ -1944,7 +1944,7 @@ public final class ExoPlayerTest { public void run(ExoPlayer player) { // Position while in error state positionHolder[0] = player.getCurrentPosition(); - windowIndexHolder[0] = player.getCurrentWindowIndex(); + mediaItemIndexHolder[0] = player.getCurrentMediaItemIndex(); } }) .prepare() @@ -1954,7 +1954,7 @@ public final class ExoPlayerTest { public void run(ExoPlayer player) { // Position while repreparing. positionHolder[1] = player.getCurrentPosition(); - windowIndexHolder[1] = player.getCurrentWindowIndex(); + mediaItemIndexHolder[1] = player.getCurrentMediaItemIndex(); } }) .waitForPlaybackState(Player.STATE_READY) @@ -1964,7 +1964,7 @@ public final class ExoPlayerTest { public void run(ExoPlayer player) { // Position after repreparation finished. positionHolder[2] = player.getCurrentPosition(); - windowIndexHolder[2] = player.getCurrentWindowIndex(); + mediaItemIndexHolder[2] = player.getCurrentMediaItemIndex(); } }) .play() @@ -1983,22 +1983,22 @@ public final class ExoPlayerTest { assertThat(positionHolder[0]).isAtLeast(500L); assertThat(positionHolder[1]).isEqualTo(positionHolder[0]); assertThat(positionHolder[2]).isEqualTo(positionHolder[0]); - assertThat(windowIndexHolder[0]).isEqualTo(1); - assertThat(windowIndexHolder[1]).isEqualTo(1); - assertThat(windowIndexHolder[2]).isEqualTo(1); + assertThat(mediaItemIndexHolder[0]).isEqualTo(1); + assertThat(mediaItemIndexHolder[1]).isEqualTo(1); + assertThat(mediaItemIndexHolder[2]).isEqualTo(1); } @Test public void seekAfterPlaybackError() throws Exception { final Timeline timeline = new FakeTimeline(/* windowCount= */ 2); final long[] positionHolder = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; - final int[] windowIndexHolder = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndexHolder = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; final FakeMediaSource firstMediaSource = new FakeMediaSource(timeline); ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .pause() .waitForPlaybackState(Player.STATE_READY) - .playUntilPosition(/* windowIndex= */ 1, /* positionMs= */ 500) + .playUntilPosition(/* mediaItemIndex= */ 1, /* positionMs= */ 500) .throwPlaybackException( ExoPlaybackException.createForSource( new IOException(), PlaybackException.ERROR_CODE_IO_UNSPECIFIED)) @@ -2009,10 +2009,10 @@ public final class ExoPlayerTest { public void run(ExoPlayer player) { // Position while in error state positionHolder[0] = player.getCurrentPosition(); - windowIndexHolder[0] = player.getCurrentWindowIndex(); + mediaItemIndexHolder[0] = player.getCurrentMediaItemIndex(); } }) - .seek(/* windowIndex= */ 0, /* positionMs= */ C.TIME_UNSET) + .seek(/* mediaItemIndex= */ 0, /* positionMs= */ C.TIME_UNSET) .waitForPendingPlayerCommands() .executeRunnable( new PlayerRunnable() { @@ -2020,7 +2020,7 @@ public final class ExoPlayerTest { public void run(ExoPlayer player) { // Position while in error state positionHolder[1] = player.getCurrentPosition(); - windowIndexHolder[1] = player.getCurrentWindowIndex(); + mediaItemIndexHolder[1] = player.getCurrentMediaItemIndex(); } }) .prepare() @@ -2030,7 +2030,7 @@ public final class ExoPlayerTest { public void run(ExoPlayer player) { // Position after prepare. positionHolder[2] = player.getCurrentPosition(); - windowIndexHolder[2] = player.getCurrentWindowIndex(); + mediaItemIndexHolder[2] = player.getCurrentMediaItemIndex(); } }) .play() @@ -2051,9 +2051,9 @@ public final class ExoPlayerTest { assertThat(positionHolder[0]).isAtLeast(500L); assertThat(positionHolder[1]).isEqualTo(0L); assertThat(positionHolder[2]).isEqualTo(0L); - assertThat(windowIndexHolder[0]).isEqualTo(1); - assertThat(windowIndexHolder[1]).isEqualTo(0); - assertThat(windowIndexHolder[2]).isEqualTo(0); + assertThat(mediaItemIndexHolder[0]).isEqualTo(1); + assertThat(mediaItemIndexHolder[1]).isEqualTo(0); + assertThat(mediaItemIndexHolder[2]).isEqualTo(0); } @Test @@ -2216,7 +2216,7 @@ public final class ExoPlayerTest { .pause() .sendMessage( (messageType, payload) -> counter.getAndIncrement(), - /* windowIndex= */ 0, + /* mediaItemIndex= */ 0, /* positionMs= */ 2000, /* deleteAfterDelivery= */ false) .seek(/* positionMs= */ 2000) @@ -2290,23 +2290,23 @@ public final class ExoPlayerTest { long duration2Ms = timeline.getWindow(1, new Window()).getDurationMs(); ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) - .sendMessage(targetStartFirstPeriod, /* windowIndex= */ 0, /* positionMs= */ 0) + .sendMessage(targetStartFirstPeriod, /* mediaItemIndex= */ 0, /* positionMs= */ 0) .sendMessage( targetEndMiddlePeriodResolved, - /* windowIndex= */ 0, + /* mediaItemIndex= */ 0, /* positionMs= */ duration1Ms - 1) .sendMessage( targetEndMiddlePeriodUnresolved, - /* windowIndex= */ 0, + /* mediaItemIndex= */ 0, /* positionMs= */ C.TIME_END_OF_SOURCE) - .sendMessage(targetStartMiddlePeriod, /* windowIndex= */ 1, /* positionMs= */ 0) + .sendMessage(targetStartMiddlePeriod, /* mediaItemIndex= */ 1, /* positionMs= */ 0) .sendMessage( targetEndLastPeriodResolved, - /* windowIndex= */ 1, + /* mediaItemIndex= */ 1, /* positionMs= */ duration2Ms - 1) .sendMessage( targetEndLastPeriodUnresolved, - /* windowIndex= */ 1, + /* mediaItemIndex= */ 1, /* positionMs= */ C.TIME_END_OF_SOURCE) .waitForMessage(targetEndLastPeriodUnresolved) .build(); @@ -2317,19 +2317,19 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertThat(targetStartFirstPeriod.windowIndex).isEqualTo(0); + assertThat(targetStartFirstPeriod.mediaItemIndex).isEqualTo(0); assertThat(targetStartFirstPeriod.positionMs).isAtLeast(0L); - assertThat(targetEndMiddlePeriodResolved.windowIndex).isEqualTo(0); + assertThat(targetEndMiddlePeriodResolved.mediaItemIndex).isEqualTo(0); assertThat(targetEndMiddlePeriodResolved.positionMs).isAtLeast(duration1Ms - 1); - assertThat(targetEndMiddlePeriodUnresolved.windowIndex).isEqualTo(0); + assertThat(targetEndMiddlePeriodUnresolved.mediaItemIndex).isEqualTo(0); assertThat(targetEndMiddlePeriodUnresolved.positionMs).isAtLeast(duration1Ms - 1); assertThat(targetEndMiddlePeriodResolved.positionMs) .isEqualTo(targetEndMiddlePeriodUnresolved.positionMs); - assertThat(targetStartMiddlePeriod.windowIndex).isEqualTo(1); + assertThat(targetStartMiddlePeriod.mediaItemIndex).isEqualTo(1); assertThat(targetStartMiddlePeriod.positionMs).isAtLeast(0L); - assertThat(targetEndLastPeriodResolved.windowIndex).isEqualTo(1); + assertThat(targetEndLastPeriodResolved.mediaItemIndex).isEqualTo(1); assertThat(targetEndLastPeriodResolved.positionMs).isAtLeast(duration2Ms - 1); - assertThat(targetEndLastPeriodUnresolved.windowIndex).isEqualTo(1); + assertThat(targetEndLastPeriodUnresolved.mediaItemIndex).isEqualTo(1); assertThat(targetEndLastPeriodUnresolved.positionMs).isAtLeast(duration2Ms - 1); assertThat(targetEndLastPeriodResolved.positionMs) .isEqualTo(targetEndLastPeriodUnresolved.positionMs); @@ -2445,12 +2445,12 @@ public final class ExoPlayerTest { .waitForPlaybackState(Player.STATE_BUFFERING) .sendMessage( target, - /* windowIndex= */ 0, + /* mediaItemIndex= */ 0, /* positionMs= */ 50, /* deleteAfterDelivery= */ false) .setRepeatMode(Player.REPEAT_MODE_ALL) - .playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 1) - .playUntilStartOfWindow(/* windowIndex= */ 0) + .playUntilPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 1) + .playUntilStartOfMediaItem(/* mediaItemIndex= */ 0) .setRepeatMode(Player.REPEAT_MODE_OFF) .play() .build(); @@ -2464,7 +2464,7 @@ public final class ExoPlayerTest { } @Test - public void sendMessagesMoveCurrentWindowIndex() throws Exception { + public void sendMessagesMoveCurrentMediaItemIndex() throws Exception { Timeline timeline = new FakeTimeline(new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 0)); final Timeline secondTimeline = @@ -2492,7 +2492,7 @@ public final class ExoPlayerTest { .start() .blockUntilEnded(TIMEOUT_MS); assertThat(target.positionMs).isAtLeast(50L); - assertThat(target.windowIndex).isEqualTo(1); + assertThat(target.mediaItemIndex).isEqualTo(1); } @Test @@ -2503,7 +2503,7 @@ public final class ExoPlayerTest { new ActionSchedule.Builder(TAG) .pause() .waitForTimelineChanged(timeline, Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) - .sendMessage(target, /* windowIndex = */ 2, /* positionMs= */ 50) + .sendMessage(target, /* mediaItemIndex = */ 2, /* positionMs= */ 50) .play() .build(); new ExoPlayerTestRunner.Builder(context) @@ -2512,7 +2512,7 @@ public final class ExoPlayerTest { .build() .start() .blockUntilEnded(TIMEOUT_MS); - assertThat(target.windowIndex).isEqualTo(2); + assertThat(target.mediaItemIndex).isEqualTo(2); assertThat(target.positionMs).isAtLeast(50L); } @@ -2525,7 +2525,7 @@ public final class ExoPlayerTest { .pause() .waitForTimelineChanged( timeline, /* expectedReason */ Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) - .sendMessage(target, /* windowIndex = */ 2, /* positionMs= */ 50) + .sendMessage(target, /* mediaItemIndex = */ 2, /* positionMs= */ 50) .play() .build(); new ExoPlayerTestRunner.Builder(context) @@ -2534,12 +2534,12 @@ public final class ExoPlayerTest { .build() .start() .blockUntilEnded(TIMEOUT_MS); - assertThat(target.windowIndex).isEqualTo(2); + assertThat(target.mediaItemIndex).isEqualTo(2); assertThat(target.positionMs).isAtLeast(50L); } @Test - public void sendMessagesMoveWindowIndex() throws Exception { + public void sendMessagesMoveMediaItemIndex() throws Exception { Timeline timeline = new FakeTimeline( new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 0), @@ -2556,11 +2556,11 @@ public final class ExoPlayerTest { .pause() .waitForTimelineChanged( timeline, /* expectedReason */ Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) - .sendMessage(target, /* windowIndex = */ 1, /* positionMs= */ 50) + .sendMessage(target, /* mediaItemIndex = */ 1, /* positionMs= */ 50) .executeRunnable(() -> mediaSource.setNewSourceInfo(secondTimeline)) .waitForTimelineChanged( secondTimeline, /* expectedReason */ Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) - .seek(/* windowIndex= */ 0, /* positionMs= */ 0) + .seek(/* mediaItemIndex= */ 0, /* positionMs= */ 0) .play() .build(); new ExoPlayerTestRunner.Builder(context) @@ -2570,7 +2570,7 @@ public final class ExoPlayerTest { .start() .blockUntilEnded(TIMEOUT_MS); assertThat(target.positionMs).isAtLeast(50L); - assertThat(target.windowIndex).isEqualTo(0); + assertThat(target.mediaItemIndex).isEqualTo(0); } @Test @@ -2590,11 +2590,11 @@ public final class ExoPlayerTest { new ActionSchedule.Builder(TAG) .pause() .waitForPlaybackState(Player.STATE_READY) - .sendMessage(target1, /* windowIndex = */ 0, /* positionMs= */ 50) - .sendMessage(target2, /* windowIndex = */ 1, /* positionMs= */ 50) - .sendMessage(target3, /* windowIndex = */ 2, /* positionMs= */ 50) + .sendMessage(target1, /* mediaItemIndex = */ 0, /* positionMs= */ 50) + .sendMessage(target2, /* mediaItemIndex = */ 1, /* positionMs= */ 50) + .sendMessage(target3, /* mediaItemIndex = */ 2, /* positionMs= */ 50) .setShuffleModeEnabled(true) - .seek(/* windowIndex= */ 2, /* positionMs= */ 0) + .seek(/* mediaItemIndex= */ 2, /* positionMs= */ 0) .play() .build(); new ExoPlayerTestRunner.Builder(context) @@ -2603,9 +2603,9 @@ public final class ExoPlayerTest { .build() .start() .blockUntilEnded(TIMEOUT_MS); - assertThat(target1.windowIndex).isEqualTo(0); - assertThat(target2.windowIndex).isEqualTo(1); - assertThat(target3.windowIndex).isEqualTo(2); + assertThat(target1.mediaItemIndex).isEqualTo(0); + assertThat(target2.mediaItemIndex).isEqualTo(1); + assertThat(target3.mediaItemIndex).isEqualTo(2); } @Test @@ -2625,7 +2625,7 @@ public final class ExoPlayerTest { } }) // Play a bit to ensure message arrived in internal player. - .playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 30) + .playUntilPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 30) .executeRunnable(() -> message.get().cancel()) .play() .build(); @@ -2659,7 +2659,7 @@ public final class ExoPlayerTest { } }) // Play until the message has been delivered. - .playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 51) + .playUntilPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 51) // Seek back, cancel the message, and play past the same position again. .seek(/* positionMs= */ 0) .executeRunnable(() -> message.get().cancel()) @@ -2681,13 +2681,13 @@ public final class ExoPlayerTest { player.addMediaSources(ImmutableList.of(new FakeMediaSource(), new FakeMediaSource())); player .createMessage((messageType, payload) -> {}) - .setPosition(/* windowIndex= */ 0, /* positionMs= */ 0) + .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 0) .setDeleteAfterDelivery(false) .send(); PlayerMessage.Target secondMediaItemTarget = mock(PlayerMessage.Target.class); player .createMessage(secondMediaItemTarget) - .setPosition(/* windowIndex= */ 1, /* positionMs= */ 0) + .setPosition(/* mediaItemIndex= */ 1, /* positionMs= */ 0) .setDeleteAfterDelivery(false) .send(); @@ -2765,7 +2765,7 @@ public final class ExoPlayerTest { .waitForPlaybackState(Player.STATE_READY) // Ensure next period is pre-buffered by playing until end of first period. .playUntilPosition( - /* windowIndex= */ 0, + /* mediaItemIndex= */ 0, /* positionMs= */ Util.usToMs(TimelineWindowDefinition.DEFAULT_WINDOW_DURATION_US)) .executeRunnable(() -> mediaSource.setNewSourceInfo(timeline2)) .waitForTimelineChanged( @@ -2921,12 +2921,12 @@ public final class ExoPlayerTest { new ActionSchedule.Builder(TAG) .pause() .waitForPlaybackState(Player.STATE_READY) - .seek(/* windowIndex= */ 0, /* positionMs= */ 9999) + .seek(/* mediaItemIndex= */ 0, /* positionMs= */ 9999) // Wait after each seek until the internal player has updated its state. .waitForPendingPlayerCommands() - .seek(/* windowIndex= */ 0, /* positionMs= */ 1) + .seek(/* mediaItemIndex= */ 0, /* positionMs= */ 1) .waitForPendingPlayerCommands() - .seek(/* windowIndex= */ 0, /* positionMs= */ 9999) + .seek(/* mediaItemIndex= */ 0, /* positionMs= */ 9999) .waitForPendingPlayerCommands() .play() .build(); @@ -2988,7 +2988,7 @@ public final class ExoPlayerTest { } catch (InterruptedException e) { throw new IllegalStateException(e); } - player.seekTo(/* windowIndex= */ 0, /* positionMs= */ 1000L); + player.seekTo(/* mediaItemIndex= */ 0, /* positionMs= */ 1000L); } }) .waitForPendingPlayerCommands() @@ -3254,8 +3254,8 @@ public final class ExoPlayerTest { .setRepeatMode(Player.REPEAT_MODE_ALL) .waitForPlaybackState(Player.STATE_READY) // Play until the media repeats once. - .playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 1) - .playUntilStartOfWindow(/* windowIndex= */ 0) + .playUntilPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 1) + .playUntilStartOfMediaItem(/* mediaItemIndex= */ 0) .setRepeatMode(Player.REPEAT_MODE_OFF) .play() .build(); @@ -3289,7 +3289,7 @@ public final class ExoPlayerTest { new ActionSchedule.Builder(TAG) .pause() .waitForPlaybackState(Player.STATE_READY) - .seek(/* windowIndex= */ 1, /* positionMs= */ 0) + .seek(/* mediaItemIndex= */ 1, /* positionMs= */ 0) .waitForPendingPlayerCommands() .play() .build(); @@ -3337,7 +3337,7 @@ public final class ExoPlayerTest { .pause() .waitForPlaybackState(Player.STATE_READY) // Play almost to end to ensure the current period is fully buffered. - .playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 90) + .playUntilPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 90) // Enable repeat mode to trigger the creation of new media periods. .setRepeatMode(Player.REPEAT_MODE_ALL) // Remove the media source. @@ -3852,20 +3852,20 @@ public final class ExoPlayerTest { return Timeline.EMPTY; } }; - int[] currentWindowIndices = new int[1]; + int[] currentMediaItemIndices = new int[1]; long[] currentPlaybackPositions = new long[1]; long[] windowCounts = new long[1]; - int seekToWindowIndex = 1; + int seekToMediaItemIndex = 1; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) - .seek(/* windowIndex= */ 1, /* positionMs= */ 5000) + .seek(/* mediaItemIndex= */ 1, /* positionMs= */ 5000) .waitForTimelineChanged( /* expectedTimeline= */ null, Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); currentPlaybackPositions[0] = player.getCurrentPosition(); windowCounts[0] = player.getCurrentTimeline().getWindowCount(); } @@ -3882,23 +3882,23 @@ public final class ExoPlayerTest { exoPlayerTestRunner.assertTimelineChangeReasonsEqual( Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE); assertArrayEquals(new long[] {2}, windowCounts); - assertArrayEquals(new int[] {seekToWindowIndex}, currentWindowIndices); + assertArrayEquals(new int[] {seekToMediaItemIndex}, currentMediaItemIndices); assertArrayEquals(new long[] {5_000}, currentPlaybackPositions); } @SuppressWarnings("deprecation") @Test - public void seekTo_windowIndexIsReset_deprecated() throws Exception { + public void seekTo_mediaItemIndexIsReset_deprecated() throws Exception { FakeTimeline fakeTimeline = new FakeTimeline(); FakeMediaSource mediaSource = new FakeMediaSource(fakeTimeline); - final int[] windowIndex = {C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET}; final long[] positionMs = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; final long[] bufferedPositions = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .pause() - .seek(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET) - .playUntilPosition(/* windowIndex= */ 1, /* positionMs= */ 3000) + .seek(/* mediaItemIndex= */ 1, /* positionMs= */ C.TIME_UNSET) + .playUntilPosition(/* mediaItemIndex= */ 1, /* positionMs= */ 3000) .executeRunnable( new PlayerRunnable() { @Override @@ -3917,7 +3917,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - windowIndex[0] = player.getCurrentWindowIndex(); + mediaItemIndex[0] = player.getCurrentMediaItemIndex(); positionMs[2] = player.getCurrentPosition(); bufferedPositions[2] = player.getBufferedPosition(); } @@ -3930,7 +3930,7 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isAtLeast(3000L); assertThat(positionMs[1]).isEqualTo(7000L); assertThat(positionMs[2]).isEqualTo(7000L); @@ -3941,17 +3941,17 @@ public final class ExoPlayerTest { } @Test - public void seekTo_windowIndexIsReset() throws Exception { + public void seekTo_mediaItemIndexIsReset() throws Exception { FakeTimeline fakeTimeline = new FakeTimeline(); FakeMediaSource mediaSource = new FakeMediaSource(fakeTimeline); - final int[] windowIndex = {C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET}; final long[] positionMs = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; final long[] bufferedPositions = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .pause() - .seek(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET) - .playUntilPosition(/* windowIndex= */ 1, /* positionMs= */ 3000) + .seek(/* mediaItemIndex= */ 1, /* positionMs= */ C.TIME_UNSET) + .playUntilPosition(/* mediaItemIndex= */ 1, /* positionMs= */ 3000) .pause() .executeRunnable( new PlayerRunnable() { @@ -3970,7 +3970,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - windowIndex[0] = player.getCurrentWindowIndex(); + mediaItemIndex[0] = player.getCurrentMediaItemIndex(); positionMs[2] = player.getCurrentPosition(); bufferedPositions[2] = player.getBufferedPosition(); } @@ -3983,7 +3983,7 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isAtLeast(3000); assertThat(positionMs[1]).isEqualTo(7000); assertThat(positionMs[2]).isEqualTo(7000); @@ -3995,7 +3995,7 @@ public final class ExoPlayerTest { @Test public void seekTo_singlePeriod_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4007,19 +4007,19 @@ public final class ExoPlayerTest { player.seekTo(9000); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 9200)); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isEqualTo(9000); assertThat(bufferedPositions[0]).isEqualTo(9200); assertThat(totalBufferedDuration[0]).isEqualTo(200); - assertThat(windowIndex[1]).isEqualTo(windowIndex[0]); + assertThat(mediaItemIndex[1]).isEqualTo(mediaItemIndex[0]); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(9200); assertThat(totalBufferedDuration[1]).isEqualTo(200); @@ -4027,7 +4027,7 @@ public final class ExoPlayerTest { @Test public void seekTo_singlePeriod_beyondBufferedData_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4039,19 +4039,19 @@ public final class ExoPlayerTest { player.seekTo(9200); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 9200)); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isEqualTo(9200); assertThat(bufferedPositions[0]).isEqualTo(9200); assertThat(totalBufferedDuration[0]).isEqualTo(0); - assertThat(windowIndex[1]).isEqualTo(windowIndex[0]); + assertThat(mediaItemIndex[1]).isEqualTo(mediaItemIndex[0]); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(9200); assertThat(totalBufferedDuration[1]).isEqualTo(0); @@ -4059,7 +4059,7 @@ public final class ExoPlayerTest { @Test public void seekTo_backwardsSinglePeriod_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4071,14 +4071,14 @@ public final class ExoPlayerTest { player.seekTo(1000); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 9200)); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isEqualTo(1000); assertThat(bufferedPositions[0]).isEqualTo(1000); assertThat(totalBufferedDuration[0]).isEqualTo(0); @@ -4086,7 +4086,7 @@ public final class ExoPlayerTest { @Test public void seekTo_backwardsMultiplePeriods_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4098,8 +4098,8 @@ public final class ExoPlayerTest { player.seekTo(0, 1000); } }, - /* pauseWindowIndex= */ 1, - windowIndex, + /* pauseMediaItemIndex= */ 1, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, @@ -4107,7 +4107,7 @@ public final class ExoPlayerTest { new FakeMediaSource(), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 9200)); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isEqualTo(1000); assertThat(bufferedPositions[0]).isEqualTo(1000); assertThat(totalBufferedDuration[0]).isEqualTo(0); @@ -4115,7 +4115,7 @@ public final class ExoPlayerTest { @Test public void seekTo_toUnbufferedPeriod_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4127,8 +4127,8 @@ public final class ExoPlayerTest { player.seekTo(2, 1000); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, @@ -4136,12 +4136,12 @@ public final class ExoPlayerTest { new FakeMediaSource(), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 0)); - assertThat(windowIndex[0]).isEqualTo(2); + assertThat(mediaItemIndex[0]).isEqualTo(2); assertThat(positionMs[0]).isEqualTo(1000); assertThat(bufferedPositions[0]).isEqualTo(1000); assertThat(totalBufferedDuration[0]).isEqualTo(0); - assertThat(windowIndex[1]).isEqualTo(2); + assertThat(mediaItemIndex[1]).isEqualTo(2); assertThat(positionMs[1]).isEqualTo(1000); assertThat(bufferedPositions[1]).isEqualTo(1000); assertThat(totalBufferedDuration[1]).isEqualTo(0); @@ -4149,7 +4149,7 @@ public final class ExoPlayerTest { @Test public void seekTo_toLoadingPeriod_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4161,22 +4161,22 @@ public final class ExoPlayerTest { player.seekTo(1, 1000); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, new FakeMediaSource(), new FakeMediaSource()); - assertThat(windowIndex[0]).isEqualTo(1); + assertThat(mediaItemIndex[0]).isEqualTo(1); assertThat(positionMs[0]).isEqualTo(1000); // TODO(b/160450903): Verify masking of buffering properties when behaviour in EPII is fully // covered. // assertThat(bufferedPositions[0]).isEqualTo(10_000); // assertThat(totalBufferedDuration[0]).isEqualTo(10_000 - positionMs[0]); - assertThat(windowIndex[1]).isEqualTo(windowIndex[0]); + assertThat(mediaItemIndex[1]).isEqualTo(mediaItemIndex[0]); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(10_000); assertThat(totalBufferedDuration[1]).isEqualTo(10_000 - positionMs[1]); @@ -4185,7 +4185,7 @@ public final class ExoPlayerTest { @Test public void seekTo_toLoadingPeriod_withinPartiallyBufferedData_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4197,22 +4197,22 @@ public final class ExoPlayerTest { player.seekTo(1, 1000); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, new FakeMediaSource(), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 4000)); - assertThat(windowIndex[0]).isEqualTo(1); + assertThat(mediaItemIndex[0]).isEqualTo(1); assertThat(positionMs[0]).isEqualTo(1000); // TODO(b/160450903): Verify masking of buffering properties when behaviour in EPII is fully // covered. // assertThat(bufferedPositions[0]).isEqualTo(1000); // assertThat(totalBufferedDuration[0]).isEqualTo(0); - assertThat(windowIndex[1]).isEqualTo(windowIndex[0]); + assertThat(mediaItemIndex[1]).isEqualTo(mediaItemIndex[0]); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(4000); assertThat(totalBufferedDuration[1]).isEqualTo(3000); @@ -4220,7 +4220,7 @@ public final class ExoPlayerTest { @Test public void seekTo_toLoadingPeriod_beyondBufferedData_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4232,20 +4232,20 @@ public final class ExoPlayerTest { player.seekTo(1, 5000); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, new FakeMediaSource(), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 4000)); - assertThat(windowIndex[0]).isEqualTo(1); + assertThat(mediaItemIndex[0]).isEqualTo(1); assertThat(positionMs[0]).isEqualTo(5000); assertThat(bufferedPositions[0]).isEqualTo(5000); assertThat(totalBufferedDuration[0]).isEqualTo(0); - assertThat(windowIndex[1]).isEqualTo(1); + assertThat(mediaItemIndex[1]).isEqualTo(1); assertThat(positionMs[1]).isEqualTo(5000); assertThat(bufferedPositions[1]).isEqualTo(5000); assertThat(totalBufferedDuration[1]).isEqualTo(0); @@ -4253,7 +4253,7 @@ public final class ExoPlayerTest { @Test public void seekTo_toInnerFullyBufferedPeriod_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4265,8 +4265,8 @@ public final class ExoPlayerTest { player.seekTo(1, 5000); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, @@ -4274,14 +4274,14 @@ public final class ExoPlayerTest { new FakeMediaSource(), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 4000)); - assertThat(windowIndex[0]).isEqualTo(1); + assertThat(mediaItemIndex[0]).isEqualTo(1); assertThat(positionMs[0]).isEqualTo(5000); // TODO(b/160450903): Verify masking of buffering properties when behaviour in EPII is fully // covered. // assertThat(bufferedPositions[0]).isEqualTo(10_000); // assertThat(totalBufferedDuration[0]).isEqualTo(10_000 - positionMs[0]); - assertThat(windowIndex[1]).isEqualTo(windowIndex[0]); + assertThat(mediaItemIndex[1]).isEqualTo(mediaItemIndex[0]); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(10_000); assertThat(totalBufferedDuration[1]).isEqualTo(10_000 - positionMs[1]); @@ -4289,7 +4289,7 @@ public final class ExoPlayerTest { @Test public void addMediaSource_withinBufferedPeriods_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4302,20 +4302,20 @@ public final class ExoPlayerTest { /* index= */ 1, createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 0)); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, new FakeMediaSource(), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 4000)); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isAtLeast(8000); assertThat(bufferedPositions[0]).isEqualTo(10_000); assertThat(totalBufferedDuration[0]).isEqualTo(10_000 - positionMs[0]); - assertThat(windowIndex[1]).isEqualTo(windowIndex[0]); + assertThat(mediaItemIndex[1]).isEqualTo(mediaItemIndex[0]); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(10_000); assertThat(totalBufferedDuration[1]).isEqualTo(10_000 - positionMs[1]); @@ -4323,7 +4323,7 @@ public final class ExoPlayerTest { @Test public void moveMediaItem_behindLoadingPeriod_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4335,8 +4335,8 @@ public final class ExoPlayerTest { player.moveMediaItem(/* currentIndex= */ 1, /* newIndex= */ 2); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, @@ -4344,12 +4344,12 @@ public final class ExoPlayerTest { new FakeMediaSource(), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 4000)); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isAtLeast(8000); assertThat(bufferedPositions[0]).isEqualTo(10_000); assertThat(totalBufferedDuration[0]).isEqualTo(10_000 - positionMs[0]); - assertThat(windowIndex[1]).isEqualTo(windowIndex[0]); + assertThat(mediaItemIndex[1]).isEqualTo(mediaItemIndex[0]); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(10_000); assertThat(totalBufferedDuration[1]).isEqualTo(10_000 - positionMs[1]); @@ -4357,7 +4357,7 @@ public final class ExoPlayerTest { @Test public void moveMediaItem_undloadedBehindPlaying_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4369,8 +4369,8 @@ public final class ExoPlayerTest { player.moveMediaItem(/* currentIndex= */ 3, /* newIndex= */ 1); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, @@ -4379,12 +4379,12 @@ public final class ExoPlayerTest { createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 4000), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 0)); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isAtLeast(8000); assertThat(bufferedPositions[0]).isEqualTo(10_000); assertThat(totalBufferedDuration[0]).isEqualTo(10_000 - positionMs[0]); - assertThat(windowIndex[1]).isEqualTo(windowIndex[0]); + assertThat(mediaItemIndex[1]).isEqualTo(mediaItemIndex[0]); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(10000); assertThat(totalBufferedDuration[1]).isEqualTo(10_000 - positionMs[1]); @@ -4392,7 +4392,7 @@ public final class ExoPlayerTest { @Test public void removeMediaItem_removePlayingWindow_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4404,22 +4404,22 @@ public final class ExoPlayerTest { player.removeMediaItem(/* index= */ 0); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, new FakeMediaSource(), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 4000)); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isEqualTo(0); // TODO(b/160450903): Verify masking of buffering properties when behaviour in EPII is fully // covered. // assertThat(bufferedPositions[0]).isEqualTo(4000); // assertThat(totalBufferedDuration[0]).isEqualTo(4000); - assertThat(windowIndex[1]).isEqualTo(windowIndex[0]); + assertThat(mediaItemIndex[1]).isEqualTo(mediaItemIndex[0]); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(4000); assertThat(totalBufferedDuration[1]).isEqualTo(4000); @@ -4427,7 +4427,7 @@ public final class ExoPlayerTest { @Test public void removeMediaItem_removeLoadingWindow_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4439,8 +4439,8 @@ public final class ExoPlayerTest { player.removeMediaItem(/* index= */ 2); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, @@ -4448,12 +4448,12 @@ public final class ExoPlayerTest { new FakeMediaSource(), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 4000)); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isAtLeast(8000); assertThat(bufferedPositions[0]).isEqualTo(10_000); assertThat(totalBufferedDuration[0]).isEqualTo(10_000 - positionMs[0]); - assertThat(windowIndex[1]).isEqualTo(windowIndex[0]); + assertThat(mediaItemIndex[1]).isEqualTo(mediaItemIndex[0]); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(10_000); assertThat(totalBufferedDuration[1]).isEqualTo(10_000 - positionMs[1]); @@ -4462,7 +4462,7 @@ public final class ExoPlayerTest { @Test public void removeMediaItem_removeInnerFullyBufferedWindow_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4474,8 +4474,8 @@ public final class ExoPlayerTest { player.removeMediaItem(/* index= */ 1); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, @@ -4483,12 +4483,12 @@ public final class ExoPlayerTest { new FakeMediaSource(), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 4000)); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isEqualTo(8000); assertThat(bufferedPositions[0]).isEqualTo(10_000); assertThat(totalBufferedDuration[0]).isEqualTo(10_000 - positionMs[0]); - assertThat(windowIndex[1]).isEqualTo(0); + assertThat(mediaItemIndex[1]).isEqualTo(0); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(10_000); assertThat(totalBufferedDuration[1]).isEqualTo(10_000 - positionMs[0]); @@ -4496,7 +4496,7 @@ public final class ExoPlayerTest { @Test public void clearMediaItems_correctMaskingPosition() throws Exception { - final int[] windowIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] mediaItemIndex = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] positionMs = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] bufferedPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] totalBufferedDuration = {C.INDEX_UNSET, C.INDEX_UNSET}; @@ -4508,8 +4508,8 @@ public final class ExoPlayerTest { player.clearMediaItems(); } }, - /* pauseWindowIndex= */ 0, - windowIndex, + /* pauseMediaItemIndex= */ 0, + mediaItemIndex, positionMs, bufferedPositions, totalBufferedDuration, @@ -4517,12 +4517,12 @@ public final class ExoPlayerTest { new FakeMediaSource(), createPartiallyBufferedMediaSource(/* maxBufferedPositionMs= */ 4000)); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(positionMs[0]).isEqualTo(0); assertThat(bufferedPositions[0]).isEqualTo(0); assertThat(totalBufferedDuration[0]).isEqualTo(0); - assertThat(windowIndex[1]).isEqualTo(windowIndex[0]); + assertThat(mediaItemIndex[1]).isEqualTo(mediaItemIndex[0]); assertThat(positionMs[1]).isEqualTo(positionMs[0]); assertThat(bufferedPositions[1]).isEqualTo(bufferedPositions[0]); assertThat(totalBufferedDuration[1]).isEqualTo(totalBufferedDuration[0]); @@ -4530,8 +4530,8 @@ public final class ExoPlayerTest { private void runPositionMaskingCapturingActionSchedule( PlayerRunnable actionRunnable, - int pauseWindowIndex, - int[] windowIndex, + int pauseMediaItemIndex, + int[] mediaItemIndex, long[] positionMs, long[] bufferedPosition, long[] totalBufferedDuration, @@ -4539,13 +4539,13 @@ public final class ExoPlayerTest { throws Exception { ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) - .playUntilPosition(pauseWindowIndex, /* positionMs= */ 8000) + .playUntilPosition(pauseMediaItemIndex, /* positionMs= */ 8000) .executeRunnable(actionRunnable) .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { - windowIndex[0] = player.getCurrentWindowIndex(); + mediaItemIndex[0] = player.getCurrentMediaItemIndex(); positionMs[0] = player.getCurrentPosition(); bufferedPosition[0] = player.getBufferedPosition(); totalBufferedDuration[0] = player.getTotalBufferedDuration(); @@ -4556,7 +4556,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - windowIndex[1] = player.getCurrentWindowIndex(); + mediaItemIndex[1] = player.getCurrentMediaItemIndex(); positionMs[1] = player.getCurrentPosition(); bufferedPosition[1] = player.getBufferedPosition(); totalBufferedDuration[1] = player.getTotalBufferedDuration(); @@ -4637,7 +4637,7 @@ public final class ExoPlayerTest { /* durationUs= */ Util.msToUs(contentDurationMs), adPlaybackState)); FakeMediaSource adsMediaSource = new FakeMediaSource(adTimeline); - int[] windowIndex = new int[] {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + int[] mediaItemIndex = new int[] {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; long[] positionMs = new long[] {C.TIME_UNSET, C.TIME_UNSET, C.INDEX_UNSET}; long[] bufferedPositionMs = new long[] {C.TIME_UNSET, C.TIME_UNSET, C.INDEX_UNSET}; long[] totalBufferedDurationMs = new long[] {C.TIME_UNSET, C.TIME_UNSET, C.INDEX_UNSET}; @@ -4653,7 +4653,7 @@ public final class ExoPlayerTest { @Override public void run(ExoPlayer player) { player.addMediaSource(/* index= */ 1, new FakeMediaSource()); - windowIndex[0] = player.getCurrentWindowIndex(); + mediaItemIndex[0] = player.getCurrentMediaItemIndex(); isPlayingAd[0] = player.isPlayingAd(); positionMs[0] = player.getCurrentPosition(); bufferedPositionMs[0] = player.getBufferedPosition(); @@ -4665,21 +4665,21 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - windowIndex[1] = player.getCurrentWindowIndex(); + mediaItemIndex[1] = player.getCurrentMediaItemIndex(); isPlayingAd[1] = player.isPlayingAd(); positionMs[1] = player.getCurrentPosition(); bufferedPositionMs[1] = player.getBufferedPosition(); totalBufferedDurationMs[1] = player.getTotalBufferedDuration(); } }) - .playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 8000) + .playUntilPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 8000) .waitForPendingPlayerCommands() .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { player.addMediaSource(new FakeMediaSource()); - windowIndex[2] = player.getCurrentWindowIndex(); + mediaItemIndex[2] = player.getCurrentMediaItemIndex(); isPlayingAd[2] = player.isPlayingAd(); positionMs[2] = player.getCurrentPosition(); bufferedPositionMs[2] = player.getBufferedPosition(); @@ -4697,19 +4697,19 @@ public final class ExoPlayerTest { .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(isPlayingAd[0]).isTrue(); assertThat(positionMs[0]).isAtMost(adDurationMs); assertThat(bufferedPositionMs[0]).isEqualTo(adDurationMs); assertThat(totalBufferedDurationMs[0]).isAtLeast(adDurationMs - positionMs[0]); - assertThat(windowIndex[1]).isEqualTo(0); + assertThat(mediaItemIndex[1]).isEqualTo(0); assertThat(isPlayingAd[1]).isTrue(); assertThat(positionMs[1]).isAtMost(adDurationMs); assertThat(bufferedPositionMs[1]).isEqualTo(adDurationMs); assertThat(totalBufferedDurationMs[1]).isAtLeast(adDurationMs - positionMs[1]); - assertThat(windowIndex[2]).isEqualTo(0); + assertThat(mediaItemIndex[2]).isEqualTo(0); assertThat(isPlayingAd[2]).isFalse(); assertThat(positionMs[2]).isEqualTo(8000); assertThat(bufferedPositionMs[2]).isEqualTo(contentDurationMs); @@ -4738,7 +4738,7 @@ public final class ExoPlayerTest { /* durationUs= */ Util.msToUs(contentDurationMs), adPlaybackState)); FakeMediaSource adsMediaSource = new FakeMediaSource(adTimeline); - int[] windowIndex = new int[] {C.INDEX_UNSET, C.INDEX_UNSET}; + int[] mediaItemIndex = new int[] {C.INDEX_UNSET, C.INDEX_UNSET}; long[] positionMs = new long[] {C.TIME_UNSET, C.TIME_UNSET}; long[] bufferedPositionMs = new long[] {C.TIME_UNSET, C.TIME_UNSET}; long[] totalBufferedDurationMs = new long[] {C.TIME_UNSET, C.TIME_UNSET}; @@ -4753,8 +4753,8 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - player.seekTo(/* windowIndex= */ 0, /* positionMs= */ 8000); - windowIndex[0] = player.getCurrentWindowIndex(); + player.seekTo(/* mediaItemIndex= */ 0, /* positionMs= */ 8000); + mediaItemIndex[0] = player.getCurrentMediaItemIndex(); isPlayingAd[0] = player.isPlayingAd(); positionMs[0] = player.getCurrentPosition(); bufferedPositionMs[0] = player.getBufferedPosition(); @@ -4766,7 +4766,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - windowIndex[1] = player.getCurrentWindowIndex(); + mediaItemIndex[1] = player.getCurrentMediaItemIndex(); isPlayingAd[1] = player.isPlayingAd(); positionMs[1] = player.getCurrentPosition(); bufferedPositionMs[1] = player.getBufferedPosition(); @@ -4784,13 +4784,13 @@ public final class ExoPlayerTest { .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertThat(windowIndex[0]).isEqualTo(0); + assertThat(mediaItemIndex[0]).isEqualTo(0); assertThat(isPlayingAd[0]).isTrue(); assertThat(positionMs[0]).isEqualTo(0); assertThat(bufferedPositionMs[0]).isEqualTo(adDurationMs); assertThat(totalBufferedDurationMs[0]).isEqualTo(adDurationMs); - assertThat(windowIndex[1]).isEqualTo(0); + assertThat(mediaItemIndex[1]).isEqualTo(0); assertThat(isPlayingAd[1]).isTrue(); assertThat(positionMs[1]).isEqualTo(0); assertThat(bufferedPositionMs[1]).isEqualTo(adDurationMs); @@ -5332,7 +5332,7 @@ public final class ExoPlayerTest { .addMediaSources(new FakeMediaSource()) .executeRunnable( new PlaybackStateCollector(/* index= */ 3, playbackStates, timelineWindowCounts)) - .seek(/* windowIndex= */ 1, /* positionMs= */ 2000) + .seek(/* mediaItemIndex= */ 1, /* positionMs= */ 2000) .prepare() // The first expected buffering state arrives after prepare but not before. .waitForPlaybackState(Player.STATE_BUFFERING) @@ -5502,7 +5502,7 @@ public final class ExoPlayerTest { @Test public void prepareWithInvalidInitialSeek_expectEndedImmediately() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET}; + final int[] currentMediaItemIndices = {C.INDEX_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForPlaybackState(Player.STATE_ENDED) @@ -5510,7 +5510,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); } }) .prepare() @@ -5518,7 +5518,7 @@ public final class ExoPlayerTest { ExoPlayerTestRunner exoPlayerTestRunner = new ExoPlayerTestRunner.Builder(context) .skipSettingMediaSources() - .initialSeek(/* windowIndex= */ 1, C.TIME_UNSET) + .initialSeek(/* mediaItemIndex= */ 1, C.TIME_UNSET) .setActionSchedule(actionSchedule) .build() .start() @@ -5528,7 +5528,7 @@ public final class ExoPlayerTest { exoPlayerTestRunner.assertPlaybackStatesEqual(Player.STATE_ENDED); exoPlayerTestRunner.assertTimelinesSame(); exoPlayerTestRunner.assertTimelineChangeReasonsEqual(); - assertArrayEquals(new int[] {1}, currentWindowIndices); + assertArrayEquals(new int[] {1}, currentMediaItemIndices); } @Test @@ -5564,9 +5564,9 @@ public final class ExoPlayerTest { /* isAtomic= */ false, new FakeMediaSource(fakeTimeline, ExoPlayerTestRunner.VIDEO_FORMAT), new FakeMediaSource(fakeTimeline, ExoPlayerTestRunner.VIDEO_FORMAT)); - int[] currentWindowIndices = new int[1]; + int[] currentMediaItemIndices = new int[1]; long[] currentPlaybackPositions = new long[1]; - int seekToWindowIndex = 1; + int seekToMediaItemIndex = 1; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForPlaybackState(Player.STATE_BUFFERING) @@ -5575,21 +5575,21 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); currentPlaybackPositions[0] = player.getCurrentPosition(); } }) .build(); new ExoPlayerTestRunner.Builder(context) .setMediaSources(concatenatingMediaSource) - .initialSeek(seekToWindowIndex, 5000) + .initialSeek(seekToMediaItemIndex, 5000) .setActionSchedule(actionSchedule) .build() .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); assertArrayEquals(new long[] {5_000}, currentPlaybackPositions); - assertArrayEquals(new int[] {seekToWindowIndex}, currentWindowIndices); + assertArrayEquals(new int[] {seekToMediaItemIndex}, currentMediaItemIndices); } @Test @@ -5600,10 +5600,10 @@ public final class ExoPlayerTest { /* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000_000)); ConcatenatingMediaSource concatenatingMediaSource = new ConcatenatingMediaSource(/* isAtomic= */ false); - int[] currentWindowIndices = new int[2]; + int[] currentMediaItemIndices = new int[2]; long[] currentPlaybackPositions = new long[2]; long[] windowCounts = new long[2]; - int seekToWindowIndex = 1; + int seekToMediaItemIndex = 1; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForPlaybackState(Player.STATE_ENDED) @@ -5611,7 +5611,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); currentPlaybackPositions[0] = player.getCurrentPosition(); windowCounts[0] = player.getCurrentTimeline().getWindowCount(); } @@ -5627,7 +5627,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); currentPlaybackPositions[1] = player.getCurrentPosition(); windowCounts[1] = player.getCurrentTimeline().getWindowCount(); } @@ -5635,14 +5635,15 @@ public final class ExoPlayerTest { .build(); new ExoPlayerTestRunner.Builder(context) .setMediaSources(concatenatingMediaSource) - .initialSeek(seekToWindowIndex, 5000) + .initialSeek(seekToMediaItemIndex, 5000) .setActionSchedule(actionSchedule) .build() .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); assertArrayEquals(new long[] {0, 2}, windowCounts); - assertArrayEquals(new int[] {seekToWindowIndex, seekToWindowIndex}, currentWindowIndices); + assertArrayEquals( + new int[] {seekToMediaItemIndex, seekToMediaItemIndex}, currentMediaItemIndices); assertArrayEquals(new long[] {5_000, 5_000}, currentPlaybackPositions); } @@ -5671,10 +5672,10 @@ public final class ExoPlayerTest { /* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000_000)); ConcatenatingMediaSource concatenatingMediaSource = new ConcatenatingMediaSource(/* isAtomic= */ false); - int[] currentWindowIndices = new int[2]; + int[] currentMediaItemIndices = new int[2]; long[] currentPlaybackPositions = new long[2]; long[] windowCounts = new long[2]; - int seekToWindowIndex = 1; + int seekToMediaItemIndex = 1; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForPlaybackState(Player.STATE_ENDED) @@ -5682,7 +5683,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); currentPlaybackPositions[0] = player.getCurrentPosition(); windowCounts[0] = player.getCurrentTimeline().getWindowCount(); } @@ -5698,7 +5699,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); currentPlaybackPositions[1] = player.getCurrentPosition(); windowCounts[1] = player.getCurrentTimeline().getWindowCount(); } @@ -5707,14 +5708,15 @@ public final class ExoPlayerTest { new ExoPlayerTestRunner.Builder(context) .setMediaSources(concatenatingMediaSource) .setUseLazyPreparation(/* useLazyPreparation= */ true) - .initialSeek(seekToWindowIndex, 5000) + .initialSeek(seekToMediaItemIndex, 5000) .setActionSchedule(actionSchedule) .build() .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); assertArrayEquals(new long[] {0, 2}, windowCounts); - assertArrayEquals(new int[] {seekToWindowIndex, seekToWindowIndex}, currentWindowIndices); + assertArrayEquals( + new int[] {seekToMediaItemIndex, seekToMediaItemIndex}, currentMediaItemIndices); assertArrayEquals(new long[] {5_000, 5_000}, currentPlaybackPositions); } @@ -5875,19 +5877,19 @@ public final class ExoPlayerTest { } @Test - public void setMediaSources_empty_whenEmpty_correctMaskingWindowIndex() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + public void setMediaSources_empty_whenEmpty_correctMaskingMediaItemIndex() throws Exception { + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); List listOfTwo = ImmutableList.of(new FakeMediaSource(), new FakeMediaSource()); player.addMediaSources(/* index= */ 0, listOfTwo); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); } }) .prepare() @@ -5896,7 +5898,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[2] = player.getCurrentWindowIndex(); + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); } }) .build(); @@ -5907,12 +5909,12 @@ public final class ExoPlayerTest { .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {0, 0, 0}, currentWindowIndices); + assertArrayEquals(new int[] {0, 0, 0}, currentMediaItemIndices); } @Test public void setMediaItems_resetPosition_resetsPosition() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] currentPositions = {C.INDEX_UNSET, C.INDEX_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) @@ -5921,14 +5923,14 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - player.seekTo(/* windowIndex= */ 1, /* positionMs= */ 1000); - currentWindowIndices[0] = player.getCurrentWindowIndex(); + player.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ 1000); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); currentPositions[0] = player.getCurrentPosition(); List listOfTwo = ImmutableList.of( MediaItem.fromUri(Uri.EMPTY), MediaItem.fromUri(Uri.EMPTY)); player.setMediaItems(listOfTwo, /* resetPosition= */ true); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); currentPositions[1] = player.getCurrentPosition(); } }) @@ -5942,14 +5944,14 @@ public final class ExoPlayerTest { .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {1, 0}, currentWindowIndices); + assertArrayEquals(new int[] {1, 0}, currentMediaItemIndices); assertArrayEquals(new long[] {1000, 0}, currentPositions); } @Test - public void setMediaSources_empty_whenEmpty_validInitialSeek_correctMaskingWindowIndex() + public void setMediaSources_empty_whenEmpty_validInitialSeek_correctMaskingMediaItemIndex() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) // Wait for initial seek to be fully handled by internal player. @@ -5959,11 +5961,11 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); List listOfTwo = ImmutableList.of(new FakeMediaSource(), new FakeMediaSource()); player.addMediaSources(/* index= */ 0, listOfTwo); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); } }) .prepare() @@ -5972,25 +5974,25 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[2] = player.getCurrentWindowIndex(); + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); } }) .build(); new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 1, C.TIME_UNSET) + .initialSeek(/* mediaItemIndex= */ 1, C.TIME_UNSET) .setMediaSources(new ConcatenatingMediaSource()) .setActionSchedule(actionSchedule) .build() .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {1, 1, 1}, currentWindowIndices); + assertArrayEquals(new int[] {1, 1, 1}, currentMediaItemIndices); } @Test - public void setMediaSources_empty_whenEmpty_invalidInitialSeek_correctMaskingWindowIndex() + public void setMediaSources_empty_whenEmpty_invalidInitialSeek_correctMaskingMediaItemIndex() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) // Wait for initial seek to be fully handled by internal player. @@ -6000,11 +6002,11 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); List listOfTwo = ImmutableList.of(new FakeMediaSource(), new FakeMediaSource()); player.addMediaSources(/* index= */ 0, listOfTwo); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); } }) .prepare() @@ -6013,24 +6015,26 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[2] = player.getCurrentWindowIndex(); + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); } }) .build(); new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 4, C.TIME_UNSET) + .initialSeek(/* mediaItemIndex= */ 4, C.TIME_UNSET) .setMediaSources(new ConcatenatingMediaSource()) .setActionSchedule(actionSchedule) .build() .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {4, 0, 0}, currentWindowIndices); + assertArrayEquals(new int[] {4, 0, 0}, currentMediaItemIndices); } @Test - public void setMediaSources_whenEmpty_correctMaskingWindowIndex() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + public void setMediaSources_whenEmpty_correctMaskingMediaItemIndex() throws Exception { + final int[] currentMediaItemIndices = { + C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET + }; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForPlaybackState(Player.STATE_READY) @@ -6038,18 +6042,18 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - // Increase current window index. + // Increase current media item index. player.addMediaSource(/* index= */ 0, new FakeMediaSource()); - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); } }) .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { - // Current window index is unchanged. + // Current media item index is unchanged. player.addMediaSource(/* index= */ 2, new FakeMediaSource()); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); } }) .executeRunnable( @@ -6059,9 +6063,9 @@ public final class ExoPlayerTest { MediaSource mediaSource = new FakeMediaSource(); ConcatenatingMediaSource concatenatingMediaSource = new ConcatenatingMediaSource(mediaSource, mediaSource, mediaSource); - // Increase current window with multi window source. + // Increase current media item with multi media item source. player.addMediaSource(/* index= */ 0, concatenatingMediaSource); - currentWindowIndices[2] = player.getCurrentWindowIndex(); + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); } }) .executeRunnable( @@ -6070,9 +6074,9 @@ public final class ExoPlayerTest { public void run(ExoPlayer player) { ConcatenatingMediaSource concatenatingMediaSource = new ConcatenatingMediaSource(); - // Current window index is unchanged when adding empty source. + // Current media item index is unchanged when adding empty source. player.addMediaSource(/* index= */ 0, concatenatingMediaSource); - currentWindowIndices[3] = player.getCurrentWindowIndex(); + currentMediaItemIndices[3] = player.getCurrentMediaItemIndex(); } }) .build(); @@ -6083,7 +6087,7 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {1, 1, 4, 4}, currentWindowIndices); + assertArrayEquals(new int[] {1, 1, 4, 4}, currentMediaItemIndices); } @Test @@ -6092,7 +6096,7 @@ public final class ExoPlayerTest { MediaSource firstMediaSource = new FakeMediaSource(firstTimeline); Timeline secondTimeline = new FakeTimeline(/* windowCount= */ 1, new Object()); MediaSource secondMediaSource = new FakeMediaSource(secondTimeline); - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; final long[] currentPositions = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; final long[] bufferedPositions = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; ActionSchedule actionSchedule = @@ -6104,12 +6108,12 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); currentPositions[0] = player.getCurrentPosition(); bufferedPositions[0] = player.getBufferedPosition(); - // Increase current window index. + // Increase current media item index. player.addMediaSource(/* index= */ 0, secondMediaSource); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); currentPositions[1] = player.getCurrentPosition(); bufferedPositions[1] = player.getBufferedPosition(); } @@ -6120,28 +6124,28 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[2] = player.getCurrentWindowIndex(); + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); currentPositions[2] = player.getCurrentPosition(); bufferedPositions[2] = player.getBufferedPosition(); } }) .build(); new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 1, 2000) + .initialSeek(/* mediaItemIndex= */ 1, 2000) .setMediaSources(firstMediaSource) .setActionSchedule(actionSchedule) .build() .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {1, 2, 2}, currentWindowIndices); + assertArrayEquals(new int[] {1, 2, 2}, currentMediaItemIndices); assertArrayEquals(new long[] {2000, 2000, 2000}, currentPositions); assertArrayEquals(new long[] {2000, 2000, 2000}, bufferedPositions); } @Test public void setMediaSources_whenEmpty_invalidInitialSeek_correctMasking() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; final long[] currentPositions = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; final long[] bufferedPositions = {C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET}; ActionSchedule actionSchedule = @@ -6153,12 +6157,12 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); currentPositions[0] = player.getCurrentPosition(); bufferedPositions[0] = player.getBufferedPosition(); - // Increase current window index. + // Increase current media item index. player.addMediaSource(/* index= */ 0, new FakeMediaSource()); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); currentPositions[1] = player.getCurrentPosition(); bufferedPositions[1] = player.getBufferedPosition(); } @@ -6169,7 +6173,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[2] = player.getCurrentWindowIndex(); + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); currentPositions[2] = player.getCurrentPosition(); bufferedPositions[2] = player.getBufferedPosition(); } @@ -6177,21 +6181,21 @@ public final class ExoPlayerTest { .waitForPlaybackState(Player.STATE_ENDED) .build(); new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 1, 2000) + .initialSeek(/* mediaItemIndex= */ 1, 2000) .setMediaSources(new FakeMediaSource()) .setActionSchedule(actionSchedule) .build() .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {0, 1, 1}, currentWindowIndices); + assertArrayEquals(new int[] {0, 1, 1}, currentMediaItemIndices); assertArrayEquals(new long[] {0, 0, 0}, currentPositions); assertArrayEquals(new long[] {0, 0, 0}, bufferedPositions); } @Test - public void setMediaSources_correctMaskingWindowIndex() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + public void setMediaSources_correctMaskingMediaItemIndex() throws Exception { + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForTimelineChanged() @@ -6199,10 +6203,10 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); - // Increase current window index. + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); + // Increase current media item index. player.addMediaSource(/* index= */ 0, new FakeMediaSource()); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); } }) .waitForTimelineChanged() @@ -6210,7 +6214,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[2] = player.getCurrentWindowIndex(); + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); } }) .build(); @@ -6221,7 +6225,7 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {0, 1, 1}, currentWindowIndices); + assertArrayEquals(new int[] {0, 1, 1}, currentMediaItemIndices); } @Test @@ -6278,7 +6282,7 @@ public final class ExoPlayerTest { .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - // Expect reset of masking to first window. + // Expect reset of masking to first media item. exoPlayerTestRunner.assertPlaybackStatesEqual(Player.STATE_ENDED); assertArrayEquals( new int[] {Player.STATE_IDLE, Player.STATE_IDLE, Player.STATE_IDLE, Player.STATE_IDLE}, @@ -6314,14 +6318,14 @@ public final class ExoPlayerTest { .build(); ExoPlayerTestRunner exoPlayerTestRunner = new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET) + .initialSeek(/* mediaItemIndex= */ 1, /* positionMs= */ C.TIME_UNSET) .setMediaSources(new ConcatenatingMediaSource()) .setActionSchedule(actionSchedule) .build() .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - // Expect reset of masking to first window. + // Expect reset of masking to first media item. exoPlayerTestRunner.assertPlaybackStatesEqual( Player.STATE_BUFFERING, Player.STATE_READY, Player.STATE_ENDED); assertArrayEquals(new int[] {Player.STATE_IDLE}, maskingPlaybackStates); @@ -6356,7 +6360,7 @@ public final class ExoPlayerTest { .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - // Expect reset of masking to first window. + // Expect reset of masking to first media item. exoPlayerTestRunner.assertPlaybackStatesEqual( Player.STATE_BUFFERING, Player.STATE_READY, Player.STATE_ENDED); assertArrayEquals(new int[] {Player.STATE_IDLE}, maskingPlaybackStates); @@ -6392,7 +6396,7 @@ public final class ExoPlayerTest { .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - // Expect reset of masking to first window. + // Expect reset of masking to first media item. exoPlayerTestRunner.assertPlaybackStatesEqual( Player.STATE_BUFFERING, Player.STATE_READY, Player.STATE_ENDED); assertArrayEquals(new int[] {Player.STATE_IDLE}, maskingPlaybackStates); @@ -6464,7 +6468,7 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - // Expect reset of masking to first window. + // Expect reset of masking to first media item. exoPlayerTestRunner.assertPlaybackStatesEqual( Player.STATE_ENDED, Player.STATE_BUFFERING, @@ -6509,14 +6513,14 @@ public final class ExoPlayerTest { .build(); ExoPlayerTestRunner exoPlayerTestRunner = new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET) + .initialSeek(/* mediaItemIndex= */ 1, /* positionMs= */ C.TIME_UNSET) .setMediaSources(new ConcatenatingMediaSource()) .setActionSchedule(actionSchedule) .build() .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - // Expect reset of masking to first window. + // Expect reset of masking to first media item. exoPlayerTestRunner.assertPlaybackStatesEqual(Player.STATE_ENDED); assertArrayEquals(new int[] {Player.STATE_ENDED}, maskingPlaybackStates); exoPlayerTestRunner.assertTimelineChangeReasonsEqual( @@ -6552,7 +6556,7 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - // Expect reset of masking to first window. + // Expect reset of masking to first media item. exoPlayerTestRunner.assertPlaybackStatesEqual( Player.STATE_BUFFERING, Player.STATE_READY, Player.STATE_ENDED); assertArrayEquals(new int[] {Player.STATE_ENDED}, maskingPlaybackStates); @@ -6591,7 +6595,7 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - // Expect reset of masking to first window. + // Expect reset of masking to first media item. exoPlayerTestRunner.assertPlaybackStatesEqual( Player.STATE_BUFFERING, Player.STATE_READY, Player.STATE_ENDED); assertArrayEquals(new int[] {Player.STATE_ENDED}, maskingPlaybackStates); @@ -6625,7 +6629,8 @@ public final class ExoPlayerTest { } }) .waitForPlaybackState(Player.STATE_ENDED) - .setMediaSources(/* windowIndex= */ 0, /* positionMs= */ C.TIME_UNSET, firstMediaSource) + .setMediaSources( + /* mediaItemIndex= */ 0, /* positionMs= */ C.TIME_UNSET, firstMediaSource) .waitForPlaybackState(Player.STATE_READY) .executeRunnable( new PlayerRunnable() { @@ -6639,7 +6644,8 @@ public final class ExoPlayerTest { } }) .waitForPlaybackState(Player.STATE_ENDED) - .setMediaSources(/* windowIndex= */ 0, /* positionMs= */ C.TIME_UNSET, firstMediaSource) + .setMediaSources( + /* mediaItemIndex= */ 0, /* positionMs= */ C.TIME_UNSET, firstMediaSource) .waitForPlaybackState(Player.STATE_READY) .executeRunnable( new PlayerRunnable() { @@ -6652,7 +6658,8 @@ public final class ExoPlayerTest { } }) .waitForPlaybackState(Player.STATE_READY) - .setMediaSources(/* windowIndex= */ 0, /* positionMs= */ C.TIME_UNSET, firstMediaSource) + .setMediaSources( + /* mediaItemIndex= */ 0, /* positionMs= */ C.TIME_UNSET, firstMediaSource) .waitForPlaybackState(Player.STATE_READY) .executeRunnable( new PlayerRunnable() { @@ -6676,7 +6683,7 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - // Expect reset of masking to first window. + // Expect reset of masking to first media item. exoPlayerTestRunner.assertPlaybackStatesEqual( Player.STATE_BUFFERING, Player.STATE_READY, // Ready after initial prepare. @@ -6737,7 +6744,8 @@ public final class ExoPlayerTest { } }) .waitForTimelineChanged() - .setMediaSources(/* windowIndex= */ 0, /* positionMs= */ C.TIME_UNSET, firstMediaSource) + .setMediaSources( + /* mediaItemIndex= */ 0, /* positionMs= */ C.TIME_UNSET, firstMediaSource) .waitForPlaybackState(Player.STATE_READY) .play() .waitForPlaybackState(Player.STATE_ENDED) @@ -6745,14 +6753,14 @@ public final class ExoPlayerTest { ExoPlayerTestRunner exoPlayerTestRunner = new ExoPlayerTestRunner.Builder(context) .setExpectedPlayerEndedCount(/* expectedPlayerEndedCount= */ 2) - .initialSeek(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET) + .initialSeek(/* mediaItemIndex= */ 1, /* positionMs= */ C.TIME_UNSET) .setMediaSources(new ConcatenatingMediaSource()) .setActionSchedule(actionSchedule) .build() .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - // Expect reset of masking to first window. + // Expect reset of masking to first media item. exoPlayerTestRunner.assertPlaybackStatesEqual( Player.STATE_ENDED, // Empty source has been prepared. Player.STATE_BUFFERING, // After setting another source. @@ -6788,7 +6796,7 @@ public final class ExoPlayerTest { .build(); new ExoPlayerTestRunner.Builder(context) .skipSettingMediaSources() - .initialSeek(/* windowIndex= */ 0, /* positionMs= */ 2000) + .initialSeek(/* mediaItemIndex= */ 0, /* positionMs= */ 2000) .setActionSchedule(actionSchedule) .build() .start(/* doPrepare= */ false) @@ -6800,8 +6808,8 @@ public final class ExoPlayerTest { @Test public void addMediaSources_skipSettingMediaItems_validInitialSeek_correctMasking() throws Exception { - final int[] currentWindowIndices = new int[5]; - Arrays.fill(currentWindowIndices, C.INDEX_UNSET); + final int[] currentMediaItemIndices = new int[5]; + Arrays.fill(currentMediaItemIndices, C.INDEX_UNSET); final long[] currentPositions = new long[3]; Arrays.fill(currentPositions, C.TIME_UNSET); final long[] bufferedPositions = new long[3]; @@ -6815,18 +6823,18 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); // If the timeline is empty masking variables are used. currentPositions[0] = player.getCurrentPosition(); bufferedPositions[0] = player.getBufferedPosition(); player.addMediaSource(/* index= */ 0, new ConcatenatingMediaSource()); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); player.addMediaSource( /* index= */ 0, new FakeMediaSource(new FakeTimeline(/* windowCount= */ 2))); - currentWindowIndices[2] = player.getCurrentWindowIndex(); + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); player.addMediaSource(/* index= */ 0, new FakeMediaSource()); - currentWindowIndices[3] = player.getCurrentWindowIndex(); + currentMediaItemIndices[3] = player.getCurrentMediaItemIndex(); // With a non-empty timeline, we mask the periodId in the playback info. currentPositions[1] = player.getCurrentPosition(); bufferedPositions[1] = player.getBufferedPosition(); @@ -6838,7 +6846,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[4] = player.getCurrentWindowIndex(); + currentMediaItemIndices[4] = player.getCurrentMediaItemIndex(); // Finally original playbackInfo coming from EPII is used. currentPositions[2] = player.getCurrentPosition(); bufferedPositions[2] = player.getBufferedPosition(); @@ -6847,13 +6855,13 @@ public final class ExoPlayerTest { .build(); new ExoPlayerTestRunner.Builder(context) .skipSettingMediaSources() - .initialSeek(/* windowIndex= */ 1, 2000) + .initialSeek(/* mediaItemIndex= */ 1, 2000) .setActionSchedule(actionSchedule) .build() .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {1, 1, 1, 2, 2}, currentWindowIndices); + assertArrayEquals(new int[] {1, 1, 1, 2, 2}, currentMediaItemIndices); assertThat(currentPositions[0]).isEqualTo(2000); assertThat(currentPositions[1]).isEqualTo(2000); assertThat(currentPositions[2]).isAtLeast(2000); @@ -6864,9 +6872,9 @@ public final class ExoPlayerTest { @Test public void - testAddMediaSources_skipSettingMediaItems_invalidInitialSeek_correctMaskingWindowIndex() + testAddMediaSources_skipSettingMediaItems_invalidInitialSeek_correctMaskingMediaItemIndex() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) // Wait for initial seek to be fully handled by internal player. @@ -6876,9 +6884,9 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); player.addMediaSource(new FakeMediaSource()); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); } }) .prepare() @@ -6887,28 +6895,28 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[2] = player.getCurrentWindowIndex(); + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); } }) .build(); new ExoPlayerTestRunner.Builder(context) .skipSettingMediaSources() - .initialSeek(/* windowIndex= */ 1, C.TIME_UNSET) + .initialSeek(/* mediaItemIndex= */ 1, C.TIME_UNSET) .setActionSchedule(actionSchedule) .build() .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {1, 0, 0}, currentWindowIndices); + assertArrayEquals(new int[] {1, 0, 0}, currentMediaItemIndices); } @Test - public void moveMediaItems_correctMaskingWindowIndex() throws Exception { + public void moveMediaItems_correctMaskingMediaItemIndex() throws Exception { Timeline timeline = new FakeTimeline(); MediaSource firstMediaSource = new FakeMediaSource(timeline); MediaSource secondMediaSource = new FakeMediaSource(timeline); MediaSource thirdMediaSource = new FakeMediaSource(timeline); - final int[] currentWindowIndices = { + final int[] currentMediaItemIndices = { C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET }; ActionSchedule actionSchedule = @@ -6920,7 +6928,7 @@ public final class ExoPlayerTest { public void run(ExoPlayer player) { // Move the current item down in the playlist. player.moveMediaItems(/* fromIndex= */ 0, /* toIndex= */ 2, /* newIndex= */ 1); - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); } }) .executeRunnable( @@ -6929,17 +6937,17 @@ public final class ExoPlayerTest { public void run(ExoPlayer player) { // Move the current item up in the playlist. player.moveMediaItems(/* fromIndex= */ 1, /* toIndex= */ 3, /* newIndex= */ 0); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); } }) - .seek(/* windowIndex= */ 2, C.TIME_UNSET) + .seek(/* mediaItemIndex= */ 2, C.TIME_UNSET) .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { // Move items from before to behind the current item. player.moveMediaItems(/* fromIndex= */ 0, /* toIndex= */ 2, /* newIndex= */ 1); - currentWindowIndices[2] = player.getCurrentWindowIndex(); + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); } }) .executeRunnable( @@ -6948,7 +6956,7 @@ public final class ExoPlayerTest { public void run(ExoPlayer player) { // Move items from behind to before the current item. player.moveMediaItems(/* fromIndex= */ 1, /* toIndex= */ 3, /* newIndex= */ 0); - currentWindowIndices[3] = player.getCurrentWindowIndex(); + currentMediaItemIndices[3] = player.getCurrentMediaItemIndex(); } }) .executeRunnable( @@ -6956,20 +6964,20 @@ public final class ExoPlayerTest { @Override public void run(ExoPlayer player) { // Move items from before to before the current item. - // No change in currentWindowIndex. + // No change in currentMediaItemIndex. player.moveMediaItems(/* fromIndex= */ 0, /* toIndex= */ 1, /* newIndex= */ 1); - currentWindowIndices[4] = player.getCurrentWindowIndex(); + currentMediaItemIndices[4] = player.getCurrentMediaItemIndex(); } }) - .seek(/* windowIndex= */ 0, C.TIME_UNSET) + .seek(/* mediaItemIndex= */ 0, C.TIME_UNSET) .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { // Move items from behind to behind the current item. - // No change in currentWindowIndex. + // No change in currentMediaItemIndex. player.moveMediaItems(/* fromIndex= */ 1, /* toIndex= */ 2, /* newIndex= */ 2); - currentWindowIndices[5] = player.getCurrentWindowIndex(); + currentMediaItemIndices[5] = player.getCurrentMediaItemIndex(); } }) .build(); @@ -6980,12 +6988,12 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {1, 0, 0, 2, 2, 0}, currentWindowIndices); + assertArrayEquals(new int[] {1, 0, 0, 2, 2, 0}, currentMediaItemIndices); } @Test - public void moveMediaItems_unprepared_correctMaskingWindowIndex() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; + public void moveMediaItems_unprepared_correctMaskingMediaItemIndex() throws Exception { + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForTimelineChanged() @@ -6993,10 +7001,10 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - // Increase current window index. - currentWindowIndices[0] = player.getCurrentWindowIndex(); + // Increase current media item index. + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); player.moveMediaItem(/* currentIndex= */ 0, /* newIndex= */ 1); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); } }) .prepare() @@ -7005,7 +7013,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[2] = player.getCurrentWindowIndex(); + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); } }) .build(); @@ -7016,12 +7024,12 @@ public final class ExoPlayerTest { .start(/* doPrepare= */ false) .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {0, 1, 1}, currentWindowIndices); + assertArrayEquals(new int[] {0, 1, 1}, currentMediaItemIndices); } @Test - public void removeMediaItems_correctMaskingWindowIndex() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET}; + public void removeMediaItems_correctMaskingMediaItemIndex() throws Exception { + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForPlaybackState(Player.STATE_BUFFERING) @@ -7029,27 +7037,27 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - // Decrease current window index. - currentWindowIndices[0] = player.getCurrentWindowIndex(); + // Decrease current media item index. + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); player.removeMediaItem(/* index= */ 0); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); } }) .build(); new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET) + .initialSeek(/* mediaItemIndex= */ 1, /* positionMs= */ C.TIME_UNSET) .setMediaSources(new FakeMediaSource(), new FakeMediaSource()) .setActionSchedule(actionSchedule) .build() .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {1, 0}, currentWindowIndices); + assertArrayEquals(new int[] {1, 0}, currentMediaItemIndices); } @Test public void removeMediaItems_currentItemRemoved_correctMasking() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET}; final long[] currentPositions = {C.TIME_UNSET, C.TIME_UNSET}; final long[] bufferedPositions = {C.TIME_UNSET, C.TIME_UNSET}; ActionSchedule actionSchedule = @@ -7060,25 +7068,25 @@ public final class ExoPlayerTest { @Override public void run(ExoPlayer player) { // Remove the current item. - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); currentPositions[0] = player.getCurrentPosition(); bufferedPositions[0] = player.getBufferedPosition(); player.removeMediaItem(/* index= */ 1); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); currentPositions[1] = player.getCurrentPosition(); bufferedPositions[1] = player.getBufferedPosition(); } }) .build(); new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 1, /* positionMs= */ 5000) + .initialSeek(/* mediaItemIndex= */ 1, /* positionMs= */ 5000) .setMediaSources(new FakeMediaSource(), new FakeMediaSource(), new FakeMediaSource()) .setActionSchedule(actionSchedule) .build() .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {1, 1}, currentWindowIndices); + assertArrayEquals(new int[] {1, 1}, currentMediaItemIndices); assertThat(currentPositions[0]).isAtLeast(5000L); assertThat(bufferedPositions[0]).isAtLeast(5000L); assertThat(currentPositions[1]).isEqualTo(0); @@ -7095,8 +7103,8 @@ public final class ExoPlayerTest { MediaSource thirdMediaSource = new FakeMediaSource(thirdTimeline); Timeline fourthTimeline = new FakeTimeline(/* windowCount= */ 1, 3L); MediaSource fourthMediaSource = new FakeMediaSource(fourthTimeline); - final int[] currentWindowIndices = new int[9]; - Arrays.fill(currentWindowIndices, C.INDEX_UNSET); + final int[] currentMediaItemIndices = new int[9]; + Arrays.fill(currentMediaItemIndices, C.INDEX_UNSET); final int[] maskingPlaybackStates = new int[4]; Arrays.fill(maskingPlaybackStates, C.INDEX_UNSET); final long[] currentPositions = new long[3]; @@ -7111,14 +7119,14 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - // Expect the current window index to be 2 after seek. - currentWindowIndices[0] = player.getCurrentWindowIndex(); + // Expect the current media item index to be 2 after seek. + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); currentPositions[0] = player.getCurrentPosition(); bufferedPositions[0] = player.getBufferedPosition(); player.removeMediaItem(/* index= */ 2); - // Expect the current window index to be 0 + // Expect the current media item index to be 0 // (default position of timeline after not finding subsequent period). - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); // Transition to ENDED. maskingPlaybackStates[0] = player.getPlaybackState(); currentPositions[1] = player.getCurrentPosition(); @@ -7130,12 +7138,12 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - // Expects the current window index still on 0. - currentWindowIndices[2] = player.getCurrentWindowIndex(); + // Expects the current media item index still on 0. + currentMediaItemIndices[2] = player.getCurrentMediaItemIndex(); // Insert an item at begin when the playlist is not empty. player.addMediaSource(/* index= */ 0, thirdMediaSource); - // Expects the current window index to be (0 + 1) after insertion at begin. - currentWindowIndices[3] = player.getCurrentWindowIndex(); + // Expects the current media item index to be (0 + 1) after insertion at begin. + currentMediaItemIndices[3] = player.getCurrentMediaItemIndex(); // Remains in ENDED. maskingPlaybackStates[1] = player.getPlaybackState(); currentPositions[2] = player.getCurrentPosition(); @@ -7147,12 +7155,12 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[4] = player.getCurrentWindowIndex(); - // Implicit seek to the current window index, which is out of bounds in new + currentMediaItemIndices[4] = player.getCurrentMediaItemIndex(); + // Implicit seek to the current media item index, which is out of bounds in new // timeline. player.setMediaSource(fourthMediaSource, /* resetPosition= */ false); // 0 after reset. - currentWindowIndices[5] = player.getCurrentWindowIndex(); + currentMediaItemIndices[5] = player.getCurrentMediaItemIndex(); // Invalid seek, so we remain in ENDED. maskingPlaybackStates[2] = player.getPlaybackState(); } @@ -7162,11 +7170,11 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[6] = player.getCurrentWindowIndex(); + currentMediaItemIndices[6] = player.getCurrentMediaItemIndex(); // Explicit seek to (0, C.TIME_UNSET). Player transitions to BUFFERING. player.setMediaSource(fourthMediaSource, /* startPositionMs= */ 5000); // 0 after explicit seek. - currentWindowIndices[7] = player.getCurrentWindowIndex(); + currentMediaItemIndices[7] = player.getCurrentMediaItemIndex(); // Transitions from ENDED to BUFFERING after explicit seek. maskingPlaybackStates[3] = player.getPlaybackState(); } @@ -7176,14 +7184,14 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - // Check whether actual window index is equal masking index from above. - currentWindowIndices[8] = player.getCurrentWindowIndex(); + // Check whether actual media item index is equal masking index from above. + currentMediaItemIndices[8] = player.getCurrentMediaItemIndex(); } }) .build(); ExoPlayerTestRunner exoPlayerTestRunner = new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 2, /* positionMs= */ C.TIME_UNSET) + .initialSeek(/* mediaItemIndex= */ 2, /* positionMs= */ C.TIME_UNSET) .setExpectedPlayerEndedCount(2) .setMediaSources(firstMediaSource, secondMediaSource, thirdMediaSource) .setActionSchedule(actionSchedule) @@ -7191,23 +7199,23 @@ public final class ExoPlayerTest { .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - // Expect reset of masking to first window. + // Expect reset of masking to first media item. exoPlayerTestRunner.assertPlaybackStatesEqual( Player.STATE_BUFFERING, Player.STATE_READY, // Ready after initial prepare. - Player.STATE_ENDED, // ended after removing current window index + Player.STATE_ENDED, // ended after removing current media item index Player.STATE_BUFFERING, // buffers after set items with seek Player.STATE_READY, Player.STATE_ENDED); assertArrayEquals( new int[] { - Player.STATE_ENDED, // ended after removing current window index + Player.STATE_ENDED, // ended after removing current media item index Player.STATE_ENDED, // adding items does not change state Player.STATE_ENDED, // set items with seek to current position. Player.STATE_BUFFERING }, // buffers after set items with seek maskingPlaybackStates); - assertArrayEquals(new int[] {2, 0, 0, 1, 1, 0, 0, 0, 0}, currentWindowIndices); + assertArrayEquals(new int[] {2, 0, 0, 1, 1, 0, 0, 0, 0}, currentMediaItemIndices); assertThat(currentPositions[0]).isEqualTo(0); assertThat(currentPositions[1]).isEqualTo(0); assertThat(currentPositions[2]).isEqualTo(0); @@ -7221,7 +7229,7 @@ public final class ExoPlayerTest { throws Exception { ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) - .seek(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET) + .seek(/* mediaItemIndex= */ 1, /* positionMs= */ C.TIME_UNSET) .waitForPendingPlayerCommands() .removeMediaItem(/* index= */ 1) .prepare() @@ -7241,7 +7249,7 @@ public final class ExoPlayerTest { @Test public void clearMediaItems_correctMasking() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET}; + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET}; final int[] maskingPlaybackState = {C.INDEX_UNSET}; final long[] currentPosition = {C.TIME_UNSET, C.TIME_UNSET}; final long[] bufferedPosition = {C.TIME_UNSET, C.TIME_UNSET}; @@ -7249,16 +7257,16 @@ public final class ExoPlayerTest { new ActionSchedule.Builder(TAG) .pause() .waitForPlaybackState(Player.STATE_BUFFERING) - .playUntilPosition(/* windowIndex= */ 1, /* positionMs= */ 150) + .playUntilPosition(/* mediaItemIndex= */ 1, /* positionMs= */ 150) .executeRunnable( new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); currentPosition[0] = player.getCurrentPosition(); bufferedPosition[0] = player.getBufferedPosition(); player.clearMediaItems(); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); currentPosition[1] = player.getCurrentPosition(); bufferedPosition[1] = player.getBufferedPosition(); maskingPlaybackState[0] = player.getPlaybackState(); @@ -7266,25 +7274,25 @@ public final class ExoPlayerTest { }) .build(); new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET) + .initialSeek(/* mediaItemIndex= */ 1, /* positionMs= */ C.TIME_UNSET) .setMediaSources(new FakeMediaSource(), new FakeMediaSource()) .setActionSchedule(actionSchedule) .build() .start() .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertArrayEquals(new int[] {1, 0}, currentWindowIndices); + assertArrayEquals(new int[] {1, 0}, currentMediaItemIndices); assertThat(currentPosition[0]).isAtLeast(150); assertThat(currentPosition[1]).isEqualTo(0); assertThat(bufferedPosition[0]).isAtLeast(150); assertThat(bufferedPosition[1]).isEqualTo(0); - assertArrayEquals(new int[] {1, 0}, currentWindowIndices); + assertArrayEquals(new int[] {1, 0}, currentMediaItemIndices); assertArrayEquals(new int[] {Player.STATE_ENDED}, maskingPlaybackState); } @Test - public void clearMediaItems_unprepared_correctMaskingWindowIndex_notEnded() throws Exception { - final int[] currentWindowIndices = {C.INDEX_UNSET, C.INDEX_UNSET}; + public void clearMediaItems_unprepared_correctMaskingMediaItemIndex_notEnded() throws Exception { + final int[] currentMediaItemIndices = {C.INDEX_UNSET, C.INDEX_UNSET}; final int[] currentStates = {C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET}; ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) @@ -7295,10 +7303,10 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - currentWindowIndices[0] = player.getCurrentWindowIndex(); + currentMediaItemIndices[0] = player.getCurrentMediaItemIndex(); currentStates[0] = player.getPlaybackState(); player.clearMediaItems(); - currentWindowIndices[1] = player.getCurrentWindowIndex(); + currentMediaItemIndices[1] = player.getCurrentMediaItemIndex(); currentStates[1] = player.getPlaybackState(); } }) @@ -7313,7 +7321,7 @@ public final class ExoPlayerTest { }) .build(); new ExoPlayerTestRunner.Builder(context) - .initialSeek(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET) + .initialSeek(/* mediaItemIndex= */ 1, /* positionMs= */ C.TIME_UNSET) .setMediaSources(new FakeMediaSource(), new FakeMediaSource()) .setActionSchedule(actionSchedule) .build() @@ -7322,7 +7330,7 @@ public final class ExoPlayerTest { .blockUntilEnded(TIMEOUT_MS); assertArrayEquals( new int[] {Player.STATE_IDLE, Player.STATE_IDLE, Player.STATE_ENDED}, currentStates); - assertArrayEquals(new int[] {1, 0}, currentWindowIndices); + assertArrayEquals(new int[] {1, 0}, currentMediaItemIndices); } @Test @@ -7351,7 +7359,7 @@ public final class ExoPlayerTest { AtomicReference timelineAfterError = new AtomicReference<>(); AtomicReference trackInfosAfterError = new AtomicReference<>(); AtomicReference trackSelectionsAfterError = new AtomicReference<>(); - AtomicInteger windowIndexAfterError = new AtomicInteger(); + AtomicInteger mediaItemIndexAfterError = new AtomicInteger(); ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .executeRunnable( @@ -7365,7 +7373,7 @@ public final class ExoPlayerTest { timelineAfterError.set(player.getCurrentTimeline()); trackInfosAfterError.set(player.getCurrentTracksInfo()); trackSelectionsAfterError.set(player.getCurrentTrackSelections()); - windowIndexAfterError.set(player.getCurrentWindowIndex()); + mediaItemIndexAfterError.set(player.getCurrentMediaItemIndex()); } }); } @@ -7392,7 +7400,7 @@ public final class ExoPlayerTest { .blockUntilEnded(TIMEOUT_MS)); assertThat(timelineAfterError.get().getWindowCount()).isEqualTo(1); - assertThat(windowIndexAfterError.get()).isEqualTo(0); + assertThat(mediaItemIndexAfterError.get()).isEqualTo(0); assertThat(trackInfosAfterError.get().getTrackGroupInfos()).hasSize(1); assertThat(trackInfosAfterError.get().getTrackGroupInfos().get(0).getTrackGroup().getFormat(0)) .isEqualTo(ExoPlayerTestRunner.AUDIO_FORMAT); @@ -7404,7 +7412,7 @@ public final class ExoPlayerTest { public void seekToCurrentPosition_inEndedState_switchesToBufferingStateAndContinuesPlayback() throws Exception { MediaSource mediaSource = new FakeMediaSource(new FakeTimeline(/* windowCount = */ 1)); - AtomicInteger windowIndexAfterFinalEndedState = new AtomicInteger(); + AtomicInteger mediaItemIndexAfterFinalEndedState = new AtomicInteger(); ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForPlaybackState(Player.STATE_ENDED) @@ -7422,7 +7430,7 @@ public final class ExoPlayerTest { new PlayerRunnable() { @Override public void run(ExoPlayer player) { - windowIndexAfterFinalEndedState.set(player.getCurrentWindowIndex()); + mediaItemIndexAfterFinalEndedState.set(player.getCurrentMediaItemIndex()); } }) .build(); @@ -7434,7 +7442,7 @@ public final class ExoPlayerTest { .blockUntilActionScheduleFinished(TIMEOUT_MS) .blockUntilEnded(TIMEOUT_MS); - assertThat(windowIndexAfterFinalEndedState.get()).isEqualTo(1); + assertThat(mediaItemIndexAfterFinalEndedState.get()).isEqualTo(1); } @Test @@ -7448,7 +7456,7 @@ public final class ExoPlayerTest { MediaSource mediaSource = new FakeMediaSource(new FakeTimeline(timelineWindowDefinition)); AtomicInteger playbackStateAfterPause = new AtomicInteger(C.INDEX_UNSET); AtomicLong positionAfterPause = new AtomicLong(C.TIME_UNSET); - AtomicInteger windowIndexAfterPause = new AtomicInteger(C.INDEX_UNSET); + AtomicInteger mediaItemIndexAfterPause = new AtomicInteger(C.INDEX_UNSET); ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForPlayWhenReady(true) @@ -7458,7 +7466,7 @@ public final class ExoPlayerTest { @Override public void run(ExoPlayer player) { playbackStateAfterPause.set(player.getPlaybackState()); - windowIndexAfterPause.set(player.getCurrentWindowIndex()); + mediaItemIndexAfterPause.set(player.getCurrentMediaItemIndex()); positionAfterPause.set(player.getContentPosition()); } }) @@ -7473,7 +7481,7 @@ public final class ExoPlayerTest { .blockUntilEnded(TIMEOUT_MS); assertThat(playbackStateAfterPause.get()).isEqualTo(Player.STATE_READY); - assertThat(windowIndexAfterPause.get()).isEqualTo(0); + assertThat(mediaItemIndexAfterPause.get()).isEqualTo(0); assertThat(positionAfterPause.get()).isEqualTo(10_000); } @@ -7487,7 +7495,7 @@ public final class ExoPlayerTest { MediaSource mediaSource = new FakeMediaSource(new FakeTimeline(timelineWindowDefinition)); AtomicInteger playbackStateAfterPause = new AtomicInteger(C.INDEX_UNSET); AtomicLong positionAfterPause = new AtomicLong(C.TIME_UNSET); - AtomicInteger windowIndexAfterPause = new AtomicInteger(C.INDEX_UNSET); + AtomicInteger mediaItemIndexAfterPause = new AtomicInteger(C.INDEX_UNSET); ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG) .waitForPlayWhenReady(true) @@ -7497,7 +7505,7 @@ public final class ExoPlayerTest { @Override public void run(ExoPlayer player) { playbackStateAfterPause.set(player.getPlaybackState()); - windowIndexAfterPause.set(player.getCurrentWindowIndex()); + mediaItemIndexAfterPause.set(player.getCurrentMediaItemIndex()); positionAfterPause.set(player.getContentPosition()); } }) @@ -7512,7 +7520,7 @@ public final class ExoPlayerTest { .blockUntilEnded(TIMEOUT_MS); assertThat(playbackStateAfterPause.get()).isEqualTo(Player.STATE_ENDED); - assertThat(windowIndexAfterPause.get()).isEqualTo(0); + assertThat(mediaItemIndexAfterPause.get()).isEqualTo(0); assertThat(positionAfterPause.get()).isEqualTo(10_000); } @@ -7846,7 +7854,7 @@ public final class ExoPlayerTest { firstMediaSource.setNewSourceInfo(timelineWithOffsets); // Wait until player transitions to second source (which also has non-zero offsets). runUntilPositionDiscontinuity(player, Player.DISCONTINUITY_REASON_AUTO_TRANSITION); - assertThat(player.getCurrentWindowIndex()).isEqualTo(1); + assertThat(player.getCurrentMediaItemIndex()).isEqualTo(1); player.release(); assertThat(rendererStreamOffsetsUs).hasSize(2); @@ -8102,7 +8110,7 @@ public final class ExoPlayerTest { player.prepare(); runUntilPlaybackState(player, Player.STATE_READY); - player.seekTo(/* windowIndex= */ 1, /* positionMs= */ 2000); + player.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ 2000); assertThat(reportedMediaItems) .containsExactly(mediaSource1.getMediaItem(), mediaSource2.getMediaItem()) @@ -8134,7 +8142,7 @@ public final class ExoPlayerTest { player.prepare(); runUntilPlaybackState(player, Player.STATE_READY); - player.seekTo(/* windowIndex= */ 0, /* positionMs= */ 2000); + player.seekTo(/* mediaItemIndex= */ 0, /* positionMs= */ 2000); assertThat(reportedMediaItems).containsExactly(mediaSource1.getMediaItem()).inOrder(); assertThat(reportedTransitionReasons) @@ -8371,7 +8379,7 @@ public final class ExoPlayerTest { player.addMediaSources( ImmutableList.of( new FakeMediaSource(), new FakeMediaSource(adTimeline), new FakeMediaSource())); - player.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0); + player.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ 0); player.prepare(); runUntilPlaybackState(player, Player.STATE_READY); @@ -8451,7 +8459,7 @@ public final class ExoPlayerTest { ExoPlayer player = new TestExoPlayerBuilder(context).build(); player.addMediaSource(new FakeMediaSource(timelineWithUnseekableLiveWindow)); - player.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0); + player.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ 0); player.prepare(); runUntilPlaybackState(player, Player.STATE_READY); @@ -8507,14 +8515,14 @@ public final class ExoPlayerTest { // Check that there were no other calls to onAvailableCommandsChanged. verify(mockListener).onAvailableCommandsChanged(any()); - player.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0); + player.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ 0); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPreviousAndNextWindow); verify(mockListener, times(2)).onAvailableCommandsChanged(any()); - player.seekTo(/* windowIndex= */ 2, /* positionMs= */ 0); + player.seekTo(/* mediaItemIndex= */ 2, /* positionMs= */ 0); verify(mockListener, times(2)).onAvailableCommandsChanged(any()); - player.seekTo(/* windowIndex= */ 3, /* positionMs= */ 0); + player.seekTo(/* mediaItemIndex= */ 3, /* positionMs= */ 0); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPreviousWindow); verify(mockListener, times(3)).onAvailableCommandsChanged(any()); } @@ -8534,7 +8542,7 @@ public final class ExoPlayerTest { ExoPlayer player = new TestExoPlayerBuilder(context).build(); player.addListener(mockListener); - player.seekTo(/* windowIndex= */ 3, /* positionMs= */ 0); + player.seekTo(/* mediaItemIndex= */ 3, /* positionMs= */ 0); player.addMediaSources( ImmutableList.of( new FakeMediaSource(), @@ -8545,14 +8553,14 @@ public final class ExoPlayerTest { // Check that there were no other calls to onAvailableCommandsChanged. verify(mockListener).onAvailableCommandsChanged(any()); - player.seekTo(/* windowIndex= */ 2, /* positionMs= */ 0); + player.seekTo(/* mediaItemIndex= */ 2, /* positionMs= */ 0); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPreviousAndNextWindow); verify(mockListener, times(2)).onAvailableCommandsChanged(any()); - player.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0); + player.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ 0); verify(mockListener, times(2)).onAvailableCommandsChanged(any()); - player.seekTo(/* windowIndex= */ 0, /* positionMs= */ 0); + player.seekTo(/* mediaItemIndex= */ 0, /* positionMs= */ 0); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNextWindow); verify(mockListener, times(3)).onAvailableCommandsChanged(any()); } @@ -8567,8 +8575,8 @@ public final class ExoPlayerTest { player.addMediaSources(ImmutableList.of(new FakeMediaSource())); verify(mockListener).onAvailableCommandsChanged(defaultCommands); - player.seekTo(/* windowIndex= */ 0, /* positionMs= */ 200); - player.seekTo(/* windowIndex= */ 0, /* positionMs= */ 100); + player.seekTo(/* mediaItemIndex= */ 0, /* positionMs= */ 200); + player.seekTo(/* mediaItemIndex= */ 0, /* positionMs= */ 100); // Check that there were no other calls to onAvailableCommandsChanged. verify(mockListener).onAvailableCommandsChanged(any()); } @@ -8617,12 +8625,12 @@ public final class ExoPlayerTest { verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToNextWindow); verify(mockListener, times(2)).onAvailableCommandsChanged(any()); - playUntilStartOfWindow(player, /* windowIndex= */ 1); + playUntilStartOfMediaItem(player, /* mediaItemIndex= */ 1); runUntilPendingCommandsAreFullyHandled(player); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekAnywhere); verify(mockListener, times(3)).onAvailableCommandsChanged(any()); - playUntilStartOfWindow(player, /* windowIndex= */ 2); + playUntilStartOfMediaItem(player, /* mediaItemIndex= */ 2); runUntilPendingCommandsAreFullyHandled(player); verify(mockListener, times(3)).onAvailableCommandsChanged(any()); @@ -8714,7 +8722,7 @@ public final class ExoPlayerTest { ExoPlayer player = new TestExoPlayerBuilder(context).build(); player.addListener(mockListener); - player.seekTo(/* windowIndex= */ 2, /* positionMs= */ 0); + player.seekTo(/* mediaItemIndex= */ 2, /* positionMs= */ 0); player.addMediaSources( ImmutableList.of(new FakeMediaSource(), new FakeMediaSource(), new FakeMediaSource())); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPreviousWindow); @@ -8838,7 +8846,7 @@ public final class ExoPlayerTest { .getPeriod(/* periodIndex= */ 1, new Timeline.Period(), /* setIds= */ true) .uid; assertThat(error.mediaPeriodId.periodUid).isEqualTo(period1Uid); - assertThat(player.getCurrentWindowIndex()).isEqualTo(1); + assertThat(player.getCurrentMediaItemIndex()).isEqualTo(1); } @Test @@ -8884,7 +8892,7 @@ public final class ExoPlayerTest { .getPeriod(/* periodIndex= */ 1, new Timeline.Period(), /* setIds= */ true) .uid; assertThat(error.mediaPeriodId.periodUid).isEqualTo(period1Uid); - assertThat(player.getCurrentWindowIndex()).isEqualTo(1); + assertThat(player.getCurrentMediaItemIndex()).isEqualTo(1); } @Test @@ -8947,7 +8955,7 @@ public final class ExoPlayerTest { .getPeriod(/* periodIndex= */ 1, new Timeline.Period(), /* setIds= */ true) .uid; assertThat(error.mediaPeriodId.periodUid).isEqualTo(period1Uid); - assertThat(player.getCurrentWindowIndex()).isEqualTo(1); + assertThat(player.getCurrentMediaItemIndex()).isEqualTo(1); } @Test @@ -8988,7 +8996,7 @@ public final class ExoPlayerTest { .uid; assertThat(error.mediaPeriodId.periodUid).isEqualTo(period1Uid); // Verify test setup by checking that playing period was indeed different. - assertThat(player.getCurrentWindowIndex()).isEqualTo(0); + assertThat(player.getCurrentMediaItemIndex()).isEqualTo(0); } @Test @@ -9127,7 +9135,8 @@ public final class ExoPlayerTest { assertThat(liveOffsetAtStart).isIn(Range.closed(11_900L, 12_100L)); // Play until close to the end of the available live window. - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 0, /* positionMs= */ 999_000); + TestPlayerRunHelper.playUntilPosition( + player, /* mediaItemIndex= */ 0, /* positionMs= */ 999_000); long liveOffsetAtEnd = player.getCurrentLiveOffset(); player.release(); @@ -9173,7 +9182,8 @@ public final class ExoPlayerTest { TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY); long liveOffsetAtStart = player.getCurrentLiveOffset(); // Play until close to the end of the available live window. - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 0, /* positionMs= */ 999_000); + TestPlayerRunHelper.playUntilPosition( + player, /* mediaItemIndex= */ 0, /* positionMs= */ 999_000); long liveOffsetAtEnd = player.getCurrentLiveOffset(); player.release(); @@ -9221,7 +9231,8 @@ public final class ExoPlayerTest { // Seek to a live offset of 2 seconds. player.seekTo(18_000); // Play until close to the end of the available live window. - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 0, /* positionMs= */ 999_000); + TestPlayerRunHelper.playUntilPosition( + player, /* mediaItemIndex= */ 0, /* positionMs= */ 999_000); long liveOffsetAtEnd = player.getCurrentLiveOffset(); player.release(); @@ -9285,11 +9296,13 @@ public final class ExoPlayerTest { assertThat(liveOffsetAtStart).isIn(Range.closed(11_900L, 12_100L)); // Play a bit and update configuration. - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 0, /* positionMs= */ 55_000); + TestPlayerRunHelper.playUntilPosition( + player, /* mediaItemIndex= */ 0, /* positionMs= */ 55_000); fakeMediaSource.setNewSourceInfo(updatedTimeline); // Play until close to the end of the available live window. - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 0, /* positionMs= */ 999_000); + TestPlayerRunHelper.playUntilPosition( + player, /* mediaItemIndex= */ 0, /* positionMs= */ 999_000); long liveOffsetAtEnd = player.getCurrentLiveOffset(); player.release(); @@ -9351,7 +9364,8 @@ public final class ExoPlayerTest { player.setPlaybackParameters(new PlaybackParameters(/* speed */ 2.0f)); // Play until close to the end of the available live window. - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 0, /* positionMs= */ 999_000); + TestPlayerRunHelper.playUntilPosition( + player, /* mediaItemIndex= */ 0, /* positionMs= */ 999_000); long liveOffsetAtEnd = player.getCurrentLiveOffset(); player.release(); @@ -9399,7 +9413,8 @@ public final class ExoPlayerTest { TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY); // Play until close to the end of the available live window. - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 1, /* positionMs= */ 999_000); + TestPlayerRunHelper.playUntilPosition( + player, /* mediaItemIndex= */ 1, /* positionMs= */ 999_000); long liveOffsetAtEnd = player.getCurrentLiveOffset(); player.release(); @@ -9463,9 +9478,10 @@ public final class ExoPlayerTest { TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY); // Seek to default position in second stream. - player.seekToNextWindow(); + player.seekToNextMediaItem(); // Play until close to the end of the available live window. - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 1, /* positionMs= */ 999_000); + TestPlayerRunHelper.playUntilPosition( + player, /* mediaItemIndex= */ 1, /* positionMs= */ 999_000); long liveOffsetAtEnd = player.getCurrentLiveOffset(); player.release(); @@ -9529,9 +9545,10 @@ public final class ExoPlayerTest { TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY); // Seek to specific position in second stream (at 2 seconds live offset). - player.seekTo(/* windowIndex= */ 1, /* positionMs= */ 18_000); + player.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ 18_000); // Play until close to the end of the available live window. - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 1, /* positionMs= */ 999_000); + TestPlayerRunHelper.playUntilPosition( + player, /* mediaItemIndex= */ 1, /* positionMs= */ 999_000); long liveOffsetAtEnd = player.getCurrentLiveOffset(); player.release(); @@ -9572,7 +9589,8 @@ public final class ExoPlayerTest { TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY); long playbackStartTimeMs = fakeClock.elapsedRealtime(); - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 0, /* positionMs= */ 999_000); + TestPlayerRunHelper.playUntilPosition( + player, /* mediaItemIndex= */ 0, /* positionMs= */ 999_000); long playbackEndTimeMs = fakeClock.elapsedRealtime(); player.release(); @@ -9613,7 +9631,8 @@ public final class ExoPlayerTest { assertThat(liveOffsetAtStart).isIn(Range.closed(11_900L, 12_100L)); // Play until close to the end of the available live window. - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 0, /* positionMs= */ 999_000); + TestPlayerRunHelper.playUntilPosition( + player, /* mediaItemIndex= */ 0, /* positionMs= */ 999_000); long liveOffsetAtEnd = player.getCurrentLiveOffset(); player.release(); @@ -9751,7 +9770,7 @@ public final class ExoPlayerTest { TestPlayerRunHelper.runUntilPositionDiscontinuity( player, Player.DISCONTINUITY_REASON_AUTO_TRANSITION); player.addMediaSource(secondMediaSource); - player.seekTo(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET); + player.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ C.TIME_UNSET); player.play(); TestPlayerRunHelper.runUntilPositionDiscontinuity( player, Player.DISCONTINUITY_REASON_AUTO_TRANSITION); @@ -9828,7 +9847,7 @@ public final class ExoPlayerTest { inOrder .verify(listener) .onMediaItemTransition(any(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_AUTO)); - // Last auto transition from window 0 to window 1 not caused by repeat mode. + // Last auto transition from media item 0 to media item 1 not caused by repeat mode. inOrder .verify(listener) .onPositionDiscontinuity(any(), any(), eq(Player.DISCONTINUITY_REASON_AUTO_TRANSITION)); @@ -10004,7 +10023,7 @@ public final class ExoPlayerTest { player.setMediaSource(new FakeMediaSource(new FakeTimeline(adTimeline))); player.prepare(); - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 0, /* positionMs= */ 1000); + TestPlayerRunHelper.playUntilPosition(player, /* mediaItemIndex= */ 0, /* positionMs= */ 1000); player.seekTo(/* positionMs= */ 8_000); player.play(); TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); @@ -10128,7 +10147,7 @@ public final class ExoPlayerTest { ArgumentCaptor.forClass(Player.PositionInfo.class); Window window = new Window(); InOrder inOrder = Mockito.inOrder(listener); - // from first to second window + // from first to second media item inOrder .verify(listener) .onPositionDiscontinuity( @@ -10154,7 +10173,7 @@ public final class ExoPlayerTest { assertThat(newPosition.getValue().contentPositionMs).isEqualTo(0); assertThat(newPosition.getValue().adGroupIndex).isEqualTo(-1); assertThat(newPosition.getValue().adIndexInAdGroup).isEqualTo(-1); - // from second window to third + // from second media item to third inOrder .verify(listener) .onPositionDiscontinuity( @@ -10180,7 +10199,7 @@ public final class ExoPlayerTest { assertThat(newPosition.getValue().contentPositionMs).isEqualTo(0); assertThat(newPosition.getValue().adGroupIndex).isEqualTo(-1); assertThat(newPosition.getValue().adIndexInAdGroup).isEqualTo(-1); - // from third window content to post roll ad + // from third media item content to post roll ad @Nullable Object lastNewWindowUid = newPosition.getValue().windowUid; inOrder .verify(listener) @@ -10201,7 +10220,7 @@ public final class ExoPlayerTest { assertThat(newPosition.getValue().contentPositionMs).isEqualTo(20_000); assertThat(newPosition.getValue().adGroupIndex).isEqualTo(0); assertThat(newPosition.getValue().adIndexInAdGroup).isEqualTo(0); - // from third window post roll to third window content end + // from third media item post roll to third media item content end lastNewWindowUid = newPosition.getValue().windowUid; inOrder .verify(listener) @@ -10223,7 +10242,7 @@ public final class ExoPlayerTest { assertThat(newPosition.getValue().contentPositionMs).isEqualTo(19_999); assertThat(newPosition.getValue().adGroupIndex).isEqualTo(-1); assertThat(newPosition.getValue().adIndexInAdGroup).isEqualTo(-1); - // from third window content end to fourth window pre roll ad + // from third media item content end to fourth media item pre roll ad lastNewWindowUid = newPosition.getValue().windowUid; inOrder .verify(listener) @@ -10248,7 +10267,7 @@ public final class ExoPlayerTest { assertThat(newPosition.getValue().contentPositionMs).isEqualTo(0); assertThat(newPosition.getValue().adGroupIndex).isEqualTo(0); assertThat(newPosition.getValue().adIndexInAdGroup).isEqualTo(0); - // from fourth window pre roll ad to fourth window content + // from fourth media item pre roll ad to fourth media item content lastNewWindowUid = newPosition.getValue().windowUid; inOrder .verify(listener) @@ -10306,7 +10325,7 @@ public final class ExoPlayerTest { player.prepare(); TestPlayerRunHelper.playUntilPosition( - player, /* windowIndex= */ 0, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); + player, /* mediaItemIndex= */ 0, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); player.setMediaSources(ImmutableList.of(secondMediaSource, secondMediaSource)); player.play(); TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); @@ -10428,11 +10447,11 @@ public final class ExoPlayerTest { player.prepare(); TestPlayerRunHelper.playUntilPosition( - player, /* windowIndex= */ 1, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); + player, /* mediaItemIndex= */ 1, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); player.removeMediaItem(/* index= */ 1); player.seekTo(/* positionMs= */ 0); TestPlayerRunHelper.playUntilPosition( - player, /* windowIndex= */ 0, /* positionMs= */ 2 * C.MILLIS_PER_SECOND); + player, /* mediaItemIndex= */ 0, /* positionMs= */ 2 * C.MILLIS_PER_SECOND); // Removing the last item resets the position to 0 with an empty timeline. player.removeMediaItem(0); TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); @@ -10517,7 +10536,7 @@ public final class ExoPlayerTest { player.prepare(); TestPlayerRunHelper.playUntilPosition( - player, /* windowIndex= */ 1, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); + player, /* mediaItemIndex= */ 1, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); concatenatingMediaSource.removeMediaSource(1); TestPlayerRunHelper.runUntilPendingCommandsAreFullyHandled(player); concatenatingMediaSource.removeMediaSource(1); @@ -10590,9 +10609,9 @@ public final class ExoPlayerTest { player.prepare(); TestPlayerRunHelper.playUntilPosition( - player, /* windowIndex= */ 1, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); + player, /* mediaItemIndex= */ 1, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); concatenatingMediaSource.removeMediaSource(1); - player.seekTo(/* windowIndex= */ 0, /* positionMs= */ 1234); + player.seekTo(/* mediaItemIndex= */ 0, /* positionMs= */ 1234); TestPlayerRunHelper.runUntilPendingCommandsAreFullyHandled(player); concatenatingMediaSource.removeMediaSource(0); player.play(); @@ -10708,9 +10727,9 @@ public final class ExoPlayerTest { player.prepare(); TestPlayerRunHelper.playUntilPosition( - player, /* windowIndex= */ 0, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); + player, /* mediaItemIndex= */ 0, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); player.seekTo(/* positionMs= */ 7 * C.MILLIS_PER_SECOND); - player.seekTo(/* windowIndex= */ 1, /* positionMs= */ C.MILLIS_PER_SECOND); + player.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ C.MILLIS_PER_SECOND); player.play(); TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); @@ -10753,7 +10772,7 @@ public final class ExoPlayerTest { player.addListener(listener); player.seekTo(/* positionMs= */ 7 * C.MILLIS_PER_SECOND); - player.seekTo(/* windowIndex= */ 1, /* positionMs= */ C.MILLIS_PER_SECOND); + player.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ C.MILLIS_PER_SECOND); player.seekTo(/* positionMs= */ 5 * C.MILLIS_PER_SECOND); ArgumentCaptor oldPosition = @@ -10787,7 +10806,7 @@ public final class ExoPlayerTest { assertThat(newPositions.get(1).mediaItemIndex).isEqualTo(1); assertThat(newPositions.get(1).positionMs).isEqualTo(1_000); assertThat(newPositions.get(1).contentPositionMs).isEqualTo(1_000); - // a seek from masked seek position to another masked position within window + // a seek from masked seek position to another masked position within media item assertThat(oldPositions.get(2).windowUid).isNull(); assertThat(oldPositions.get(2).mediaItemIndex).isEqualTo(1); assertThat(oldPositions.get(2).mediaItem).isNull(); @@ -10815,7 +10834,7 @@ public final class ExoPlayerTest { player.prepare(); TestPlayerRunHelper.playUntilPosition( - player, /* windowIndex= */ 0, /* positionMs= */ 2 * C.DEFAULT_SEEK_BACK_INCREMENT_MS); + player, /* mediaItemIndex= */ 0, /* positionMs= */ 2 * C.DEFAULT_SEEK_BACK_INCREMENT_MS); player.seekBack(); ArgumentCaptor oldPosition = @@ -10862,7 +10881,7 @@ public final class ExoPlayerTest { player.prepare(); TestPlayerRunHelper.playUntilPosition( - player, /* windowIndex= */ 0, /* positionMs= */ C.DEFAULT_SEEK_BACK_INCREMENT_MS / 2); + player, /* mediaItemIndex= */ 0, /* positionMs= */ C.DEFAULT_SEEK_BACK_INCREMENT_MS / 2); player.seekBack(); assertThat(player.getCurrentPosition()).isEqualTo(0); @@ -10933,11 +10952,11 @@ public final class ExoPlayerTest { public void seekToPrevious_withPreviousWindowAndCloseToStart_seeksToPreviousWindow() { ExoPlayer player = new TestExoPlayerBuilder(context).build(); player.addMediaSources(ImmutableList.of(new FakeMediaSource(), new FakeMediaSource())); - player.seekTo(/* windowIndex= */ 1, C.DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION_MS); + player.seekTo(/* mediaItemIndex= */ 1, C.DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION_MS); player.seekToPrevious(); - assertThat(player.getCurrentWindowIndex()).isEqualTo(0); + assertThat(player.getCurrentMediaItemIndex()).isEqualTo(0); assertThat(player.getCurrentPosition()).isEqualTo(0); player.release(); @@ -10947,11 +10966,11 @@ public final class ExoPlayerTest { public void seekToPrevious_notCloseToStart_seeksToZero() { ExoPlayer player = new TestExoPlayerBuilder(context).build(); player.addMediaSources(ImmutableList.of(new FakeMediaSource(), new FakeMediaSource())); - player.seekTo(/* windowIndex= */ 1, C.DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION_MS + 1); + player.seekTo(/* mediaItemIndex= */ 1, C.DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION_MS + 1); player.seekToPrevious(); - assertThat(player.getCurrentWindowIndex()).isEqualTo(1); + assertThat(player.getCurrentMediaItemIndex()).isEqualTo(1); assertThat(player.getCurrentPosition()).isEqualTo(0); player.release(); @@ -10964,7 +10983,7 @@ public final class ExoPlayerTest { player.seekToNext(); - assertThat(player.getCurrentWindowIndex()).isEqualTo(1); + assertThat(player.getCurrentMediaItemIndex()).isEqualTo(1); assertThat(player.getCurrentPosition()).isEqualTo(0); player.release(); @@ -10994,7 +11013,7 @@ public final class ExoPlayerTest { player.seekTo(/* positionMs = */ 0); player.seekToNext(); - assertThat(player.getCurrentWindowIndex()).isEqualTo(0); + assertThat(player.getCurrentMediaItemIndex()).isEqualTo(0); assertThat(player.getCurrentPosition()).isEqualTo(500); player.release(); @@ -11009,7 +11028,7 @@ public final class ExoPlayerTest { player.prepare(); TestPlayerRunHelper.playUntilPosition( - player, /* windowIndex= */ 0, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); + player, /* mediaItemIndex= */ 0, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); player.stop(); verify(listener, never()).onPositionDiscontinuity(any(), any(), anyInt()); @@ -11027,7 +11046,7 @@ public final class ExoPlayerTest { player.prepare(); TestPlayerRunHelper.playUntilPosition( - player, /* windowIndex= */ 0, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); + player, /* mediaItemIndex= */ 0, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); player.stop(/* reset= */ true); ArgumentCaptor oldPosition = @@ -11071,13 +11090,13 @@ public final class ExoPlayerTest { player.setMediaSource(mediaSource); player.prepare(); - TestPlayerRunHelper.playUntilPosition(player, /* windowIndex= */ 1, /* positionMs= */ 2000); - player.seekTo(/* windowIndex= */ 1, /* positionMs= */ 2122); + TestPlayerRunHelper.playUntilPosition(player, /* mediaItemIndex= */ 1, /* positionMs= */ 2000); + player.seekTo(/* mediaItemIndex= */ 1, /* positionMs= */ 2122); // This causes a DISCONTINUITY_REASON_REMOVE between pending operations that needs to be // cancelled by the seek below. mediaSource.setNewSourceInfo(timeline2); player.play(); - player.seekTo(/* windowIndex= */ 0, /* positionMs= */ 2222); + player.seekTo(/* mediaItemIndex= */ 0, /* positionMs= */ 2222); TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); ArgumentCaptor oldPosition = @@ -11176,7 +11195,7 @@ public final class ExoPlayerTest { .send(); player.setMediaSource(mediaSource); player.prepare(); - playUntilPosition(player, /* windowIndex= */ 0, /* positionMs= */ 40_000); + playUntilPosition(player, /* mediaItemIndex= */ 0, /* positionMs= */ 40_000); player.release(); // Assert that the renderer hasn't been reset despite the inserted ad group. @@ -11215,7 +11234,7 @@ public final class ExoPlayerTest { player.prepare(); TestPlayerRunHelper.playUntilPosition( - player, /* windowIndex= */ 0, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); + player, /* mediaItemIndex= */ 0, /* positionMs= */ 5 * C.MILLIS_PER_SECOND); player.stop(); shadowOf(Looper.getMainLooper()).idle(); @@ -11360,18 +11379,18 @@ public final class ExoPlayerTest { private static final class PositionGrabbingMessageTarget extends PlayerTarget { - public int windowIndex; + public int mediaItemIndex; public long positionMs; public int messageCount; public PositionGrabbingMessageTarget() { - windowIndex = C.INDEX_UNSET; + mediaItemIndex = C.INDEX_UNSET; positionMs = C.POSITION_UNSET; } @Override public void handleMessage(ExoPlayer player, int messageType, @Nullable Object message) { - windowIndex = player.getCurrentWindowIndex(); + mediaItemIndex = player.getCurrentMediaItemIndex(); positionMs = player.getCurrentPosition(); messageCount++; } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java index 6adfe54b4f..a7838377bf 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java @@ -950,7 +950,7 @@ public class PlayerControlView extends FrameLayout { int adGroupCount = 0; Timeline timeline = player.getCurrentTimeline(); if (!timeline.isEmpty()) { - int currentWindowIndex = player.getCurrentWindowIndex(); + int currentWindowIndex = player.getCurrentMediaItemIndex(); int firstWindowIndex = multiWindowTimeBar ? 0 : currentWindowIndex; int lastWindowIndex = multiWindowTimeBar ? timeline.getWindowCount() - 1 : currentWindowIndex; for (int i = firstWindowIndex; i <= lastWindowIndex; i++) { @@ -1110,7 +1110,7 @@ public class PlayerControlView extends FrameLayout { windowIndex++; } } else { - windowIndex = player.getCurrentWindowIndex(); + windowIndex = player.getCurrentMediaItemIndex(); } seekTo(player, windowIndex, positionMs); updateProgress(); @@ -1228,7 +1228,7 @@ public class PlayerControlView extends FrameLayout { if (state == Player.STATE_IDLE) { player.prepare(); } else if (state == Player.STATE_ENDED) { - seekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET); + seekTo(player, player.getCurrentMediaItemIndex(), C.TIME_UNSET); } player.play(); } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java index 26075126d0..682483cd4e 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java @@ -605,9 +605,9 @@ public class PlayerNotificationManager { public static final String ACTION_PLAY = "com.google.android.exoplayer.play"; /** The action which pauses playback. */ public static final String ACTION_PAUSE = "com.google.android.exoplayer.pause"; - /** The action which skips to the previous window. */ + /** The action which skips to the previous media item. */ public static final String ACTION_PREVIOUS = "com.google.android.exoplayer.prev"; - /** The action which skips to the next window. */ + /** The action which skips to the next media item. */ public static final String ACTION_NEXT = "com.google.android.exoplayer.next"; /** The action which fast forwards. */ public static final String ACTION_FAST_FORWARD = "com.google.android.exoplayer.ffwd"; @@ -1095,7 +1095,7 @@ public class PlayerNotificationManager { * *
      *
    • The media is {@link Player#isPlaying() actively playing}. - *
    • The media is not {@link Player#isCurrentWindowDynamic() dynamically changing its + *
    • The media is not {@link Player#isCurrentMediaItemDynamic() dynamically changing its * duration} (like for example a live stream). *
    • The media is not {@link Player#isPlayingAd() interrupted by an ad}. *
    • The media is played at {@link Player#getPlaybackParameters() regular speed}. @@ -1253,7 +1253,7 @@ public class PlayerNotificationManager { && useChronometer && player.isPlaying() && !player.isPlayingAd() - && !player.isCurrentWindowDynamic() + && !player.isCurrentMediaItemDynamic() && player.getPlaybackParameters().speed == 1f) { builder .setWhen(System.currentTimeMillis() - player.getContentPosition()) @@ -1531,7 +1531,7 @@ public class PlayerNotificationManager { if (player.getPlaybackState() == Player.STATE_IDLE) { player.prepare(); } else if (player.getPlaybackState() == Player.STATE_ENDED) { - player.seekToDefaultPosition(player.getCurrentWindowIndex()); + player.seekToDefaultPosition(player.getCurrentMediaItemIndex()); } player.play(); } else if (ACTION_PAUSE.equals(action)) { diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java index 4836774bb2..30533dcd19 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java @@ -1501,8 +1501,8 @@ public class PlayerView extends FrameLayout implements AdViewProvider { if (lastPeriodIndexWithTracks != C.INDEX_UNSET) { int lastWindowIndexWithTracks = timeline.getPeriod(lastPeriodIndexWithTracks, period).windowIndex; - if (player.getCurrentWindowIndex() == lastWindowIndexWithTracks) { - // We're in the same window. Suppress the update. + if (player.getCurrentMediaItemIndex() == lastWindowIndexWithTracks) { + // We're in the same media item. Suppress the update. return; } } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java index 279e907476..c6e0aadad0 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java @@ -1269,7 +1269,7 @@ public class StyledPlayerControlView extends FrameLayout { int adGroupCount = 0; Timeline timeline = player.getCurrentTimeline(); if (!timeline.isEmpty()) { - int currentWindowIndex = player.getCurrentWindowIndex(); + int currentWindowIndex = player.getCurrentMediaItemIndex(); int firstWindowIndex = multiWindowTimeBar ? 0 : currentWindowIndex; int lastWindowIndex = multiWindowTimeBar ? timeline.getWindowCount() - 1 : currentWindowIndex; for (int i = firstWindowIndex; i <= lastWindowIndex; i++) { @@ -1453,7 +1453,7 @@ public class StyledPlayerControlView extends FrameLayout { windowIndex++; } } else { - windowIndex = player.getCurrentWindowIndex(); + windowIndex = player.getCurrentMediaItemIndex(); } seekTo(player, windowIndex, positionMs); updateProgress(); @@ -1616,13 +1616,12 @@ public class StyledPlayerControlView extends FrameLayout { } } - @SuppressWarnings("deprecation") private void dispatchPlay(Player player) { @State int state = player.getPlaybackState(); if (state == Player.STATE_IDLE) { player.prepare(); } else if (state == Player.STATE_ENDED) { - seekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET); + seekTo(player, player.getCurrentMediaItemIndex(), C.TIME_UNSET); } player.play(); } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java index 4434aef516..b8907094fd 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java @@ -1540,8 +1540,8 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider { if (lastPeriodIndexWithTracks != C.INDEX_UNSET) { int lastWindowIndexWithTracks = timeline.getPeriod(lastPeriodIndexWithTracks, period).windowIndex; - if (player.getCurrentWindowIndex() == lastWindowIndexWithTracks) { - // We're in the same window. Suppress the update. + if (player.getCurrentMediaItemIndex() == lastWindowIndexWithTracks) { + // We're in the same media item. Suppress the update. return; } } diff --git a/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java index efcb290579..58ed22f289 100644 --- a/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java +++ b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java @@ -284,12 +284,12 @@ public class TestPlayerRunHelper { *

      If a playback error occurs it will be thrown wrapped in an {@link IllegalStateException}. * * @param player The {@link Player}. - * @param windowIndex The window. - * @param positionMs The position within the window, in milliseconds. + * @param mediaItemIndex The index of the media item. + * @param positionMs The position within the media item, in milliseconds. * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is * exceeded. */ - public static void playUntilPosition(ExoPlayer player, int windowIndex, long positionMs) + public static void playUntilPosition(ExoPlayer player, int mediaItemIndex, long positionMs) throws TimeoutException { verifyMainTestThread(player); Looper applicationLooper = Util.getCurrentOrMainLooper(); @@ -315,7 +315,7 @@ public class TestPlayerRunHelper { // Ignore. } }) - .setPosition(windowIndex, positionMs) + .setPosition(mediaItemIndex, positionMs) .send(); player.play(); runMainLooperUntil(() -> messageHandled.get() || player.getPlayerError() != null); @@ -326,18 +326,19 @@ public class TestPlayerRunHelper { /** * Calls {@link Player#play()}, runs tasks of the main {@link Looper} until the {@code player} - * reaches the specified window or a playback error occurs, and then pauses the {@code player}. + * reaches the specified media item or a playback error occurs, and then pauses the {@code + * player}. * *

      If a playback error occurs it will be thrown wrapped in an {@link IllegalStateException}. * * @param player The {@link Player}. - * @param windowIndex The window. + * @param mediaItemIndex The index of the media item. * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is * exceeded. */ - public static void playUntilStartOfWindow(ExoPlayer player, int windowIndex) + public static void playUntilStartOfMediaItem(ExoPlayer player, int mediaItemIndex) throws TimeoutException { - playUntilPosition(player, windowIndex, /* positionMs= */ 0); + playUntilPosition(player, mediaItemIndex, /* positionMs= */ 0); } /** diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java index 43d5162bd3..b5cdf77d5c 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java @@ -121,7 +121,7 @@ public abstract class Action { /** Calls {@link Player#seekTo(long)} or {@link Player#seekTo(int, long)}. */ public static final class Seek extends Action { - @Nullable private final Integer windowIndex; + @Nullable private final Integer mediaItemIndex; private final long positionMs; private final boolean catchIllegalSeekException; @@ -133,7 +133,7 @@ public abstract class Action { */ public Seek(String tag, long positionMs) { super(tag, "Seek:" + positionMs); - this.windowIndex = null; + this.mediaItemIndex = null; this.positionMs = positionMs; catchIllegalSeekException = false; } @@ -142,14 +142,15 @@ public abstract class Action { * Action calls {@link Player#seekTo(int, long)}. * * @param tag A tag to use for logging. - * @param windowIndex The window to seek to. + * @param mediaItemIndex The media item to seek to. * @param positionMs The seek position. * @param catchIllegalSeekException Whether {@link IllegalSeekPositionException} should be * silently caught or not. */ - public Seek(String tag, int windowIndex, long positionMs, boolean catchIllegalSeekException) { + public Seek( + String tag, int mediaItemIndex, long positionMs, boolean catchIllegalSeekException) { super(tag, "Seek:" + positionMs); - this.windowIndex = windowIndex; + this.mediaItemIndex = mediaItemIndex; this.positionMs = positionMs; this.catchIllegalSeekException = catchIllegalSeekException; } @@ -158,10 +159,10 @@ public abstract class Action { protected void doActionImpl( ExoPlayer player, DefaultTrackSelector trackSelector, @Nullable Surface surface) { try { - if (windowIndex == null) { + if (mediaItemIndex == null) { player.seekTo(positionMs); } else { - player.seekTo(windowIndex, positionMs); + player.seekTo(mediaItemIndex, positionMs); } } catch (IllegalSeekPositionException e) { if (!catchIllegalSeekException) { @@ -174,20 +175,20 @@ public abstract class Action { /** Calls {@link ExoPlayer#setMediaSources(List, int, long)}. */ public static final class SetMediaItems extends Action { - private final int windowIndex; + private final int mediaItemIndex; private final long positionMs; private final MediaSource[] mediaSources; /** * @param tag A tag to use for logging. - * @param windowIndex The window index to start playback from. + * @param mediaItemIndex The media item index to start playback from. * @param positionMs The position in milliseconds to start playback from. * @param mediaSources The media sources to populate the playlist with. */ public SetMediaItems( - String tag, int windowIndex, long positionMs, MediaSource... mediaSources) { + String tag, int mediaItemIndex, long positionMs, MediaSource... mediaSources) { super(tag, "SetMediaItems"); - this.windowIndex = windowIndex; + this.mediaItemIndex = mediaItemIndex; this.positionMs = positionMs; this.mediaSources = mediaSources; } @@ -195,7 +196,7 @@ public abstract class Action { @Override protected void doActionImpl( ExoPlayer player, DefaultTrackSelector trackSelector, @Nullable Surface surface) { - player.setMediaSources(Arrays.asList(mediaSources), windowIndex, positionMs); + player.setMediaSources(Arrays.asList(mediaSources), mediaItemIndex, positionMs); } } @@ -553,7 +554,7 @@ public abstract class Action { public static final class SendMessages extends Action { private final Target target; - private final int windowIndex; + private final int mediaItemIndex; private final long positionMs; private final boolean deleteAfterDelivery; @@ -566,7 +567,7 @@ public abstract class Action { this( tag, target, - /* windowIndex= */ C.INDEX_UNSET, + /* mediaItemIndex= */ C.INDEX_UNSET, positionMs, /* deleteAfterDelivery= */ true); } @@ -574,16 +575,20 @@ public abstract class Action { /** * @param tag A tag to use for logging. * @param target A message target. - * @param windowIndex The window index at which the message should be sent, or {@link - * C#INDEX_UNSET} for the current window. + * @param mediaItemIndex The media item index at which the message should be sent, or {@link + * C#INDEX_UNSET} for the current media item. * @param positionMs The position at which the message should be sent, in milliseconds. * @param deleteAfterDelivery Whether the message will be deleted after delivery. */ public SendMessages( - String tag, Target target, int windowIndex, long positionMs, boolean deleteAfterDelivery) { + String tag, + Target target, + int mediaItemIndex, + long positionMs, + boolean deleteAfterDelivery) { super(tag, "SendMessages"); this.target = target; - this.windowIndex = windowIndex; + this.mediaItemIndex = mediaItemIndex; this.positionMs = positionMs; this.deleteAfterDelivery = deleteAfterDelivery; } @@ -595,8 +600,8 @@ public abstract class Action { ((PlayerTarget) target).setPlayer(player); } PlayerMessage message = player.createMessage(target); - if (windowIndex != C.INDEX_UNSET) { - message.setPosition(windowIndex, positionMs); + if (mediaItemIndex != C.INDEX_UNSET) { + message.setPosition(mediaItemIndex, positionMs); } else { message.setPosition(positionMs); } @@ -661,17 +666,17 @@ public abstract class Action { */ public static final class PlayUntilPosition extends Action { - private final int windowIndex; + private final int mediaItemIndex; private final long positionMs; /** * @param tag A tag to use for logging. - * @param windowIndex The window index at which the player should be paused again. - * @param positionMs The position in that window at which the player should be paused again. + * @param mediaItemIndex The media item index at which the player should be paused again. + * @param positionMs The position in that media item at which the player should be paused again. */ - public PlayUntilPosition(String tag, int windowIndex, long positionMs) { - super(tag, "PlayUntilPosition:" + windowIndex + ":" + positionMs); - this.windowIndex = windowIndex; + public PlayUntilPosition(String tag, int mediaItemIndex, long positionMs) { + super(tag, "PlayUntilPosition:" + mediaItemIndex + ":" + positionMs); + this.mediaItemIndex = mediaItemIndex; this.positionMs = positionMs; } @@ -704,7 +709,7 @@ public abstract class Action { // Ignore. } }) - .setPosition(windowIndex, positionMs) + .setPosition(mediaItemIndex, positionMs) .send(); if (nextAction != null) { // Schedule another message on this test thread to continue action schedule. @@ -712,7 +717,7 @@ public abstract class Action { .createMessage( (messageType, payload) -> nextAction.schedule(player, trackSelector, surface, handler)) - .setPosition(windowIndex, positionMs) + .setPosition(mediaItemIndex, positionMs) .setLooper(applicationLooper) .send(); } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java index 4590d5fd6b..0282e57a8c 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java @@ -161,24 +161,25 @@ public final class ActionSchedule { /** * Schedules a seek action. * - * @param windowIndex The window to seek to. + * @param mediaItemIndex The media item to seek to. * @param positionMs The seek position. * @return The builder, for convenience. */ - public Builder seek(int windowIndex, long positionMs) { - return apply(new Seek(tag, windowIndex, positionMs, /* catchIllegalSeekException= */ false)); + public Builder seek(int mediaItemIndex, long positionMs) { + return apply( + new Seek(tag, mediaItemIndex, positionMs, /* catchIllegalSeekException= */ false)); } /** * Schedules a seek action to be executed. * - * @param windowIndex The window to seek to. + * @param mediaItemIndex The media item to seek to. * @param positionMs The seek position. * @param catchIllegalSeekException Whether an illegal seek position should be caught or not. * @return The builder, for convenience. */ - public Builder seek(int windowIndex, long positionMs, boolean catchIllegalSeekException) { - return apply(new Seek(tag, windowIndex, positionMs, catchIllegalSeekException)); + public Builder seek(int mediaItemIndex, long positionMs, boolean catchIllegalSeekException) { + return apply(new Seek(tag, mediaItemIndex, positionMs, catchIllegalSeekException)); } /** @@ -247,23 +248,23 @@ public final class ActionSchedule { * Schedules a play action, waits until the player reaches the specified position, and pauses * the player again. * - * @param windowIndex The window index at which the player should be paused again. - * @param positionMs The position in that window at which the player should be paused again. + * @param mediaItemIndex The media item index at which the player should be paused again. + * @param positionMs The position in that media item at which the player should be paused again. * @return The builder, for convenience. */ - public Builder playUntilPosition(int windowIndex, long positionMs) { - return apply(new PlayUntilPosition(tag, windowIndex, positionMs)); + public Builder playUntilPosition(int mediaItemIndex, long positionMs) { + return apply(new PlayUntilPosition(tag, mediaItemIndex, positionMs)); } /** - * Schedules a play action, waits until the player reaches the start of the specified window, - * and pauses the player again. + * Schedules a play action, waits until the player reaches the start of the specified media + * item, and pauses the player again. * - * @param windowIndex The window index at which the player should be paused again. + * @param mediaItemIndex The media item index at which the player should be paused again. * @return The builder, for convenience. */ - public Builder playUntilStartOfWindow(int windowIndex) { - return apply(new PlayUntilPosition(tag, windowIndex, /* positionMs= */ 0)); + public Builder playUntilStartOfMediaItem(int mediaItemIndex) { + return apply(new PlayUntilPosition(tag, mediaItemIndex, /* positionMs= */ 0)); } /** @@ -323,16 +324,16 @@ public final class ActionSchedule { /** * Schedules a set media items action to be executed. * - * @param windowIndex The window index to start playback from or {@link C#INDEX_UNSET} if the - * playback position should not be reset. + * @param mediaItemIndex The media item index to start playback from or {@link C#INDEX_UNSET} if + * the playback position should not be reset. * @param positionMs The position in milliseconds from where playback should start. If {@link - * C#TIME_UNSET} is passed the default position is used. In any case, if {@code windowIndex} - * is set to {@link C#INDEX_UNSET} the position is not reset at all and this parameter is - * ignored. + * C#TIME_UNSET} is passed the default position is used. In any case, if {@code + * mediaItemIndex} is set to {@link C#INDEX_UNSET} the position is not reset at all and this + * parameter is ignored. * @return The builder, for convenience. */ - public Builder setMediaSources(int windowIndex, long positionMs, MediaSource... sources) { - return apply(new Action.SetMediaItems(tag, windowIndex, positionMs, sources)); + public Builder setMediaSources(int mediaItemIndex, long positionMs, MediaSource... sources) { + return apply(new Action.SetMediaItems(tag, mediaItemIndex, positionMs, sources)); } /** @@ -354,7 +355,10 @@ public final class ActionSchedule { public Builder setMediaSources(MediaSource... mediaSources) { return apply( new Action.SetMediaItems( - tag, /* windowIndex= */ C.INDEX_UNSET, /* positionMs= */ C.TIME_UNSET, mediaSources)); + tag, + /* mediaItemIndex= */ C.INDEX_UNSET, + /* positionMs= */ C.TIME_UNSET, + mediaSources)); } /** * Schedules a add media items action to be executed. @@ -447,8 +451,8 @@ public final class ActionSchedule { /** * Schedules sending a {@link PlayerMessage}. * - * @param positionMs The position in the current window at which the message should be sent, in - * milliseconds. + * @param positionMs The position in the current media item at which the message should be sent, + * in milliseconds. * @return The builder, for convenience. */ public Builder sendMessage(Target target, long positionMs) { @@ -459,27 +463,28 @@ public final class ActionSchedule { * Schedules sending a {@link PlayerMessage}. * * @param target A message target. - * @param windowIndex The window index at which the message should be sent. + * @param mediaItemIndex The media item index at which the message should be sent. * @param positionMs The position at which the message should be sent, in milliseconds. * @return The builder, for convenience. */ - public Builder sendMessage(Target target, int windowIndex, long positionMs) { + public Builder sendMessage(Target target, int mediaItemIndex, long positionMs) { return apply( - new SendMessages(tag, target, windowIndex, positionMs, /* deleteAfterDelivery= */ true)); + new SendMessages( + tag, target, mediaItemIndex, positionMs, /* deleteAfterDelivery= */ true)); } /** * Schedules to send a {@link PlayerMessage}. * * @param target A message target. - * @param windowIndex The window index at which the message should be sent. + * @param mediaItemIndex The media item index at which the message should be sent. * @param positionMs The position at which the message should be sent, in milliseconds. * @param deleteAfterDelivery Whether the message will be deleted after delivery. * @return The builder, for convenience. */ public Builder sendMessage( - Target target, int windowIndex, long positionMs, boolean deleteAfterDelivery) { - return apply(new SendMessages(tag, target, windowIndex, positionMs, deleteAfterDelivery)); + Target target, int mediaItemIndex, long positionMs, boolean deleteAfterDelivery) { + return apply(new SendMessages(tag, target, mediaItemIndex, positionMs, deleteAfterDelivery)); } /** diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java index 6df171442d..1a305f0e35 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java @@ -85,7 +85,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul private AnalyticsListener analyticsListener; private Integer expectedPlayerEndedCount; private boolean pauseAtEndOfMediaItems; - private int initialWindowIndex; + private int initialMediaItemIndex; private long initialPositionMs; private boolean skipSettingMediaSources; @@ -93,7 +93,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul testPlayerBuilder = new TestExoPlayerBuilder(context); mediaSources = new ArrayList<>(); supportedFormats = new Format[] {VIDEO_FORMAT}; - initialWindowIndex = C.INDEX_UNSET; + initialMediaItemIndex = C.INDEX_UNSET; initialPositionMs = C.TIME_UNSET; } @@ -133,12 +133,12 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul /** * Seeks before setting the media sources and preparing the player. * - * @param windowIndex The window index to seek to. + * @param mediaItemIndex The media item index to seek to. * @param positionMs The position in milliseconds to seek to. * @return This builder. */ - public Builder initialSeek(int windowIndex, long positionMs) { - this.initialWindowIndex = windowIndex; + public Builder initialSeek(int mediaItemIndex, long positionMs) { + this.initialMediaItemIndex = mediaItemIndex; this.initialPositionMs = positionMs; return this; } @@ -343,7 +343,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul testPlayerBuilder, mediaSources, skipSettingMediaSources, - initialWindowIndex, + initialMediaItemIndex, initialPositionMs, surface, actionSchedule, @@ -357,7 +357,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul private final TestExoPlayerBuilder playerBuilder; private final List mediaSources; private final boolean skipSettingMediaSources; - private final int initialWindowIndex; + private final int initialMediaItemIndex; private final long initialPositionMs; @Nullable private final Surface surface; @Nullable private final ActionSchedule actionSchedule; @@ -386,7 +386,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul TestExoPlayerBuilder playerBuilder, List mediaSources, boolean skipSettingMediaSources, - int initialWindowIndex, + int initialMediaItemIndex, long initialPositionMs, @Nullable Surface surface, @Nullable ActionSchedule actionSchedule, @@ -397,7 +397,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul this.playerBuilder = playerBuilder; this.mediaSources = mediaSources; this.skipSettingMediaSources = skipSettingMediaSources; - this.initialWindowIndex = initialWindowIndex; + this.initialMediaItemIndex = initialMediaItemIndex; this.initialPositionMs = initialPositionMs; this.surface = surface; this.actionSchedule = actionSchedule; @@ -466,8 +466,8 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul handler, /* callback= */ ExoPlayerTestRunner.this); } - if (initialWindowIndex != C.INDEX_UNSET) { - player.seekTo(initialWindowIndex, initialPositionMs); + if (initialMediaItemIndex != C.INDEX_UNSET) { + player.seekTo(initialMediaItemIndex, initialPositionMs); } if (!skipSettingMediaSources) { player.setMediaSources(mediaSources, /* resetPosition= */ false); diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java index c0acae1da6..136327739f 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java @@ -162,7 +162,7 @@ public class StubExoPlayer extends StubPlayer implements ExoPlayer { @Override public void setMediaSources( - List mediaSources, int startWindowIndex, long startPositionMs) { + List mediaSources, int startMediaItemIndex, long startPositionMs) { throw new UnsupportedOperationException(); } From ee4af48a10084c0aca95dd2ed4b23a39187f62c0 Mon Sep 17 00:00:00 2001 From: christosts Date: Tue, 2 Nov 2021 10:49:18 +0000 Subject: [PATCH 030/497] Replace map with a switch statement in bandwidth meter implementations #minor-release PiperOrigin-RevId: 407042882 --- .../upstream/DefaultBandwidthMeter.java | 713 +++++++++++------- 1 file changed, 438 insertions(+), 275 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java index 07b3185b43..2db19fb6a7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java @@ -26,10 +26,8 @@ import com.google.android.exoplayer2.util.NetworkTypeObserver; import com.google.android.exoplayer2.util.Util; import com.google.common.base.Ascii; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableMap; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -42,13 +40,6 @@ import java.util.Map; */ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferListener { - /** - * Country groups used to determine the default initial bitrate estimate. The group assignment for - * each country is a list for [Wifi, 2G, 3G, 4G, 5G_NSA, 5G_SA]. - */ - public static final ImmutableListMultimap - DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS = createInitialBitrateCountryGroupAssignment(); - /** Default initial Wifi bitrate estimate in bits per second. */ public static final ImmutableList DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI = ImmutableList.of(5_400_000L, 3_300_000L, 2_000_000L, 1_300_000L, 760_000L); @@ -82,17 +73,35 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList /** Default maximum weight for the sliding window. */ public static final int DEFAULT_SLIDING_WINDOW_MAX_WEIGHT = 2000; - /** Index for the Wifi group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */ + /** + * Index for the Wifi group index in the array returned by {@link + * #getInitialBitrateCountryGroupAssignment}. + */ private static final int COUNTRY_GROUP_INDEX_WIFI = 0; - /** Index for the 2G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */ + /** + * Index for the 2G group index in the array returned by {@link + * #getInitialBitrateCountryGroupAssignment}. + */ private static final int COUNTRY_GROUP_INDEX_2G = 1; - /** Index for the 3G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */ + /** + * Index for the 3G group index in the array returned by {@link + * #getInitialBitrateCountryGroupAssignment}. + */ private static final int COUNTRY_GROUP_INDEX_3G = 2; - /** Index for the 4G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */ + /** + * Index for the 4G group index in the array returned by {@link + * #getInitialBitrateCountryGroupAssignment}. + */ private static final int COUNTRY_GROUP_INDEX_4G = 3; - /** Index for the 5G-NSA group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */ + /** + * Index for the 5G-NSA group index in the array returned by {@link + * #getInitialBitrateCountryGroupAssignment}. + */ private static final int COUNTRY_GROUP_INDEX_5G_NSA = 4; - /** Index for the 5G-SA group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */ + /** + * Index for the 5G-SA group index in the array returned by {@link + * #getInitialBitrateCountryGroupAssignment}. + */ private static final int COUNTRY_GROUP_INDEX_5G_SA = 5; @Nullable private static DefaultBandwidthMeter singletonInstance; @@ -212,40 +221,33 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList } private static Map getInitialBitrateEstimatesForCountry(String countryCode) { - List groupIndices = getCountryGroupIndices(countryCode); + int[] groupIndices = getInitialBitrateCountryGroupAssignment(countryCode); Map result = new HashMap<>(/* initialCapacity= */ 8); result.put(C.NETWORK_TYPE_UNKNOWN, DEFAULT_INITIAL_BITRATE_ESTIMATE); result.put( C.NETWORK_TYPE_WIFI, - DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI.get(groupIndices.get(COUNTRY_GROUP_INDEX_WIFI))); + DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI.get(groupIndices[COUNTRY_GROUP_INDEX_WIFI])); result.put( C.NETWORK_TYPE_2G, - DEFAULT_INITIAL_BITRATE_ESTIMATES_2G.get(groupIndices.get(COUNTRY_GROUP_INDEX_2G))); + DEFAULT_INITIAL_BITRATE_ESTIMATES_2G.get(groupIndices[COUNTRY_GROUP_INDEX_2G])); result.put( C.NETWORK_TYPE_3G, - DEFAULT_INITIAL_BITRATE_ESTIMATES_3G.get(groupIndices.get(COUNTRY_GROUP_INDEX_3G))); + DEFAULT_INITIAL_BITRATE_ESTIMATES_3G.get(groupIndices[COUNTRY_GROUP_INDEX_3G])); result.put( C.NETWORK_TYPE_4G, - DEFAULT_INITIAL_BITRATE_ESTIMATES_4G.get(groupIndices.get(COUNTRY_GROUP_INDEX_4G))); + DEFAULT_INITIAL_BITRATE_ESTIMATES_4G.get(groupIndices[COUNTRY_GROUP_INDEX_4G])); result.put( C.NETWORK_TYPE_5G_NSA, - DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA.get( - groupIndices.get(COUNTRY_GROUP_INDEX_5G_NSA))); + DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA.get(groupIndices[COUNTRY_GROUP_INDEX_5G_NSA])); result.put( C.NETWORK_TYPE_5G_SA, - DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_SA.get(groupIndices.get(COUNTRY_GROUP_INDEX_5G_SA))); + DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_SA.get(groupIndices[COUNTRY_GROUP_INDEX_5G_SA])); // Assume default Wifi speed for Ethernet to prevent using the slower fallback. result.put( C.NETWORK_TYPE_ETHERNET, - DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI.get(groupIndices.get(COUNTRY_GROUP_INDEX_WIFI))); + DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI.get(groupIndices[COUNTRY_GROUP_INDEX_WIFI])); return result; } - - private static ImmutableList getCountryGroupIndices(String countryCode) { - ImmutableList groupIndices = DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS.get(countryCode); - // Assume median group if not found. - return groupIndices.isEmpty() ? ImmutableList.of(2, 2, 2, 2, 2, 2) : groupIndices; - } } /** @@ -461,250 +463,411 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList return isNetwork && !dataSpec.isFlagSet(DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED); } - private static ImmutableListMultimap - createInitialBitrateCountryGroupAssignment() { - return ImmutableListMultimap.builder() - .putAll("AD", 1, 2, 0, 0, 2, 2) - .putAll("AE", 1, 4, 4, 4, 3, 2) - .putAll("AF", 4, 4, 4, 4, 2, 2) - .putAll("AG", 2, 3, 1, 2, 2, 2) - .putAll("AI", 1, 2, 2, 2, 2, 2) - .putAll("AL", 1, 2, 0, 1, 2, 2) - .putAll("AM", 2, 3, 2, 4, 2, 2) - .putAll("AO", 3, 4, 3, 2, 2, 2) - .putAll("AQ", 4, 2, 2, 2, 2, 2) - .putAll("AR", 2, 4, 1, 1, 2, 2) - .putAll("AS", 2, 2, 2, 3, 2, 2) - .putAll("AT", 0, 0, 0, 0, 0, 2) - .putAll("AU", 0, 1, 0, 1, 2, 2) - .putAll("AW", 1, 2, 4, 4, 2, 2) - .putAll("AX", 0, 2, 2, 2, 2, 2) - .putAll("AZ", 3, 2, 4, 4, 2, 2) - .putAll("BA", 1, 2, 0, 1, 2, 2) - .putAll("BB", 0, 2, 0, 0, 2, 2) - .putAll("BD", 2, 1, 3, 3, 2, 2) - .putAll("BE", 0, 0, 3, 3, 2, 2) - .putAll("BF", 4, 3, 4, 3, 2, 2) - .putAll("BG", 0, 0, 0, 0, 1, 2) - .putAll("BH", 1, 2, 2, 4, 4, 2) - .putAll("BI", 4, 3, 4, 4, 2, 2) - .putAll("BJ", 4, 4, 3, 4, 2, 2) - .putAll("BL", 1, 2, 2, 2, 2, 2) - .putAll("BM", 1, 2, 0, 0, 2, 2) - .putAll("BN", 3, 2, 1, 1, 2, 2) - .putAll("BO", 1, 3, 3, 2, 2, 2) - .putAll("BQ", 1, 2, 2, 0, 2, 2) - .putAll("BR", 2, 3, 2, 2, 2, 2) - .putAll("BS", 4, 2, 2, 3, 2, 2) - .putAll("BT", 3, 1, 3, 2, 2, 2) - .putAll("BW", 3, 4, 1, 0, 2, 2) - .putAll("BY", 0, 1, 1, 3, 2, 2) - .putAll("BZ", 2, 4, 2, 2, 2, 2) - .putAll("CA", 0, 2, 1, 2, 4, 1) - .putAll("CD", 4, 2, 3, 1, 2, 2) - .putAll("CF", 4, 2, 3, 2, 2, 2) - .putAll("CG", 2, 4, 3, 4, 2, 2) - .putAll("CH", 0, 0, 0, 0, 0, 2) - .putAll("CI", 3, 3, 3, 4, 2, 2) - .putAll("CK", 2, 2, 2, 1, 2, 2) - .putAll("CL", 1, 1, 2, 2, 3, 2) - .putAll("CM", 3, 4, 3, 2, 2, 2) - .putAll("CN", 2, 0, 2, 2, 3, 1) - .putAll("CO", 2, 2, 4, 2, 2, 2) - .putAll("CR", 2, 2, 4, 4, 2, 2) - .putAll("CU", 4, 4, 3, 2, 2, 2) - .putAll("CV", 2, 3, 1, 0, 2, 2) - .putAll("CW", 2, 2, 0, 0, 2, 2) - .putAll("CX", 1, 2, 2, 2, 2, 2) - .putAll("CY", 1, 0, 0, 0, 1, 2) - .putAll("CZ", 0, 0, 0, 0, 1, 2) - .putAll("DE", 0, 0, 2, 2, 1, 2) - .putAll("DJ", 4, 1, 4, 4, 2, 2) - .putAll("DK", 0, 0, 1, 0, 0, 2) - .putAll("DM", 1, 2, 2, 2, 2, 2) - .putAll("DO", 3, 4, 4, 4, 2, 2) - .putAll("DZ", 4, 3, 4, 4, 2, 2) - .putAll("EC", 2, 4, 2, 1, 2, 2) - .putAll("EE", 0, 0, 0, 0, 2, 2) - .putAll("EG", 3, 4, 2, 3, 2, 2) - .putAll("EH", 2, 2, 2, 2, 2, 2) - .putAll("ER", 4, 2, 2, 2, 2, 2) - .putAll("ES", 0, 1, 1, 1, 2, 2) - .putAll("ET", 4, 4, 3, 1, 2, 2) - .putAll("FI", 0, 0, 0, 1, 0, 2) - .putAll("FJ", 3, 1, 3, 3, 2, 2) - .putAll("FK", 3, 2, 2, 2, 2, 2) - .putAll("FM", 3, 2, 4, 2, 2, 2) - .putAll("FO", 0, 2, 0, 0, 2, 2) - .putAll("FR", 1, 1, 2, 1, 1, 1) - .putAll("GA", 2, 3, 1, 1, 2, 2) - .putAll("GB", 0, 0, 1, 1, 2, 3) - .putAll("GD", 1, 2, 2, 2, 2, 2) - .putAll("GE", 1, 1, 1, 3, 2, 2) - .putAll("GF", 2, 1, 2, 3, 2, 2) - .putAll("GG", 0, 2, 0, 0, 2, 2) - .putAll("GH", 3, 2, 3, 2, 2, 2) - .putAll("GI", 0, 2, 2, 2, 2, 2) - .putAll("GL", 1, 2, 0, 0, 2, 2) - .putAll("GM", 4, 2, 2, 4, 2, 2) - .putAll("GN", 4, 3, 4, 2, 2, 2) - .putAll("GP", 2, 1, 2, 3, 2, 2) - .putAll("GQ", 4, 2, 3, 4, 2, 2) - .putAll("GR", 1, 0, 0, 0, 2, 2) - .putAll("GT", 2, 3, 2, 1, 2, 2) - .putAll("GU", 1, 2, 4, 4, 2, 2) - .putAll("GW", 3, 4, 3, 3, 2, 2) - .putAll("GY", 3, 4, 1, 0, 2, 2) - .putAll("HK", 0, 1, 2, 3, 2, 0) - .putAll("HN", 3, 2, 3, 3, 2, 2) - .putAll("HR", 1, 0, 0, 0, 2, 2) - .putAll("HT", 4, 4, 4, 4, 2, 2) - .putAll("HU", 0, 0, 0, 1, 3, 2) - .putAll("ID", 3, 2, 3, 3, 3, 2) - .putAll("IE", 0, 1, 1, 1, 2, 2) - .putAll("IL", 1, 1, 2, 3, 4, 2) - .putAll("IM", 0, 2, 0, 1, 2, 2) - .putAll("IN", 1, 1, 3, 2, 4, 3) - .putAll("IO", 4, 2, 2, 2, 2, 2) - .putAll("IQ", 3, 3, 3, 3, 2, 2) - .putAll("IR", 3, 0, 1, 1, 3, 0) - .putAll("IS", 0, 0, 0, 0, 0, 2) - .putAll("IT", 0, 1, 0, 1, 1, 2) - .putAll("JE", 3, 2, 1, 2, 2, 2) - .putAll("JM", 3, 4, 4, 4, 2, 2) - .putAll("JO", 1, 0, 0, 1, 2, 2) - .putAll("JP", 0, 1, 0, 1, 1, 1) - .putAll("KE", 3, 3, 2, 2, 2, 2) - .putAll("KG", 2, 1, 1, 1, 2, 2) - .putAll("KH", 1, 1, 4, 2, 2, 2) - .putAll("KI", 4, 2, 4, 3, 2, 2) - .putAll("KM", 4, 2, 4, 3, 2, 2) - .putAll("KN", 2, 2, 2, 2, 2, 2) - .putAll("KP", 3, 2, 2, 2, 2, 2) - .putAll("KR", 0, 0, 1, 3, 4, 4) - .putAll("KW", 1, 1, 0, 0, 0, 2) - .putAll("KY", 1, 2, 0, 1, 2, 2) - .putAll("KZ", 1, 1, 2, 2, 2, 2) - .putAll("LA", 2, 2, 1, 2, 2, 2) - .putAll("LB", 3, 2, 1, 4, 2, 2) - .putAll("LC", 1, 2, 0, 0, 2, 2) - .putAll("LI", 0, 2, 2, 2, 2, 2) - .putAll("LK", 3, 1, 3, 4, 4, 2) - .putAll("LR", 3, 4, 4, 3, 2, 2) - .putAll("LS", 3, 3, 4, 3, 2, 2) - .putAll("LT", 0, 0, 0, 0, 2, 2) - .putAll("LU", 1, 0, 2, 2, 2, 2) - .putAll("LV", 0, 0, 0, 0, 2, 2) - .putAll("LY", 4, 2, 4, 3, 2, 2) - .putAll("MA", 3, 2, 2, 2, 2, 2) - .putAll("MC", 0, 2, 2, 0, 2, 2) - .putAll("MD", 1, 0, 0, 0, 2, 2) - .putAll("ME", 1, 0, 0, 1, 2, 2) - .putAll("MF", 1, 2, 1, 0, 2, 2) - .putAll("MG", 3, 4, 2, 2, 2, 2) - .putAll("MH", 3, 2, 2, 4, 2, 2) - .putAll("MK", 1, 0, 0, 0, 2, 2) - .putAll("ML", 4, 3, 3, 1, 2, 2) - .putAll("MM", 2, 4, 3, 3, 2, 2) - .putAll("MN", 2, 0, 1, 2, 2, 2) - .putAll("MO", 0, 2, 4, 4, 2, 2) - .putAll("MP", 0, 2, 2, 2, 2, 2) - .putAll("MQ", 2, 1, 2, 3, 2, 2) - .putAll("MR", 4, 1, 3, 4, 2, 2) - .putAll("MS", 1, 2, 2, 2, 2, 2) - .putAll("MT", 0, 0, 0, 0, 2, 2) - .putAll("MU", 3, 1, 1, 2, 2, 2) - .putAll("MV", 3, 4, 1, 4, 2, 2) - .putAll("MW", 4, 2, 1, 0, 2, 2) - .putAll("MX", 2, 4, 3, 4, 2, 2) - .putAll("MY", 2, 1, 3, 3, 2, 2) - .putAll("MZ", 3, 2, 2, 2, 2, 2) - .putAll("NA", 4, 3, 2, 2, 2, 2) - .putAll("NC", 3, 2, 4, 4, 2, 2) - .putAll("NE", 4, 4, 4, 4, 2, 2) - .putAll("NF", 2, 2, 2, 2, 2, 2) - .putAll("NG", 3, 4, 1, 1, 2, 2) - .putAll("NI", 2, 3, 4, 3, 2, 2) - .putAll("NL", 0, 0, 3, 2, 0, 4) - .putAll("NO", 0, 0, 2, 0, 0, 2) - .putAll("NP", 2, 1, 4, 3, 2, 2) - .putAll("NR", 3, 2, 2, 0, 2, 2) - .putAll("NU", 4, 2, 2, 2, 2, 2) - .putAll("NZ", 1, 0, 1, 2, 4, 2) - .putAll("OM", 2, 3, 1, 3, 4, 2) - .putAll("PA", 1, 3, 3, 3, 2, 2) - .putAll("PE", 2, 3, 4, 4, 4, 2) - .putAll("PF", 2, 3, 3, 1, 2, 2) - .putAll("PG", 4, 4, 3, 2, 2, 2) - .putAll("PH", 2, 2, 3, 3, 3, 2) - .putAll("PK", 3, 2, 3, 3, 2, 2) - .putAll("PL", 1, 1, 2, 2, 3, 2) - .putAll("PM", 0, 2, 2, 2, 2, 2) - .putAll("PR", 2, 3, 2, 2, 3, 3) - .putAll("PS", 3, 4, 1, 2, 2, 2) - .putAll("PT", 0, 1, 0, 0, 2, 2) - .putAll("PW", 2, 2, 4, 1, 2, 2) - .putAll("PY", 2, 2, 3, 2, 2, 2) - .putAll("QA", 2, 4, 2, 4, 4, 2) - .putAll("RE", 1, 1, 1, 2, 2, 2) - .putAll("RO", 0, 0, 1, 1, 1, 2) - .putAll("RS", 1, 0, 0, 0, 2, 2) - .putAll("RU", 0, 0, 0, 1, 2, 2) - .putAll("RW", 3, 4, 3, 0, 2, 2) - .putAll("SA", 2, 2, 1, 1, 2, 2) - .putAll("SB", 4, 2, 4, 3, 2, 2) - .putAll("SC", 4, 3, 0, 2, 2, 2) - .putAll("SD", 4, 4, 4, 4, 2, 2) - .putAll("SE", 0, 0, 0, 0, 0, 2) - .putAll("SG", 1, 1, 2, 3, 1, 4) - .putAll("SH", 4, 2, 2, 2, 2, 2) - .putAll("SI", 0, 0, 0, 0, 1, 2) - .putAll("SJ", 0, 2, 2, 2, 2, 2) - .putAll("SK", 0, 0, 0, 0, 0, 2) - .putAll("SL", 4, 3, 4, 1, 2, 2) - .putAll("SM", 0, 2, 2, 2, 2, 2) - .putAll("SN", 4, 4, 4, 4, 2, 2) - .putAll("SO", 3, 2, 3, 3, 2, 2) - .putAll("SR", 2, 3, 2, 2, 2, 2) - .putAll("SS", 4, 2, 2, 2, 2, 2) - .putAll("ST", 3, 2, 2, 2, 2, 2) - .putAll("SV", 2, 2, 3, 3, 2, 2) - .putAll("SX", 2, 2, 1, 0, 2, 2) - .putAll("SY", 4, 3, 4, 4, 2, 2) - .putAll("SZ", 4, 3, 2, 4, 2, 2) - .putAll("TC", 2, 2, 1, 0, 2, 2) - .putAll("TD", 4, 4, 4, 4, 2, 2) - .putAll("TG", 3, 3, 2, 0, 2, 2) - .putAll("TH", 0, 3, 2, 3, 3, 0) - .putAll("TJ", 4, 2, 4, 4, 2, 2) - .putAll("TL", 4, 3, 4, 4, 2, 2) - .putAll("TM", 4, 2, 4, 2, 2, 2) - .putAll("TN", 2, 2, 1, 1, 2, 2) - .putAll("TO", 4, 2, 3, 3, 2, 2) - .putAll("TR", 1, 1, 0, 1, 2, 2) - .putAll("TT", 1, 4, 1, 1, 2, 2) - .putAll("TV", 4, 2, 2, 2, 2, 2) - .putAll("TW", 0, 0, 0, 0, 0, 0) - .putAll("TZ", 3, 4, 3, 3, 2, 2) - .putAll("UA", 0, 3, 1, 1, 2, 2) - .putAll("UG", 3, 3, 3, 3, 2, 2) - .putAll("US", 1, 1, 2, 2, 3, 2) - .putAll("UY", 2, 2, 1, 2, 2, 2) - .putAll("UZ", 2, 2, 3, 4, 2, 2) - .putAll("VC", 1, 2, 2, 2, 2, 2) - .putAll("VE", 4, 4, 4, 4, 2, 2) - .putAll("VG", 2, 2, 1, 1, 2, 2) - .putAll("VI", 1, 2, 1, 3, 2, 2) - .putAll("VN", 0, 3, 3, 4, 2, 2) - .putAll("VU", 4, 2, 2, 1, 2, 2) - .putAll("WF", 4, 2, 2, 4, 2, 2) - .putAll("WS", 3, 1, 2, 1, 2, 2) - .putAll("XK", 1, 1, 1, 1, 2, 2) - .putAll("YE", 4, 4, 4, 4, 2, 2) - .putAll("YT", 4, 1, 1, 1, 2, 2) - .putAll("ZA", 3, 3, 1, 1, 1, 2) - .putAll("ZM", 3, 3, 4, 2, 2, 2) - .putAll("ZW", 3, 2, 4, 3, 2, 2) - .build(); + /** + * Returns initial bitrate group assignments for a {@code country}. The initial bitrate is a list + * of indexes for [Wifi, 2G, 3G, 4G, 5G_NSA, 5G_SA]. + */ + private static int[] getInitialBitrateCountryGroupAssignment(String country) { + switch (country) { + case "AE": + return new int[] {1, 4, 4, 4, 3, 2}; + case "AG": + return new int[] {2, 3, 1, 2, 2, 2}; + case "AM": + return new int[] {2, 3, 2, 4, 2, 2}; + case "AR": + return new int[] {2, 4, 1, 1, 2, 2}; + case "AS": + return new int[] {2, 2, 2, 3, 2, 2}; + case "AU": + return new int[] {0, 1, 0, 1, 2, 2}; + case "BE": + return new int[] {0, 0, 3, 3, 2, 2}; + case "BF": + return new int[] {4, 3, 4, 3, 2, 2}; + case "BH": + return new int[] {1, 2, 2, 4, 4, 2}; + case "BJ": + return new int[] {4, 4, 3, 4, 2, 2}; + case "BN": + return new int[] {3, 2, 1, 1, 2, 2}; + case "BO": + return new int[] {1, 3, 3, 2, 2, 2}; + case "BQ": + return new int[] {1, 2, 2, 0, 2, 2}; + case "BS": + return new int[] {4, 2, 2, 3, 2, 2}; + case "BT": + return new int[] {3, 1, 3, 2, 2, 2}; + case "BY": + return new int[] {0, 1, 1, 3, 2, 2}; + case "BZ": + return new int[] {2, 4, 2, 2, 2, 2}; + case "CA": + return new int[] {0, 2, 1, 2, 4, 1}; + case "CD": + return new int[] {4, 2, 3, 1, 2, 2}; + case "CF": + return new int[] {4, 2, 3, 2, 2, 2}; + case "CI": + return new int[] {3, 3, 3, 4, 2, 2}; + case "CK": + return new int[] {2, 2, 2, 1, 2, 2}; + case "AO": + case "CM": + return new int[] {3, 4, 3, 2, 2, 2}; + case "CN": + return new int[] {2, 0, 2, 2, 3, 1}; + case "CO": + return new int[] {2, 2, 4, 2, 2, 2}; + case "CR": + return new int[] {2, 2, 4, 4, 2, 2}; + case "CV": + return new int[] {2, 3, 1, 0, 2, 2}; + case "CW": + return new int[] {2, 2, 0, 0, 2, 2}; + case "CY": + return new int[] {1, 0, 0, 0, 1, 2}; + case "DE": + return new int[] {0, 0, 2, 2, 1, 2}; + case "DJ": + return new int[] {4, 1, 4, 4, 2, 2}; + case "DK": + return new int[] {0, 0, 1, 0, 0, 2}; + case "EC": + return new int[] {2, 4, 2, 1, 2, 2}; + case "EG": + return new int[] {3, 4, 2, 3, 2, 2}; + case "ET": + return new int[] {4, 4, 3, 1, 2, 2}; + case "FI": + return new int[] {0, 0, 0, 1, 0, 2}; + case "FJ": + return new int[] {3, 1, 3, 3, 2, 2}; + case "FM": + return new int[] {3, 2, 4, 2, 2, 2}; + case "FR": + return new int[] {1, 1, 2, 1, 1, 1}; + case "GA": + return new int[] {2, 3, 1, 1, 2, 2}; + case "GB": + return new int[] {0, 0, 1, 1, 2, 3}; + case "GE": + return new int[] {1, 1, 1, 3, 2, 2}; + case "BB": + case "FO": + case "GG": + return new int[] {0, 2, 0, 0, 2, 2}; + case "GH": + return new int[] {3, 2, 3, 2, 2, 2}; + case "GN": + return new int[] {4, 3, 4, 2, 2, 2}; + case "GQ": + return new int[] {4, 2, 3, 4, 2, 2}; + case "GT": + return new int[] {2, 3, 2, 1, 2, 2}; + case "AW": + case "GU": + return new int[] {1, 2, 4, 4, 2, 2}; + case "BW": + case "GY": + return new int[] {3, 4, 1, 0, 2, 2}; + case "HK": + return new int[] {0, 1, 2, 3, 2, 0}; + case "HU": + return new int[] {0, 0, 0, 1, 3, 2}; + case "ID": + return new int[] {3, 2, 3, 3, 3, 2}; + case "ES": + case "IE": + return new int[] {0, 1, 1, 1, 2, 2}; + case "IL": + return new int[] {1, 1, 2, 3, 4, 2}; + case "IM": + return new int[] {0, 2, 0, 1, 2, 2}; + case "IN": + return new int[] {1, 1, 3, 2, 4, 3}; + case "IR": + return new int[] {3, 0, 1, 1, 3, 0}; + case "IT": + return new int[] {0, 1, 0, 1, 1, 2}; + case "JE": + return new int[] {3, 2, 1, 2, 2, 2}; + case "DO": + case "JM": + return new int[] {3, 4, 4, 4, 2, 2}; + case "JP": + return new int[] {0, 1, 0, 1, 1, 1}; + case "KE": + return new int[] {3, 3, 2, 2, 2, 2}; + case "KG": + return new int[] {2, 1, 1, 1, 2, 2}; + case "KH": + return new int[] {1, 1, 4, 2, 2, 2}; + case "KR": + return new int[] {0, 0, 1, 3, 4, 4}; + case "KW": + return new int[] {1, 1, 0, 0, 0, 2}; + case "AL": + case "BA": + case "KY": + return new int[] {1, 2, 0, 1, 2, 2}; + case "KZ": + return new int[] {1, 1, 2, 2, 2, 2}; + case "LB": + return new int[] {3, 2, 1, 4, 2, 2}; + case "AD": + case "BM": + case "GL": + case "LC": + return new int[] {1, 2, 0, 0, 2, 2}; + case "LK": + return new int[] {3, 1, 3, 4, 4, 2}; + case "LR": + return new int[] {3, 4, 4, 3, 2, 2}; + case "LS": + return new int[] {3, 3, 4, 3, 2, 2}; + case "LU": + return new int[] {1, 0, 2, 2, 2, 2}; + case "MC": + return new int[] {0, 2, 2, 0, 2, 2}; + case "JO": + case "ME": + return new int[] {1, 0, 0, 1, 2, 2}; + case "MF": + return new int[] {1, 2, 1, 0, 2, 2}; + case "MG": + return new int[] {3, 4, 2, 2, 2, 2}; + case "MH": + return new int[] {3, 2, 2, 4, 2, 2}; + case "ML": + return new int[] {4, 3, 3, 1, 2, 2}; + case "MM": + return new int[] {2, 4, 3, 3, 2, 2}; + case "MN": + return new int[] {2, 0, 1, 2, 2, 2}; + case "MO": + return new int[] {0, 2, 4, 4, 2, 2}; + case "GF": + case "GP": + case "MQ": + return new int[] {2, 1, 2, 3, 2, 2}; + case "MR": + return new int[] {4, 1, 3, 4, 2, 2}; + case "EE": + case "LT": + case "LV": + case "MT": + return new int[] {0, 0, 0, 0, 2, 2}; + case "MU": + return new int[] {3, 1, 1, 2, 2, 2}; + case "MV": + return new int[] {3, 4, 1, 4, 2, 2}; + case "MW": + return new int[] {4, 2, 1, 0, 2, 2}; + case "CG": + case "MX": + return new int[] {2, 4, 3, 4, 2, 2}; + case "BD": + case "MY": + return new int[] {2, 1, 3, 3, 2, 2}; + case "NA": + return new int[] {4, 3, 2, 2, 2, 2}; + case "AZ": + case "NC": + return new int[] {3, 2, 4, 4, 2, 2}; + case "NG": + return new int[] {3, 4, 1, 1, 2, 2}; + case "NI": + return new int[] {2, 3, 4, 3, 2, 2}; + case "NL": + return new int[] {0, 0, 3, 2, 0, 4}; + case "NO": + return new int[] {0, 0, 2, 0, 0, 2}; + case "NP": + return new int[] {2, 1, 4, 3, 2, 2}; + case "NR": + return new int[] {3, 2, 2, 0, 2, 2}; + case "NZ": + return new int[] {1, 0, 1, 2, 4, 2}; + case "OM": + return new int[] {2, 3, 1, 3, 4, 2}; + case "PA": + return new int[] {1, 3, 3, 3, 2, 2}; + case "PE": + return new int[] {2, 3, 4, 4, 4, 2}; + case "PF": + return new int[] {2, 3, 3, 1, 2, 2}; + case "CU": + case "PG": + return new int[] {4, 4, 3, 2, 2, 2}; + case "PH": + return new int[] {2, 2, 3, 3, 3, 2}; + case "PR": + return new int[] {2, 3, 2, 2, 3, 3}; + case "PS": + return new int[] {3, 4, 1, 2, 2, 2}; + case "PT": + return new int[] {0, 1, 0, 0, 2, 2}; + case "PW": + return new int[] {2, 2, 4, 1, 2, 2}; + case "PY": + return new int[] {2, 2, 3, 2, 2, 2}; + case "QA": + return new int[] {2, 4, 2, 4, 4, 2}; + case "RE": + return new int[] {1, 1, 1, 2, 2, 2}; + case "RO": + return new int[] {0, 0, 1, 1, 1, 2}; + case "GR": + case "HR": + case "MD": + case "MK": + case "RS": + return new int[] {1, 0, 0, 0, 2, 2}; + case "RU": + return new int[] {0, 0, 0, 1, 2, 2}; + case "RW": + return new int[] {3, 4, 3, 0, 2, 2}; + case "KI": + case "KM": + case "LY": + case "SB": + return new int[] {4, 2, 4, 3, 2, 2}; + case "SC": + return new int[] {4, 3, 0, 2, 2, 2}; + case "SG": + return new int[] {1, 1, 2, 3, 1, 4}; + case "BG": + case "CZ": + case "SI": + return new int[] {0, 0, 0, 0, 1, 2}; + case "AT": + case "CH": + case "IS": + case "SE": + case "SK": + return new int[] {0, 0, 0, 0, 0, 2}; + case "SL": + return new int[] {4, 3, 4, 1, 2, 2}; + case "AX": + case "GI": + case "LI": + case "MP": + case "PM": + case "SJ": + case "SM": + return new int[] {0, 2, 2, 2, 2, 2}; + case "HN": + case "PK": + case "SO": + return new int[] {3, 2, 3, 3, 2, 2}; + case "BR": + case "SR": + return new int[] {2, 3, 2, 2, 2, 2}; + case "FK": + case "KP": + case "MA": + case "MZ": + case "ST": + return new int[] {3, 2, 2, 2, 2, 2}; + case "SV": + return new int[] {2, 2, 3, 3, 2, 2}; + case "SZ": + return new int[] {4, 3, 2, 4, 2, 2}; + case "SX": + case "TC": + return new int[] {2, 2, 1, 0, 2, 2}; + case "TG": + return new int[] {3, 3, 2, 0, 2, 2}; + case "TH": + return new int[] {0, 3, 2, 3, 3, 0}; + case "TJ": + return new int[] {4, 2, 4, 4, 2, 2}; + case "BI": + case "DZ": + case "SY": + case "TL": + return new int[] {4, 3, 4, 4, 2, 2}; + case "TM": + return new int[] {4, 2, 4, 2, 2, 2}; + case "TO": + return new int[] {4, 2, 3, 3, 2, 2}; + case "TR": + return new int[] {1, 1, 0, 1, 2, 2}; + case "TT": + return new int[] {1, 4, 1, 1, 2, 2}; + case "AQ": + case "ER": + case "IO": + case "NU": + case "SH": + case "SS": + case "TV": + return new int[] {4, 2, 2, 2, 2, 2}; + case "TW": + return new int[] {0, 0, 0, 0, 0, 0}; + case "GW": + case "TZ": + return new int[] {3, 4, 3, 3, 2, 2}; + case "UA": + return new int[] {0, 3, 1, 1, 2, 2}; + case "IQ": + case "UG": + return new int[] {3, 3, 3, 3, 2, 2}; + case "CL": + case "PL": + case "US": + return new int[] {1, 1, 2, 2, 3, 2}; + case "LA": + case "UY": + return new int[] {2, 2, 1, 2, 2, 2}; + case "UZ": + return new int[] {2, 2, 3, 4, 2, 2}; + case "AI": + case "BL": + case "CX": + case "DM": + case "GD": + case "MS": + case "VC": + return new int[] {1, 2, 2, 2, 2, 2}; + case "SA": + case "TN": + case "VG": + return new int[] {2, 2, 1, 1, 2, 2}; + case "VI": + return new int[] {1, 2, 1, 3, 2, 2}; + case "VN": + return new int[] {0, 3, 3, 4, 2, 2}; + case "VU": + return new int[] {4, 2, 2, 1, 2, 2}; + case "GM": + case "WF": + return new int[] {4, 2, 2, 4, 2, 2}; + case "WS": + return new int[] {3, 1, 2, 1, 2, 2}; + case "XK": + return new int[] {1, 1, 1, 1, 2, 2}; + case "AF": + case "HT": + case "NE": + case "SD": + case "SN": + case "TD": + case "VE": + case "YE": + return new int[] {4, 4, 4, 4, 2, 2}; + case "YT": + return new int[] {4, 1, 1, 1, 2, 2}; + case "ZA": + return new int[] {3, 3, 1, 1, 1, 2}; + case "ZM": + return new int[] {3, 3, 4, 2, 2, 2}; + case "ZW": + return new int[] {3, 2, 4, 3, 2, 2}; + default: + return new int[] {2, 2, 2, 2, 2, 2}; + } } } From 623be98d536c6c9c846a56aead8b2b23bedfff20 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 2 Nov 2021 11:28:50 +0000 Subject: [PATCH 031/497] Suppress lint warning about IntDef assignment. The values returned by the framework method are equivalent to the local IntDef values. PiperOrigin-RevId: 407048748 --- .../com/google/android/exoplayer2/drm/FrameworkMediaDrm.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java index e4ccaf1853..9cc9910443 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java @@ -182,6 +182,8 @@ public final class FrameworkMediaDrm implements ExoMediaDrm { mediaDrm.closeSession(sessionId); } + // Return values of MediaDrm.KeyRequest.getRequestType are equal to KeyRequest.RequestType. + @SuppressLint("WrongConstant") @Override public KeyRequest getKeyRequest( byte[] scope, From 0830c06cd7e72695543978484446180512fad842 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 2 Nov 2021 14:58:15 +0000 Subject: [PATCH 032/497] PR feedback --- .../exoplayer2/source/rtsp/RtspClient.java | 11 ++++----- .../source/rtsp/RtspMediaPeriod.java | 10 ++++---- .../source/rtsp/RtspMediaSource.java | 23 ++++++++---------- .../source/rtsp/RtspClientTest.java | 24 +++++++++---------- .../source/rtsp/RtspMediaPeriodTest.java | 5 ++-- .../source/rtsp/RtspPlaybackTest.java | 5 ++-- 6 files changed, 38 insertions(+), 40 deletions(-) diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java index c1b982634a..e4f94403e6 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java @@ -123,8 +123,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private final SessionInfoListener sessionInfoListener; private final PlaybackEventListener playbackEventListener; private final String userAgent; + private final SocketFactory socketFactory; private final boolean debugLoggingEnabled; - @Nullable private final SocketFactory socketFactory; private final ArrayDeque pendingSetupRtpLoadInfos; // TODO(b/172331505) Add a timeout monitor for pending requests. private final SparseArray pendingRequests; @@ -156,14 +156,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * @param playbackEventListener The {@link PlaybackEventListener}. * @param userAgent The user agent. * @param uri The RTSP playback URI. + * @param socketFactory The {@link SocketFactory} for the client connection. + * @param debugLoggingEnabled Whether to print RTSP messages. */ public RtspClient( SessionInfoListener sessionInfoListener, PlaybackEventListener playbackEventListener, String userAgent, Uri uri, - boolean debugLoggingEnabled, - @Nullable SocketFactory socketFactory) { + SocketFactory socketFactory, + boolean debugLoggingEnabled) { this.sessionInfoListener = sessionInfoListener; this.playbackEventListener = playbackEventListener; this.userAgent = userAgent; @@ -293,9 +295,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; checkArgument(uri.getHost() != null); int rtspPort = uri.getPort() > 0 ? uri.getPort() : DEFAULT_RTSP_PORT; - SocketFactory socketFactory = - this.socketFactory != null ? this.socketFactory : SocketFactory.getDefault(); - return socketFactory.createSocket(checkNotNull(uri.getHost()), rtspPort); } diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java index 8d0347138b..cea3c4e85d 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java @@ -103,7 +103,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * @param listener A {@link Listener} to receive session information updates. * @param userAgent The user agent. * @param debugLoggingEnabled Whether to log RTSP messages. - * @param socketFactory A socket factory. + * @param socketFactory A socket factory for {@link RtspClient}'s connection. */ public RtspMediaPeriod( Allocator allocator, @@ -111,8 +111,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; Uri uri, Listener listener, String userAgent, - boolean debugLoggingEnabled, - @Nullable SocketFactory socketFactory) { + SocketFactory socketFactory, + boolean debugLoggingEnabled) { this.allocator = allocator; this.rtpDataChannelFactory = rtpDataChannelFactory; this.listener = listener; @@ -125,8 +125,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /* playbackEventListener= */ internalListener, /* userAgent= */ userAgent, /* uri= */ uri, - debugLoggingEnabled, - socketFactory); + socketFactory, + debugLoggingEnabled); rtspLoaderWrappers = new ArrayList<>(); selectedLoadInfos = new ArrayList<>(); diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java index 54145cad9b..9fb0912f9d 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java @@ -69,9 +69,9 @@ public final class RtspMediaSource extends BaseMediaSource { private long timeoutMs; private String userAgent; + @Nullable private SocketFactory socketFactory; private boolean forceUseRtpTcp; private boolean debugLoggingEnabled; - private SocketFactory socketFactory; public Factory() { timeoutMs = DEFAULT_TIMEOUT_MS; @@ -120,9 +120,8 @@ public final class RtspMediaSource extends BaseMediaSource { } /** - * Configures a socket factory to be used for client connections. - * - * When unspecified, {@link SocketFactory#getDefault()} is used. + * Sets a socket factory for {@link RtspClient}'s connection, the default value is {@link + * SocketFactory#getDefault()}. * * @param socketFactory A socket factory. * @return This Factory, for convenience. @@ -217,8 +216,8 @@ public final class RtspMediaSource extends BaseMediaSource { ? new TransferRtpDataChannelFactory(timeoutMs) : new UdpDataSourceRtpDataChannelFactory(timeoutMs), userAgent, - debugLoggingEnabled, - socketFactory); + socketFactory == null ? SocketFactory.getDefault() : socketFactory, + debugLoggingEnabled); } } @@ -241,10 +240,8 @@ public final class RtspMediaSource extends BaseMediaSource { private final RtpDataChannel.Factory rtpDataChannelFactory; private final String userAgent; private final Uri uri; - private final boolean debugLoggingEnabled; - - @Nullable private final SocketFactory socketFactory; + private final boolean debugLoggingEnabled; private long timelineDurationUs; private boolean timelineIsSeekable; @@ -256,8 +253,8 @@ public final class RtspMediaSource extends BaseMediaSource { MediaItem mediaItem, RtpDataChannel.Factory rtpDataChannelFactory, String userAgent, - boolean debugLoggingEnabled, - @Nullable SocketFactory socketFactory) { + SocketFactory socketFactory, + boolean debugLoggingEnabled) { this.mediaItem = mediaItem; this.rtpDataChannelFactory = rtpDataChannelFactory; this.userAgent = userAgent; @@ -302,8 +299,8 @@ public final class RtspMediaSource extends BaseMediaSource { notifySourceInfoRefreshed(); }, userAgent, - debugLoggingEnabled, - socketFactory); + socketFactory, + debugLoggingEnabled); } @Override diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java index 2ffb507de2..89a0b24287 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspClientTest.java @@ -146,8 +146,8 @@ public final class RtspClientTest { EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - socketFactory); + socketFactory, + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -190,8 +190,8 @@ public final class RtspClientTest { EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ null, + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -242,8 +242,8 @@ public final class RtspClientTest { EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -286,8 +286,8 @@ public final class RtspClientTest { EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> tracksInSession.get() != null); @@ -333,8 +333,8 @@ public final class RtspClientTest { EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> failureMessage.get() != null); @@ -380,8 +380,8 @@ public final class RtspClientTest { EMPTY_PLAYBACK_LISTENER, /* userAgent= */ "ExoPlayer:RtspClientTest", RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false); rtspClient.start(); RobolectricUtil.runMainLooperUntil(() -> failureCause.get() != null); diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java index 9c77d5406e..45da1a3785 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriodTest.java @@ -27,6 +27,7 @@ import com.google.android.exoplayer2.util.Util; import com.google.common.collect.ImmutableList; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import javax.net.SocketFactory; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -84,8 +85,8 @@ public final class RtspMediaPeriodTest { RtspTestUtils.getTestUri(rtspServer.startAndGetPortNumber()), /* listener= */ timing -> refreshedSourceDurationMs.set(timing.getDurationMs()), /* userAgent= */ "ExoPlayer:RtspPeriodTest", - /* debugLoggingEnabled= */ false, - /* socketFactory */ null); + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false); mediaPeriod.prepare( new MediaPeriod.Callback() { diff --git a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java index 625f310387..9f464ee5c3 100644 --- a/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java +++ b/library/rtsp/src/test/java/com/google/android/exoplayer2/source/rtsp/RtspPlaybackTest.java @@ -46,6 +46,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicReference; +import javax.net.SocketFactory; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -156,8 +157,8 @@ public final class RtspPlaybackTest { MediaItem.fromUri(RtspTestUtils.getTestUri(serverRtspPortNumber)), rtpDataChannelFactory, "ExoPlayer:PlaybackTest", - /* debugLoggingEnabled= */ false, - /* socketFactory */ null), + /* socketFactory */ SocketFactory.getDefault(), + /* debugLoggingEnabled= */ false), false); return player; } From b7b490326268a4a097a2c276e42474a5df52cdd4 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 2 Nov 2021 15:07:46 +0000 Subject: [PATCH 033/497] some RTSP docs --- docs/rtsp.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/rtsp.md b/docs/rtsp.md index 9c4cd38753..674f100efd 100644 --- a/docs/rtsp.md +++ b/docs/rtsp.md @@ -51,6 +51,30 @@ player.prepare(); ~~~ {: .language-java} +### Passing a custom SocketFactory + +By default, `RtspMediaSource` will use Java's standard socket factory (`SocketFactory.getDefault()`) +to create connections to the remote endpoints. This behavior can be overridden using +`.setSocketFactory()`. + +~~~ +// Create an RTSP media source pointing to an RTSP uri and override the socket factory. +MediaSource mediaSource = + new RtspMediaSource.Factory() + .setSocketFactory(...) + .createMediaSource(MediaItem.fromUri(rtspUri)); +// Create a player instance. +ExoPlayer player = new ExoPlayer.Builder(context).build(); +// Set the media source to be played. +player.setMediaSource(mediaSource); +// Prepare the player. +player.prepare(); +~~~ +{: .language-java} + +Custom `SocketFactory` instances can be useful when particular routing is required (e.g. when RTSP +traffic needs to pass a specific interface, or the socket needs additional connectivity flags). + ## Using RTSP behind a NAT (RTP/TCP support) ## ExoPlayer uses UDP as the default protocol for RTP transport. From 9970aaf6738c1e149e2c669aa0d7a4e703a79cc3 Mon Sep 17 00:00:00 2001 From: samrobinson Date: Tue, 2 Nov 2021 15:18:29 +0000 Subject: [PATCH 034/497] Update the TransformerMediaClock trackTime before deducting the offset. #minor-release PiperOrigin-RevId: 407086818 --- .../exoplayer2/transformer/TransformerAudioRenderer.java | 2 +- .../exoplayer2/transformer/TransformerBaseRenderer.java | 3 +-- .../exoplayer2/transformer/TransformerMuxingVideoRenderer.java | 2 +- .../transformer/TransformerTranscodingVideoRenderer.java | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java index 8da9dcd2e1..f20915c120 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java @@ -279,8 +279,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; int result = readSource(getFormatHolder(), decoderInputBuffer, /* readFlags= */ 0); switch (result) { case C.RESULT_BUFFER_READ: - decoderInputBuffer.timeUs -= streamOffsetUs; mediaClock.updateTimeForTrackType(getTrackType(), decoderInputBuffer.timeUs); + decoderInputBuffer.timeUs -= streamOffsetUs; decoderInputBuffer.flip(); decoder.queueInputBuffer(decoderInputBuffer); return !decoderInputBuffer.isEndOfStream(); diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java index 6e19f0b9f9..d3fe72d65b 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java @@ -48,8 +48,7 @@ import com.google.android.exoplayer2.util.MimeTypes; } @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) - throws ExoPlaybackException { + protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) { this.streamOffsetUs = offsetUs; } diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerMuxingVideoRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerMuxingVideoRenderer.java index d14378754e..4692a6ca81 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerMuxingVideoRenderer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerMuxingVideoRenderer.java @@ -117,8 +117,8 @@ import java.nio.ByteBuffer; muxerWrapper.endTrack(getTrackType()); return false; } - buffer.timeUs -= streamOffsetUs; mediaClock.updateTimeForTrackType(getTrackType(), buffer.timeUs); + buffer.timeUs -= streamOffsetUs; ByteBuffer data = checkNotNull(buffer.data); data.flip(); if (sampleTransformer != null) { diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerTranscodingVideoRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerTranscodingVideoRenderer.java index 931e985a5d..f4836e49df 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerTranscodingVideoRenderer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerTranscodingVideoRenderer.java @@ -320,8 +320,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; case C.RESULT_FORMAT_READ: throw new IllegalStateException("Format changes are not supported."); case C.RESULT_BUFFER_READ: - decoderInputBuffer.timeUs -= streamOffsetUs; mediaClock.updateTimeForTrackType(getTrackType(), decoderInputBuffer.timeUs); + decoderInputBuffer.timeUs -= streamOffsetUs; ByteBuffer data = checkNotNull(decoderInputBuffer.data); data.flip(); decoder.queueInputBuffer(decoderInputBuffer); From 1ed5861a725e98886d9a174f112087b3d9fb37af Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 2 Nov 2021 17:01:13 +0000 Subject: [PATCH 035/497] Suppress lint warnings in leanback module. These warnings are caused by the fact that this is a library and the lint check doesn't see any app using the library in a TV context. PiperOrigin-RevId: 407110725 --- extensions/leanback/src/main/AndroidManifest.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/leanback/src/main/AndroidManifest.xml b/extensions/leanback/src/main/AndroidManifest.xml index e385551143..1649d3c386 100644 --- a/extensions/leanback/src/main/AndroidManifest.xml +++ b/extensions/leanback/src/main/AndroidManifest.xml @@ -14,6 +14,8 @@ limitations under the License. --> - + From 41e338229af5c6e666b8006e992f8aef47fcabe4 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Tue, 2 Nov 2021 18:36:26 +0000 Subject: [PATCH 036/497] Parse HDR static metadata from MP4 files #minor-release PiperOrigin-RevId: 407136922 --- RELEASENOTES.md | 1 + .../exoplayer2/extractor/mp4/Atom.java | 6 + .../exoplayer2/extractor/mp4/AtomParsers.java | 87 +++- .../extractor/mp4/Mp4ExtractorTest.java | 6 + .../sample_with_colr_mdcv_and_clli.mp4.0.dump | 454 ++++++++++++++++++ .../sample_with_colr_mdcv_and_clli.mp4.1.dump | 398 +++++++++++++++ .../sample_with_colr_mdcv_and_clli.mp4.2.dump | 338 +++++++++++++ .../sample_with_colr_mdcv_and_clli.mp4.3.dump | 282 +++++++++++ ...colr_mdcv_and_clli.mp4.unknown_length.dump | 454 ++++++++++++++++++ .../mp4/sample_with_colr_mdcv_and_clli.mp4 | Bin 0 -> 285393 bytes 10 files changed, 2015 insertions(+), 11 deletions(-) create mode 100644 testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.0.dump create mode 100644 testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.1.dump create mode 100644 testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.2.dump create mode 100644 testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.3.dump create mode 100644 testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.unknown_length.dump create mode 100644 testdata/src/test/assets/media/mp4/sample_with_colr_mdcv_and_clli.mp4 diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 0d8bf3fdb5..586144ca28 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -64,6 +64,7 @@ * MP4: Avoid throwing `ArrayIndexOutOfBoundsException` when parsing invalid `colr` boxes produced by some device cameras ([#9332](https://github.com/google/ExoPlayer/issues/9332)). + * MP4: Parse HDR static metadata from the `clli` and `mdcv` boxes. * TS: Correctly handle HEVC tracks with pixel aspect ratios other than 1. * TS: Map stream type 0x80 to H262 ([#9472](https://github.com/google/ExoPlayer/issues/9472)). diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java index bc8633acc8..9c5de24b70 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java @@ -410,6 +410,12 @@ import java.util.List; @SuppressWarnings("ConstantCaseForConstants") public static final int TYPE_twos = 0x74776f73; + @SuppressWarnings("ConstantCaseForConstants") + public static final int TYPE_clli = 0x636c6c69; + + @SuppressWarnings("ConstantCaseForConstants") + public static final int TYPE_mdcv = 0x6d646376; + public final int type; public Atom(int type) { diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index bc5fa10fe3..442758716a 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -45,6 +45,8 @@ import com.google.android.exoplayer2.video.DolbyVisionConfig; import com.google.android.exoplayer2.video.HevcConfig; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -1061,6 +1063,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; .build(); } + // hdrStaticInfo is allocated using allocate() in allocateHdrStaticInfo(). + @SuppressWarnings("ByteBufferBackingArray") private static void parseVideoSampleEntry( ParsableByteArray parent, int atomType, @@ -1112,7 +1116,14 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; @Nullable String codecs = null; @Nullable byte[] projectionData = null; @C.StereoMode int stereoMode = Format.NO_VALUE; - @Nullable ColorInfo colorInfo = null; + + // HDR related metadata. + @C.ColorSpace int colorSpace = Format.NO_VALUE; + @C.ColorRange int colorRange = Format.NO_VALUE; + @C.ColorTransfer int colorTransfer = Format.NO_VALUE; + // The format of HDR static info is defined in CTA-861-G:2017, Table 45. + @Nullable ByteBuffer hdrStaticInfo = null; + while (childPosition - position < size) { parent.setPosition(childPosition); int childStartPosition = parent.getPosition(); @@ -1157,6 +1168,43 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; } else if (childAtomType == Atom.TYPE_av1C) { ExtractorUtil.checkContainerInput(mimeType == null, /* message= */ null); mimeType = MimeTypes.VIDEO_AV1; + } else if (childAtomType == Atom.TYPE_clli) { + if (hdrStaticInfo == null) { + hdrStaticInfo = allocateHdrStaticInfo(); + } + // The contents of the clli box occupy the last 4 bytes of the HDR static info array. Note + // that each field is read in big endian and written in little endian. + hdrStaticInfo.position(21); + hdrStaticInfo.putShort(parent.readShort()); // max_content_light_level. + hdrStaticInfo.putShort(parent.readShort()); // max_pic_average_light_level. + } else if (childAtomType == Atom.TYPE_mdcv) { + if (hdrStaticInfo == null) { + hdrStaticInfo = allocateHdrStaticInfo(); + } + // The contents of the mdcv box occupy 20 bytes after the first byte of the HDR static info + // array. Note that each field is read in big endian and written in little endian. + short displayPrimariesGX = parent.readShort(); + short displayPrimariesGY = parent.readShort(); + short displayPrimariesBX = parent.readShort(); + short displayPrimariesBY = parent.readShort(); + short displayPrimariesRX = parent.readShort(); + short displayPrimariesRY = parent.readShort(); + short whitePointX = parent.readShort(); + short whitePointY = parent.readShort(); + long maxDisplayMasteringLuminance = parent.readUnsignedInt(); + long minDisplayMasteringLuminance = parent.readUnsignedInt(); + + hdrStaticInfo.position(1); + hdrStaticInfo.putShort(displayPrimariesRX); + hdrStaticInfo.putShort(displayPrimariesRY); + hdrStaticInfo.putShort(displayPrimariesGX); + hdrStaticInfo.putShort(displayPrimariesGY); + hdrStaticInfo.putShort(displayPrimariesBX); + hdrStaticInfo.putShort(displayPrimariesBY); + hdrStaticInfo.putShort(whitePointX); + hdrStaticInfo.putShort(whitePointY); + hdrStaticInfo.putShort((short) (maxDisplayMasteringLuminance / 10000)); + hdrStaticInfo.putShort((short) (minDisplayMasteringLuminance / 10000)); } else if (childAtomType == Atom.TYPE_d263) { ExtractorUtil.checkContainerInput(mimeType == null, /* message= */ null); mimeType = MimeTypes.VIDEO_H263; @@ -1211,12 +1259,10 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; // size=18): https://github.com/google/ExoPlayer/issues/9332 boolean fullRangeFlag = childAtomSize == 19 && (parent.readUnsignedByte() & 0b10000000) != 0; - colorInfo = - new ColorInfo( - ColorInfo.isoColorPrimariesToColorSpace(colorPrimaries), - fullRangeFlag ? C.COLOR_RANGE_FULL : C.COLOR_RANGE_LIMITED, - ColorInfo.isoTransferCharacteristicsToColorTransfer(transferCharacteristics), - /* hdrStaticInfo= */ null); + colorSpace = ColorInfo.isoColorPrimariesToColorSpace(colorPrimaries); + colorRange = fullRangeFlag ? C.COLOR_RANGE_FULL : C.COLOR_RANGE_LIMITED; + colorTransfer = + ColorInfo.isoTransferCharacteristicsToColorTransfer(transferCharacteristics); } else { Log.w(TAG, "Unsupported color type: " + Atom.getAtomTypeString(colorType)); } @@ -1229,7 +1275,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; return; } - out.format = + Format.Builder formatBuilder = new Format.Builder() .setId(trackId) .setSampleMimeType(mimeType) @@ -1241,9 +1287,28 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; .setProjectionData(projectionData) .setStereoMode(stereoMode) .setInitializationData(initializationData) - .setDrmInitData(drmInitData) - .setColorInfo(colorInfo) - .build(); + .setDrmInitData(drmInitData); + if (colorSpace != Format.NO_VALUE + || colorRange != Format.NO_VALUE + || colorTransfer != Format.NO_VALUE + || hdrStaticInfo != null) { + // Note that if either mdcv or clli are missing, we leave the corresponding HDR static + // metadata bytes with value zero. See [Internal ref: b/194535665]. + formatBuilder.setColorInfo( + new ColorInfo( + colorSpace, + colorRange, + colorTransfer, + hdrStaticInfo != null ? hdrStaticInfo.array() : null)); + } + out.format = formatBuilder.build(); + } + + private static ByteBuffer allocateHdrStaticInfo() { + // For HDR static info, Android decoders expect a 25-byte array. The first byte is zero to + // represent Static Metadata Type 1, as per CTA-861-G:2017, Table 44. The following 24 bytes + // follow CTA-861-G:2017, Table 45. + return ByteBuffer.allocate(25).order(ByteOrder.LITTLE_ENDIAN); } private static void parseMetaDataSampleEntry( diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java index 911f3f477e..88aba133e3 100644 --- a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java +++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java @@ -119,4 +119,10 @@ public final class Mp4ExtractorTest { ExtractorAsserts.assertBehavior( Mp4Extractor::new, "media/mp4/sample_dthd.mp4", simulationConfig); } + + @Test + public void mp4SampleWithColrMdcvAndClli() throws Exception { + ExtractorAsserts.assertBehavior( + Mp4Extractor::new, "media/mp4/sample_with_colr_mdcv_and_clli.mp4", simulationConfig); + } } diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.0.dump b/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.0.dump new file mode 100644 index 0000000000..8ef4f19b16 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.0.dump @@ -0,0 +1,454 @@ +seekMap: + isSeekable = true + duration = 1022000 + getPosition(0) = [[timeUs=0, position=48]] + getPosition(1) = [[timeUs=0, position=48]] + getPosition(511000) = [[timeUs=0, position=48]] + getPosition(1022000) = [[timeUs=0, position=48]] +numberOfTracks = 2 +track 0: + total output bytes = 266091 + sample count = 60 + format 0: + id = 1 + sampleMimeType = video/av01 + maxInputSize = 144656 + width = 1920 + height = 1080 + frameRate = 59.940056 + colorInfo: + colorSpace = 6 + colorRange = 2 + colorTransfer = 6 + hdrStaticInfo = length 25, hash 423AFC35 + sample 0: + time = 0 + flags = 1 + data = length 144626, hash 7C021D5F + sample 1: + time = 16683 + flags = 0 + data = length 4018, hash FA5E79FA + sample 2: + time = 33366 + flags = 0 + data = length 3, hash D5E0 + sample 3: + time = 50050 + flags = 0 + data = length 144, hash 4A868A2F + sample 4: + time = 66733 + flags = 0 + data = length 3, hash D5D0 + sample 5: + time = 83416 + flags = 0 + data = length 342, hash 5A2E1C3C + sample 6: + time = 100100 + flags = 0 + data = length 3, hash D610 + sample 7: + time = 116783 + flags = 0 + data = length 173, hash CFE014B3 + sample 8: + time = 133466 + flags = 0 + data = length 3, hash D5C0 + sample 9: + time = 150150 + flags = 0 + data = length 655, hash 3A7738B6 + sample 10: + time = 166833 + flags = 0 + data = length 3, hash D5D0 + sample 11: + time = 183516 + flags = 0 + data = length 208, hash E7D2035A + sample 12: + time = 200200 + flags = 0 + data = length 3, hash D600 + sample 13: + time = 216883 + flags = 0 + data = length 385, hash 4D025B28 + sample 14: + time = 233566 + flags = 0 + data = length 3, hash D5E0 + sample 15: + time = 250250 + flags = 0 + data = length 192, hash CC0BD164 + sample 16: + time = 266933 + flags = 0 + data = length 3, hash D5B0 + sample 17: + time = 283616 + flags = 0 + data = length 36989, hash C213D35E + sample 18: + time = 300300 + flags = 0 + data = length 3, hash D5C0 + sample 19: + time = 316983 + flags = 0 + data = length 213, hash 2BBA39D3 + sample 20: + time = 333666 + flags = 0 + data = length 3, hash D600 + sample 21: + time = 350350 + flags = 0 + data = length 474, hash 83D66E3F + sample 22: + time = 367033 + flags = 0 + data = length 3, hash D5E0 + sample 23: + time = 383716 + flags = 0 + data = length 246, hash CF512AF0 + sample 24: + time = 400400 + flags = 0 + data = length 3, hash D610 + sample 25: + time = 417083 + flags = 0 + data = length 880, hash 8BFDE683 + sample 26: + time = 433766 + flags = 0 + data = length 3, hash D5C0 + sample 27: + time = 450450 + flags = 0 + data = length 246, hash 16B70503 + sample 28: + time = 467133 + flags = 0 + data = length 3, hash D600 + sample 29: + time = 483816 + flags = 0 + data = length 402, hash 51B5FAC9 + sample 30: + time = 500500 + flags = 0 + data = length 3, hash D610 + sample 31: + time = 517183 + flags = 0 + data = length 199, hash 12005069 + sample 32: + time = 533866 + flags = 0 + data = length 3, hash D5D0 + sample 33: + time = 550550 + flags = 0 + data = length 32362, hash F9FE31F7 + sample 34: + time = 567233 + flags = 0 + data = length 3, hash D5E0 + sample 35: + time = 583916 + flags = 0 + data = length 215, hash 2D4E3DC4 + sample 36: + time = 600600 + flags = 0 + data = length 3, hash D600 + sample 37: + time = 617283 + flags = 0 + data = length 450, hash C1A95E3 + sample 38: + time = 633966 + flags = 0 + data = length 3, hash D610 + sample 39: + time = 650650 + flags = 0 + data = length 221, hash 964386D9 + sample 40: + time = 667333 + flags = 0 + data = length 3, hash D5F0 + sample 41: + time = 684016 + flags = 0 + data = length 853, hash 2B9E0AAF + sample 42: + time = 700700 + flags = 0 + data = length 3, hash D5E0 + sample 43: + time = 717383 + flags = 0 + data = length 236, hash 7E84BBAE + sample 44: + time = 734066 + flags = 0 + data = length 3, hash D600 + sample 45: + time = 750750 + flags = 0 + data = length 419, hash 619235F2 + sample 46: + time = 767433 + flags = 0 + data = length 3, hash D5F0 + sample 47: + time = 784116 + flags = 0 + data = length 194, hash D386F352 + sample 48: + time = 800800 + flags = 0 + data = length 3, hash D5A0 + sample 49: + time = 817483 + flags = 0 + data = length 38679, hash 17E63FCD + sample 50: + time = 834166 + flags = 0 + data = length 3, hash D610 + sample 51: + time = 850850 + flags = 0 + data = length 183, hash C8DD98E2 + sample 52: + time = 867533 + flags = 0 + data = length 3, hash D600 + sample 53: + time = 884216 + flags = 0 + data = length 457, hash 2B4E3476 + sample 54: + time = 900900 + flags = 0 + data = length 3, hash D5F0 + sample 55: + time = 917583 + flags = 0 + data = length 216, hash 7233540A + sample 56: + time = 934266 + flags = 0 + data = length 3, hash D5C0 + sample 57: + time = 950950 + flags = 0 + data = length 894, hash 7319F313 + sample 58: + time = 967633 + flags = 0 + data = length 3, hash D610 + sample 59: + time = 984316 + flags = 536870912 + data = length 233, hash DE4DBE67 +track 1: + total output bytes = 16638 + sample count = 44 + format 0: + id = 2 + sampleMimeType = audio/mp4a-latm + codecs = mp4a.40.2 + maxInputSize = 441 + channelCount = 2 + sampleRate = 44100 + language = und + metadata = entries=[TSSE: description=null: value=Lavf58.76.100] + initializationData: + data = length 16, hash CAA21BBF + sample 0: + time = 0 + flags = 1 + data = length 393, hash 706D1B6F + sample 1: + time = 23219 + flags = 1 + data = length 400, hash B48107D1 + sample 2: + time = 46439 + flags = 1 + data = length 398, hash E5F4E9C1 + sample 3: + time = 69659 + flags = 1 + data = length 400, hash 4317B40D + sample 4: + time = 92879 + flags = 1 + data = length 403, hash CB949D88 + sample 5: + time = 116099 + flags = 1 + data = length 411, hash 616C8F82 + sample 6: + time = 139319 + flags = 1 + data = length 392, hash 3BA50F06 + sample 7: + time = 162539 + flags = 1 + data = length 401, hash 1C62F82C + sample 8: + time = 185759 + flags = 1 + data = length 400, hash 180FEA17 + sample 9: + time = 208979 + flags = 1 + data = length 378, hash 2F6B0AE6 + sample 10: + time = 232199 + flags = 1 + data = length 375, hash 6AE86D08 + sample 11: + time = 255419 + flags = 1 + data = length 375, hash EF2FD9CC + sample 12: + time = 278639 + flags = 1 + data = length 374, hash 97B83243 + sample 13: + time = 301859 + flags = 1 + data = length 382, hash 8BD6191C + sample 14: + time = 325079 + flags = 1 + data = length 393, hash D5F53221 + sample 15: + time = 348299 + flags = 1 + data = length 375, hash 2437C16B + sample 16: + time = 371519 + flags = 1 + data = length 372, hash EE50108B + sample 17: + time = 394739 + flags = 1 + data = length 364, hash 9952E0FE + sample 18: + time = 417959 + flags = 1 + data = length 387, hash C4EC0E45 + sample 19: + time = 441179 + flags = 1 + data = length 384, hash 7DFB424F + sample 20: + time = 464399 + flags = 1 + data = length 370, hash 28619E43 + sample 21: + time = 487619 + flags = 1 + data = length 373, hash 440EB9E8 + sample 22: + time = 510839 + flags = 1 + data = length 363, hash B7655913 + sample 23: + time = 534058 + flags = 1 + data = length 362, hash A0690E92 + sample 24: + time = 557278 + flags = 1 + data = length 377, hash 41BF1244 + sample 25: + time = 580498 + flags = 1 + data = length 371, hash EE4124CD + sample 26: + time = 603718 + flags = 1 + data = length 372, hash 7A512168 + sample 27: + time = 626938 + flags = 1 + data = length 370, hash ED00D55C + sample 28: + time = 650158 + flags = 1 + data = length 356, hash 43F4FFCA + sample 29: + time = 673378 + flags = 1 + data = length 373, hash 1950F38C + sample 30: + time = 696598 + flags = 1 + data = length 366, hash 5F426A7A + sample 31: + time = 719818 + flags = 1 + data = length 371, hash FCC286D2 + sample 32: + time = 743038 + flags = 1 + data = length 366, hash CF6F5DD9 + sample 33: + time = 766258 + flags = 1 + data = length 386, hash 83E3B1E6 + sample 34: + time = 789478 + flags = 1 + data = length 369, hash 5BDF670B + sample 35: + time = 812698 + flags = 1 + data = length 367, hash DC847E4D + sample 36: + time = 835918 + flags = 1 + data = length 366, hash 8AC0C55C + sample 37: + time = 859138 + flags = 1 + data = length 375, hash C0D4BF4 + sample 38: + time = 882358 + flags = 1 + data = length 367, hash 6C5284E2 + sample 39: + time = 905578 + flags = 1 + data = length 380, hash BDFAB187 + sample 40: + time = 928798 + flags = 1 + data = length 372, hash CEF87EB6 + sample 41: + time = 952018 + flags = 1 + data = length 369, hash B0FF049B + sample 42: + time = 975238 + flags = 1 + data = length 366, hash BADD46E6 + sample 43: + time = 998458 + flags = 536870913 + data = length 374, hash 6102A531 +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.1.dump b/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.1.dump new file mode 100644 index 0000000000..1e1023afb0 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.1.dump @@ -0,0 +1,398 @@ +seekMap: + isSeekable = true + duration = 1022000 + getPosition(0) = [[timeUs=0, position=48]] + getPosition(1) = [[timeUs=0, position=48]] + getPosition(511000) = [[timeUs=0, position=48]] + getPosition(1022000) = [[timeUs=0, position=48]] +numberOfTracks = 2 +track 0: + total output bytes = 266091 + sample count = 60 + format 0: + id = 1 + sampleMimeType = video/av01 + maxInputSize = 144656 + width = 1920 + height = 1080 + frameRate = 59.940056 + colorInfo: + colorSpace = 6 + colorRange = 2 + colorTransfer = 6 + hdrStaticInfo = length 25, hash 423AFC35 + sample 0: + time = 0 + flags = 1 + data = length 144626, hash 7C021D5F + sample 1: + time = 16683 + flags = 0 + data = length 4018, hash FA5E79FA + sample 2: + time = 33366 + flags = 0 + data = length 3, hash D5E0 + sample 3: + time = 50050 + flags = 0 + data = length 144, hash 4A868A2F + sample 4: + time = 66733 + flags = 0 + data = length 3, hash D5D0 + sample 5: + time = 83416 + flags = 0 + data = length 342, hash 5A2E1C3C + sample 6: + time = 100100 + flags = 0 + data = length 3, hash D610 + sample 7: + time = 116783 + flags = 0 + data = length 173, hash CFE014B3 + sample 8: + time = 133466 + flags = 0 + data = length 3, hash D5C0 + sample 9: + time = 150150 + flags = 0 + data = length 655, hash 3A7738B6 + sample 10: + time = 166833 + flags = 0 + data = length 3, hash D5D0 + sample 11: + time = 183516 + flags = 0 + data = length 208, hash E7D2035A + sample 12: + time = 200200 + flags = 0 + data = length 3, hash D600 + sample 13: + time = 216883 + flags = 0 + data = length 385, hash 4D025B28 + sample 14: + time = 233566 + flags = 0 + data = length 3, hash D5E0 + sample 15: + time = 250250 + flags = 0 + data = length 192, hash CC0BD164 + sample 16: + time = 266933 + flags = 0 + data = length 3, hash D5B0 + sample 17: + time = 283616 + flags = 0 + data = length 36989, hash C213D35E + sample 18: + time = 300300 + flags = 0 + data = length 3, hash D5C0 + sample 19: + time = 316983 + flags = 0 + data = length 213, hash 2BBA39D3 + sample 20: + time = 333666 + flags = 0 + data = length 3, hash D600 + sample 21: + time = 350350 + flags = 0 + data = length 474, hash 83D66E3F + sample 22: + time = 367033 + flags = 0 + data = length 3, hash D5E0 + sample 23: + time = 383716 + flags = 0 + data = length 246, hash CF512AF0 + sample 24: + time = 400400 + flags = 0 + data = length 3, hash D610 + sample 25: + time = 417083 + flags = 0 + data = length 880, hash 8BFDE683 + sample 26: + time = 433766 + flags = 0 + data = length 3, hash D5C0 + sample 27: + time = 450450 + flags = 0 + data = length 246, hash 16B70503 + sample 28: + time = 467133 + flags = 0 + data = length 3, hash D600 + sample 29: + time = 483816 + flags = 0 + data = length 402, hash 51B5FAC9 + sample 30: + time = 500500 + flags = 0 + data = length 3, hash D610 + sample 31: + time = 517183 + flags = 0 + data = length 199, hash 12005069 + sample 32: + time = 533866 + flags = 0 + data = length 3, hash D5D0 + sample 33: + time = 550550 + flags = 0 + data = length 32362, hash F9FE31F7 + sample 34: + time = 567233 + flags = 0 + data = length 3, hash D5E0 + sample 35: + time = 583916 + flags = 0 + data = length 215, hash 2D4E3DC4 + sample 36: + time = 600600 + flags = 0 + data = length 3, hash D600 + sample 37: + time = 617283 + flags = 0 + data = length 450, hash C1A95E3 + sample 38: + time = 633966 + flags = 0 + data = length 3, hash D610 + sample 39: + time = 650650 + flags = 0 + data = length 221, hash 964386D9 + sample 40: + time = 667333 + flags = 0 + data = length 3, hash D5F0 + sample 41: + time = 684016 + flags = 0 + data = length 853, hash 2B9E0AAF + sample 42: + time = 700700 + flags = 0 + data = length 3, hash D5E0 + sample 43: + time = 717383 + flags = 0 + data = length 236, hash 7E84BBAE + sample 44: + time = 734066 + flags = 0 + data = length 3, hash D600 + sample 45: + time = 750750 + flags = 0 + data = length 419, hash 619235F2 + sample 46: + time = 767433 + flags = 0 + data = length 3, hash D5F0 + sample 47: + time = 784116 + flags = 0 + data = length 194, hash D386F352 + sample 48: + time = 800800 + flags = 0 + data = length 3, hash D5A0 + sample 49: + time = 817483 + flags = 0 + data = length 38679, hash 17E63FCD + sample 50: + time = 834166 + flags = 0 + data = length 3, hash D610 + sample 51: + time = 850850 + flags = 0 + data = length 183, hash C8DD98E2 + sample 52: + time = 867533 + flags = 0 + data = length 3, hash D600 + sample 53: + time = 884216 + flags = 0 + data = length 457, hash 2B4E3476 + sample 54: + time = 900900 + flags = 0 + data = length 3, hash D5F0 + sample 55: + time = 917583 + flags = 0 + data = length 216, hash 7233540A + sample 56: + time = 934266 + flags = 0 + data = length 3, hash D5C0 + sample 57: + time = 950950 + flags = 0 + data = length 894, hash 7319F313 + sample 58: + time = 967633 + flags = 0 + data = length 3, hash D610 + sample 59: + time = 984316 + flags = 536870912 + data = length 233, hash DE4DBE67 +track 1: + total output bytes = 11156 + sample count = 30 + format 0: + id = 2 + sampleMimeType = audio/mp4a-latm + codecs = mp4a.40.2 + maxInputSize = 441 + channelCount = 2 + sampleRate = 44100 + language = und + metadata = entries=[TSSE: description=null: value=Lavf58.76.100] + initializationData: + data = length 16, hash CAA21BBF + sample 0: + time = 325079 + flags = 1 + data = length 393, hash D5F53221 + sample 1: + time = 348299 + flags = 1 + data = length 375, hash 2437C16B + sample 2: + time = 371519 + flags = 1 + data = length 372, hash EE50108B + sample 3: + time = 394739 + flags = 1 + data = length 364, hash 9952E0FE + sample 4: + time = 417959 + flags = 1 + data = length 387, hash C4EC0E45 + sample 5: + time = 441179 + flags = 1 + data = length 384, hash 7DFB424F + sample 6: + time = 464399 + flags = 1 + data = length 370, hash 28619E43 + sample 7: + time = 487619 + flags = 1 + data = length 373, hash 440EB9E8 + sample 8: + time = 510839 + flags = 1 + data = length 363, hash B7655913 + sample 9: + time = 534058 + flags = 1 + data = length 362, hash A0690E92 + sample 10: + time = 557278 + flags = 1 + data = length 377, hash 41BF1244 + sample 11: + time = 580498 + flags = 1 + data = length 371, hash EE4124CD + sample 12: + time = 603718 + flags = 1 + data = length 372, hash 7A512168 + sample 13: + time = 626938 + flags = 1 + data = length 370, hash ED00D55C + sample 14: + time = 650158 + flags = 1 + data = length 356, hash 43F4FFCA + sample 15: + time = 673378 + flags = 1 + data = length 373, hash 1950F38C + sample 16: + time = 696598 + flags = 1 + data = length 366, hash 5F426A7A + sample 17: + time = 719818 + flags = 1 + data = length 371, hash FCC286D2 + sample 18: + time = 743038 + flags = 1 + data = length 366, hash CF6F5DD9 + sample 19: + time = 766258 + flags = 1 + data = length 386, hash 83E3B1E6 + sample 20: + time = 789478 + flags = 1 + data = length 369, hash 5BDF670B + sample 21: + time = 812698 + flags = 1 + data = length 367, hash DC847E4D + sample 22: + time = 835918 + flags = 1 + data = length 366, hash 8AC0C55C + sample 23: + time = 859138 + flags = 1 + data = length 375, hash C0D4BF4 + sample 24: + time = 882358 + flags = 1 + data = length 367, hash 6C5284E2 + sample 25: + time = 905578 + flags = 1 + data = length 380, hash BDFAB187 + sample 26: + time = 928798 + flags = 1 + data = length 372, hash CEF87EB6 + sample 27: + time = 952018 + flags = 1 + data = length 369, hash B0FF049B + sample 28: + time = 975238 + flags = 1 + data = length 366, hash BADD46E6 + sample 29: + time = 998458 + flags = 536870913 + data = length 374, hash 6102A531 +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.2.dump b/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.2.dump new file mode 100644 index 0000000000..5b51396c83 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.2.dump @@ -0,0 +1,338 @@ +seekMap: + isSeekable = true + duration = 1022000 + getPosition(0) = [[timeUs=0, position=48]] + getPosition(1) = [[timeUs=0, position=48]] + getPosition(511000) = [[timeUs=0, position=48]] + getPosition(1022000) = [[timeUs=0, position=48]] +numberOfTracks = 2 +track 0: + total output bytes = 266091 + sample count = 60 + format 0: + id = 1 + sampleMimeType = video/av01 + maxInputSize = 144656 + width = 1920 + height = 1080 + frameRate = 59.940056 + colorInfo: + colorSpace = 6 + colorRange = 2 + colorTransfer = 6 + hdrStaticInfo = length 25, hash 423AFC35 + sample 0: + time = 0 + flags = 1 + data = length 144626, hash 7C021D5F + sample 1: + time = 16683 + flags = 0 + data = length 4018, hash FA5E79FA + sample 2: + time = 33366 + flags = 0 + data = length 3, hash D5E0 + sample 3: + time = 50050 + flags = 0 + data = length 144, hash 4A868A2F + sample 4: + time = 66733 + flags = 0 + data = length 3, hash D5D0 + sample 5: + time = 83416 + flags = 0 + data = length 342, hash 5A2E1C3C + sample 6: + time = 100100 + flags = 0 + data = length 3, hash D610 + sample 7: + time = 116783 + flags = 0 + data = length 173, hash CFE014B3 + sample 8: + time = 133466 + flags = 0 + data = length 3, hash D5C0 + sample 9: + time = 150150 + flags = 0 + data = length 655, hash 3A7738B6 + sample 10: + time = 166833 + flags = 0 + data = length 3, hash D5D0 + sample 11: + time = 183516 + flags = 0 + data = length 208, hash E7D2035A + sample 12: + time = 200200 + flags = 0 + data = length 3, hash D600 + sample 13: + time = 216883 + flags = 0 + data = length 385, hash 4D025B28 + sample 14: + time = 233566 + flags = 0 + data = length 3, hash D5E0 + sample 15: + time = 250250 + flags = 0 + data = length 192, hash CC0BD164 + sample 16: + time = 266933 + flags = 0 + data = length 3, hash D5B0 + sample 17: + time = 283616 + flags = 0 + data = length 36989, hash C213D35E + sample 18: + time = 300300 + flags = 0 + data = length 3, hash D5C0 + sample 19: + time = 316983 + flags = 0 + data = length 213, hash 2BBA39D3 + sample 20: + time = 333666 + flags = 0 + data = length 3, hash D600 + sample 21: + time = 350350 + flags = 0 + data = length 474, hash 83D66E3F + sample 22: + time = 367033 + flags = 0 + data = length 3, hash D5E0 + sample 23: + time = 383716 + flags = 0 + data = length 246, hash CF512AF0 + sample 24: + time = 400400 + flags = 0 + data = length 3, hash D610 + sample 25: + time = 417083 + flags = 0 + data = length 880, hash 8BFDE683 + sample 26: + time = 433766 + flags = 0 + data = length 3, hash D5C0 + sample 27: + time = 450450 + flags = 0 + data = length 246, hash 16B70503 + sample 28: + time = 467133 + flags = 0 + data = length 3, hash D600 + sample 29: + time = 483816 + flags = 0 + data = length 402, hash 51B5FAC9 + sample 30: + time = 500500 + flags = 0 + data = length 3, hash D610 + sample 31: + time = 517183 + flags = 0 + data = length 199, hash 12005069 + sample 32: + time = 533866 + flags = 0 + data = length 3, hash D5D0 + sample 33: + time = 550550 + flags = 0 + data = length 32362, hash F9FE31F7 + sample 34: + time = 567233 + flags = 0 + data = length 3, hash D5E0 + sample 35: + time = 583916 + flags = 0 + data = length 215, hash 2D4E3DC4 + sample 36: + time = 600600 + flags = 0 + data = length 3, hash D600 + sample 37: + time = 617283 + flags = 0 + data = length 450, hash C1A95E3 + sample 38: + time = 633966 + flags = 0 + data = length 3, hash D610 + sample 39: + time = 650650 + flags = 0 + data = length 221, hash 964386D9 + sample 40: + time = 667333 + flags = 0 + data = length 3, hash D5F0 + sample 41: + time = 684016 + flags = 0 + data = length 853, hash 2B9E0AAF + sample 42: + time = 700700 + flags = 0 + data = length 3, hash D5E0 + sample 43: + time = 717383 + flags = 0 + data = length 236, hash 7E84BBAE + sample 44: + time = 734066 + flags = 0 + data = length 3, hash D600 + sample 45: + time = 750750 + flags = 0 + data = length 419, hash 619235F2 + sample 46: + time = 767433 + flags = 0 + data = length 3, hash D5F0 + sample 47: + time = 784116 + flags = 0 + data = length 194, hash D386F352 + sample 48: + time = 800800 + flags = 0 + data = length 3, hash D5A0 + sample 49: + time = 817483 + flags = 0 + data = length 38679, hash 17E63FCD + sample 50: + time = 834166 + flags = 0 + data = length 3, hash D610 + sample 51: + time = 850850 + flags = 0 + data = length 183, hash C8DD98E2 + sample 52: + time = 867533 + flags = 0 + data = length 3, hash D600 + sample 53: + time = 884216 + flags = 0 + data = length 457, hash 2B4E3476 + sample 54: + time = 900900 + flags = 0 + data = length 3, hash D5F0 + sample 55: + time = 917583 + flags = 0 + data = length 216, hash 7233540A + sample 56: + time = 934266 + flags = 0 + data = length 3, hash D5C0 + sample 57: + time = 950950 + flags = 0 + data = length 894, hash 7319F313 + sample 58: + time = 967633 + flags = 0 + data = length 3, hash D610 + sample 59: + time = 984316 + flags = 536870912 + data = length 233, hash DE4DBE67 +track 1: + total output bytes = 5567 + sample count = 15 + format 0: + id = 2 + sampleMimeType = audio/mp4a-latm + codecs = mp4a.40.2 + maxInputSize = 441 + channelCount = 2 + sampleRate = 44100 + language = und + metadata = entries=[TSSE: description=null: value=Lavf58.76.100] + initializationData: + data = length 16, hash CAA21BBF + sample 0: + time = 673378 + flags = 1 + data = length 373, hash 1950F38C + sample 1: + time = 696598 + flags = 1 + data = length 366, hash 5F426A7A + sample 2: + time = 719818 + flags = 1 + data = length 371, hash FCC286D2 + sample 3: + time = 743038 + flags = 1 + data = length 366, hash CF6F5DD9 + sample 4: + time = 766258 + flags = 1 + data = length 386, hash 83E3B1E6 + sample 5: + time = 789478 + flags = 1 + data = length 369, hash 5BDF670B + sample 6: + time = 812698 + flags = 1 + data = length 367, hash DC847E4D + sample 7: + time = 835918 + flags = 1 + data = length 366, hash 8AC0C55C + sample 8: + time = 859138 + flags = 1 + data = length 375, hash C0D4BF4 + sample 9: + time = 882358 + flags = 1 + data = length 367, hash 6C5284E2 + sample 10: + time = 905578 + flags = 1 + data = length 380, hash BDFAB187 + sample 11: + time = 928798 + flags = 1 + data = length 372, hash CEF87EB6 + sample 12: + time = 952018 + flags = 1 + data = length 369, hash B0FF049B + sample 13: + time = 975238 + flags = 1 + data = length 366, hash BADD46E6 + sample 14: + time = 998458 + flags = 536870913 + data = length 374, hash 6102A531 +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.3.dump b/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.3.dump new file mode 100644 index 0000000000..d66f9234a1 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.3.dump @@ -0,0 +1,282 @@ +seekMap: + isSeekable = true + duration = 1022000 + getPosition(0) = [[timeUs=0, position=48]] + getPosition(1) = [[timeUs=0, position=48]] + getPosition(511000) = [[timeUs=0, position=48]] + getPosition(1022000) = [[timeUs=0, position=48]] +numberOfTracks = 2 +track 0: + total output bytes = 266091 + sample count = 60 + format 0: + id = 1 + sampleMimeType = video/av01 + maxInputSize = 144656 + width = 1920 + height = 1080 + frameRate = 59.940056 + colorInfo: + colorSpace = 6 + colorRange = 2 + colorTransfer = 6 + hdrStaticInfo = length 25, hash 423AFC35 + sample 0: + time = 0 + flags = 1 + data = length 144626, hash 7C021D5F + sample 1: + time = 16683 + flags = 0 + data = length 4018, hash FA5E79FA + sample 2: + time = 33366 + flags = 0 + data = length 3, hash D5E0 + sample 3: + time = 50050 + flags = 0 + data = length 144, hash 4A868A2F + sample 4: + time = 66733 + flags = 0 + data = length 3, hash D5D0 + sample 5: + time = 83416 + flags = 0 + data = length 342, hash 5A2E1C3C + sample 6: + time = 100100 + flags = 0 + data = length 3, hash D610 + sample 7: + time = 116783 + flags = 0 + data = length 173, hash CFE014B3 + sample 8: + time = 133466 + flags = 0 + data = length 3, hash D5C0 + sample 9: + time = 150150 + flags = 0 + data = length 655, hash 3A7738B6 + sample 10: + time = 166833 + flags = 0 + data = length 3, hash D5D0 + sample 11: + time = 183516 + flags = 0 + data = length 208, hash E7D2035A + sample 12: + time = 200200 + flags = 0 + data = length 3, hash D600 + sample 13: + time = 216883 + flags = 0 + data = length 385, hash 4D025B28 + sample 14: + time = 233566 + flags = 0 + data = length 3, hash D5E0 + sample 15: + time = 250250 + flags = 0 + data = length 192, hash CC0BD164 + sample 16: + time = 266933 + flags = 0 + data = length 3, hash D5B0 + sample 17: + time = 283616 + flags = 0 + data = length 36989, hash C213D35E + sample 18: + time = 300300 + flags = 0 + data = length 3, hash D5C0 + sample 19: + time = 316983 + flags = 0 + data = length 213, hash 2BBA39D3 + sample 20: + time = 333666 + flags = 0 + data = length 3, hash D600 + sample 21: + time = 350350 + flags = 0 + data = length 474, hash 83D66E3F + sample 22: + time = 367033 + flags = 0 + data = length 3, hash D5E0 + sample 23: + time = 383716 + flags = 0 + data = length 246, hash CF512AF0 + sample 24: + time = 400400 + flags = 0 + data = length 3, hash D610 + sample 25: + time = 417083 + flags = 0 + data = length 880, hash 8BFDE683 + sample 26: + time = 433766 + flags = 0 + data = length 3, hash D5C0 + sample 27: + time = 450450 + flags = 0 + data = length 246, hash 16B70503 + sample 28: + time = 467133 + flags = 0 + data = length 3, hash D600 + sample 29: + time = 483816 + flags = 0 + data = length 402, hash 51B5FAC9 + sample 30: + time = 500500 + flags = 0 + data = length 3, hash D610 + sample 31: + time = 517183 + flags = 0 + data = length 199, hash 12005069 + sample 32: + time = 533866 + flags = 0 + data = length 3, hash D5D0 + sample 33: + time = 550550 + flags = 0 + data = length 32362, hash F9FE31F7 + sample 34: + time = 567233 + flags = 0 + data = length 3, hash D5E0 + sample 35: + time = 583916 + flags = 0 + data = length 215, hash 2D4E3DC4 + sample 36: + time = 600600 + flags = 0 + data = length 3, hash D600 + sample 37: + time = 617283 + flags = 0 + data = length 450, hash C1A95E3 + sample 38: + time = 633966 + flags = 0 + data = length 3, hash D610 + sample 39: + time = 650650 + flags = 0 + data = length 221, hash 964386D9 + sample 40: + time = 667333 + flags = 0 + data = length 3, hash D5F0 + sample 41: + time = 684016 + flags = 0 + data = length 853, hash 2B9E0AAF + sample 42: + time = 700700 + flags = 0 + data = length 3, hash D5E0 + sample 43: + time = 717383 + flags = 0 + data = length 236, hash 7E84BBAE + sample 44: + time = 734066 + flags = 0 + data = length 3, hash D600 + sample 45: + time = 750750 + flags = 0 + data = length 419, hash 619235F2 + sample 46: + time = 767433 + flags = 0 + data = length 3, hash D5F0 + sample 47: + time = 784116 + flags = 0 + data = length 194, hash D386F352 + sample 48: + time = 800800 + flags = 0 + data = length 3, hash D5A0 + sample 49: + time = 817483 + flags = 0 + data = length 38679, hash 17E63FCD + sample 50: + time = 834166 + flags = 0 + data = length 3, hash D610 + sample 51: + time = 850850 + flags = 0 + data = length 183, hash C8DD98E2 + sample 52: + time = 867533 + flags = 0 + data = length 3, hash D600 + sample 53: + time = 884216 + flags = 0 + data = length 457, hash 2B4E3476 + sample 54: + time = 900900 + flags = 0 + data = length 3, hash D5F0 + sample 55: + time = 917583 + flags = 0 + data = length 216, hash 7233540A + sample 56: + time = 934266 + flags = 0 + data = length 3, hash D5C0 + sample 57: + time = 950950 + flags = 0 + data = length 894, hash 7319F313 + sample 58: + time = 967633 + flags = 0 + data = length 3, hash D610 + sample 59: + time = 984316 + flags = 536870912 + data = length 233, hash DE4DBE67 +track 1: + total output bytes = 374 + sample count = 1 + format 0: + id = 2 + sampleMimeType = audio/mp4a-latm + codecs = mp4a.40.2 + maxInputSize = 441 + channelCount = 2 + sampleRate = 44100 + language = und + metadata = entries=[TSSE: description=null: value=Lavf58.76.100] + initializationData: + data = length 16, hash CAA21BBF + sample 0: + time = 998458 + flags = 536870913 + data = length 374, hash 6102A531 +tracksEnded = true diff --git a/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.unknown_length.dump b/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.unknown_length.dump new file mode 100644 index 0000000000..8ef4f19b16 --- /dev/null +++ b/testdata/src/test/assets/extractordumps/mp4/sample_with_colr_mdcv_and_clli.mp4.unknown_length.dump @@ -0,0 +1,454 @@ +seekMap: + isSeekable = true + duration = 1022000 + getPosition(0) = [[timeUs=0, position=48]] + getPosition(1) = [[timeUs=0, position=48]] + getPosition(511000) = [[timeUs=0, position=48]] + getPosition(1022000) = [[timeUs=0, position=48]] +numberOfTracks = 2 +track 0: + total output bytes = 266091 + sample count = 60 + format 0: + id = 1 + sampleMimeType = video/av01 + maxInputSize = 144656 + width = 1920 + height = 1080 + frameRate = 59.940056 + colorInfo: + colorSpace = 6 + colorRange = 2 + colorTransfer = 6 + hdrStaticInfo = length 25, hash 423AFC35 + sample 0: + time = 0 + flags = 1 + data = length 144626, hash 7C021D5F + sample 1: + time = 16683 + flags = 0 + data = length 4018, hash FA5E79FA + sample 2: + time = 33366 + flags = 0 + data = length 3, hash D5E0 + sample 3: + time = 50050 + flags = 0 + data = length 144, hash 4A868A2F + sample 4: + time = 66733 + flags = 0 + data = length 3, hash D5D0 + sample 5: + time = 83416 + flags = 0 + data = length 342, hash 5A2E1C3C + sample 6: + time = 100100 + flags = 0 + data = length 3, hash D610 + sample 7: + time = 116783 + flags = 0 + data = length 173, hash CFE014B3 + sample 8: + time = 133466 + flags = 0 + data = length 3, hash D5C0 + sample 9: + time = 150150 + flags = 0 + data = length 655, hash 3A7738B6 + sample 10: + time = 166833 + flags = 0 + data = length 3, hash D5D0 + sample 11: + time = 183516 + flags = 0 + data = length 208, hash E7D2035A + sample 12: + time = 200200 + flags = 0 + data = length 3, hash D600 + sample 13: + time = 216883 + flags = 0 + data = length 385, hash 4D025B28 + sample 14: + time = 233566 + flags = 0 + data = length 3, hash D5E0 + sample 15: + time = 250250 + flags = 0 + data = length 192, hash CC0BD164 + sample 16: + time = 266933 + flags = 0 + data = length 3, hash D5B0 + sample 17: + time = 283616 + flags = 0 + data = length 36989, hash C213D35E + sample 18: + time = 300300 + flags = 0 + data = length 3, hash D5C0 + sample 19: + time = 316983 + flags = 0 + data = length 213, hash 2BBA39D3 + sample 20: + time = 333666 + flags = 0 + data = length 3, hash D600 + sample 21: + time = 350350 + flags = 0 + data = length 474, hash 83D66E3F + sample 22: + time = 367033 + flags = 0 + data = length 3, hash D5E0 + sample 23: + time = 383716 + flags = 0 + data = length 246, hash CF512AF0 + sample 24: + time = 400400 + flags = 0 + data = length 3, hash D610 + sample 25: + time = 417083 + flags = 0 + data = length 880, hash 8BFDE683 + sample 26: + time = 433766 + flags = 0 + data = length 3, hash D5C0 + sample 27: + time = 450450 + flags = 0 + data = length 246, hash 16B70503 + sample 28: + time = 467133 + flags = 0 + data = length 3, hash D600 + sample 29: + time = 483816 + flags = 0 + data = length 402, hash 51B5FAC9 + sample 30: + time = 500500 + flags = 0 + data = length 3, hash D610 + sample 31: + time = 517183 + flags = 0 + data = length 199, hash 12005069 + sample 32: + time = 533866 + flags = 0 + data = length 3, hash D5D0 + sample 33: + time = 550550 + flags = 0 + data = length 32362, hash F9FE31F7 + sample 34: + time = 567233 + flags = 0 + data = length 3, hash D5E0 + sample 35: + time = 583916 + flags = 0 + data = length 215, hash 2D4E3DC4 + sample 36: + time = 600600 + flags = 0 + data = length 3, hash D600 + sample 37: + time = 617283 + flags = 0 + data = length 450, hash C1A95E3 + sample 38: + time = 633966 + flags = 0 + data = length 3, hash D610 + sample 39: + time = 650650 + flags = 0 + data = length 221, hash 964386D9 + sample 40: + time = 667333 + flags = 0 + data = length 3, hash D5F0 + sample 41: + time = 684016 + flags = 0 + data = length 853, hash 2B9E0AAF + sample 42: + time = 700700 + flags = 0 + data = length 3, hash D5E0 + sample 43: + time = 717383 + flags = 0 + data = length 236, hash 7E84BBAE + sample 44: + time = 734066 + flags = 0 + data = length 3, hash D600 + sample 45: + time = 750750 + flags = 0 + data = length 419, hash 619235F2 + sample 46: + time = 767433 + flags = 0 + data = length 3, hash D5F0 + sample 47: + time = 784116 + flags = 0 + data = length 194, hash D386F352 + sample 48: + time = 800800 + flags = 0 + data = length 3, hash D5A0 + sample 49: + time = 817483 + flags = 0 + data = length 38679, hash 17E63FCD + sample 50: + time = 834166 + flags = 0 + data = length 3, hash D610 + sample 51: + time = 850850 + flags = 0 + data = length 183, hash C8DD98E2 + sample 52: + time = 867533 + flags = 0 + data = length 3, hash D600 + sample 53: + time = 884216 + flags = 0 + data = length 457, hash 2B4E3476 + sample 54: + time = 900900 + flags = 0 + data = length 3, hash D5F0 + sample 55: + time = 917583 + flags = 0 + data = length 216, hash 7233540A + sample 56: + time = 934266 + flags = 0 + data = length 3, hash D5C0 + sample 57: + time = 950950 + flags = 0 + data = length 894, hash 7319F313 + sample 58: + time = 967633 + flags = 0 + data = length 3, hash D610 + sample 59: + time = 984316 + flags = 536870912 + data = length 233, hash DE4DBE67 +track 1: + total output bytes = 16638 + sample count = 44 + format 0: + id = 2 + sampleMimeType = audio/mp4a-latm + codecs = mp4a.40.2 + maxInputSize = 441 + channelCount = 2 + sampleRate = 44100 + language = und + metadata = entries=[TSSE: description=null: value=Lavf58.76.100] + initializationData: + data = length 16, hash CAA21BBF + sample 0: + time = 0 + flags = 1 + data = length 393, hash 706D1B6F + sample 1: + time = 23219 + flags = 1 + data = length 400, hash B48107D1 + sample 2: + time = 46439 + flags = 1 + data = length 398, hash E5F4E9C1 + sample 3: + time = 69659 + flags = 1 + data = length 400, hash 4317B40D + sample 4: + time = 92879 + flags = 1 + data = length 403, hash CB949D88 + sample 5: + time = 116099 + flags = 1 + data = length 411, hash 616C8F82 + sample 6: + time = 139319 + flags = 1 + data = length 392, hash 3BA50F06 + sample 7: + time = 162539 + flags = 1 + data = length 401, hash 1C62F82C + sample 8: + time = 185759 + flags = 1 + data = length 400, hash 180FEA17 + sample 9: + time = 208979 + flags = 1 + data = length 378, hash 2F6B0AE6 + sample 10: + time = 232199 + flags = 1 + data = length 375, hash 6AE86D08 + sample 11: + time = 255419 + flags = 1 + data = length 375, hash EF2FD9CC + sample 12: + time = 278639 + flags = 1 + data = length 374, hash 97B83243 + sample 13: + time = 301859 + flags = 1 + data = length 382, hash 8BD6191C + sample 14: + time = 325079 + flags = 1 + data = length 393, hash D5F53221 + sample 15: + time = 348299 + flags = 1 + data = length 375, hash 2437C16B + sample 16: + time = 371519 + flags = 1 + data = length 372, hash EE50108B + sample 17: + time = 394739 + flags = 1 + data = length 364, hash 9952E0FE + sample 18: + time = 417959 + flags = 1 + data = length 387, hash C4EC0E45 + sample 19: + time = 441179 + flags = 1 + data = length 384, hash 7DFB424F + sample 20: + time = 464399 + flags = 1 + data = length 370, hash 28619E43 + sample 21: + time = 487619 + flags = 1 + data = length 373, hash 440EB9E8 + sample 22: + time = 510839 + flags = 1 + data = length 363, hash B7655913 + sample 23: + time = 534058 + flags = 1 + data = length 362, hash A0690E92 + sample 24: + time = 557278 + flags = 1 + data = length 377, hash 41BF1244 + sample 25: + time = 580498 + flags = 1 + data = length 371, hash EE4124CD + sample 26: + time = 603718 + flags = 1 + data = length 372, hash 7A512168 + sample 27: + time = 626938 + flags = 1 + data = length 370, hash ED00D55C + sample 28: + time = 650158 + flags = 1 + data = length 356, hash 43F4FFCA + sample 29: + time = 673378 + flags = 1 + data = length 373, hash 1950F38C + sample 30: + time = 696598 + flags = 1 + data = length 366, hash 5F426A7A + sample 31: + time = 719818 + flags = 1 + data = length 371, hash FCC286D2 + sample 32: + time = 743038 + flags = 1 + data = length 366, hash CF6F5DD9 + sample 33: + time = 766258 + flags = 1 + data = length 386, hash 83E3B1E6 + sample 34: + time = 789478 + flags = 1 + data = length 369, hash 5BDF670B + sample 35: + time = 812698 + flags = 1 + data = length 367, hash DC847E4D + sample 36: + time = 835918 + flags = 1 + data = length 366, hash 8AC0C55C + sample 37: + time = 859138 + flags = 1 + data = length 375, hash C0D4BF4 + sample 38: + time = 882358 + flags = 1 + data = length 367, hash 6C5284E2 + sample 39: + time = 905578 + flags = 1 + data = length 380, hash BDFAB187 + sample 40: + time = 928798 + flags = 1 + data = length 372, hash CEF87EB6 + sample 41: + time = 952018 + flags = 1 + data = length 369, hash B0FF049B + sample 42: + time = 975238 + flags = 1 + data = length 366, hash BADD46E6 + sample 43: + time = 998458 + flags = 536870913 + data = length 374, hash 6102A531 +tracksEnded = true diff --git a/testdata/src/test/assets/media/mp4/sample_with_colr_mdcv_and_clli.mp4 b/testdata/src/test/assets/media/mp4/sample_with_colr_mdcv_and_clli.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..608d6ec440cca8d7c74b8135723256c0925ab81a GIT binary patch literal 285393 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 R3mI@y@Dpx-h-GDW4x?ZGuP4m1 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%0DT>fyB|HXxYtUeH);X0N&E=-m}t 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 Cke;Ui literal 0 HcmV?d00001 From 7b9b878aeb762b04561bec19b24389c44cf5892e Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 2 Nov 2021 20:21:34 +0000 Subject: [PATCH 037/497] Add missing RetentionPolicy for IntDef PiperOrigin-RevId: 407162673 --- .../android/exoplayer2/source/rtsp/RtspMessageChannel.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMessageChannel.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMessageChannel.java index 526f508953..a877d72b13 100644 --- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMessageChannel.java +++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMessageChannel.java @@ -39,6 +39,9 @@ import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.net.Socket; import java.nio.charset.Charset; import java.util.ArrayList; @@ -334,6 +337,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** Processes RTSP messages line-by-line. */ private static final class MessageParser { + @Documented + @Retention(RetentionPolicy.SOURCE) @IntDef({STATE_READING_FIRST_LINE, STATE_READING_HEADER, STATE_READING_BODY}) @interface ReadingState {} From a9f7b943c823b9337ec19ad2510514b93ec942c9 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 3 Nov 2021 07:57:55 +0000 Subject: [PATCH 038/497] Prepare for adding ServerSideInsertedAdsMediaSource for IMA PiperOrigin-RevId: 407274072 --- .../android/exoplayer2/ext/ima/ImaUtil.java | 30 +++++++++++++++++++ .../exoplayer2/offline/DownloadHelper.java | 3 +- .../source/DefaultMediaSourceFactory.java | 27 ++++++++++++++--- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java index 13952abd72..9a40ba74de 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java @@ -41,6 +41,7 @@ import com.google.android.exoplayer2.upstream.DataSchemeDataSource; 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 java.io.IOException; import java.util.Arrays; import java.util.Collection; @@ -134,6 +135,35 @@ import java.util.Set; } } + /** Stores configuration for DAI ad playback. */ + static final class DaiConfiguration { + + public final AdErrorEvent.AdErrorListener applicationAdErrorListener; + public final boolean debugModeEnabled; + + @Nullable public final List companionAdSlots; + @Nullable public final AdEvent.AdEventListener applicationAdEventListener; + @Nullable public final VideoAdPlayer.VideoAdPlayerCallback applicationVideoAdPlayerCallback; + @Nullable public final ImaSdkSettings imaSdkSettings; + + public DaiConfiguration( + AdErrorEvent.AdErrorListener applicationAdErrorListener, + @Nullable List companionAdSlots, + @Nullable AdEvent.AdEventListener applicationAdEventListener, + @Nullable VideoAdPlayer.VideoAdPlayerCallback applicationVideoAdPlayerCallback, + @Nullable ImaSdkSettings imaSdkSettings, + boolean debugModeEnabled) { + + this.applicationAdErrorListener = applicationAdErrorListener; + this.companionAdSlots = + companionAdSlots != null ? ImmutableList.copyOf(companionAdSlots) : null; + this.applicationAdEventListener = applicationAdEventListener; + this.applicationVideoAdPlayerCallback = applicationVideoAdPlayerCallback; + this.imaSdkSettings = imaSdkSettings; + this.debugModeEnabled = debugModeEnabled; + } + } + public static final int TIMEOUT_UNSET = -1; public static final int BITRATE_UNSET = -1; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java index 7fea1c5a43..e9d6c5829a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java @@ -891,7 +891,8 @@ public final class DownloadHelper { MediaItem mediaItem, DataSource.Factory dataSourceFactory, @Nullable DrmSessionManager drmSessionManager) { - return new DefaultMediaSourceFactory(dataSourceFactory, ExtractorsFactory.EMPTY) + return new DefaultMediaSourceFactory( + dataSourceFactory, ExtractorsFactory.EMPTY, /* serverSideDaiMediaSourceFactory= */ null) .setDrmSessionManager(drmSessionManager) .createMediaSource(mediaItem); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java index a98b8f4a1b..0cbae12170 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java @@ -45,6 +45,7 @@ import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DefaultDataSource; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; @@ -119,6 +120,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { private final DataSource.Factory dataSourceFactory; private final DelegateFactoryLoader delegateFactoryLoader; + @Nullable private final MediaSourceFactory serverSideDaiMediaSourceFactory; @Nullable private AdsLoaderProvider adsLoaderProvider; @Nullable private AdViewProvider adViewProvider; @Nullable private LoadErrorHandlingPolicy loadErrorHandlingPolicy; @@ -146,7 +148,10 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { * its container. */ public DefaultMediaSourceFactory(Context context, ExtractorsFactory extractorsFactory) { - this(new DefaultDataSource.Factory(context), extractorsFactory); + this( + new DefaultDataSource.Factory(context), + extractorsFactory, + /* serverSideDaiMediaSourceFactory= */ null); } /** @@ -156,7 +161,10 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { * for requesting media data. */ public DefaultMediaSourceFactory(DataSource.Factory dataSourceFactory) { - this(dataSourceFactory, new DefaultExtractorsFactory()); + this( + dataSourceFactory, + new DefaultExtractorsFactory(), + /* serverSideDaiMediaSourceFactory= */ null); } /** @@ -166,10 +174,17 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { * for requesting media data. * @param extractorsFactory An {@link ExtractorsFactory} used to extract progressive media from * its container. + * @param serverSideDaiMediaSourceFactory A {@link MediaSourceFactory} for creating server side + * inserted ad media sources. */ public DefaultMediaSourceFactory( - DataSource.Factory dataSourceFactory, ExtractorsFactory extractorsFactory) { + DataSource.Factory dataSourceFactory, + ExtractorsFactory extractorsFactory, + @Nullable MediaSourceFactory serverSideDaiMediaSourceFactory) { this.dataSourceFactory = dataSourceFactory; + // Temporary until factory registration is agreed upon. + this.serverSideDaiMediaSourceFactory = serverSideDaiMediaSourceFactory; + delegateFactoryLoader = new DelegateFactoryLoader(dataSourceFactory, extractorsFactory); liveTargetOffsetMs = C.TIME_UNSET; liveMinOffsetMs = C.TIME_UNSET; @@ -333,7 +348,11 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { @Override public MediaSource createMediaSource(MediaItem mediaItem) { - checkNotNull(mediaItem.localConfiguration); + Assertions.checkNotNull(mediaItem.localConfiguration); + @Nullable String scheme = mediaItem.localConfiguration.uri.getScheme(); + if (scheme != null && scheme.equals("imadai")) { + return checkNotNull(serverSideDaiMediaSourceFactory).createMediaSource(mediaItem); + } @C.ContentType int type = Util.inferContentTypeForUriAndMimeType( From 113939919325e271c854e939bc713c7287aa3b2d Mon Sep 17 00:00:00 2001 From: kimvde Date: Wed, 3 Nov 2021 11:01:07 +0000 Subject: [PATCH 039/497] WavExtractor: split header reading state into 2 states This refactoring is the basis to support RF64 (see Issue: google/ExoPlayer#9543). #minor-release PiperOrigin-RevId: 407301056 --- .../extractor/wav/WavExtractor.java | 135 ++++++++++-------- .../wav/{WavHeader.java => WavFormat.java} | 8 +- .../extractor/wav/WavHeaderReader.java | 57 ++++---- .../exoplayer2/extractor/wav/WavSeekMap.java | 16 +-- 4 files changed, 121 insertions(+), 95 deletions(-) rename library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/{WavHeader.java => WavFormat.java} (91%) diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java index 97d98b5fcc..6d3fc254b1 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java @@ -61,12 +61,18 @@ public final class WavExtractor implements Extractor { @Documented @Retention(RetentionPolicy.SOURCE) @Target({ElementType.TYPE_USE}) - @IntDef({STATE_READING_HEADER, STATE_SKIPPING_TO_SAMPLE_DATA, STATE_READING_SAMPLE_DATA}) + @IntDef({ + STATE_READING_FILE_TYPE, + STATE_READING_FORMAT, + STATE_SKIPPING_TO_SAMPLE_DATA, + STATE_READING_SAMPLE_DATA + }) private @interface State {} - private static final int STATE_READING_HEADER = 0; - private static final int STATE_SKIPPING_TO_SAMPLE_DATA = 1; - private static final int STATE_READING_SAMPLE_DATA = 2; + private static final int STATE_READING_FILE_TYPE = 0; + private static final int STATE_READING_FORMAT = 1; + private static final int STATE_SKIPPING_TO_SAMPLE_DATA = 2; + private static final int STATE_READING_SAMPLE_DATA = 3; private @MonotonicNonNull ExtractorOutput extractorOutput; private @MonotonicNonNull TrackOutput trackOutput; @@ -76,14 +82,14 @@ public final class WavExtractor implements Extractor { private long dataEndPosition; public WavExtractor() { - state = STATE_READING_HEADER; + state = STATE_READING_FILE_TYPE; dataStartPosition = C.POSITION_UNSET; dataEndPosition = C.POSITION_UNSET; } @Override public boolean sniff(ExtractorInput input) throws IOException { - return WavHeaderReader.peek(input) != null; + return WavHeaderReader.checkFileType(input); } @Override @@ -95,7 +101,7 @@ public final class WavExtractor implements Extractor { @Override public void seek(long position, long timeUs) { - state = position == 0 ? STATE_READING_HEADER : STATE_READING_SAMPLE_DATA; + state = position == 0 ? STATE_READING_FILE_TYPE : STATE_READING_SAMPLE_DATA; if (outputWriter != null) { outputWriter.reset(timeUs); } @@ -111,8 +117,11 @@ public final class WavExtractor implements Extractor { public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException { assertInitialized(); switch (state) { - case STATE_READING_HEADER: - readHeader(input); + case STATE_READING_FILE_TYPE: + readFileType(input); + return Extractor.RESULT_CONTINUE; + case STATE_READING_FORMAT: + readFormat(input); return Extractor.RESULT_CONTINUE; case STATE_SKIPPING_TO_SAMPLE_DATA: skipToSampleData(input); @@ -130,50 +139,54 @@ public final class WavExtractor implements Extractor { Util.castNonNull(extractorOutput); } - @RequiresNonNull({"extractorOutput", "trackOutput"}) - private void readHeader(ExtractorInput input) throws IOException { + private void readFileType(ExtractorInput input) throws IOException { Assertions.checkState(input.getPosition() == 0); if (dataStartPosition != C.POSITION_UNSET) { input.skipFully(dataStartPosition); state = STATE_READING_SAMPLE_DATA; return; } - WavHeader header = WavHeaderReader.peek(input); - if (header == null) { + if (!WavHeaderReader.checkFileType(input)) { // Should only happen if the media wasn't sniffed. throw ParserException.createForMalformedContainer( - "Unsupported or unrecognized wav header.", /* cause= */ null); + "Unsupported or unrecognized wav file type.", /* cause= */ null); } input.skipFully((int) (input.getPeekPosition() - input.getPosition())); + state = STATE_READING_FORMAT; + } - if (header.formatType == WavUtil.TYPE_IMA_ADPCM) { - outputWriter = new ImaAdPcmOutputWriter(extractorOutput, trackOutput, header); - } else if (header.formatType == WavUtil.TYPE_ALAW) { + @RequiresNonNull({"extractorOutput", "trackOutput"}) + private void readFormat(ExtractorInput input) throws IOException { + WavFormat wavFormat = WavHeaderReader.readFormat(input); + if (wavFormat.formatType == WavUtil.TYPE_IMA_ADPCM) { + outputWriter = new ImaAdPcmOutputWriter(extractorOutput, trackOutput, wavFormat); + } else if (wavFormat.formatType == WavUtil.TYPE_ALAW) { outputWriter = new PassthroughOutputWriter( extractorOutput, trackOutput, - header, + wavFormat, MimeTypes.AUDIO_ALAW, /* pcmEncoding= */ Format.NO_VALUE); - } else if (header.formatType == WavUtil.TYPE_MLAW) { + } else if (wavFormat.formatType == WavUtil.TYPE_MLAW) { outputWriter = new PassthroughOutputWriter( extractorOutput, trackOutput, - header, + wavFormat, MimeTypes.AUDIO_MLAW, /* pcmEncoding= */ Format.NO_VALUE); } else { @C.PcmEncoding - int pcmEncoding = WavUtil.getPcmEncodingForType(header.formatType, header.bitsPerSample); + int pcmEncoding = + WavUtil.getPcmEncodingForType(wavFormat.formatType, wavFormat.bitsPerSample); if (pcmEncoding == C.ENCODING_INVALID) { throw ParserException.createForUnsupportedContainerFeature( - "Unsupported WAV format type: " + header.formatType); + "Unsupported WAV format type: " + wavFormat.formatType); } outputWriter = new PassthroughOutputWriter( - extractorOutput, trackOutput, header, MimeTypes.AUDIO_RAW, pcmEncoding); + extractorOutput, trackOutput, wavFormat, MimeTypes.AUDIO_RAW, pcmEncoding); } state = STATE_SKIPPING_TO_SAMPLE_DATA; } @@ -234,7 +247,7 @@ public final class WavExtractor implements Extractor { private final ExtractorOutput extractorOutput; private final TrackOutput trackOutput; - private final WavHeader header; + private final WavFormat wavFormat; private final Format format; /** The target size of each output sample, in bytes. */ private final int targetSampleSizeBytes; @@ -256,33 +269,33 @@ public final class WavExtractor implements Extractor { public PassthroughOutputWriter( ExtractorOutput extractorOutput, TrackOutput trackOutput, - WavHeader header, + WavFormat wavFormat, String mimeType, @C.PcmEncoding int pcmEncoding) throws ParserException { this.extractorOutput = extractorOutput; this.trackOutput = trackOutput; - this.header = header; + this.wavFormat = wavFormat; - int bytesPerFrame = header.numChannels * header.bitsPerSample / 8; - // Validate the header. Blocks are expected to correspond to single frames. - if (header.blockSize != bytesPerFrame) { + int bytesPerFrame = wavFormat.numChannels * wavFormat.bitsPerSample / 8; + // Validate the WAV format. Blocks are expected to correspond to single frames. + if (wavFormat.blockSize != bytesPerFrame) { throw ParserException.createForMalformedContainer( - "Expected block size: " + bytesPerFrame + "; got: " + header.blockSize, + "Expected block size: " + bytesPerFrame + "; got: " + wavFormat.blockSize, /* cause= */ null); } - int constantBitrate = header.frameRateHz * bytesPerFrame * 8; + int constantBitrate = wavFormat.frameRateHz * bytesPerFrame * 8; targetSampleSizeBytes = - max(bytesPerFrame, header.frameRateHz * bytesPerFrame / TARGET_SAMPLES_PER_SECOND); + max(bytesPerFrame, wavFormat.frameRateHz * bytesPerFrame / TARGET_SAMPLES_PER_SECOND); format = new Format.Builder() .setSampleMimeType(mimeType) .setAverageBitrate(constantBitrate) .setPeakBitrate(constantBitrate) .setMaxInputSize(targetSampleSizeBytes) - .setChannelCount(header.numChannels) - .setSampleRate(header.frameRateHz) + .setChannelCount(wavFormat.numChannels) + .setSampleRate(wavFormat.frameRateHz) .setPcmEncoding(pcmEncoding) .build(); } @@ -297,7 +310,7 @@ public final class WavExtractor implements Extractor { @Override public void init(int dataStartPosition, long dataEndPosition) { extractorOutput.seekMap( - new WavSeekMap(header, /* framesPerBlock= */ 1, dataStartPosition, dataEndPosition)); + new WavSeekMap(wavFormat, /* framesPerBlock= */ 1, dataStartPosition, dataEndPosition)); trackOutput.format(format); } @@ -318,13 +331,13 @@ public final class WavExtractor implements Extractor { // Write the corresponding sample metadata. Samples must be a whole number of frames. It's // possible that the number of pending output bytes is not a whole number of frames if the // stream ended unexpectedly. - int bytesPerFrame = header.blockSize; + int bytesPerFrame = wavFormat.blockSize; int pendingFrames = pendingOutputBytes / bytesPerFrame; if (pendingFrames > 0) { long timeUs = startTimeUs + Util.scaleLargeTimestamp( - outputFrameCount, C.MICROS_PER_SECOND, header.frameRateHz); + outputFrameCount, C.MICROS_PER_SECOND, wavFormat.frameRateHz); int size = pendingFrames * bytesPerFrame; int offset = pendingOutputBytes - size; trackOutput.sampleMetadata( @@ -354,7 +367,7 @@ public final class WavExtractor implements Extractor { private final ExtractorOutput extractorOutput; private final TrackOutput trackOutput; - private final WavHeader header; + private final WavFormat wavFormat; /** Number of frames per block of the input (yet to be decoded) data. */ private final int framesPerBlock; @@ -384,23 +397,26 @@ public final class WavExtractor implements Extractor { private long outputFrameCount; public ImaAdPcmOutputWriter( - ExtractorOutput extractorOutput, TrackOutput trackOutput, WavHeader header) + ExtractorOutput extractorOutput, TrackOutput trackOutput, WavFormat wavFormat) throws ParserException { this.extractorOutput = extractorOutput; this.trackOutput = trackOutput; - this.header = header; - targetSampleSizeFrames = max(1, header.frameRateHz / TARGET_SAMPLES_PER_SECOND); + this.wavFormat = wavFormat; + targetSampleSizeFrames = max(1, wavFormat.frameRateHz / TARGET_SAMPLES_PER_SECOND); - ParsableByteArray scratch = new ParsableByteArray(header.extraData); + ParsableByteArray scratch = new ParsableByteArray(wavFormat.extraData); scratch.readLittleEndianUnsignedShort(); framesPerBlock = scratch.readLittleEndianUnsignedShort(); - int numChannels = header.numChannels; - // Validate the header. This calculation is defined in "Microsoft Multimedia Standards Update + int numChannels = wavFormat.numChannels; + // Validate the WAV format. This calculation is defined in "Microsoft Multimedia Standards + // Update // - New Multimedia Types and Data Techniques" (1994). See the "IMA ADPCM Wave Type" and "DVI // ADPCM Wave Type" sections, and the calculation of wSamplesPerBlock in the latter. int expectedFramesPerBlock = - (((header.blockSize - (4 * numChannels)) * 8) / (header.bitsPerSample * numChannels)) + 1; + (((wavFormat.blockSize - (4 * numChannels)) * 8) + / (wavFormat.bitsPerSample * numChannels)) + + 1; if (framesPerBlock != expectedFramesPerBlock) { throw ParserException.createForMalformedContainer( "Expected frames per block: " + expectedFramesPerBlock + "; got: " + framesPerBlock, @@ -410,22 +426,22 @@ public final class WavExtractor implements Extractor { // Calculate the number of blocks we'll need to decode to obtain an output sample of the // target sample size, and allocate suitably sized buffers for input and decoded data. int maxBlocksToDecode = Util.ceilDivide(targetSampleSizeFrames, framesPerBlock); - inputData = new byte[maxBlocksToDecode * header.blockSize]; + inputData = new byte[maxBlocksToDecode * wavFormat.blockSize]; decodedData = new ParsableByteArray( maxBlocksToDecode * numOutputFramesToBytes(framesPerBlock, numChannels)); // Create the format. We calculate the bitrate of the data before decoding, since this is the // bitrate of the stream itself. - int constantBitrate = header.frameRateHz * header.blockSize * 8 / framesPerBlock; + int constantBitrate = wavFormat.frameRateHz * wavFormat.blockSize * 8 / framesPerBlock; format = new Format.Builder() .setSampleMimeType(MimeTypes.AUDIO_RAW) .setAverageBitrate(constantBitrate) .setPeakBitrate(constantBitrate) .setMaxInputSize(numOutputFramesToBytes(targetSampleSizeFrames, numChannels)) - .setChannelCount(header.numChannels) - .setSampleRate(header.frameRateHz) + .setChannelCount(wavFormat.numChannels) + .setSampleRate(wavFormat.frameRateHz) .setPcmEncoding(C.ENCODING_PCM_16BIT) .build(); } @@ -441,7 +457,7 @@ public final class WavExtractor implements Extractor { @Override public void init(int dataStartPosition, long dataEndPosition) { extractorOutput.seekMap( - new WavSeekMap(header, framesPerBlock, dataStartPosition, dataEndPosition)); + new WavSeekMap(wavFormat, framesPerBlock, dataStartPosition, dataEndPosition)); trackOutput.format(format); } @@ -453,7 +469,7 @@ public final class WavExtractor implements Extractor { targetSampleSizeFrames - numOutputBytesToFrames(pendingOutputBytes); // Calculate the whole number of blocks that we need to decode to obtain this many frames. int blocksToDecode = Util.ceilDivide(targetFramesRemaining, framesPerBlock); - int targetReadBytes = blocksToDecode * header.blockSize; + int targetReadBytes = blocksToDecode * wavFormat.blockSize; // Read input data until we've reached the target number of blocks, or the end of the data. boolean endOfSampleData = bytesLeft == 0; @@ -467,11 +483,11 @@ public final class WavExtractor implements Extractor { } } - int pendingBlockCount = pendingInputBytes / header.blockSize; + int pendingBlockCount = pendingInputBytes / wavFormat.blockSize; if (pendingBlockCount > 0) { // We have at least one whole block to decode. decode(inputData, pendingBlockCount, decodedData); - pendingInputBytes -= pendingBlockCount * header.blockSize; + pendingInputBytes -= pendingBlockCount * wavFormat.blockSize; // Write all of the decoded data to the track output. int decodedDataSize = decodedData.limit(); @@ -499,7 +515,8 @@ public final class WavExtractor implements Extractor { private void writeSampleMetadata(int sampleFrames) { long timeUs = startTimeUs - + Util.scaleLargeTimestamp(outputFrameCount, C.MICROS_PER_SECOND, header.frameRateHz); + + Util.scaleLargeTimestamp( + outputFrameCount, C.MICROS_PER_SECOND, wavFormat.frameRateHz); int size = numOutputFramesToBytes(sampleFrames); int offset = pendingOutputBytes - size; trackOutput.sampleMetadata( @@ -517,7 +534,7 @@ public final class WavExtractor implements Extractor { */ private void decode(byte[] input, int blockCount, ParsableByteArray output) { for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) { - for (int channelIndex = 0; channelIndex < header.numChannels; channelIndex++) { + for (int channelIndex = 0; channelIndex < wavFormat.numChannels; channelIndex++) { decodeBlockForChannel(input, blockIndex, channelIndex, output.getData()); } } @@ -528,8 +545,8 @@ public final class WavExtractor implements Extractor { private void decodeBlockForChannel( byte[] input, int blockIndex, int channelIndex, byte[] output) { - int blockSize = header.blockSize; - int numChannels = header.numChannels; + int blockSize = wavFormat.blockSize; + int numChannels = wavFormat.numChannels; // The input data consists for a four byte header [Ci] for each of the N channels, followed // by interleaved data segments [Ci-DATAj], each of which are four bytes long. @@ -590,11 +607,11 @@ public final class WavExtractor implements Extractor { } private int numOutputBytesToFrames(int bytes) { - return bytes / (2 * header.numChannels); + return bytes / (2 * wavFormat.numChannels); } private int numOutputFramesToBytes(int frames) { - return numOutputFramesToBytes(frames, header.numChannels); + return numOutputFramesToBytes(frames, wavFormat.numChannels); } private static int numOutputFramesToBytes(int frames, int numChannels) { diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavFormat.java similarity index 91% rename from library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeader.java rename to library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavFormat.java index ca34e32cc0..ca9e1d8dd7 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavFormat.java @@ -15,8 +15,8 @@ */ package com.google.android.exoplayer2.extractor.wav; -/** Header for a WAV file. */ -/* package */ final class WavHeader { +/** Format information for a WAV file. */ +/* package */ final class WavFormat { /** * The format type. Standard format types are the "WAVE form Registration Number" constants @@ -33,10 +33,10 @@ package com.google.android.exoplayer2.extractor.wav; public final int blockSize; /** Bits per sample for a single channel. */ public final int bitsPerSample; - /** Extra data appended to the format chunk of the header. */ + /** Extra data appended to the format chunk. */ public final byte[] extraData; - public WavHeader( + public WavFormat( int formatType, int numChannels, int frameRateHz, diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java index 147fba9c53..4541a305d6 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java @@ -16,7 +16,6 @@ package com.google.android.exoplayer2.extractor.wav; import android.util.Pair; -import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.audio.WavUtil; @@ -27,45 +26,56 @@ import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.Util; import java.io.IOException; -/** Reads a {@code WavHeader} from an input stream; supports resuming from input failures. */ +/** Reads a WAV header from an input stream; supports resuming from input failures. */ /* package */ final class WavHeaderReader { private static final String TAG = "WavHeaderReader"; /** - * Peeks and returns a {@code WavHeader}. + * Returns whether the given {@code input} starts with a RIFF chunk header, followed by a WAVE + * tag. * - * @param input Input stream to peek the WAV header from. - * @throws ParserException If the input file is an incorrect RIFF WAV. + * @param input The input stream to peek from. The position should point to the start of the + * stream. + * @return Whether the given {@code input} starts with a RIFF chunk header, followed by a WAVE + * tag. * @throws IOException If peeking from the input fails. - * @return A new {@code WavHeader} peeked from {@code input}, or null if the input is not a - * supported WAV format. */ - @Nullable - public static WavHeader peek(ExtractorInput input) throws IOException { - Assertions.checkNotNull(input); - - // Allocate a scratch buffer large enough to store the format chunk. - ParsableByteArray scratch = new ParsableByteArray(16); - + public static boolean checkFileType(ExtractorInput input) throws IOException { + ParsableByteArray scratch = new ParsableByteArray(ChunkHeader.SIZE_IN_BYTES); // Attempt to read the RIFF chunk. ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch); if (chunkHeader.id != WavUtil.RIFF_FOURCC) { - return null; + return false; } input.peekFully(scratch.getData(), 0, 4); scratch.setPosition(0); - int riffFormat = scratch.readInt(); - if (riffFormat != WavUtil.WAVE_FOURCC) { - Log.e(TAG, "Unsupported RIFF format: " + riffFormat); - return null; + int formType = scratch.readInt(); + if (formType != WavUtil.WAVE_FOURCC) { + Log.e(TAG, "Unsupported form type: " + formType); + return false; } + return true; + } + + /** + * Reads and returns a {@code WavFormat}. + * + * @param input Input stream to read the WAV format from. The position should point to the byte + * following the WAVE tag. + * @throws IOException If reading from the input fails. + * @return A new {@code WavFormat} read from {@code input}. + */ + public static WavFormat readFormat(ExtractorInput input) throws IOException { + // Allocate a scratch buffer large enough to store the format chunk. + ParsableByteArray scratch = new ParsableByteArray(16); + // Skip chunks until we find the format chunk. - chunkHeader = ChunkHeader.peek(input, scratch); + ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch); while (chunkHeader.id != WavUtil.FMT_FOURCC) { - input.advancePeekPosition((int) chunkHeader.size); + input.skipFully(ChunkHeader.SIZE_IN_BYTES + (int) chunkHeader.size); chunkHeader = ChunkHeader.peek(input, scratch); } @@ -88,7 +98,8 @@ import java.io.IOException; extraData = Util.EMPTY_BYTE_ARRAY; } - return new WavHeader( + input.skipFully((int) (input.getPeekPosition() - input.getPosition())); + return new WavFormat( audioFormatType, numChannels, frameRateHz, @@ -109,8 +120,6 @@ import java.io.IOException; * @throws IOException If reading from the input fails. */ public static Pair skipToSampleData(ExtractorInput input) throws IOException { - Assertions.checkNotNull(input); - // Make sure the peek position is set to the read position before we peek the first header. input.resetPeekPosition(); diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavSeekMap.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavSeekMap.java index 2a92c38431..1d5c8fdae1 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavSeekMap.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavSeekMap.java @@ -22,18 +22,18 @@ import com.google.android.exoplayer2.util.Util; /* package */ final class WavSeekMap implements SeekMap { - private final WavHeader wavHeader; + private final WavFormat wavFormat; private final int framesPerBlock; private final long firstBlockPosition; private final long blockCount; private final long durationUs; public WavSeekMap( - WavHeader wavHeader, int framesPerBlock, long dataStartPosition, long dataEndPosition) { - this.wavHeader = wavHeader; + WavFormat wavFormat, int framesPerBlock, long dataStartPosition, long dataEndPosition) { + this.wavFormat = wavFormat; this.framesPerBlock = framesPerBlock; this.firstBlockPosition = dataStartPosition; - this.blockCount = (dataEndPosition - dataStartPosition) / wavHeader.blockSize; + this.blockCount = (dataEndPosition - dataStartPosition) / wavFormat.blockSize; durationUs = blockIndexToTimeUs(blockCount); } @@ -50,17 +50,17 @@ import com.google.android.exoplayer2.util.Util; @Override public SeekPoints getSeekPoints(long timeUs) { // Calculate the containing block index, constraining to valid indices. - long blockIndex = (timeUs * wavHeader.frameRateHz) / (C.MICROS_PER_SECOND * framesPerBlock); + long blockIndex = (timeUs * wavFormat.frameRateHz) / (C.MICROS_PER_SECOND * framesPerBlock); blockIndex = Util.constrainValue(blockIndex, 0, blockCount - 1); - long seekPosition = firstBlockPosition + (blockIndex * wavHeader.blockSize); + long seekPosition = firstBlockPosition + (blockIndex * wavFormat.blockSize); long seekTimeUs = blockIndexToTimeUs(blockIndex); SeekPoint seekPoint = new SeekPoint(seekTimeUs, seekPosition); if (seekTimeUs >= timeUs || blockIndex == blockCount - 1) { return new SeekPoints(seekPoint); } else { long secondBlockIndex = blockIndex + 1; - long secondSeekPosition = firstBlockPosition + (secondBlockIndex * wavHeader.blockSize); + long secondSeekPosition = firstBlockPosition + (secondBlockIndex * wavFormat.blockSize); long secondSeekTimeUs = blockIndexToTimeUs(secondBlockIndex); SeekPoint secondSeekPoint = new SeekPoint(secondSeekTimeUs, secondSeekPosition); return new SeekPoints(seekPoint, secondSeekPoint); @@ -69,6 +69,6 @@ import com.google.android.exoplayer2.util.Util; private long blockIndexToTimeUs(long blockIndex) { return Util.scaleLargeTimestamp( - blockIndex * framesPerBlock, C.MICROS_PER_SECOND, wavHeader.frameRateHz); + blockIndex * framesPerBlock, C.MICROS_PER_SECOND, wavFormat.frameRateHz); } } From d5a87d13b79004ec3039932946c63d0c4238634f Mon Sep 17 00:00:00 2001 From: ibaker Date: Wed, 3 Nov 2021 11:33:57 +0000 Subject: [PATCH 040/497] Fix broken link on supported-formats dev guide page #minor-release PiperOrigin-RevId: 407305661 --- docs/supported-formats.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/supported-formats.md b/docs/supported-formats.md index 8270866bcd..70b24416a8 100644 --- a/docs/supported-formats.md +++ b/docs/supported-formats.md @@ -92,7 +92,7 @@ FFmpeg decoder name. ## Standalone subtitle formats ## ExoPlayer supports standalone subtitle files in a variety of formats. Subtitle -files can be side-loaded as described on the [Media source page][]. +files can be side-loaded as described on the [media items page][]. | Container format | Supported | MIME type | |---------------------------|:------------:|:----------| @@ -101,7 +101,7 @@ files can be side-loaded as described on the [Media source page][]. | SubRip | YES | MimeTypes.APPLICATION_SUBRIP | | SubStationAlpha (SSA/ASS) | YES | MimeTypes.TEXT_SSA | -[Media source page]: {{ site.baseurl }}/media-sources.html#side-loading-a-subtitle-file +[media items page]: {{ site.baseurl }}/media-items.html#sideloading-subtitle-tracks ## HDR video playback ## From 0c4f5ebc910667a38892c51e316a90d68fe00e77 Mon Sep 17 00:00:00 2001 From: samrobinson Date: Wed, 3 Nov 2021 11:57:41 +0000 Subject: [PATCH 041/497] Fix END_OF_STREAM transformer timestamp matching previous. This cause the muxer to fail to stop on older devices/API levels. #minor-release PiperOrigin-RevId: 407309028 --- RELEASENOTES.md | 3 +++ .../exoplayer2/transformer/TransformerAudioRenderer.java | 1 + 2 files changed, 4 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 586144ca28..cbf79d1a9d 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -90,6 +90,9 @@ * Rename `MediaSessionConnector.QueueNavigator#onCurrentWindowIndexChanged` to `onCurrentMediaItemIndexChanged`. +* Transformer: + * Avoid sending a duplicate timestamp to the encoder with the end of + stream buffer. * Remove deprecated symbols: * Remove `Renderer.VIDEO_SCALING_MODE_*` constants. Use identically named constants in `C` instead. diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java index f20915c120..7efa0eb780 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java @@ -316,6 +316,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; private void queueEndOfStreamToEncoder(MediaCodecAdapterWrapper encoder) { checkState(checkNotNull(encoderInputBuffer.data).position() == 0); + encoderInputBuffer.timeUs = nextEncoderInputBufferTimeUs; encoderInputBuffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM); encoderInputBuffer.flip(); // Queuing EOS should only occur with an empty buffer. From 2d311002642d5410dbcb83b7a9f0f2c86becdc60 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 3 Nov 2021 12:36:06 +0000 Subject: [PATCH 042/497] Bump version to 2.16.0 PiperOrigin-RevId: 407314385 --- constants.gradle | 4 ++-- .../com/google/android/exoplayer2/ExoPlayerLibraryInfo.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/constants.gradle b/constants.gradle index 400eba8c9f..bd4a545c4c 100644 --- a/constants.gradle +++ b/constants.gradle @@ -13,8 +13,8 @@ // limitations under the License. project.ext { // ExoPlayer version and version code. - releaseVersion = '2.15.1' - releaseVersionCode = 2015001 + releaseVersion = '2.16.0' + releaseVersionCode = 2016000 minSdkVersion = 16 appTargetSdkVersion = 29 // Upgrading this requires [Internal ref: b/193254928] to be fixed, or some diff --git a/library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index 9f13465861..4784575659 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -27,11 +27,11 @@ public final class ExoPlayerLibraryInfo { /** The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - public static final String VERSION = "2.15.1"; + public static final String VERSION = "2.16.0"; /** The version of the library expressed as {@code TAG + "/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final String VERSION_SLASHY = "ExoPlayerLib/2.15.1"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.16.0"; /** * The version of the library expressed as an integer, for example 1002003. @@ -41,7 +41,7 @@ public final class ExoPlayerLibraryInfo { * integer version 123045006 (123-045-006). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final int VERSION_INT = 2015001; + public static final int VERSION_INT = 2016000; /** Whether the library was compiled with {@link Assertions} checks enabled. */ public static final boolean ASSERTIONS_ENABLED = true; From bc3360e5d44238308d569dabbd26b472a01084fa Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 3 Nov 2021 14:37:41 +0000 Subject: [PATCH 043/497] Update release notes for 2.16.0 PiperOrigin-RevId: 407333525 --- RELEASENOTES.md | 50 +++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index cbf79d1a9d..ae006ebdde 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -2,38 +2,34 @@ ### dev-v2 (not yet released) +### 2.16.0 (2021-11-04) + * Core Library: + * Deprecate `SimpleExoPlayer`. All functionality has been moved to + `ExoPlayer` instead. `ExoPlayer.Builder` can be used instead of + `SimpleExoPlayer.Builder`. + * Add track selection methods to the `Player` interface, for example, + `Player.getCurrentTracksInfo` and `Player.setTrackSelectionParameters`. + These methods can be used instead of directly accessing the track + selector. * Enable MediaCodec asynchronous queueing by default on devices with API level >= 31. Add methods in `DefaultMediaCodecRendererFactory` and `DefaultRenderersFactory` to force enable or force disable asynchronous queueing ([6348](https://github.com/google/ExoPlayer/issues/6348)). - * Add 12 public method headers to `ExoPlayer` that exist in - `SimpleExoPlayer`, such that all public methods in `SimpleExoPlayer` are - overrides. + * Remove final dependency on `jcenter()`. + * Fix `mediaMetadata` being reset when media is repeated + ([#9458](https://github.com/google/ExoPlayer/issues/9458)). + * Adjust `ExoPlayer` `MediaMetadata` update priority, such that values + input through the `MediaItem.MediaMetadata` are used above media derived + values. * Move `com.google.android.exoplayer2.device.DeviceInfo` to `com.google.android.exoplayer2.DeviceInfo`. * Move `com.google.android.exoplayer2.drm.DecryptionException` to `com.google.android.exoplayer2.decoder.CryptoException`. * Move `com.google.android.exoplayer2.upstream.cache.CachedRegionTracker` to `com.google.android.exoplayer2.upstream.CachedRegionTracker`. - * Remove `ExoPlayerLibraryInfo.GL_ASSERTIONS_ENABLED`. Use - `GlUtil.glAssertionsEnabled` instead. * Move `Player.addListener(EventListener)` and `Player.removeListener(EventListener)` out of `Player` into subclasses. - * Fix `mediaMetadata` being reset when media is repeated - ([#9458](https://github.com/google/ExoPlayer/issues/9458)). - * Remove final dependency on `jcenter()`. - * Adjust `ExoPlayer` `MediaMetadata` update priority, such that values - input through the `MediaItem.MediaMetadata` are used above media derived - values. -* Video: - * Fix bug in `MediaCodecVideoRenderer` that resulted in re-using a - released `Surface` when playing without an app-provided `Surface` - ([#9476](https://github.com/google/ExoPlayer/issues/9476)). -* DRM: - * Log an error (instead of throwing `IllegalStateException`) when calling - `DefaultDrmSession#release()` on a fully released session - ([#9392](https://github.com/google/ExoPlayer/issues/9392)). * Android 12 compatibility: * Keep `DownloadService` started and in the foreground whilst waiting for requirements to be met on Android 12. This is necessary due to new @@ -49,6 +45,14 @@ are not compatible with apps targeting Android 12, and will crash with an `IllegalArgumentException` when creating `PendingIntent`s ([#9181](https://github.com/google/ExoPlayer/issues/9181)). +* Video: + * Fix bug in `MediaCodecVideoRenderer` that resulted in re-using a + released `Surface` when playing without an app-provided `Surface` + ([#9476](https://github.com/google/ExoPlayer/issues/9476)). +* DRM: + * Log an error (instead of throwing `IllegalStateException`) when calling + `DefaultDrmSession#release()` on a fully released session + ([#9392](https://github.com/google/ExoPlayer/issues/9392)). * UI: * `SubtitleView` no longer implements `TextOutput`. `SubtitleView` implements `Player.Listener`, so can be registered to a player with @@ -74,7 +78,7 @@ requirements for downloads to continue. In both cases, `DownloadService` will now remain started and in the foreground whilst waiting for requirements to be met. - * Modify `DownlaodService` behavior when running on Android 12 and above. + * Modify `DownloadService` behavior when running on Android 12 and above. See the "Android 12 compatibility" section above. * RTSP: * Support RFC4566 SDP attribute field grammar @@ -83,6 +87,12 @@ * Populate `Format.sampleMimeType`, `width` and `height` for image `AdaptationSet` elements ([#9500](https://github.com/google/ExoPlayer/issues/9500)). +* HLS: + * Fix rounding error in HLS playlists + ([#9575](https://github.com/google/ExoPlayer/issues/9575)). + * Fix `NoSuchElementException` thrown when an HLS manifest declares + `#EXT-X-RENDITION-REPORT` at the beginning of the playlist + ([#9592](https://github.com/google/ExoPlayer/issues/9592)). * RTMP extension: * Upgrade to `io.antmedia:rtmp_client`, which does not rely on `jcenter()` ([#9591](https://github.com/google/ExoPlayer/issues/9591)). From 5d2df8349672a106d7231b353688090e8277b80f Mon Sep 17 00:00:00 2001 From: christosts Date: Wed, 3 Nov 2021 15:45:07 +0000 Subject: [PATCH 044/497] Add DefaultMediaCodecFactory.getCodecAdapter() method Add protected method DefaultRenderersFactory.getCodecAdapter(), so that subclasses of DefaultRenderersFactory that override buildVideoRenderers() or buildAudioRenderers() can access the DefaultRenderersFactory codec adapter factory and pass it to MediaCodecRenderer instances they may create. #minor-release PiperOrigin-RevId: 407345431 --- RELEASENOTES.md | 7 +++++++ .../android/exoplayer2/DefaultRenderersFactory.java | 13 +++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ae006ebdde..b53b2f6226 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -2,6 +2,13 @@ ### dev-v2 (not yet released) +* Core Library: + * Add protected method `DefaultRenderersFactory.getCodecAdapterFactory()` + so that subclasses of `DefaultRenderersFactory` that override + `buildVideoRenderers()` or `buildAudioRenderers()` can access the codec + adapter factory and pass it to `MediaCodecRenderer` instances they + create. + ### 2.16.0 (2021-11-04) * Core Library: diff --git a/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java index 03ccc297a8..ca205c2901 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java @@ -29,6 +29,7 @@ import com.google.android.exoplayer2.audio.DefaultAudioSink; import com.google.android.exoplayer2.audio.DefaultAudioSink.DefaultAudioProcessorChain; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; import com.google.android.exoplayer2.mediacodec.DefaultMediaCodecAdapterFactory; +import com.google.android.exoplayer2.mediacodec.MediaCodecAdapter; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.metadata.MetadataOutput; import com.google.android.exoplayer2.metadata.MetadataRenderer; @@ -368,7 +369,7 @@ public class DefaultRenderersFactory implements RenderersFactory { MediaCodecVideoRenderer videoRenderer = new MediaCodecVideoRenderer( context, - codecAdapterFactory, + getCodecAdapterFactory(), mediaCodecSelector, allowedVideoJoiningTimeMs, enableDecoderFallback, @@ -488,7 +489,7 @@ public class DefaultRenderersFactory implements RenderersFactory { MediaCodecAudioRenderer audioRenderer = new MediaCodecAudioRenderer( context, - codecAdapterFactory, + getCodecAdapterFactory(), mediaCodecSelector, enableDecoderFallback, eventHandler, @@ -655,4 +656,12 @@ public class DefaultRenderersFactory implements RenderersFactory { ? DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED : DefaultAudioSink.OFFLOAD_MODE_DISABLED); } + + /** + * Returns the {@link MediaCodecAdapter.Factory} that will be used when creating {@link + * com.google.android.exoplayer2.mediacodec.MediaCodecRenderer} instances. + */ + protected MediaCodecAdapter.Factory getCodecAdapterFactory() { + return codecAdapterFactory; + } } From 49a93e31d7a97cab7f14c22517f58b134e87a977 Mon Sep 17 00:00:00 2001 From: hschlueter Date: Wed, 3 Nov 2021 15:49:09 +0000 Subject: [PATCH 045/497] Write sample size to dumpfile in transformer tests. If the number of samples changes, the sizes will help us to verify whether they are just split differently or extra data was added. PiperOrigin-RevId: 407346280 --- .../exoplayer2/transformer/TestMuxer.java | 5 +- .../transformerdumps/amr/sample_nb.amr.dump | 218 ++++++++++++++++++ .../transformerdumps/mkv/sample.mkv.dump | 30 +++ .../mkv/sample_with_srt.mkv.dump | 30 +++ .../transformerdumps/mp4/sample.mp4.dump | 75 ++++++ .../mp4/sample.mp4.noaudio.dump | 30 +++ .../mp4/sample.mp4.novideo.dump | 45 ++++ .../mp4/sample_sef_slow_motion.mp4.dump | 41 ++++ 8 files changed, 473 insertions(+), 1 deletion(-) diff --git a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TestMuxer.java b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TestMuxer.java index d47dd0d32f..b4836e27a2 100644 --- a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TestMuxer.java +++ b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TestMuxer.java @@ -79,6 +79,7 @@ public final class TestMuxer implements Muxer, Dumper.Dumpable { private final long presentationTimeUs; private final boolean isKeyFrame; private final int sampleDataHashCode; + private final int sampleSize; public DumpableSample( int trackIndex, ByteBuffer sample, boolean isKeyFrame, long presentationTimeUs) { @@ -86,7 +87,8 @@ public final class TestMuxer implements Muxer, Dumper.Dumpable { this.presentationTimeUs = presentationTimeUs; this.isKeyFrame = isKeyFrame; int initialPosition = sample.position(); - byte[] data = new byte[sample.remaining()]; + sampleSize = sample.remaining(); + byte[] data = new byte[sampleSize]; sample.get(data); sample.position(initialPosition); sampleDataHashCode = Arrays.hashCode(data); @@ -98,6 +100,7 @@ public final class TestMuxer implements Muxer, Dumper.Dumpable { .startBlock("sample") .add("trackIndex", trackIndex) .add("dataHashCode", sampleDataHashCode) + .add("size", sampleSize) .add("isKeyFrame", isKeyFrame) .add("presentationTimeUs", presentationTimeUs) .endBlock(); diff --git a/testdata/src/test/assets/transformerdumps/amr/sample_nb.amr.dump b/testdata/src/test/assets/transformerdumps/amr/sample_nb.amr.dump index c18193c16f..18836cbc5d 100644 --- a/testdata/src/test/assets/transformerdumps/amr/sample_nb.amr.dump +++ b/testdata/src/test/assets/transformerdumps/amr/sample_nb.amr.dump @@ -7,1091 +7,1309 @@ format 0: sample: trackIndex = 0 dataHashCode = 924517484 + size = 13 isKeyFrame = true presentationTimeUs = 0 sample: trackIndex = 0 dataHashCode = -835666085 + size = 13 isKeyFrame = true presentationTimeUs = 750 sample: trackIndex = 0 dataHashCode = 430283125 + size = 13 isKeyFrame = true presentationTimeUs = 1500 sample: trackIndex = 0 dataHashCode = 1215919932 + size = 13 isKeyFrame = true presentationTimeUs = 2250 sample: trackIndex = 0 dataHashCode = -386387943 + size = 13 isKeyFrame = true presentationTimeUs = 3000 sample: trackIndex = 0 dataHashCode = -765080119 + size = 13 isKeyFrame = true presentationTimeUs = 3750 sample: trackIndex = 0 dataHashCode = -1855636054 + size = 13 isKeyFrame = true presentationTimeUs = 4500 sample: trackIndex = 0 dataHashCode = -946579722 + size = 13 isKeyFrame = true presentationTimeUs = 5250 sample: trackIndex = 0 dataHashCode = -841202654 + size = 13 isKeyFrame = true presentationTimeUs = 6000 sample: trackIndex = 0 dataHashCode = -638764303 + size = 13 isKeyFrame = true presentationTimeUs = 6750 sample: trackIndex = 0 dataHashCode = -1162388941 + size = 13 isKeyFrame = true presentationTimeUs = 7500 sample: trackIndex = 0 dataHashCode = 572634367 + size = 13 isKeyFrame = true presentationTimeUs = 8250 sample: trackIndex = 0 dataHashCode = -1774188021 + size = 13 isKeyFrame = true presentationTimeUs = 9000 sample: trackIndex = 0 dataHashCode = 92464891 + size = 13 isKeyFrame = true presentationTimeUs = 9750 sample: trackIndex = 0 dataHashCode = -991397659 + size = 13 isKeyFrame = true presentationTimeUs = 10500 sample: trackIndex = 0 dataHashCode = -934698563 + size = 13 isKeyFrame = true presentationTimeUs = 11250 sample: trackIndex = 0 dataHashCode = -811030035 + size = 13 isKeyFrame = true presentationTimeUs = 12000 sample: trackIndex = 0 dataHashCode = 1892305159 + size = 13 isKeyFrame = true presentationTimeUs = 12750 sample: trackIndex = 0 dataHashCode = -1266858924 + size = 13 isKeyFrame = true presentationTimeUs = 13500 sample: trackIndex = 0 dataHashCode = 673814721 + size = 13 isKeyFrame = true presentationTimeUs = 14250 sample: trackIndex = 0 dataHashCode = 1061124709 + size = 13 isKeyFrame = true presentationTimeUs = 15000 sample: trackIndex = 0 dataHashCode = -869356712 + size = 13 isKeyFrame = true presentationTimeUs = 15750 sample: trackIndex = 0 dataHashCode = 664729362 + size = 13 isKeyFrame = true presentationTimeUs = 16500 sample: trackIndex = 0 dataHashCode = -1439741143 + size = 13 isKeyFrame = true presentationTimeUs = 17250 sample: trackIndex = 0 dataHashCode = -151627580 + size = 13 isKeyFrame = true presentationTimeUs = 18000 sample: trackIndex = 0 dataHashCode = -673268457 + size = 13 isKeyFrame = true presentationTimeUs = 18750 sample: trackIndex = 0 dataHashCode = 1839962647 + size = 13 isKeyFrame = true presentationTimeUs = 19500 sample: trackIndex = 0 dataHashCode = 1858999665 + size = 13 isKeyFrame = true presentationTimeUs = 20250 sample: trackIndex = 0 dataHashCode = -1278193537 + size = 13 isKeyFrame = true presentationTimeUs = 21000 sample: trackIndex = 0 dataHashCode = 568547001 + size = 13 isKeyFrame = true presentationTimeUs = 21750 sample: trackIndex = 0 dataHashCode = 68217362 + size = 13 isKeyFrame = true presentationTimeUs = 22500 sample: trackIndex = 0 dataHashCode = 1396217256 + size = 13 isKeyFrame = true presentationTimeUs = 23250 sample: trackIndex = 0 dataHashCode = -971293094 + size = 13 isKeyFrame = true presentationTimeUs = 24000 sample: trackIndex = 0 dataHashCode = -1742638874 + size = 13 isKeyFrame = true presentationTimeUs = 24750 sample: trackIndex = 0 dataHashCode = 2047109317 + size = 13 isKeyFrame = true presentationTimeUs = 25500 sample: trackIndex = 0 dataHashCode = -1668945241 + size = 13 isKeyFrame = true presentationTimeUs = 26250 sample: trackIndex = 0 dataHashCode = -1229766218 + size = 13 isKeyFrame = true presentationTimeUs = 27000 sample: trackIndex = 0 dataHashCode = 1765233454 + size = 13 isKeyFrame = true presentationTimeUs = 27750 sample: trackIndex = 0 dataHashCode = -1930255456 + size = 13 isKeyFrame = true presentationTimeUs = 28500 sample: trackIndex = 0 dataHashCode = -764925242 + size = 13 isKeyFrame = true presentationTimeUs = 29250 sample: trackIndex = 0 dataHashCode = -1144688369 + size = 13 isKeyFrame = true presentationTimeUs = 30000 sample: trackIndex = 0 dataHashCode = 1493699436 + size = 13 isKeyFrame = true presentationTimeUs = 30750 sample: trackIndex = 0 dataHashCode = -468614511 + size = 13 isKeyFrame = true presentationTimeUs = 31500 sample: trackIndex = 0 dataHashCode = -1578782058 + size = 13 isKeyFrame = true presentationTimeUs = 32250 sample: trackIndex = 0 dataHashCode = -675743397 + size = 13 isKeyFrame = true presentationTimeUs = 33000 sample: trackIndex = 0 dataHashCode = -863790111 + size = 13 isKeyFrame = true presentationTimeUs = 33750 sample: trackIndex = 0 dataHashCode = -732307506 + size = 13 isKeyFrame = true presentationTimeUs = 34500 sample: trackIndex = 0 dataHashCode = -693298708 + size = 13 isKeyFrame = true presentationTimeUs = 35250 sample: trackIndex = 0 dataHashCode = -799131843 + size = 13 isKeyFrame = true presentationTimeUs = 36000 sample: trackIndex = 0 dataHashCode = 1782866119 + size = 13 isKeyFrame = true presentationTimeUs = 36750 sample: trackIndex = 0 dataHashCode = -912205505 + size = 13 isKeyFrame = true presentationTimeUs = 37500 sample: trackIndex = 0 dataHashCode = 1067981287 + size = 13 isKeyFrame = true presentationTimeUs = 38250 sample: trackIndex = 0 dataHashCode = 490520060 + size = 13 isKeyFrame = true presentationTimeUs = 39000 sample: trackIndex = 0 dataHashCode = -1950632957 + size = 13 isKeyFrame = true presentationTimeUs = 39750 sample: trackIndex = 0 dataHashCode = 565485817 + size = 13 isKeyFrame = true presentationTimeUs = 40500 sample: trackIndex = 0 dataHashCode = -1057414703 + size = 13 isKeyFrame = true presentationTimeUs = 41250 sample: trackIndex = 0 dataHashCode = 1568746155 + size = 13 isKeyFrame = true presentationTimeUs = 42000 sample: trackIndex = 0 dataHashCode = 1355412472 + size = 13 isKeyFrame = true presentationTimeUs = 42750 sample: trackIndex = 0 dataHashCode = 1546368465 + size = 13 isKeyFrame = true presentationTimeUs = 43500 sample: trackIndex = 0 dataHashCode = 1811529381 + size = 13 isKeyFrame = true presentationTimeUs = 44250 sample: trackIndex = 0 dataHashCode = 658031078 + size = 13 isKeyFrame = true presentationTimeUs = 45000 sample: trackIndex = 0 dataHashCode = 1606584486 + size = 13 isKeyFrame = true presentationTimeUs = 45750 sample: trackIndex = 0 dataHashCode = 2123252778 + size = 13 isKeyFrame = true presentationTimeUs = 46500 sample: trackIndex = 0 dataHashCode = -1364579398 + size = 13 isKeyFrame = true presentationTimeUs = 47250 sample: trackIndex = 0 dataHashCode = 1311427887 + size = 13 isKeyFrame = true presentationTimeUs = 48000 sample: trackIndex = 0 dataHashCode = -691467569 + size = 13 isKeyFrame = true presentationTimeUs = 48750 sample: trackIndex = 0 dataHashCode = 1876470084 + size = 13 isKeyFrame = true presentationTimeUs = 49500 sample: trackIndex = 0 dataHashCode = -1472873479 + size = 13 isKeyFrame = true presentationTimeUs = 50250 sample: trackIndex = 0 dataHashCode = -143574992 + size = 13 isKeyFrame = true presentationTimeUs = 51000 sample: trackIndex = 0 dataHashCode = 984180453 + size = 13 isKeyFrame = true presentationTimeUs = 51750 sample: trackIndex = 0 dataHashCode = -113645527 + size = 13 isKeyFrame = true presentationTimeUs = 52500 sample: trackIndex = 0 dataHashCode = 1987501641 + size = 13 isKeyFrame = true presentationTimeUs = 53250 sample: trackIndex = 0 dataHashCode = -1816426230 + size = 13 isKeyFrame = true presentationTimeUs = 54000 sample: trackIndex = 0 dataHashCode = -1250050360 + size = 13 isKeyFrame = true presentationTimeUs = 54750 sample: trackIndex = 0 dataHashCode = 1722852790 + size = 13 isKeyFrame = true presentationTimeUs = 55500 sample: trackIndex = 0 dataHashCode = 225656333 + size = 13 isKeyFrame = true presentationTimeUs = 56250 sample: trackIndex = 0 dataHashCode = -2137778394 + size = 13 isKeyFrame = true presentationTimeUs = 57000 sample: trackIndex = 0 dataHashCode = 1433327155 + size = 13 isKeyFrame = true presentationTimeUs = 57750 sample: trackIndex = 0 dataHashCode = -974261023 + size = 13 isKeyFrame = true presentationTimeUs = 58500 sample: trackIndex = 0 dataHashCode = 1797813317 + size = 13 isKeyFrame = true presentationTimeUs = 59250 sample: trackIndex = 0 dataHashCode = -594033497 + size = 13 isKeyFrame = true presentationTimeUs = 60000 sample: trackIndex = 0 dataHashCode = -628310540 + size = 13 isKeyFrame = true presentationTimeUs = 60750 sample: trackIndex = 0 dataHashCode = 1868627831 + size = 13 isKeyFrame = true presentationTimeUs = 61500 sample: trackIndex = 0 dataHashCode = 1051863958 + size = 13 isKeyFrame = true presentationTimeUs = 62250 sample: trackIndex = 0 dataHashCode = -1279059211 + size = 13 isKeyFrame = true presentationTimeUs = 63000 sample: trackIndex = 0 dataHashCode = 408201874 + size = 13 isKeyFrame = true presentationTimeUs = 63750 sample: trackIndex = 0 dataHashCode = 1686644299 + size = 13 isKeyFrame = true presentationTimeUs = 64500 sample: trackIndex = 0 dataHashCode = 1288226241 + size = 13 isKeyFrame = true presentationTimeUs = 65250 sample: trackIndex = 0 dataHashCode = 432829731 + size = 13 isKeyFrame = true presentationTimeUs = 66000 sample: trackIndex = 0 dataHashCode = -1679312600 + size = 13 isKeyFrame = true presentationTimeUs = 66750 sample: trackIndex = 0 dataHashCode = 1206680829 + size = 13 isKeyFrame = true presentationTimeUs = 67500 sample: trackIndex = 0 dataHashCode = -325844704 + size = 13 isKeyFrame = true presentationTimeUs = 68250 sample: trackIndex = 0 dataHashCode = 1941808848 + size = 13 isKeyFrame = true presentationTimeUs = 69000 sample: trackIndex = 0 dataHashCode = -87346412 + size = 13 isKeyFrame = true presentationTimeUs = 69750 sample: trackIndex = 0 dataHashCode = -329133765 + size = 13 isKeyFrame = true presentationTimeUs = 70500 sample: trackIndex = 0 dataHashCode = -1299416212 + size = 13 isKeyFrame = true presentationTimeUs = 71250 sample: trackIndex = 0 dataHashCode = -1314599219 + size = 13 isKeyFrame = true presentationTimeUs = 72000 sample: trackIndex = 0 dataHashCode = 1456741286 + size = 13 isKeyFrame = true presentationTimeUs = 72750 sample: trackIndex = 0 dataHashCode = 151296500 + size = 13 isKeyFrame = true presentationTimeUs = 73500 sample: trackIndex = 0 dataHashCode = 1708763603 + size = 13 isKeyFrame = true presentationTimeUs = 74250 sample: trackIndex = 0 dataHashCode = 227542220 + size = 13 isKeyFrame = true presentationTimeUs = 75000 sample: trackIndex = 0 dataHashCode = 1094305517 + size = 13 isKeyFrame = true presentationTimeUs = 75750 sample: trackIndex = 0 dataHashCode = -990377604 + size = 13 isKeyFrame = true presentationTimeUs = 76500 sample: trackIndex = 0 dataHashCode = -1798036230 + size = 13 isKeyFrame = true presentationTimeUs = 77250 sample: trackIndex = 0 dataHashCode = -1027148291 + size = 13 isKeyFrame = true presentationTimeUs = 78000 sample: trackIndex = 0 dataHashCode = 359763976 + size = 13 isKeyFrame = true presentationTimeUs = 78750 sample: trackIndex = 0 dataHashCode = 1332016420 + size = 13 isKeyFrame = true presentationTimeUs = 79500 sample: trackIndex = 0 dataHashCode = -102753250 + size = 13 isKeyFrame = true presentationTimeUs = 80250 sample: trackIndex = 0 dataHashCode = 1959063156 + size = 13 isKeyFrame = true presentationTimeUs = 81000 sample: trackIndex = 0 dataHashCode = 2129089853 + size = 13 isKeyFrame = true presentationTimeUs = 81750 sample: trackIndex = 0 dataHashCode = 1658742073 + size = 13 isKeyFrame = true presentationTimeUs = 82500 sample: trackIndex = 0 dataHashCode = 2136916514 + size = 13 isKeyFrame = true presentationTimeUs = 83250 sample: trackIndex = 0 dataHashCode = 105121407 + size = 13 isKeyFrame = true presentationTimeUs = 84000 sample: trackIndex = 0 dataHashCode = -839464484 + size = 13 isKeyFrame = true presentationTimeUs = 84750 sample: trackIndex = 0 dataHashCode = -1956791168 + size = 13 isKeyFrame = true presentationTimeUs = 85500 sample: trackIndex = 0 dataHashCode = -1387546109 + size = 13 isKeyFrame = true presentationTimeUs = 86250 sample: trackIndex = 0 dataHashCode = 128410432 + size = 13 isKeyFrame = true presentationTimeUs = 87000 sample: trackIndex = 0 dataHashCode = 907081136 + size = 13 isKeyFrame = true presentationTimeUs = 87750 sample: trackIndex = 0 dataHashCode = 1124845067 + size = 13 isKeyFrame = true presentationTimeUs = 88500 sample: trackIndex = 0 dataHashCode = -1714479962 + size = 13 isKeyFrame = true presentationTimeUs = 89250 sample: trackIndex = 0 dataHashCode = 322029323 + size = 13 isKeyFrame = true presentationTimeUs = 90000 sample: trackIndex = 0 dataHashCode = -1116281187 + size = 13 isKeyFrame = true presentationTimeUs = 90750 sample: trackIndex = 0 dataHashCode = 1571181228 + size = 13 isKeyFrame = true presentationTimeUs = 91500 sample: trackIndex = 0 dataHashCode = 997979854 + size = 13 isKeyFrame = true presentationTimeUs = 92250 sample: trackIndex = 0 dataHashCode = -1413492413 + size = 13 isKeyFrame = true presentationTimeUs = 93000 sample: trackIndex = 0 dataHashCode = -381390490 + size = 13 isKeyFrame = true presentationTimeUs = 93750 sample: trackIndex = 0 dataHashCode = -331348340 + size = 13 isKeyFrame = true presentationTimeUs = 94500 sample: trackIndex = 0 dataHashCode = -1568238592 + size = 13 isKeyFrame = true presentationTimeUs = 95250 sample: trackIndex = 0 dataHashCode = -941591445 + size = 13 isKeyFrame = true presentationTimeUs = 96000 sample: trackIndex = 0 dataHashCode = 1616911281 + size = 13 isKeyFrame = true presentationTimeUs = 96750 sample: trackIndex = 0 dataHashCode = -1755664741 + size = 13 isKeyFrame = true presentationTimeUs = 97500 sample: trackIndex = 0 dataHashCode = -1950609742 + size = 13 isKeyFrame = true presentationTimeUs = 98250 sample: trackIndex = 0 dataHashCode = 1476082149 + size = 13 isKeyFrame = true presentationTimeUs = 99000 sample: trackIndex = 0 dataHashCode = 1289547483 + size = 13 isKeyFrame = true presentationTimeUs = 99750 sample: trackIndex = 0 dataHashCode = -367599018 + size = 13 isKeyFrame = true presentationTimeUs = 100500 sample: trackIndex = 0 dataHashCode = 679378334 + size = 13 isKeyFrame = true presentationTimeUs = 101250 sample: trackIndex = 0 dataHashCode = 1437306809 + size = 13 isKeyFrame = true presentationTimeUs = 102000 sample: trackIndex = 0 dataHashCode = 311988463 + size = 13 isKeyFrame = true presentationTimeUs = 102750 sample: trackIndex = 0 dataHashCode = -1870442665 + size = 13 isKeyFrame = true presentationTimeUs = 103500 sample: trackIndex = 0 dataHashCode = 1530013920 + size = 13 isKeyFrame = true presentationTimeUs = 104250 sample: trackIndex = 0 dataHashCode = -585506443 + size = 13 isKeyFrame = true presentationTimeUs = 105000 sample: trackIndex = 0 dataHashCode = -293690558 + size = 13 isKeyFrame = true presentationTimeUs = 105750 sample: trackIndex = 0 dataHashCode = -616893325 + size = 13 isKeyFrame = true presentationTimeUs = 106500 sample: trackIndex = 0 dataHashCode = 632210495 + size = 13 isKeyFrame = true presentationTimeUs = 107250 sample: trackIndex = 0 dataHashCode = -291767937 + size = 13 isKeyFrame = true presentationTimeUs = 108000 sample: trackIndex = 0 dataHashCode = -270265 + size = 13 isKeyFrame = true presentationTimeUs = 108750 sample: trackIndex = 0 dataHashCode = -1095959376 + size = 13 isKeyFrame = true presentationTimeUs = 109500 sample: trackIndex = 0 dataHashCode = -1363867284 + size = 13 isKeyFrame = true presentationTimeUs = 110250 sample: trackIndex = 0 dataHashCode = 185415707 + size = 13 isKeyFrame = true presentationTimeUs = 111000 sample: trackIndex = 0 dataHashCode = 1033720098 + size = 13 isKeyFrame = true presentationTimeUs = 111750 sample: trackIndex = 0 dataHashCode = 1813896085 + size = 13 isKeyFrame = true presentationTimeUs = 112500 sample: trackIndex = 0 dataHashCode = -1381192241 + size = 13 isKeyFrame = true presentationTimeUs = 113250 sample: trackIndex = 0 dataHashCode = 362689054 + size = 13 isKeyFrame = true presentationTimeUs = 114000 sample: trackIndex = 0 dataHashCode = -1320787356 + size = 13 isKeyFrame = true presentationTimeUs = 114750 sample: trackIndex = 0 dataHashCode = 1306489379 + size = 13 isKeyFrame = true presentationTimeUs = 115500 sample: trackIndex = 0 dataHashCode = -910313430 + size = 13 isKeyFrame = true presentationTimeUs = 116250 sample: trackIndex = 0 dataHashCode = -1533334115 + size = 13 isKeyFrame = true presentationTimeUs = 117000 sample: trackIndex = 0 dataHashCode = -700061723 + size = 13 isKeyFrame = true presentationTimeUs = 117750 sample: trackIndex = 0 dataHashCode = 474100444 + size = 13 isKeyFrame = true presentationTimeUs = 118500 sample: trackIndex = 0 dataHashCode = -2096659943 + size = 13 isKeyFrame = true presentationTimeUs = 119250 sample: trackIndex = 0 dataHashCode = -690442126 + size = 13 isKeyFrame = true presentationTimeUs = 120000 sample: trackIndex = 0 dataHashCode = 158718784 + size = 13 isKeyFrame = true presentationTimeUs = 120750 sample: trackIndex = 0 dataHashCode = -1587553019 + size = 13 isKeyFrame = true presentationTimeUs = 121500 sample: trackIndex = 0 dataHashCode = 1266916929 + size = 13 isKeyFrame = true presentationTimeUs = 122250 sample: trackIndex = 0 dataHashCode = 1947792537 + size = 13 isKeyFrame = true presentationTimeUs = 123000 sample: trackIndex = 0 dataHashCode = 2051622372 + size = 13 isKeyFrame = true presentationTimeUs = 123750 sample: trackIndex = 0 dataHashCode = 1648973196 + size = 13 isKeyFrame = true presentationTimeUs = 124500 sample: trackIndex = 0 dataHashCode = -1119069213 + size = 13 isKeyFrame = true presentationTimeUs = 125250 sample: trackIndex = 0 dataHashCode = -1162670307 + size = 13 isKeyFrame = true presentationTimeUs = 126000 sample: trackIndex = 0 dataHashCode = 505180178 + size = 13 isKeyFrame = true presentationTimeUs = 126750 sample: trackIndex = 0 dataHashCode = -1707111799 + size = 13 isKeyFrame = true presentationTimeUs = 127500 sample: trackIndex = 0 dataHashCode = 549350779 + size = 13 isKeyFrame = true presentationTimeUs = 128250 sample: trackIndex = 0 dataHashCode = -895461091 + size = 13 isKeyFrame = true presentationTimeUs = 129000 sample: trackIndex = 0 dataHashCode = 1834306839 + size = 13 isKeyFrame = true presentationTimeUs = 129750 sample: trackIndex = 0 dataHashCode = -646169807 + size = 13 isKeyFrame = true presentationTimeUs = 130500 sample: trackIndex = 0 dataHashCode = 123454915 + size = 13 isKeyFrame = true presentationTimeUs = 131250 sample: trackIndex = 0 dataHashCode = 2074179659 + size = 13 isKeyFrame = true presentationTimeUs = 132000 sample: trackIndex = 0 dataHashCode = 488070546 + size = 13 isKeyFrame = true presentationTimeUs = 132750 sample: trackIndex = 0 dataHashCode = -1379245827 + size = 13 isKeyFrame = true presentationTimeUs = 133500 sample: trackIndex = 0 dataHashCode = 922846867 + size = 13 isKeyFrame = true presentationTimeUs = 134250 sample: trackIndex = 0 dataHashCode = 1163092079 + size = 13 isKeyFrame = true presentationTimeUs = 135000 sample: trackIndex = 0 dataHashCode = -817674907 + size = 13 isKeyFrame = true presentationTimeUs = 135750 sample: trackIndex = 0 dataHashCode = -765143209 + size = 13 isKeyFrame = true presentationTimeUs = 136500 sample: trackIndex = 0 dataHashCode = 1337234415 + size = 13 isKeyFrame = true presentationTimeUs = 137250 sample: trackIndex = 0 dataHashCode = 152696122 + size = 13 isKeyFrame = true presentationTimeUs = 138000 sample: trackIndex = 0 dataHashCode = -1037369189 + size = 13 isKeyFrame = true presentationTimeUs = 138750 sample: trackIndex = 0 dataHashCode = 93852784 + size = 13 isKeyFrame = true presentationTimeUs = 139500 sample: trackIndex = 0 dataHashCode = -1512860804 + size = 13 isKeyFrame = true presentationTimeUs = 140250 sample: trackIndex = 0 dataHashCode = -1571797975 + size = 13 isKeyFrame = true presentationTimeUs = 141000 sample: trackIndex = 0 dataHashCode = -1390710594 + size = 13 isKeyFrame = true presentationTimeUs = 141750 sample: trackIndex = 0 dataHashCode = 775548254 + size = 13 isKeyFrame = true presentationTimeUs = 142500 sample: trackIndex = 0 dataHashCode = 329825934 + size = 13 isKeyFrame = true presentationTimeUs = 143250 sample: trackIndex = 0 dataHashCode = 449672203 + size = 13 isKeyFrame = true presentationTimeUs = 144000 sample: trackIndex = 0 dataHashCode = 135215283 + size = 13 isKeyFrame = true presentationTimeUs = 144750 sample: trackIndex = 0 dataHashCode = -627202145 + size = 13 isKeyFrame = true presentationTimeUs = 145500 sample: trackIndex = 0 dataHashCode = 565795710 + size = 13 isKeyFrame = true presentationTimeUs = 146250 sample: trackIndex = 0 dataHashCode = -853390981 + size = 13 isKeyFrame = true presentationTimeUs = 147000 sample: trackIndex = 0 dataHashCode = 1904980829 + size = 13 isKeyFrame = true presentationTimeUs = 147750 sample: trackIndex = 0 dataHashCode = 1772857005 + size = 13 isKeyFrame = true presentationTimeUs = 148500 sample: trackIndex = 0 dataHashCode = -1159621303 + size = 13 isKeyFrame = true presentationTimeUs = 149250 sample: trackIndex = 0 dataHashCode = 712585139 + size = 13 isKeyFrame = true presentationTimeUs = 150000 sample: trackIndex = 0 dataHashCode = 7470296 + size = 13 isKeyFrame = true presentationTimeUs = 150750 sample: trackIndex = 0 dataHashCode = 1154659763 + size = 13 isKeyFrame = true presentationTimeUs = 151500 sample: trackIndex = 0 dataHashCode = 512209179 + size = 13 isKeyFrame = true presentationTimeUs = 152250 sample: trackIndex = 0 dataHashCode = 2026712081 + size = 13 isKeyFrame = true presentationTimeUs = 153000 sample: trackIndex = 0 dataHashCode = -1625715216 + size = 13 isKeyFrame = true presentationTimeUs = 153750 sample: trackIndex = 0 dataHashCode = -1299058326 + size = 13 isKeyFrame = true presentationTimeUs = 154500 sample: trackIndex = 0 dataHashCode = -813560096 + size = 13 isKeyFrame = true presentationTimeUs = 155250 sample: trackIndex = 0 dataHashCode = 1311045251 + size = 13 isKeyFrame = true presentationTimeUs = 156000 sample: trackIndex = 0 dataHashCode = 1388107407 + size = 13 isKeyFrame = true presentationTimeUs = 156750 sample: trackIndex = 0 dataHashCode = 1113099440 + size = 13 isKeyFrame = true presentationTimeUs = 157500 sample: trackIndex = 0 dataHashCode = -339743582 + size = 13 isKeyFrame = true presentationTimeUs = 158250 sample: trackIndex = 0 dataHashCode = -1055895345 + size = 13 isKeyFrame = true presentationTimeUs = 159000 sample: trackIndex = 0 dataHashCode = 1869841923 + size = 13 isKeyFrame = true presentationTimeUs = 159750 sample: trackIndex = 0 dataHashCode = 229443301 + size = 13 isKeyFrame = true presentationTimeUs = 160500 sample: trackIndex = 0 dataHashCode = 1526951012 + size = 13 isKeyFrame = true presentationTimeUs = 161250 sample: trackIndex = 0 dataHashCode = -1517436626 + size = 13 isKeyFrame = true presentationTimeUs = 162000 sample: trackIndex = 0 dataHashCode = -1403405700 + size = 13 isKeyFrame = true presentationTimeUs = 162750 released = true diff --git a/testdata/src/test/assets/transformerdumps/mkv/sample.mkv.dump b/testdata/src/test/assets/transformerdumps/mkv/sample.mkv.dump index 00d39b034e..095c54577e 100644 --- a/testdata/src/test/assets/transformerdumps/mkv/sample.mkv.dump +++ b/testdata/src/test/assets/transformerdumps/mkv/sample.mkv.dump @@ -13,151 +13,181 @@ format 0: sample: trackIndex = 0 dataHashCode = -252482306 + size = 36477 isKeyFrame = true presentationTimeUs = 67000 sample: trackIndex = 0 dataHashCode = 67864034 + size = 5341 isKeyFrame = false presentationTimeUs = 134000 sample: trackIndex = 0 dataHashCode = 897273234 + size = 596 isKeyFrame = false presentationTimeUs = 100000 sample: trackIndex = 0 dataHashCode = -1549870586 + size = 7704 isKeyFrame = false presentationTimeUs = 267000 sample: trackIndex = 0 dataHashCode = 672384813 + size = 989 isKeyFrame = false presentationTimeUs = 200000 sample: trackIndex = 0 dataHashCode = -988996493 + size = 721 isKeyFrame = false presentationTimeUs = 167000 sample: trackIndex = 0 dataHashCode = 1711151377 + size = 519 isKeyFrame = false presentationTimeUs = 234000 sample: trackIndex = 0 dataHashCode = -506806036 + size = 6160 isKeyFrame = false presentationTimeUs = 400000 sample: trackIndex = 0 dataHashCode = 1902167649 + size = 953 isKeyFrame = false presentationTimeUs = 334000 sample: trackIndex = 0 dataHashCode = 2054873212 + size = 620 isKeyFrame = false presentationTimeUs = 300000 sample: trackIndex = 0 dataHashCode = 1556608231 + size = 405 isKeyFrame = false presentationTimeUs = 367000 sample: trackIndex = 0 dataHashCode = -1648978019 + size = 4852 isKeyFrame = false presentationTimeUs = 500000 sample: trackIndex = 0 dataHashCode = -484808327 + size = 547 isKeyFrame = false presentationTimeUs = 467000 sample: trackIndex = 0 dataHashCode = -20706048 + size = 570 isKeyFrame = false presentationTimeUs = 434000 sample: trackIndex = 0 dataHashCode = 2085064574 + size = 5525 isKeyFrame = false presentationTimeUs = 634000 sample: trackIndex = 0 dataHashCode = -637074022 + size = 1082 isKeyFrame = false presentationTimeUs = 567000 sample: trackIndex = 0 dataHashCode = -1824027029 + size = 807 isKeyFrame = false presentationTimeUs = 534000 sample: trackIndex = 0 dataHashCode = -1701945306 + size = 744 isKeyFrame = false presentationTimeUs = 600000 sample: trackIndex = 0 dataHashCode = -952425536 + size = 4732 isKeyFrame = false presentationTimeUs = 767000 sample: trackIndex = 0 dataHashCode = -1978031576 + size = 1004 isKeyFrame = false presentationTimeUs = 700000 sample: trackIndex = 0 dataHashCode = -2128215508 + size = 794 isKeyFrame = false presentationTimeUs = 667000 sample: trackIndex = 0 dataHashCode = -259850011 + size = 645 isKeyFrame = false presentationTimeUs = 734000 sample: trackIndex = 0 dataHashCode = 1920983928 + size = 2684 isKeyFrame = false presentationTimeUs = 900000 sample: trackIndex = 0 dataHashCode = 1100642337 + size = 787 isKeyFrame = false presentationTimeUs = 834000 sample: trackIndex = 0 dataHashCode = 1544917830 + size = 649 isKeyFrame = false presentationTimeUs = 800000 sample: trackIndex = 0 dataHashCode = -116205995 + size = 509 isKeyFrame = false presentationTimeUs = 867000 sample: trackIndex = 0 dataHashCode = 696343585 + size = 1226 isKeyFrame = false presentationTimeUs = 1034000 sample: trackIndex = 0 dataHashCode = -644371190 + size = 898 isKeyFrame = false presentationTimeUs = 967000 sample: trackIndex = 0 dataHashCode = -1606273467 + size = 476 isKeyFrame = false presentationTimeUs = 934000 sample: trackIndex = 0 dataHashCode = -571265861 + size = 486 isKeyFrame = false presentationTimeUs = 1000000 released = true diff --git a/testdata/src/test/assets/transformerdumps/mkv/sample_with_srt.mkv.dump b/testdata/src/test/assets/transformerdumps/mkv/sample_with_srt.mkv.dump index 05a19cd924..bf39e2d187 100644 --- a/testdata/src/test/assets/transformerdumps/mkv/sample_with_srt.mkv.dump +++ b/testdata/src/test/assets/transformerdumps/mkv/sample_with_srt.mkv.dump @@ -13,151 +13,181 @@ format 0: sample: trackIndex = 0 dataHashCode = -252482306 + size = 36477 isKeyFrame = true presentationTimeUs = 0 sample: trackIndex = 0 dataHashCode = 67864034 + size = 5341 isKeyFrame = false presentationTimeUs = 67000 sample: trackIndex = 0 dataHashCode = 897273234 + size = 596 isKeyFrame = false presentationTimeUs = 33000 sample: trackIndex = 0 dataHashCode = -1549870586 + size = 7704 isKeyFrame = false presentationTimeUs = 200000 sample: trackIndex = 0 dataHashCode = 672384813 + size = 989 isKeyFrame = false presentationTimeUs = 133000 sample: trackIndex = 0 dataHashCode = -988996493 + size = 721 isKeyFrame = false presentationTimeUs = 100000 sample: trackIndex = 0 dataHashCode = 1711151377 + size = 519 isKeyFrame = false presentationTimeUs = 167000 sample: trackIndex = 0 dataHashCode = -506806036 + size = 6160 isKeyFrame = false presentationTimeUs = 333000 sample: trackIndex = 0 dataHashCode = 1902167649 + size = 953 isKeyFrame = false presentationTimeUs = 267000 sample: trackIndex = 0 dataHashCode = 2054873212 + size = 620 isKeyFrame = false presentationTimeUs = 233000 sample: trackIndex = 0 dataHashCode = 1556608231 + size = 405 isKeyFrame = false presentationTimeUs = 300000 sample: trackIndex = 0 dataHashCode = -1648978019 + size = 4852 isKeyFrame = false presentationTimeUs = 433000 sample: trackIndex = 0 dataHashCode = -484808327 + size = 547 isKeyFrame = false presentationTimeUs = 400000 sample: trackIndex = 0 dataHashCode = -20706048 + size = 570 isKeyFrame = false presentationTimeUs = 367000 sample: trackIndex = 0 dataHashCode = 2085064574 + size = 5525 isKeyFrame = false presentationTimeUs = 567000 sample: trackIndex = 0 dataHashCode = -637074022 + size = 1082 isKeyFrame = false presentationTimeUs = 500000 sample: trackIndex = 0 dataHashCode = -1824027029 + size = 807 isKeyFrame = false presentationTimeUs = 467000 sample: trackIndex = 0 dataHashCode = -1701945306 + size = 744 isKeyFrame = false presentationTimeUs = 533000 sample: trackIndex = 0 dataHashCode = -952425536 + size = 4732 isKeyFrame = false presentationTimeUs = 700000 sample: trackIndex = 0 dataHashCode = -1978031576 + size = 1004 isKeyFrame = false presentationTimeUs = 633000 sample: trackIndex = 0 dataHashCode = -2128215508 + size = 794 isKeyFrame = false presentationTimeUs = 600000 sample: trackIndex = 0 dataHashCode = -259850011 + size = 645 isKeyFrame = false presentationTimeUs = 667000 sample: trackIndex = 0 dataHashCode = 1920983928 + size = 2684 isKeyFrame = false presentationTimeUs = 833000 sample: trackIndex = 0 dataHashCode = 1100642337 + size = 787 isKeyFrame = false presentationTimeUs = 767000 sample: trackIndex = 0 dataHashCode = 1544917830 + size = 649 isKeyFrame = false presentationTimeUs = 733000 sample: trackIndex = 0 dataHashCode = -116205995 + size = 509 isKeyFrame = false presentationTimeUs = 800000 sample: trackIndex = 0 dataHashCode = 696343585 + size = 1226 isKeyFrame = false presentationTimeUs = 967000 sample: trackIndex = 0 dataHashCode = -644371190 + size = 898 isKeyFrame = false presentationTimeUs = 900000 sample: trackIndex = 0 dataHashCode = -1606273467 + size = 476 isKeyFrame = false presentationTimeUs = 867000 sample: trackIndex = 0 dataHashCode = -571265861 + size = 486 isKeyFrame = false presentationTimeUs = 933000 released = true diff --git a/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.dump b/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.dump index 3d74318819..dd820ba6ab 100644 --- a/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.dump +++ b/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.dump @@ -18,376 +18,451 @@ format 1: sample: trackIndex = 1 dataHashCode = -770308242 + size = 36692 isKeyFrame = true presentationTimeUs = 0 sample: trackIndex = 1 dataHashCode = -732087136 + size = 5312 isKeyFrame = false presentationTimeUs = 66733 sample: trackIndex = 1 dataHashCode = 468156717 + size = 599 isKeyFrame = false presentationTimeUs = 33366 sample: trackIndex = 1 dataHashCode = 1150349584 + size = 7735 isKeyFrame = false presentationTimeUs = 200200 sample: trackIndex = 1 dataHashCode = 1443582006 + size = 987 isKeyFrame = false presentationTimeUs = 133466 sample: trackIndex = 1 dataHashCode = -310585145 + size = 673 isKeyFrame = false presentationTimeUs = 100100 sample: trackIndex = 1 dataHashCode = 807460688 + size = 523 isKeyFrame = false presentationTimeUs = 166833 sample: trackIndex = 1 dataHashCode = 1936487090 + size = 6061 isKeyFrame = false presentationTimeUs = 333666 sample: trackIndex = 1 dataHashCode = -32297181 + size = 992 isKeyFrame = false presentationTimeUs = 266933 sample: trackIndex = 1 dataHashCode = 1529616406 + size = 623 isKeyFrame = false presentationTimeUs = 233566 sample: trackIndex = 1 dataHashCode = 1949198785 + size = 421 isKeyFrame = false presentationTimeUs = 300300 sample: trackIndex = 1 dataHashCode = -147880287 + size = 4899 isKeyFrame = false presentationTimeUs = 433766 sample: trackIndex = 1 dataHashCode = 1369083472 + size = 568 isKeyFrame = false presentationTimeUs = 400400 sample: trackIndex = 1 dataHashCode = 965782073 + size = 620 isKeyFrame = false presentationTimeUs = 367033 sample: trackIndex = 1 dataHashCode = -261176150 + size = 5450 isKeyFrame = false presentationTimeUs = 567233 sample: trackIndex = 0 dataHashCode = 1205768497 + size = 23 isKeyFrame = true presentationTimeUs = 0 sample: trackIndex = 0 dataHashCode = 837571078 + size = 6 isKeyFrame = true presentationTimeUs = 249 sample: trackIndex = 0 dataHashCode = -1991633045 + size = 148 isKeyFrame = true presentationTimeUs = 317 sample: trackIndex = 0 dataHashCode = -822987359 + size = 189 isKeyFrame = true presentationTimeUs = 1995 sample: trackIndex = 0 dataHashCode = -1141508176 + size = 205 isKeyFrame = true presentationTimeUs = 4126 sample: trackIndex = 0 dataHashCode = -226971245 + size = 210 isKeyFrame = true presentationTimeUs = 6438 sample: trackIndex = 0 dataHashCode = -2099636855 + size = 210 isKeyFrame = true presentationTimeUs = 8818 sample: trackIndex = 0 dataHashCode = 1541550559 + size = 207 isKeyFrame = true presentationTimeUs = 11198 sample: trackIndex = 0 dataHashCode = 411148001 + size = 225 isKeyFrame = true presentationTimeUs = 13533 sample: trackIndex = 0 dataHashCode = -897603973 + size = 215 isKeyFrame = true presentationTimeUs = 16072 sample: trackIndex = 0 dataHashCode = 1478106136 + size = 211 isKeyFrame = true presentationTimeUs = 18498 sample: trackIndex = 0 dataHashCode = -1380417145 + size = 216 isKeyFrame = true presentationTimeUs = 20878 sample: trackIndex = 0 dataHashCode = 780903644 + size = 229 isKeyFrame = true presentationTimeUs = 23326 sample: trackIndex = 0 dataHashCode = 586204432 + size = 232 isKeyFrame = true presentationTimeUs = 25911 sample: trackIndex = 0 dataHashCode = -2038771492 + size = 235 isKeyFrame = true presentationTimeUs = 28541 sample: trackIndex = 0 dataHashCode = -2065161304 + size = 231 isKeyFrame = true presentationTimeUs = 31194 sample: trackIndex = 0 dataHashCode = 468662933 + size = 226 isKeyFrame = true presentationTimeUs = 33801 sample: trackIndex = 0 dataHashCode = -358398546 + size = 216 isKeyFrame = true presentationTimeUs = 36363 sample: trackIndex = 0 dataHashCode = 1767325983 + size = 229 isKeyFrame = true presentationTimeUs = 38811 sample: trackIndex = 0 dataHashCode = 1093095458 + size = 219 isKeyFrame = true presentationTimeUs = 41396 sample: trackIndex = 0 dataHashCode = 1687543702 + size = 241 isKeyFrame = true presentationTimeUs = 43867 sample: trackIndex = 0 dataHashCode = 1675188486 + size = 228 isKeyFrame = true presentationTimeUs = 46588 sample: trackIndex = 0 dataHashCode = 888567545 + size = 238 isKeyFrame = true presentationTimeUs = 49173 sample: trackIndex = 0 dataHashCode = -439631803 + size = 234 isKeyFrame = true presentationTimeUs = 51871 sample: trackIndex = 0 dataHashCode = 1606694497 + size = 231 isKeyFrame = true presentationTimeUs = 54524 sample: trackIndex = 0 dataHashCode = 1747388653 + size = 217 isKeyFrame = true presentationTimeUs = 57131 sample: trackIndex = 0 dataHashCode = -734560004 + size = 239 isKeyFrame = true presentationTimeUs = 59579 sample: trackIndex = 0 dataHashCode = -975079040 + size = 243 isKeyFrame = true presentationTimeUs = 62277 sample: trackIndex = 0 dataHashCode = -1403504710 + size = 231 isKeyFrame = true presentationTimeUs = 65020 sample: trackIndex = 0 dataHashCode = 379512981 + size = 230 isKeyFrame = true presentationTimeUs = 67627 sample: trackIndex = 1 dataHashCode = -1830836678 + size = 1051 isKeyFrame = false presentationTimeUs = 500500 sample: trackIndex = 1 dataHashCode = 1767407540 + size = 874 isKeyFrame = false presentationTimeUs = 467133 sample: trackIndex = 1 dataHashCode = 918440283 + size = 781 isKeyFrame = false presentationTimeUs = 533866 sample: trackIndex = 1 dataHashCode = -1408463661 + size = 4725 isKeyFrame = false presentationTimeUs = 700700 sample: trackIndex = 0 dataHashCode = -997198863 + size = 238 isKeyFrame = true presentationTimeUs = 70234 sample: trackIndex = 0 dataHashCode = 1394492825 + size = 225 isKeyFrame = true presentationTimeUs = 72932 sample: trackIndex = 0 dataHashCode = -885232755 + size = 232 isKeyFrame = true presentationTimeUs = 75471 sample: trackIndex = 0 dataHashCode = 260871367 + size = 243 isKeyFrame = true presentationTimeUs = 78101 sample: trackIndex = 0 dataHashCode = -1505318960 + size = 232 isKeyFrame = true presentationTimeUs = 80844 sample: trackIndex = 0 dataHashCode = -390625371 + size = 237 isKeyFrame = true presentationTimeUs = 83474 sample: trackIndex = 0 dataHashCode = 1067950751 + size = 228 isKeyFrame = true presentationTimeUs = 86149 sample: trackIndex = 0 dataHashCode = -1179436278 + size = 235 isKeyFrame = true presentationTimeUs = 88734 sample: trackIndex = 0 dataHashCode = 1906607774 + size = 264 isKeyFrame = true presentationTimeUs = 91387 sample: trackIndex = 0 dataHashCode = -800475828 + size = 257 isKeyFrame = true presentationTimeUs = 94380 sample: trackIndex = 0 dataHashCode = 1718972977 + size = 227 isKeyFrame = true presentationTimeUs = 97282 sample: trackIndex = 0 dataHashCode = -1120448741 + size = 227 isKeyFrame = true presentationTimeUs = 99844 sample: trackIndex = 0 dataHashCode = -1718323210 + size = 235 isKeyFrame = true presentationTimeUs = 102406 sample: trackIndex = 0 dataHashCode = -422416 + size = 229 isKeyFrame = true presentationTimeUs = 105059 sample: trackIndex = 0 dataHashCode = 833757830 + size = 6 isKeyFrame = true presentationTimeUs = 107644 sample: trackIndex = 1 dataHashCode = 1569455924 + size = 1022 isKeyFrame = false presentationTimeUs = 633966 sample: trackIndex = 1 dataHashCode = -1723778407 + size = 790 isKeyFrame = false presentationTimeUs = 600600 sample: trackIndex = 1 dataHashCode = 1578275472 + size = 610 isKeyFrame = false presentationTimeUs = 667333 sample: trackIndex = 1 dataHashCode = 1989768395 + size = 2751 isKeyFrame = false presentationTimeUs = 834166 sample: trackIndex = 1 dataHashCode = -1215674502 + size = 745 isKeyFrame = false presentationTimeUs = 767433 sample: trackIndex = 1 dataHashCode = -814473606 + size = 621 isKeyFrame = false presentationTimeUs = 734066 sample: trackIndex = 1 dataHashCode = 498370894 + size = 505 isKeyFrame = false presentationTimeUs = 800800 sample: trackIndex = 1 dataHashCode = -1051506468 + size = 1268 isKeyFrame = false presentationTimeUs = 967633 sample: trackIndex = 1 dataHashCode = -1025604144 + size = 880 isKeyFrame = false presentationTimeUs = 900900 sample: trackIndex = 1 dataHashCode = -913586520 + size = 530 isKeyFrame = false presentationTimeUs = 867533 sample: trackIndex = 1 dataHashCode = 1340459242 + size = 568 isKeyFrame = false presentationTimeUs = 934266 released = true diff --git a/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.noaudio.dump b/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.noaudio.dump index d4484cbfb4..f18acde209 100644 --- a/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.noaudio.dump +++ b/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.noaudio.dump @@ -13,151 +13,181 @@ format 0: sample: trackIndex = 0 dataHashCode = -770308242 + size = 36692 isKeyFrame = true presentationTimeUs = 0 sample: trackIndex = 0 dataHashCode = -732087136 + size = 5312 isKeyFrame = false presentationTimeUs = 66733 sample: trackIndex = 0 dataHashCode = 468156717 + size = 599 isKeyFrame = false presentationTimeUs = 33366 sample: trackIndex = 0 dataHashCode = 1150349584 + size = 7735 isKeyFrame = false presentationTimeUs = 200200 sample: trackIndex = 0 dataHashCode = 1443582006 + size = 987 isKeyFrame = false presentationTimeUs = 133466 sample: trackIndex = 0 dataHashCode = -310585145 + size = 673 isKeyFrame = false presentationTimeUs = 100100 sample: trackIndex = 0 dataHashCode = 807460688 + size = 523 isKeyFrame = false presentationTimeUs = 166833 sample: trackIndex = 0 dataHashCode = 1936487090 + size = 6061 isKeyFrame = false presentationTimeUs = 333666 sample: trackIndex = 0 dataHashCode = -32297181 + size = 992 isKeyFrame = false presentationTimeUs = 266933 sample: trackIndex = 0 dataHashCode = 1529616406 + size = 623 isKeyFrame = false presentationTimeUs = 233566 sample: trackIndex = 0 dataHashCode = 1949198785 + size = 421 isKeyFrame = false presentationTimeUs = 300300 sample: trackIndex = 0 dataHashCode = -147880287 + size = 4899 isKeyFrame = false presentationTimeUs = 433766 sample: trackIndex = 0 dataHashCode = 1369083472 + size = 568 isKeyFrame = false presentationTimeUs = 400400 sample: trackIndex = 0 dataHashCode = 965782073 + size = 620 isKeyFrame = false presentationTimeUs = 367033 sample: trackIndex = 0 dataHashCode = -261176150 + size = 5450 isKeyFrame = false presentationTimeUs = 567233 sample: trackIndex = 0 dataHashCode = -1830836678 + size = 1051 isKeyFrame = false presentationTimeUs = 500500 sample: trackIndex = 0 dataHashCode = 1767407540 + size = 874 isKeyFrame = false presentationTimeUs = 467133 sample: trackIndex = 0 dataHashCode = 918440283 + size = 781 isKeyFrame = false presentationTimeUs = 533866 sample: trackIndex = 0 dataHashCode = -1408463661 + size = 4725 isKeyFrame = false presentationTimeUs = 700700 sample: trackIndex = 0 dataHashCode = 1569455924 + size = 1022 isKeyFrame = false presentationTimeUs = 633966 sample: trackIndex = 0 dataHashCode = -1723778407 + size = 790 isKeyFrame = false presentationTimeUs = 600600 sample: trackIndex = 0 dataHashCode = 1578275472 + size = 610 isKeyFrame = false presentationTimeUs = 667333 sample: trackIndex = 0 dataHashCode = 1989768395 + size = 2751 isKeyFrame = false presentationTimeUs = 834166 sample: trackIndex = 0 dataHashCode = -1215674502 + size = 745 isKeyFrame = false presentationTimeUs = 767433 sample: trackIndex = 0 dataHashCode = -814473606 + size = 621 isKeyFrame = false presentationTimeUs = 734066 sample: trackIndex = 0 dataHashCode = 498370894 + size = 505 isKeyFrame = false presentationTimeUs = 800800 sample: trackIndex = 0 dataHashCode = -1051506468 + size = 1268 isKeyFrame = false presentationTimeUs = 967633 sample: trackIndex = 0 dataHashCode = -1025604144 + size = 880 isKeyFrame = false presentationTimeUs = 900900 sample: trackIndex = 0 dataHashCode = -913586520 + size = 530 isKeyFrame = false presentationTimeUs = 867533 sample: trackIndex = 0 dataHashCode = 1340459242 + size = 568 isKeyFrame = false presentationTimeUs = 934266 released = true diff --git a/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.novideo.dump b/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.novideo.dump index 2e520ebb02..e94ff8bb7f 100644 --- a/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.novideo.dump +++ b/testdata/src/test/assets/transformerdumps/mp4/sample.mp4.novideo.dump @@ -7,226 +7,271 @@ format 0: sample: trackIndex = 0 dataHashCode = 1205768497 + size = 23 isKeyFrame = true presentationTimeUs = 0 sample: trackIndex = 0 dataHashCode = 837571078 + size = 6 isKeyFrame = true presentationTimeUs = 249 sample: trackIndex = 0 dataHashCode = -1991633045 + size = 148 isKeyFrame = true presentationTimeUs = 317 sample: trackIndex = 0 dataHashCode = -822987359 + size = 189 isKeyFrame = true presentationTimeUs = 1995 sample: trackIndex = 0 dataHashCode = -1141508176 + size = 205 isKeyFrame = true presentationTimeUs = 4126 sample: trackIndex = 0 dataHashCode = -226971245 + size = 210 isKeyFrame = true presentationTimeUs = 6438 sample: trackIndex = 0 dataHashCode = -2099636855 + size = 210 isKeyFrame = true presentationTimeUs = 8818 sample: trackIndex = 0 dataHashCode = 1541550559 + size = 207 isKeyFrame = true presentationTimeUs = 11198 sample: trackIndex = 0 dataHashCode = 411148001 + size = 225 isKeyFrame = true presentationTimeUs = 13533 sample: trackIndex = 0 dataHashCode = -897603973 + size = 215 isKeyFrame = true presentationTimeUs = 16072 sample: trackIndex = 0 dataHashCode = 1478106136 + size = 211 isKeyFrame = true presentationTimeUs = 18498 sample: trackIndex = 0 dataHashCode = -1380417145 + size = 216 isKeyFrame = true presentationTimeUs = 20878 sample: trackIndex = 0 dataHashCode = 780903644 + size = 229 isKeyFrame = true presentationTimeUs = 23326 sample: trackIndex = 0 dataHashCode = 586204432 + size = 232 isKeyFrame = true presentationTimeUs = 25911 sample: trackIndex = 0 dataHashCode = -2038771492 + size = 235 isKeyFrame = true presentationTimeUs = 28541 sample: trackIndex = 0 dataHashCode = -2065161304 + size = 231 isKeyFrame = true presentationTimeUs = 31194 sample: trackIndex = 0 dataHashCode = 468662933 + size = 226 isKeyFrame = true presentationTimeUs = 33801 sample: trackIndex = 0 dataHashCode = -358398546 + size = 216 isKeyFrame = true presentationTimeUs = 36363 sample: trackIndex = 0 dataHashCode = 1767325983 + size = 229 isKeyFrame = true presentationTimeUs = 38811 sample: trackIndex = 0 dataHashCode = 1093095458 + size = 219 isKeyFrame = true presentationTimeUs = 41396 sample: trackIndex = 0 dataHashCode = 1687543702 + size = 241 isKeyFrame = true presentationTimeUs = 43867 sample: trackIndex = 0 dataHashCode = 1675188486 + size = 228 isKeyFrame = true presentationTimeUs = 46588 sample: trackIndex = 0 dataHashCode = 888567545 + size = 238 isKeyFrame = true presentationTimeUs = 49173 sample: trackIndex = 0 dataHashCode = -439631803 + size = 234 isKeyFrame = true presentationTimeUs = 51871 sample: trackIndex = 0 dataHashCode = 1606694497 + size = 231 isKeyFrame = true presentationTimeUs = 54524 sample: trackIndex = 0 dataHashCode = 1747388653 + size = 217 isKeyFrame = true presentationTimeUs = 57131 sample: trackIndex = 0 dataHashCode = -734560004 + size = 239 isKeyFrame = true presentationTimeUs = 59579 sample: trackIndex = 0 dataHashCode = -975079040 + size = 243 isKeyFrame = true presentationTimeUs = 62277 sample: trackIndex = 0 dataHashCode = -1403504710 + size = 231 isKeyFrame = true presentationTimeUs = 65020 sample: trackIndex = 0 dataHashCode = 379512981 + size = 230 isKeyFrame = true presentationTimeUs = 67627 sample: trackIndex = 0 dataHashCode = -997198863 + size = 238 isKeyFrame = true presentationTimeUs = 70234 sample: trackIndex = 0 dataHashCode = 1394492825 + size = 225 isKeyFrame = true presentationTimeUs = 72932 sample: trackIndex = 0 dataHashCode = -885232755 + size = 232 isKeyFrame = true presentationTimeUs = 75471 sample: trackIndex = 0 dataHashCode = 260871367 + size = 243 isKeyFrame = true presentationTimeUs = 78101 sample: trackIndex = 0 dataHashCode = -1505318960 + size = 232 isKeyFrame = true presentationTimeUs = 80844 sample: trackIndex = 0 dataHashCode = -390625371 + size = 237 isKeyFrame = true presentationTimeUs = 83474 sample: trackIndex = 0 dataHashCode = 1067950751 + size = 228 isKeyFrame = true presentationTimeUs = 86149 sample: trackIndex = 0 dataHashCode = -1179436278 + size = 235 isKeyFrame = true presentationTimeUs = 88734 sample: trackIndex = 0 dataHashCode = 1906607774 + size = 264 isKeyFrame = true presentationTimeUs = 91387 sample: trackIndex = 0 dataHashCode = -800475828 + size = 257 isKeyFrame = true presentationTimeUs = 94380 sample: trackIndex = 0 dataHashCode = 1718972977 + size = 227 isKeyFrame = true presentationTimeUs = 97282 sample: trackIndex = 0 dataHashCode = -1120448741 + size = 227 isKeyFrame = true presentationTimeUs = 99844 sample: trackIndex = 0 dataHashCode = -1718323210 + size = 235 isKeyFrame = true presentationTimeUs = 102406 sample: trackIndex = 0 dataHashCode = -422416 + size = 229 isKeyFrame = true presentationTimeUs = 105059 sample: trackIndex = 0 dataHashCode = 833757830 + size = 6 isKeyFrame = true presentationTimeUs = 107644 released = true diff --git a/testdata/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump b/testdata/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump index 89f996e530..6115358157 100644 --- a/testdata/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump +++ b/testdata/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump @@ -19,206 +19,247 @@ format 1: sample: trackIndex = 1 dataHashCode = -549003117 + size = 5438 isKeyFrame = true presentationTimeUs = 0 sample: trackIndex = 1 dataHashCode = 593600631 + size = 117 isKeyFrame = false presentationTimeUs = 14000 sample: trackIndex = 1 dataHashCode = -961321612 + size = 139 isKeyFrame = false presentationTimeUs = 47333 sample: trackIndex = 1 dataHashCode = -386347143 + size = 141 isKeyFrame = false presentationTimeUs = 80667 sample: trackIndex = 1 dataHashCode = -1289764147 + size = 141 isKeyFrame = false presentationTimeUs = 114000 sample: trackIndex = 1 dataHashCode = 1337088875 + size = 161 isKeyFrame = false presentationTimeUs = 147333 sample: trackIndex = 1 dataHashCode = -322406979 + size = 118 isKeyFrame = false presentationTimeUs = 180667 sample: trackIndex = 1 dataHashCode = -1688033783 + size = 112 isKeyFrame = false presentationTimeUs = 228042 sample: trackIndex = 1 dataHashCode = -700344608 + size = 118 isKeyFrame = false presentationTimeUs = 244708 sample: trackIndex = 1 dataHashCode = -1441653629 + size = 1172 isKeyFrame = false presentationTimeUs = 334083 sample: trackIndex = 1 dataHashCode = 1201357091 + size = 208 isKeyFrame = false presentationTimeUs = 267416 sample: trackIndex = 1 dataHashCode = -668484307 + size = 111 isKeyFrame = false presentationTimeUs = 234083 sample: trackIndex = 1 dataHashCode = 653508165 + size = 137 isKeyFrame = false presentationTimeUs = 300750 sample: trackIndex = 1 dataHashCode = -816848987 + size = 1266 isKeyFrame = false presentationTimeUs = 467416 sample: trackIndex = 1 dataHashCode = 1842436292 + size = 182 isKeyFrame = false presentationTimeUs = 400750 sample: trackIndex = 1 dataHashCode = -559603233 + size = 99 isKeyFrame = false presentationTimeUs = 367416 sample: trackIndex = 1 dataHashCode = -666437886 + size = 117 isKeyFrame = false presentationTimeUs = 434083 sample: trackIndex = 1 dataHashCode = 182521759 + size = 1101 isKeyFrame = false presentationTimeUs = 600750 sample: trackIndex = 0 dataHashCode = -212376212 + size = 20 isKeyFrame = true presentationTimeUs = 0 sample: trackIndex = 0 dataHashCode = -833872563 + size = 1732 isKeyFrame = true presentationTimeUs = 416 sample: trackIndex = 0 dataHashCode = -135901925 + size = 380 isKeyFrame = true presentationTimeUs = 36499 sample: trackIndex = 0 dataHashCode = 250093960 + size = 751 isKeyFrame = true presentationTimeUs = 44415 sample: trackIndex = 0 dataHashCode = 1895536226 + size = 1045 isKeyFrame = true presentationTimeUs = 59998 sample: trackIndex = 0 dataHashCode = 1723596464 + size = 947 isKeyFrame = true presentationTimeUs = 81748 sample: trackIndex = 0 dataHashCode = -978803114 + size = 946 isKeyFrame = true presentationTimeUs = 101414 sample: trackIndex = 0 dataHashCode = 387377078 + size = 946 isKeyFrame = true presentationTimeUs = 121080 sample: trackIndex = 0 dataHashCode = -132658698 + size = 901 isKeyFrame = true presentationTimeUs = 140746 sample: trackIndex = 0 dataHashCode = 1495036471 + size = 899 isKeyFrame = true presentationTimeUs = 159496 sample: trackIndex = 0 dataHashCode = 304440590 + size = 878 isKeyFrame = true presentationTimeUs = 178162 sample: trackIndex = 1 dataHashCode = 2139021989 + size = 242 isKeyFrame = false presentationTimeUs = 534083 sample: trackIndex = 1 dataHashCode = 2013165108 + size = 116 isKeyFrame = false presentationTimeUs = 500750 sample: trackIndex = 1 dataHashCode = 405675195 + size = 126 isKeyFrame = false presentationTimeUs = 567416 sample: trackIndex = 1 dataHashCode = -1893277090 + size = 1193 isKeyFrame = false presentationTimeUs = 734083 sample: trackIndex = 0 dataHashCode = -752661703 + size = 228 isKeyFrame = true presentationTimeUs = 196412 sample: trackIndex = 1 dataHashCode = -1554795381 + size = 205 isKeyFrame = false presentationTimeUs = 667416 sample: trackIndex = 1 dataHashCode = 1197099206 + size = 117 isKeyFrame = false presentationTimeUs = 634083 sample: trackIndex = 1 dataHashCode = -674808173 + size = 106 isKeyFrame = false presentationTimeUs = 700750 sample: trackIndex = 1 dataHashCode = -775517313 + size = 1002 isKeyFrame = false presentationTimeUs = 867416 sample: trackIndex = 1 dataHashCode = -2045106113 + size = 201 isKeyFrame = false presentationTimeUs = 800750 sample: trackIndex = 1 dataHashCode = 305167697 + size = 131 isKeyFrame = false presentationTimeUs = 767416 sample: trackIndex = 1 dataHashCode = 554021920 + size = 130 isKeyFrame = false presentationTimeUs = 834083 released = true From 468e4aa0c4ac7e16d95a56a3c10480a37b273dd9 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 3 Nov 2021 18:06:31 +0000 Subject: [PATCH 046/497] Update Javadoc for 2.16.0 PiperOrigin-RevId: 407379522 --- docs/doc/reference/allclasses-index.html | 2524 ++++---- docs/doc/reference/allclasses.html | 85 +- docs/doc/reference/allpackages-index.html | 18 +- .../AbstractConcatenatedTimeline.html | 26 +- .../google/android/exoplayer2/BasePlayer.html | 591 +- .../android/exoplayer2/BaseRenderer.html | 37 +- .../google/android/exoplayer2/Bundleable.html | 2 +- .../C.AudioAllowedCapturePolicy.html | 1 + .../exoplayer2/C.AudioContentType.html | 1 + .../android/exoplayer2/C.AudioFlags.html | 1 + ...ry.html => C.AudioManagerOffloadMode.html} | 102 +- .../android/exoplayer2/C.AudioUsage.html | 1 + .../android/exoplayer2/C.CryptoType.html | 187 + .../android/exoplayer2/C.RoleFlags.html | 1 + .../android/exoplayer2/C.SelectionFlags.html | 1 + .../android/exoplayer2/C.SelectionReason.html | 186 + .../android/exoplayer2/C.StreamType.html | 2 +- .../android/exoplayer2/C.TrackType.html | 187 + ...ml => C.VideoChangeFrameRateStrategy.html} | 13 +- .../exoplayer2/C.VideoScalingMode.html | 3 +- .../google/android/exoplayer2/C.WakeMode.html | 1 + .../com/google/android/exoplayer2/C.html | 779 +-- .../android/exoplayer2/ControlDispatcher.html | 576 -- .../exoplayer2/DefaultControlDispatcher.html | 746 --- .../exoplayer2/DefaultLoadControl.html | 39 +- .../exoplayer2/DefaultRenderersFactory.html | 50 +- .../{device => }/DeviceInfo.PlaybackType.html | 42 +- .../exoplayer2/{device => }/DeviceInfo.html | 82 +- .../exoplayer2/ExoPlaybackException.html | 22 +- .../exoplayer2/ExoPlayer.AudioComponent.html | 232 +- .../android/exoplayer2/ExoPlayer.Builder.html | 574 +- .../exoplayer2/ExoPlayer.DeviceComponent.html | 163 +- .../ExoPlayer.MetadataComponent.html | 295 - .../exoplayer2/ExoPlayer.TextComponent.html | 71 +- .../exoplayer2/ExoPlayer.VideoComponent.html | 337 +- .../google/android/exoplayer2/ExoPlayer.html | 880 ++- .../exoplayer2/ExoPlayerLibraryInfo.html | 62 +- .../android/exoplayer2/Format.Builder.html | 41 +- .../com/google/android/exoplayer2/Format.html | 166 +- .../android/exoplayer2/ForwardingPlayer.html | 1046 +-- ...> MediaItem.AdsConfiguration.Builder.html} | 168 +- .../MediaItem.AdsConfiguration.html | 56 +- .../android/exoplayer2/MediaItem.Builder.html | 597 +- ...diaItem.ClippingConfiguration.Builder.html | 434 ++ .../MediaItem.ClippingConfiguration.html | 521 ++ .../MediaItem.ClippingProperties.html | 227 +- .../MediaItem.DrmConfiguration.Builder.html | 503 ++ .../MediaItem.DrmConfiguration.html | 144 +- .../MediaItem.LiveConfiguration.Builder.html | 414 ++ .../MediaItem.LiveConfiguration.html | 68 +- .../MediaItem.LocalConfiguration.html | 490 ++ .../MediaItem.PlaybackProperties.html | 267 +- .../exoplayer2/MediaItem.Subtitle.html | 317 +- ...diaItem.SubtitleConfiguration.Builder.html | 423 ++ .../MediaItem.SubtitleConfiguration.html | 471 ++ .../google/android/exoplayer2/MediaItem.html | 103 +- .../exoplayer2/MediaMetadata.Builder.html | 106 +- .../exoplayer2/MediaMetadata.FolderType.html | 1 + .../exoplayer2/MediaMetadata.PictureType.html | 1 + .../android/exoplayer2/MediaMetadata.html | 8 +- .../android/exoplayer2/NoSampleRenderer.html | 13 +- .../PlaybackException.ErrorCode.html | 1 + .../android/exoplayer2/PlaybackException.html | 30 +- .../exoplayer2/PlaybackParameters.html | 9 +- .../android/exoplayer2/Player.Command.html | 3 +- .../exoplayer2/Player.Commands.Builder.html | 36 +- .../android/exoplayer2/Player.Commands.html | 10 +- .../Player.DiscontinuityReason.html | 1 + .../android/exoplayer2/Player.Event.html | 1 + .../exoplayer2/Player.EventListener.html | 188 +- .../android/exoplayer2/Player.Events.html | 16 +- .../android/exoplayer2/Player.Listener.html | 194 +- .../Player.MediaItemTransitionReason.html | 1 + .../Player.PlayWhenReadyChangeReason.html | 1 + .../Player.PlaybackSuppressionReason.html | 1 + .../exoplayer2/Player.PositionInfo.html | 102 +- .../android/exoplayer2/Player.RepeatMode.html | 1 + .../android/exoplayer2/Player.State.html | 1 + .../Player.TimelineChangeReason.html | 1 + .../com/google/android/exoplayer2/Player.html | 1471 +++-- .../exoplayer2/PlayerMessage.Target.html | 3 +- .../android/exoplayer2/PlayerMessage.html | 72 +- .../exoplayer2/Renderer.MessageType.html | 186 + .../google/android/exoplayer2/Renderer.html | 140 +- .../exoplayer2/RendererCapabilities.html | 6 +- .../android/exoplayer2/RenderersFactory.html | 6 +- .../exoplayer2/SimpleExoPlayer.Builder.html | 660 +- .../android/exoplayer2/SimpleExoPlayer.html | 1522 +++-- .../Timeline.RemotableTimeline.html | 26 +- .../google/android/exoplayer2/Timeline.html | 137 +- .../exoplayer2/TracksInfo.TrackGroupInfo.html | 584 ++ .../google/android/exoplayer2/TracksInfo.html | 502 ++ .../analytics/AnalyticsCollector.html | 212 +- .../AnalyticsListener.EventTime.html | 6 +- .../analytics/AnalyticsListener.html | 220 +- .../DefaultPlaybackSessionManager.html | 14 +- .../analytics/PlaybackSessionManager.html | 10 +- .../analytics/PlaybackStatsListener.html | 30 +- .../android/exoplayer2/audio/AacUtil.html | 25 +- .../android/exoplayer2/audio/Ac3Util.html | 30 +- .../audio/AudioAttributes.Builder.html | 24 +- .../exoplayer2/audio/AudioAttributes.html | 16 +- .../exoplayer2/audio/AudioListener.html | 337 - .../exoplayer2/audio/AudioProcessor.html | 2 +- .../audio/DecoderAudioRenderer.html | 29 +- .../audio/MediaCodecAudioRenderer.html | 15 +- .../android/exoplayer2/audio/OpusUtil.html | 52 +- .../exoplayer2/audio/TeeAudioProcessor.html | 4 +- .../exoplayer2/audio/package-summary.html | 18 +- .../exoplayer2/audio/package-tree.html | 1 - .../exoplayer2/database/DatabaseProvider.html | 8 +- .../database/ExoDatabaseProvider.html | 176 +- .../database/StandaloneDatabaseProvider.html | 446 ++ .../exoplayer2/database/VersionTable.html | 4 +- .../exoplayer2/database/package-summary.html | 14 +- .../exoplayer2/database/package-tree.html | 6 +- .../android/exoplayer2/decoder/Buffer.html | 2 +- .../CryptoConfig.html} | 15 +- .../CryptoException.html} | 24 +- .../exoplayer2/decoder/CryptoInfo.html | 4 +- .../android/exoplayer2/decoder/Decoder.html | 2 +- .../decoder/DecoderInputBuffer.html | 24 +- ...er.html => DecoderOutputBuffer.Owner.html} | 16 +- ...utBuffer.html => DecoderOutputBuffer.html} | 20 +- .../exoplayer2/decoder/SimpleDecoder.html | 20 +- ...er.html => SimpleDecoderOutputBuffer.html} | 38 +- .../VideoDecoderOutputBuffer.html | 48 +- .../exoplayer2/decoder/package-summary.html | 42 +- .../exoplayer2/decoder/package-tree.html | 9 +- .../drm/DefaultDrmSessionManager.Builder.html | 8 +- .../drm/DefaultDrmSessionManager.html | 30 +- .../drm/DefaultDrmSessionManagerProvider.html | 4 +- .../drm/DrmSession.DrmSessionException.html | 12 +- .../android/exoplayer2/drm/DrmSession.html | 48 +- .../exoplayer2/drm/DrmSessionManager.html | 36 +- .../android/exoplayer2/drm/DrmUtil.html | 8 +- .../exoplayer2/drm/DummyExoMediaDrm.html | 80 +- .../exoplayer2/drm/ErrorStateDrmSession.html | 57 +- .../android/exoplayer2/drm/ExoMediaDrm.html | 73 +- ...Crypto.html => FrameworkCryptoConfig.html} | 32 +- .../exoplayer2/drm/FrameworkMediaDrm.html | 84 +- .../exoplayer2/drm/package-summary.html | 41 +- .../android/exoplayer2/drm/package-tree.html | 5 +- .../exoplayer2/ext/av1/Gav1Decoder.html | 50 +- .../ext/av1/Libgav1VideoRenderer.html | 36 +- .../exoplayer2/ext/cast/CastPlayer.html | 386 +- .../ext/cronet/CronetDataSource.Factory.html | 48 +- .../CronetDataSource.OpenException.html | 46 +- .../ext/cronet/CronetDataSourceFactory.html | 2 +- .../ext/cronet/CronetEngineWrapper.html | 4 +- .../exoplayer2/ext/cronet/CronetUtil.html | 39 +- .../ext/ffmpeg/FfmpegAudioRenderer.html | 22 +- .../exoplayer2/ext/flac/FlacDecoder.html | 30 +- .../ext/flac/LibflacAudioRenderer.html | 22 +- .../exoplayer2/ext/gvr/GvrAudioProcessor.html | 593 -- .../exoplayer2/ext/gvr/package-tree.html | 159 - .../ext/ima/ImaAdsLoader.Builder.html | 9 +- .../exoplayer2/ext/ima/ImaAdsLoader.html | 61 +- .../ext/leanback/LeanbackPlayerAdapter.html | 37 +- .../ext/media2/SessionPlayerConnector.html | 46 +- ...MediaSessionConnector.CaptionCallback.html | 2 +- ...MediaSessionConnector.CommandReceiver.html | 11 +- ...SessionConnector.CustomActionProvider.html | 11 +- ...sionConnector.MediaButtonEventHandler.html | 11 +- ...ediaSessionConnector.PlaybackPreparer.html | 2 +- .../MediaSessionConnector.QueueEditor.html | 2 +- .../MediaSessionConnector.QueueNavigator.html | 59 +- .../MediaSessionConnector.RatingCallback.html | 2 +- .../mediasession/MediaSessionConnector.html | 60 +- .../RepeatModeActionProvider.html | 15 +- .../ext/mediasession/TimelineQueueEditor.html | 15 +- .../mediasession/TimelineQueueNavigator.html | 80 +- .../ext/okhttp/OkHttpDataSource.Factory.html | 40 +- .../ext/okhttp/OkHttpDataSourceFactory.html | 2 +- .../ext/opus/LibopusAudioRenderer.html | 22 +- .../exoplayer2/ext/opus/OpusDecoder.html | 42 +- .../exoplayer2/ext/opus/OpusLibrary.html | 39 +- .../exoplayer2/ext/rtmp/RtmpDataSource.html | 4 +- .../ext/vp9/LibvpxVideoRenderer.html | 36 +- .../exoplayer2/ext/vp9/VpxDecoder.html | 62 +- .../exoplayer2/ext/vp9/VpxLibrary.html | 35 +- .../WorkManagerScheduler.SchedulerWorker.html | 2 +- .../extractor/ConstantBitrateSeekMap.html | 40 +- .../extractor/DefaultExtractorsFactory.html | 55 +- .../extractor/DummyExtractorOutput.html | 11 +- .../exoplayer2/extractor/Extractor.html | 2 +- .../exoplayer2/extractor/ExtractorOutput.html | 15 +- .../extractor/FlacMetadataReader.html | 2 +- .../extractor/TrueHdSampleRechunker.html | 365 ++ .../extractor/amr/AmrExtractor.Flags.html | 2 +- .../extractor/amr/AmrExtractor.html | 29 +- .../flac}/FlacConstants.html | 60 +- .../extractor/flac/package-summary.html | 6 + .../extractor/flac/package-tree.html | 1 + .../jpeg/StartOffsetExtractorOutput.html | 11 +- .../extractor/mp3/Mp3Extractor.Flags.html | 3 +- .../extractor/mp3/Mp3Extractor.html | 29 + .../exoplayer2/extractor/mp4/Track.html | 12 +- .../exoplayer2/extractor/package-summary.html | 14 +- .../exoplayer2/extractor/package-tree.html | 1 + .../extractor/ts/AdtsExtractor.Flags.html | 2 +- .../extractor/ts/AdtsExtractor.html | 29 +- .../exoplayer2/extractor/ts/TsExtractor.html | 42 +- .../extractor/wav/WavExtractor.html | 3 +- .../DefaultMediaCodecAdapterFactory.html | 411 ++ .../MediaCodecAdapter.Configuration.html | 239 +- .../mediacodec/MediaCodecAdapter.Factory.html | 2 +- .../mediacodec/MediaCodecAdapter.html | 71 +- .../mediacodec/MediaCodecRenderer.html | 189 +- .../SynchronousMediaCodecAdapter.html | 75 +- .../mediacodec/package-summary.html | 16 +- .../exoplayer2/mediacodec/package-tree.html | 1 + .../exoplayer2/metadata/Metadata.Entry.html | 2 +- .../metadata/MetadataInputBuffer.html | 2 +- .../exoplayer2/metadata/MetadataOutput.html | 8 - .../exoplayer2/metadata/MetadataRenderer.html | 6 +- .../android/exoplayer2/offline/Download.html | 10 +- .../exoplayer2/offline/DownloadManager.html | 3 +- .../exoplayer2/offline/DownloadRequest.html | 2 +- .../exoplayer2/offline/DownloadService.html | 134 +- .../android/exoplayer2/package-summary.html | 207 +- .../android/exoplayer2/package-tree.html | 64 +- .../robolectric/PlaybackOutput.html | 8 +- .../robolectric/TestPlayerRunHelper.html | 64 +- .../robolectric/package-summary.html | 4 +- ...ormScheduler.PlatformSchedulerService.html | 4 +- .../source/ClippingMediaPeriod.html | 25 +- ...tMediaSourceFactory.AdsLoaderProvider.html | 8 +- .../source/DefaultMediaSourceFactory.html | 102 +- .../exoplayer2/source/ForwardingTimeline.html | 26 +- .../exoplayer2/source/LoopingMediaSource.html | 4 +- ...askingMediaSource.PlaceholderTimeline.html | 2 +- .../exoplayer2/source/MediaLoadData.html | 26 +- .../exoplayer2/source/MediaSource.html | 8 +- ...iaSourceEventListener.EventDispatcher.html | 43 +- .../exoplayer2/source/MediaSourceFactory.html | 63 +- .../ProgressiveMediaSource.Factory.html | 25 +- .../source/SilenceMediaSource.Factory.html | 9 +- .../source/SinglePeriodTimeline.html | 4 +- .../SingleSampleMediaSource.Factory.html | 66 +- .../android/exoplayer2/source/TrackGroup.html | 81 +- .../exoplayer2/source/TrackGroupArray.html | 85 +- .../source/ads/AdPlaybackState.AdGroup.html | 17 +- .../source/ads/AdPlaybackState.html | 51 +- .../source/ads/SinglePeriodAdTimeline.html | 4 +- .../source/chunk/BaseMediaChunk.html | 1 + .../source/chunk/BaseMediaChunkOutput.html | 15 +- .../source/chunk/BundledChunkExtractor.html | 21 +- .../exoplayer2/source/chunk/Chunk.html | 11 +- .../source/chunk/ChunkExtractor.Factory.html | 8 +- .../ChunkExtractor.TrackOutputProvider.html | 11 +- .../source/chunk/ChunkSampleStream.html | 15 +- .../source/chunk/ContainerMediaChunk.html | 1 + .../exoplayer2/source/chunk/DataChunk.html | 1 + .../source/chunk/InitializationChunk.html | 1 + .../exoplayer2/source/chunk/MediaChunk.html | 1 + .../chunk/MediaParserChunkExtractor.html | 9 +- .../source/chunk/SingleSampleMediaChunk.html | 12 +- .../source/dash/DashChunkSource.Factory.html | 12 +- .../source/dash/DashMediaSource.Factory.html | 31 +- .../exoplayer2/source/dash/DashUtil.html | 8 +- .../dash/DefaultDashChunkSource.Factory.html | 16 +- .../source/dash/DefaultDashChunkSource.html | 21 +- .../source/dash/manifest/AdaptationSet.html | 20 +- .../dash/manifest/DashManifestParser.html | 46 +- .../source/dash/offline/DashDownloader.html | 2 +- .../exoplayer2/source/hls/HlsMediaPeriod.html | 9 +- .../source/hls/HlsMediaSource.Factory.html | 32 +- .../hls/HlsMediaSource.MetadataType.html | 3 +- .../source/hls/offline/HlsDownloader.html | 2 +- .../mediaparser/OutputConsumerAdapterV30.html | 15 +- .../exoplayer2/source/package-summary.html | 4 +- .../exoplayer2/source/package-tree.html | 4 +- .../source/rtsp/RtspMediaSource.Factory.html | 73 +- .../SsMediaSource.Factory.html | 25 +- .../manifest/SsManifest.StreamElement.html | 12 +- .../smoothstreaming/offline/SsDownloader.html | 2 +- .../testutil/Action.AddMediaItems.html | 18 +- .../testutil/Action.ClearMediaItems.html | 18 +- .../testutil/Action.ClearVideoSurface.html | 18 +- .../testutil/Action.ExecuteRunnable.html | 16 +- .../testutil/Action.MoveMediaItem.html | 18 +- .../testutil/Action.PlayUntilPosition.html | 38 +- .../exoplayer2/testutil/Action.Prepare.html | 16 +- .../testutil/Action.RemoveMediaItem.html | 18 +- .../testutil/Action.RemoveMediaItems.html | 18 +- .../exoplayer2/testutil/Action.Seek.html | 22 +- .../testutil/Action.SendMessages.html | 22 +- .../testutil/Action.SetAudioAttributes.html | 18 +- .../testutil/Action.SetMediaItems.html | 24 +- .../Action.SetMediaItemsResetPosition.html | 18 +- .../testutil/Action.SetPlayWhenReady.html | 16 +- .../Action.SetPlaybackParameters.html | 16 +- .../testutil/Action.SetRendererDisabled.html | 16 +- .../testutil/Action.SetRepeatMode.html | 26 +- .../Action.SetShuffleModeEnabled.html | 16 +- .../testutil/Action.SetShuffleOrder.html | 16 +- .../testutil/Action.SetVideoSurface.html | 18 +- .../exoplayer2/testutil/Action.Stop.html | 16 +- .../Action.ThrowPlaybackException.html | 16 +- .../testutil/Action.WaitForIsLoading.html | 30 +- .../testutil/Action.WaitForMessage.html | 30 +- .../Action.WaitForPendingPlayerCommands.html | 30 +- .../testutil/Action.WaitForPlayWhenReady.html | 32 +- .../testutil/Action.WaitForPlaybackState.html | 40 +- .../Action.WaitForPositionDiscontinuity.html | 32 +- .../Action.WaitForTimelineChanged.html | 40 +- .../android/exoplayer2/testutil/Action.html | 56 +- .../testutil/ActionSchedule.Builder.html | 88 +- .../ActionSchedule.PlayerRunnable.html | 6 +- .../testutil/ActionSchedule.PlayerTarget.html | 9 +- .../testutil/AdditionalFailureInfo.html | 4 +- .../testutil/AssetContentProvider.html | 535 ++ .../testutil/CapturingRenderersFactory.html | 4 +- .../DefaultRenderersFactoryAsserts.html | 8 +- .../exoplayer2/testutil/ExoHostedTest.html | 26 +- .../testutil/ExoPlayerTestRunner.Builder.html | 17 +- .../testutil/ExoPlayerTestRunner.html | 231 +- .../testutil/FakeAdaptiveMediaSource.html | 2 +- .../testutil/FakeAudioRenderer.html | 12 +- .../FakeCryptoConfig.html} | 78 +- .../testutil/FakeExoMediaDrm.Builder.html | 46 +- .../FakeExoMediaDrm.LicenseServer.html | 31 +- .../exoplayer2/testutil/FakeExoMediaDrm.html | 91 +- .../testutil/FakeExtractorOutput.html | 11 +- .../exoplayer2/testutil/FakeMediaChunk.html | 3 +- .../testutil/FakeMediaClockRenderer.html | 10 +- .../FakeMediaSource.InitialTimeline.html | 4 +- .../exoplayer2/testutil/FakeMediaSource.html | 49 +- .../testutil/FakeMediaSourceFactory.html | 570 ++ .../testutil/FakeMetadataEntry.html | 456 ++ .../exoplayer2/testutil/FakeRenderer.html | 111 +- .../exoplayer2/testutil/FakeTimeline.html | 26 +- .../testutil/FakeTrackSelection.html | 7 + .../testutil/FakeTrackSelector.html | 2 +- .../testutil/FakeVideoRenderer.html | 15 +- .../exoplayer2/testutil/HostActivity.html | 6 +- .../exoplayer2/testutil/NoUidTimeline.html | 4 +- .../exoplayer2/testutil/StubExoPlayer.html | 2360 ++----- .../exoplayer2/testutil/StubPlayer.html | 1958 ++++++ .../testutil/TestExoPlayerBuilder.html | 77 +- .../android/exoplayer2/testutil/TestUtil.html | 66 +- .../exoplayer2/testutil/TimelineAsserts.html | 34 +- .../exoplayer2/testutil/package-summary.html | 137 +- .../exoplayer2/testutil/package-tree.html | 12 + .../exoplayer2/text/Cue.AnchorType.html | 1 + .../android/exoplayer2/text/Cue.Builder.html | 78 +- .../android/exoplayer2/text/Cue.LineType.html | 1 + .../exoplayer2/text/Cue.TextSizeType.html | 1 + .../exoplayer2/text/Cue.VerticalType.html | 1 + .../google/android/exoplayer2/text/Cue.html | 78 +- .../CueDecoder.html} | 133 +- .../android/exoplayer2/text/CueEncoder.html | 312 + .../exoplayer2/text/ExoplayerCuesDecoder.html | 472 ++ .../exoplayer2/text/SubtitleDecoder.html | 2 +- .../text/SubtitleDecoderFactory.html | 1 + .../exoplayer2/text/SubtitleExtractor.html | 493 ++ .../exoplayer2/text/SubtitleInputBuffer.html | 2 +- .../exoplayer2/text/SubtitleOutputBuffer.html | 22 +- .../android/exoplayer2/text/TextOutput.html | 8 - .../android/exoplayer2/text/TextRenderer.html | 6 +- .../exoplayer2/text/package-summary.html | 24 + .../android/exoplayer2/text/package-tree.html | 6 +- .../AdaptiveTrackSelection.Factory.html | 115 +- .../AdaptiveTrackSelection.html | 67 +- .../trackselection/BaseTrackSelection.html | 15 +- .../DefaultTrackSelector.Parameters.html | 106 +- ...efaultTrackSelector.ParametersBuilder.html | 222 +- ...efaultTrackSelector.SelectionOverride.html | 92 +- .../trackselection/DefaultTrackSelector.html | 158 +- .../ExoTrackSelection.Definition.html | 12 +- .../trackselection/ExoTrackSelection.html | 7 + .../trackselection/FixedTrackSelection.html | 23 +- .../MappingTrackSelector.MappedTrackInfo.html | 14 +- .../trackselection/MappingTrackSelector.html | 2 +- .../trackselection/RandomTrackSelection.html | 7 + .../TrackSelection.Type.html} | 101 +- .../trackselection/TrackSelection.html | 33 +- .../TrackSelectionOverrides.Builder.html | 381 ++ ...ctionOverrides.TrackSelectionOverride.html | 488 ++ .../TrackSelectionOverrides.html | 484 ++ .../TrackSelectionParameters.Builder.html | 156 +- .../TrackSelectionParameters.html | 188 +- .../trackselection/TrackSelectionUtil.html | 21 +- .../trackselection/TrackSelector.html | 67 +- .../trackselection/TrackSelectorResult.html | 58 +- .../trackselection/package-summary.html | 43 +- .../trackselection/package-tree.html | 15 +- .../TranscodingTransformer.Builder.html | 620 ++ .../TranscodingTransformer.Listener.html} | 71 +- ...TranscodingTransformer.ProgressState.html} | 76 +- .../transformer/TranscodingTransformer.html | 616 ++ .../exoplayer2/transformer/Transformer.html | 14 +- .../transformer/package-summary.html | 24 + .../exoplayer2/transformer/package-tree.html | 4 + .../exoplayer2/ui/AspectRatioFrameLayout.html | 6 +- .../android/exoplayer2/ui/DefaultTimeBar.html | 4 +- .../ui/DownloadNotificationHelper.html | 47 +- .../exoplayer2/ui/PlayerControlView.html | 68 +- .../ui/PlayerNotificationManager.Builder.html | 1 + .../ui/PlayerNotificationManager.html | 74 +- .../android/exoplayer2/ui/PlayerView.html | 104 +- .../ui/StyledPlayerControlView.html | 74 +- .../exoplayer2/ui/StyledPlayerView.html | 108 +- .../android/exoplayer2/ui/SubtitleView.html | 36 +- .../exoplayer2/ui/TrackSelectionView.html | 6 +- .../android/exoplayer2/ui/package-tree.html | 2 +- ...etDataSource.AssetDataSourceException.html | 12 +- .../{cache => }/CachedRegionTracker.html | 126 +- ...DataSource.ContentDataSourceException.html | 12 +- .../exoplayer2/upstream/DataSink.Factory.html | 2 +- .../upstream/DataSource.Factory.html | 2 +- .../upstream/DataSourceException.html | 34 +- .../exoplayer2/upstream/DataSourceUtil.html | 331 + .../upstream/DefaultBandwidthMeter.html | 34 +- .../upstream/DefaultDataSource.Factory.html | 379 ++ .../upstream/DefaultDataSource.html | 22 +- .../upstream/DefaultDataSourceFactory.html | 25 +- .../DefaultHttpDataSource.Factory.html | 46 +- .../DefaultHttpDataSourceFactory.html | 474 -- .../DefaultLoadErrorHandlingPolicy.html | 6 +- ...ileDataSource.FileDataSourceException.html | 24 +- .../upstream/HttpDataSource.BaseFactory.html | 34 +- .../upstream/HttpDataSource.Factory.html | 30 +- ...ttpDataSource.HttpDataSourceException.html | 88 +- ...y.html => PriorityDataSource.Factory.html} | 73 +- .../upstream/PriorityDataSource.html | 22 +- .../upstream/PriorityDataSourceFactory.html | 20 +- ...Source.RawResourceDataSourceException.html | 16 +- .../{util => upstream}/SlidingPercentile.html | 4 +- .../UdpDataSource.UdpDataSourceException.html | 8 +- .../upstream/cache/Cache.Listener.html | 2 +- .../cache/CacheDataSourceFactory.html | 430 -- .../upstream/cache/package-summary.html | 33 +- .../upstream/cache/package-tree.html | 3 - .../upstream/crypto/AesFlushingCipher.html | 20 + .../exoplayer2/upstream/package-summary.html | 81 +- .../exoplayer2/upstream/package-tree.html | 12 +- ...ndleableUtils.html => BundleableUtil.html} | 123 +- .../util/CodecSpecificDataUtil.html | 25 +- .../exoplayer2/util/DebugTextViewHelper.html | 63 +- .../android/exoplayer2/util/EventLogger.html | 80 +- .../exoplayer2/util/GlUtil.Attribute.html | 23 +- .../exoplayer2/util/GlUtil.GlException.html | 302 + ...dOutputStream.html => GlUtil.Program.html} | 271 +- .../exoplayer2/util/GlUtil.Uniform.html | 22 +- ...GlUtil.UnsupportedEglVersionException.html | 294 + .../android/exoplayer2/util/GlUtil.html | 316 +- .../exoplayer2/util/ListenerSet.Event.html | 2 +- .../ListenerSet.IterationFinishedEvent.html | 2 +- .../android/exoplayer2/util/ListenerSet.html | 4 +- .../exoplayer2/util/MediaFormatUtil.html | 28 +- .../android/exoplayer2/util/MimeTypes.html | 176 +- .../util/NalUnitUtil.H265SpsData.html | 455 ++ .../exoplayer2/util/NalUnitUtil.SpsData.html | 14 +- .../android/exoplayer2/util/NalUnitUtil.html | 145 +- .../exoplayer2/util/RepeatModeUtil.html | 18 +- .../google/android/exoplayer2/util/Util.html | 455 +- .../exoplayer2/util/package-summary.html | 75 +- .../android/exoplayer2/util/package-tree.html | 22 +- .../android/exoplayer2/video/AvcConfig.html | 42 +- .../android/exoplayer2/video/ColorInfo.html | 71 +- .../video/DecoderVideoRenderer.html | 65 +- .../exoplayer2/video/DummySurface.html | 4 +- .../android/exoplayer2/video/HevcConfig.html | 78 +- .../video/MediaCodecVideoRenderer.html | 73 +- .../video/VideoDecoderGLSurfaceView.html | 20 +- .../video/VideoDecoderInputBuffer.html | 396 -- .../VideoDecoderOutputBufferRenderer.html | 8 +- .../video/VideoFrameReleaseHelper.html | 20 +- .../exoplayer2/video/VideoListener.html | 347 - .../exoplayer2/video/package-summary.html | 22 +- .../exoplayer2/video/package-tree.html | 17 +- .../video/spherical/CameraMotionRenderer.html | 9 +- .../spherical/SphericalGLSurfaceView.html | 6 +- docs/doc/reference/constant-values.html | 1269 ++-- docs/doc/reference/deprecated-list.html | 1429 +++-- docs/doc/reference/element-list | 2 - docs/doc/reference/index-all.html | 5614 +++++++++++------ docs/doc/reference/index.html | 156 +- docs/doc/reference/member-search-index.js | 2 +- docs/doc/reference/member-search-index.zip | Bin 136486 -> 140976 bytes docs/doc/reference/overview-tree.html | 166 +- docs/doc/reference/package-search-index.js | 2 +- docs/doc/reference/package-search-index.zip | Bin 706 -> 697 bytes docs/doc/reference/serialized-form.html | 50 +- docs/doc/reference/type-search-index.js | 2 +- docs/doc/reference/type-search-index.zip | Bin 10091 -> 10295 bytes 488 files changed, 37457 insertions(+), 21429 deletions(-) rename docs/doc/reference/com/google/android/exoplayer2/{ext/gvr/package-summary.html => C.AudioManagerOffloadMode.html} (51%) create mode 100644 docs/doc/reference/com/google/android/exoplayer2/C.CryptoType.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/C.SelectionReason.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/C.TrackType.html rename docs/doc/reference/com/google/android/exoplayer2/{Renderer.VideoScalingMode.html => C.VideoChangeFrameRateStrategy.html} (89%) delete mode 100644 docs/doc/reference/com/google/android/exoplayer2/ControlDispatcher.html delete mode 100644 docs/doc/reference/com/google/android/exoplayer2/DefaultControlDispatcher.html rename docs/doc/reference/com/google/android/exoplayer2/{device => }/DeviceInfo.PlaybackType.html (75%) rename docs/doc/reference/com/google/android/exoplayer2/{device => }/DeviceInfo.html (80%) delete mode 100644 docs/doc/reference/com/google/android/exoplayer2/ExoPlayer.MetadataComponent.html rename docs/doc/reference/com/google/android/exoplayer2/{upstream/cache/CacheDataSinkFactory.html => MediaItem.AdsConfiguration.Builder.html} (60%) create mode 100644 docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingConfiguration.Builder.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingConfiguration.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/MediaItem.DrmConfiguration.Builder.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/MediaItem.LiveConfiguration.Builder.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/MediaItem.LocalConfiguration.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/MediaItem.SubtitleConfiguration.Builder.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/MediaItem.SubtitleConfiguration.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/Renderer.MessageType.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/TracksInfo.TrackGroupInfo.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/TracksInfo.html delete mode 100644 docs/doc/reference/com/google/android/exoplayer2/audio/AudioListener.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/database/StandaloneDatabaseProvider.html rename docs/doc/reference/com/google/android/exoplayer2/{drm/ExoMediaCrypto.html => decoder/CryptoConfig.html} (88%) rename docs/doc/reference/com/google/android/exoplayer2/{drm/DecryptionException.html => decoder/CryptoException.html} (93%) rename docs/doc/reference/com/google/android/exoplayer2/decoder/{OutputBuffer.Owner.html => DecoderOutputBuffer.Owner.html} (89%) rename docs/doc/reference/com/google/android/exoplayer2/decoder/{OutputBuffer.html => DecoderOutputBuffer.html} (92%) rename docs/doc/reference/com/google/android/exoplayer2/decoder/{SimpleOutputBuffer.html => SimpleDecoderOutputBuffer.html} (86%) rename docs/doc/reference/com/google/android/exoplayer2/{video => decoder}/VideoDecoderOutputBuffer.html (87%) rename docs/doc/reference/com/google/android/exoplayer2/drm/{FrameworkMediaCrypto.html => FrameworkCryptoConfig.html} (88%) delete mode 100644 docs/doc/reference/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.html delete mode 100644 docs/doc/reference/com/google/android/exoplayer2/ext/gvr/package-tree.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/extractor/TrueHdSampleRechunker.html rename docs/doc/reference/com/google/android/exoplayer2/{util => extractor/flac}/FlacConstants.html (82%) create mode 100644 docs/doc/reference/com/google/android/exoplayer2/mediacodec/DefaultMediaCodecAdapterFactory.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/testutil/AssetContentProvider.html rename docs/doc/reference/com/google/android/exoplayer2/{drm/UnsupportedMediaCrypto.html => testutil/FakeCryptoConfig.html} (80%) create mode 100644 docs/doc/reference/com/google/android/exoplayer2/testutil/FakeMediaSourceFactory.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/testutil/FakeMetadataEntry.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/testutil/StubPlayer.html rename docs/doc/reference/com/google/android/exoplayer2/{util/IntArrayQueue.html => text/CueDecoder.html} (72%) create mode 100644 docs/doc/reference/com/google/android/exoplayer2/text/CueEncoder.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/text/ExoplayerCuesDecoder.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/text/SubtitleExtractor.html rename docs/doc/reference/com/google/android/exoplayer2/{device/package-summary.html => trackselection/TrackSelection.Type.html} (66%) create mode 100644 docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectionOverrides.Builder.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectionOverrides.TrackSelectionOverride.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectionOverrides.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/transformer/TranscodingTransformer.Builder.html rename docs/doc/reference/com/google/android/exoplayer2/{device/DeviceListener.html => transformer/TranscodingTransformer.Listener.html} (69%) rename docs/doc/reference/com/google/android/exoplayer2/{device/package-tree.html => transformer/TranscodingTransformer.ProgressState.html} (66%) create mode 100644 docs/doc/reference/com/google/android/exoplayer2/transformer/TranscodingTransformer.html rename docs/doc/reference/com/google/android/exoplayer2/upstream/{cache => }/CachedRegionTracker.html (65%) create mode 100644 docs/doc/reference/com/google/android/exoplayer2/upstream/DataSourceUtil.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/upstream/DefaultDataSource.Factory.html delete mode 100644 docs/doc/reference/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceFactory.html rename docs/doc/reference/com/google/android/exoplayer2/upstream/{FileDataSourceFactory.html => PriorityDataSource.Factory.html} (78%) rename docs/doc/reference/com/google/android/exoplayer2/{util => upstream}/SlidingPercentile.html (99%) delete mode 100644 docs/doc/reference/com/google/android/exoplayer2/upstream/cache/CacheDataSourceFactory.html rename docs/doc/reference/com/google/android/exoplayer2/util/{BundleableUtils.html => BundleableUtil.html} (58%) create mode 100644 docs/doc/reference/com/google/android/exoplayer2/util/GlUtil.GlException.html rename docs/doc/reference/com/google/android/exoplayer2/util/{ReusableBufferedOutputStream.html => GlUtil.Program.html} (52%) create mode 100644 docs/doc/reference/com/google/android/exoplayer2/util/GlUtil.UnsupportedEglVersionException.html create mode 100644 docs/doc/reference/com/google/android/exoplayer2/util/NalUnitUtil.H265SpsData.html delete mode 100644 docs/doc/reference/com/google/android/exoplayer2/video/VideoDecoderInputBuffer.html delete mode 100644 docs/doc/reference/com/google/android/exoplayer2/video/VideoListener.html diff --git a/docs/doc/reference/allclasses-index.html b/docs/doc/reference/allclasses-index.html index 0b597a9f2a..f99c81d555 100644 --- a/docs/doc/reference/allclasses-index.html +++ b/docs/doc/reference/allclasses-index.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":2,"i1":32,"i2":2,"i3":2,"i4":2,"i5":2,"i6":2,"i7":2,"i8":32,"i9":2,"i10":2,"i11":2,"i12":2,"i13":2,"i14":2,"i15":2,"i16":2,"i17":2,"i18":2,"i19":2,"i20":2,"i21":2,"i22":2,"i23":2,"i24":2,"i25":2,"i26":2,"i27":2,"i28":2,"i29":2,"i30":2,"i31":2,"i32":2,"i33":2,"i34":2,"i35":2,"i36":2,"i37":2,"i38":2,"i39":2,"i40":2,"i41":2,"i42":2,"i43":2,"i44":2,"i45":1,"i46":2,"i47":2,"i48":1,"i49":2,"i50":2,"i51":1,"i52":2,"i53":2,"i54":2,"i55":2,"i56":2,"i57":2,"i58":32,"i59":2,"i60":2,"i61":32,"i62":1,"i63":1,"i64":2,"i65":8,"i66":32,"i67":2,"i68":32,"i69":2,"i70":1,"i71":2,"i72":2,"i73":2,"i74":2,"i75":1,"i76":2,"i77":32,"i78":2,"i79":1,"i80":32,"i81":2,"i82":2,"i83":2,"i84":2,"i85":2,"i86":2,"i87":1,"i88":32,"i89":2,"i90":2,"i91":8,"i92":2,"i93":2,"i94":2,"i95":2,"i96":2,"i97":1,"i98":1,"i99":1,"i100":2,"i101":8,"i102":1,"i103":2,"i104":1,"i105":8,"i106":8,"i107":1,"i108":32,"i109":8,"i110":8,"i111":2,"i112":2,"i113":1,"i114":1,"i115":2,"i116":2,"i117":2,"i118":2,"i119":2,"i120":2,"i121":2,"i122":2,"i123":2,"i124":2,"i125":2,"i126":2,"i127":8,"i128":2,"i129":2,"i130":2,"i131":2,"i132":2,"i133":1,"i134":2,"i135":1,"i136":2,"i137":1,"i138":1,"i139":2,"i140":2,"i141":2,"i142":2,"i143":2,"i144":2,"i145":2,"i146":2,"i147":2,"i148":32,"i149":32,"i150":32,"i151":32,"i152":32,"i153":32,"i154":32,"i155":32,"i156":32,"i157":32,"i158":32,"i159":32,"i160":32,"i161":32,"i162":32,"i163":32,"i164":32,"i165":32,"i166":32,"i167":32,"i168":32,"i169":32,"i170":32,"i171":32,"i172":1,"i173":8,"i174":1,"i175":2,"i176":2,"i177":2,"i178":8,"i179":2,"i180":2,"i181":2,"i182":32,"i183":1,"i184":2,"i185":32,"i186":2,"i187":2,"i188":1,"i189":1,"i190":2,"i191":2,"i192":1,"i193":1,"i194":2,"i195":2,"i196":32,"i197":2,"i198":2,"i199":2,"i200":2,"i201":2,"i202":2,"i203":2,"i204":2,"i205":2,"i206":1,"i207":1,"i208":1,"i209":2,"i210":2,"i211":2,"i212":1,"i213":1,"i214":2,"i215":2,"i216":8,"i217":32,"i218":1,"i219":2,"i220":2,"i221":2,"i222":2,"i223":2,"i224":2,"i225":1,"i226":2,"i227":2,"i228":2,"i229":1,"i230":2,"i231":2,"i232":8,"i233":1,"i234":2,"i235":1,"i236":2,"i237":2,"i238":2,"i239":8,"i240":2,"i241":2,"i242":2,"i243":2,"i244":2,"i245":32,"i246":2,"i247":32,"i248":32,"i249":32,"i250":1,"i251":1,"i252":2,"i253":2,"i254":2,"i255":2,"i256":8,"i257":2,"i258":2,"i259":1,"i260":2,"i261":2,"i262":8,"i263":1,"i264":2,"i265":1,"i266":2,"i267":1,"i268":1,"i269":1,"i270":1,"i271":2,"i272":2,"i273":2,"i274":2,"i275":8,"i276":2,"i277":2,"i278":2,"i279":32,"i280":32,"i281":2,"i282":1,"i283":2,"i284":2,"i285":2,"i286":8,"i287":2,"i288":32,"i289":8,"i290":2,"i291":32,"i292":32,"i293":2,"i294":8,"i295":2,"i296":2,"i297":1,"i298":2,"i299":8,"i300":32,"i301":2,"i302":2,"i303":2,"i304":2,"i305":2,"i306":2,"i307":2,"i308":2,"i309":2,"i310":2,"i311":2,"i312":2,"i313":2,"i314":2,"i315":2,"i316":2,"i317":2,"i318":8,"i319":32,"i320":2,"i321":2,"i322":2,"i323":2,"i324":2,"i325":2,"i326":2,"i327":2,"i328":2,"i329":2,"i330":2,"i331":2,"i332":2,"i333":2,"i334":2,"i335":2,"i336":2,"i337":2,"i338":2,"i339":1,"i340":2,"i341":2,"i342":32,"i343":2,"i344":2,"i345":2,"i346":2,"i347":2,"i348":2,"i349":2,"i350":2,"i351":2,"i352":2,"i353":2,"i354":2,"i355":2,"i356":2,"i357":2,"i358":32,"i359":2,"i360":2,"i361":32,"i362":1,"i363":2,"i364":2,"i365":32,"i366":32,"i367":2,"i368":1,"i369":1,"i370":1,"i371":1,"i372":8,"i373":2,"i374":1,"i375":8,"i376":1,"i377":2,"i378":1,"i379":2,"i380":2,"i381":2,"i382":2,"i383":8,"i384":2,"i385":2,"i386":2,"i387":1,"i388":8,"i389":32,"i390":1,"i391":2,"i392":1,"i393":1,"i394":1,"i395":2,"i396":32,"i397":2,"i398":2,"i399":2,"i400":2,"i401":2,"i402":2,"i403":1,"i404":2,"i405":2,"i406":2,"i407":2,"i408":1,"i409":2,"i410":2,"i411":2,"i412":1,"i413":32,"i414":2,"i415":8,"i416":32,"i417":1,"i418":1,"i419":2,"i420":1,"i421":2,"i422":2,"i423":2,"i424":2,"i425":2,"i426":2,"i427":2,"i428":2,"i429":1,"i430":1,"i431":2,"i432":2,"i433":32,"i434":2,"i435":1,"i436":1,"i437":1,"i438":1,"i439":2,"i440":8,"i441":32,"i442":1,"i443":1,"i444":1,"i445":2,"i446":1,"i447":1,"i448":1,"i449":1,"i450":2,"i451":2,"i452":2,"i453":8,"i454":32,"i455":1,"i456":2,"i457":1,"i458":1,"i459":32,"i460":2,"i461":2,"i462":2,"i463":1,"i464":2,"i465":1,"i466":1,"i467":1,"i468":2,"i469":2,"i470":2,"i471":2,"i472":2,"i473":2,"i474":2,"i475":2,"i476":2,"i477":2,"i478":2,"i479":2,"i480":2,"i481":2,"i482":2,"i483":2,"i484":2,"i485":2,"i486":2,"i487":2,"i488":2,"i489":2,"i490":8,"i491":2,"i492":2,"i493":2,"i494":2,"i495":2,"i496":1,"i497":2,"i498":2,"i499":2,"i500":2,"i501":2,"i502":2,"i503":2,"i504":2,"i505":2,"i506":1,"i507":2,"i508":2,"i509":2,"i510":2,"i511":8,"i512":2,"i513":2,"i514":2,"i515":8,"i516":2,"i517":2,"i518":32,"i519":1,"i520":2,"i521":2,"i522":2,"i523":2,"i524":2,"i525":8,"i526":2,"i527":2,"i528":32,"i529":32,"i530":2,"i531":2,"i532":2,"i533":2,"i534":2,"i535":2,"i536":2,"i537":2,"i538":2,"i539":2,"i540":2,"i541":2,"i542":2,"i543":2,"i544":2,"i545":2,"i546":2,"i547":2,"i548":2,"i549":32,"i550":2,"i551":2,"i552":2,"i553":2,"i554":8,"i555":2,"i556":2,"i557":2,"i558":2,"i559":2,"i560":2,"i561":2,"i562":2,"i563":2,"i564":2,"i565":1,"i566":1,"i567":2,"i568":2,"i569":1,"i570":2,"i571":1,"i572":2,"i573":2,"i574":2,"i575":2,"i576":1,"i577":2,"i578":2,"i579":2,"i580":32,"i581":2,"i582":2,"i583":2,"i584":2,"i585":2,"i586":2,"i587":32,"i588":2,"i589":2,"i590":8,"i591":1,"i592":1,"i593":1,"i594":1,"i595":8,"i596":8,"i597":1,"i598":2,"i599":2,"i600":2,"i601":2,"i602":1,"i603":1,"i604":2,"i605":8,"i606":1,"i607":8,"i608":32,"i609":8,"i610":8,"i611":2,"i612":2,"i613":2,"i614":2,"i615":2,"i616":2,"i617":2,"i618":2,"i619":1,"i620":2,"i621":2,"i622":2,"i623":8,"i624":2,"i625":2,"i626":2,"i627":2,"i628":2,"i629":2,"i630":2,"i631":2,"i632":8,"i633":1,"i634":2,"i635":2,"i636":2,"i637":2,"i638":2,"i639":2,"i640":2,"i641":2,"i642":2,"i643":1,"i644":1,"i645":1,"i646":1,"i647":2,"i648":1,"i649":1,"i650":2,"i651":1,"i652":8,"i653":1,"i654":2,"i655":1,"i656":2,"i657":2,"i658":32,"i659":2,"i660":2,"i661":2,"i662":2,"i663":2,"i664":2,"i665":2,"i666":2,"i667":2,"i668":1,"i669":2,"i670":2,"i671":2,"i672":32,"i673":2,"i674":2,"i675":1,"i676":1,"i677":1,"i678":2,"i679":1,"i680":1,"i681":2,"i682":8,"i683":2,"i684":2,"i685":8,"i686":1,"i687":2,"i688":8,"i689":8,"i690":2,"i691":2,"i692":1,"i693":8,"i694":2,"i695":2,"i696":2,"i697":2,"i698":2,"i699":2,"i700":2,"i701":2,"i702":2,"i703":1,"i704":1,"i705":2,"i706":2,"i707":2,"i708":32,"i709":32,"i710":2,"i711":2,"i712":2,"i713":2,"i714":1,"i715":1,"i716":2,"i717":1,"i718":2,"i719":2,"i720":1,"i721":1,"i722":1,"i723":2,"i724":1,"i725":1,"i726":32,"i727":1,"i728":1,"i729":1,"i730":1,"i731":1,"i732":2,"i733":1,"i734":1,"i735":2,"i736":1,"i737":2,"i738":2,"i739":8,"i740":32,"i741":2,"i742":1,"i743":1,"i744":1,"i745":2,"i746":1,"i747":2,"i748":2,"i749":2,"i750":2,"i751":2,"i752":2,"i753":32,"i754":2,"i755":32,"i756":2,"i757":2,"i758":2,"i759":2,"i760":2,"i761":2,"i762":2,"i763":2,"i764":2,"i765":1,"i766":32,"i767":2,"i768":2,"i769":2,"i770":32,"i771":2,"i772":2,"i773":2,"i774":2,"i775":2,"i776":2,"i777":2,"i778":8,"i779":2,"i780":2,"i781":2,"i782":1,"i783":2,"i784":2,"i785":2,"i786":2,"i787":8,"i788":2,"i789":1,"i790":2,"i791":2,"i792":2,"i793":2,"i794":2,"i795":2,"i796":2,"i797":2,"i798":8,"i799":32,"i800":32,"i801":2,"i802":2,"i803":1,"i804":1,"i805":2,"i806":2,"i807":2,"i808":2,"i809":2,"i810":1,"i811":1,"i812":32,"i813":2,"i814":2,"i815":32,"i816":32,"i817":1,"i818":2,"i819":1,"i820":32,"i821":32,"i822":32,"i823":2,"i824":32,"i825":32,"i826":32,"i827":2,"i828":1,"i829":1,"i830":2,"i831":1,"i832":2,"i833":1,"i834":1,"i835":2,"i836":2,"i837":1,"i838":1,"i839":1,"i840":32,"i841":32,"i842":2,"i843":32,"i844":2,"i845":2,"i846":2,"i847":2,"i848":8,"i849":2,"i850":2,"i851":2,"i852":2,"i853":2,"i854":1,"i855":1,"i856":2,"i857":2,"i858":2,"i859":2,"i860":2,"i861":2,"i862":2,"i863":2,"i864":2,"i865":2,"i866":2,"i867":8,"i868":1,"i869":32,"i870":32,"i871":1,"i872":1,"i873":32,"i874":32,"i875":32,"i876":32,"i877":2,"i878":1,"i879":2,"i880":2,"i881":32,"i882":2,"i883":2,"i884":2,"i885":2,"i886":32,"i887":2,"i888":1,"i889":2,"i890":2,"i891":1,"i892":2,"i893":2,"i894":2,"i895":2,"i896":2,"i897":2,"i898":2,"i899":2,"i900":2,"i901":1,"i902":1,"i903":2,"i904":2,"i905":2,"i906":8,"i907":2,"i908":2,"i909":2,"i910":1,"i911":8,"i912":1,"i913":32,"i914":32,"i915":1,"i916":1,"i917":2,"i918":1,"i919":2,"i920":2,"i921":2,"i922":2,"i923":2,"i924":2,"i925":2,"i926":2,"i927":2,"i928":2,"i929":2,"i930":2,"i931":2,"i932":1,"i933":1,"i934":2,"i935":2,"i936":2,"i937":1,"i938":2,"i939":1,"i940":1,"i941":2,"i942":1,"i943":2,"i944":1,"i945":1,"i946":1,"i947":1,"i948":2,"i949":2,"i950":1,"i951":2,"i952":2,"i953":2,"i954":2,"i955":2,"i956":2,"i957":2,"i958":2,"i959":2,"i960":2,"i961":2,"i962":2,"i963":2,"i964":2,"i965":2,"i966":2,"i967":2,"i968":2,"i969":2,"i970":2,"i971":2,"i972":2,"i973":1,"i974":2,"i975":2,"i976":1,"i977":1,"i978":1,"i979":1,"i980":1,"i981":1,"i982":1,"i983":1,"i984":1,"i985":2,"i986":2,"i987":1,"i988":2,"i989":2,"i990":2,"i991":2,"i992":2,"i993":2,"i994":2,"i995":2,"i996":2,"i997":1,"i998":1,"i999":2,"i1000":2,"i1001":2,"i1002":2,"i1003":2,"i1004":8,"i1005":2,"i1006":2,"i1007":2,"i1008":2,"i1009":2,"i1010":2,"i1011":2,"i1012":2,"i1013":2,"i1014":1,"i1015":1,"i1016":1,"i1017":2,"i1018":32,"i1019":2,"i1020":1,"i1021":1,"i1022":8,"i1023":1,"i1024":2,"i1025":2,"i1026":2,"i1027":32,"i1028":2,"i1029":2,"i1030":2,"i1031":2,"i1032":1,"i1033":2,"i1034":2,"i1035":2,"i1036":2,"i1037":2,"i1038":2,"i1039":2,"i1040":32,"i1041":2,"i1042":32,"i1043":32,"i1044":2,"i1045":1,"i1046":2,"i1047":2,"i1048":1,"i1049":1,"i1050":2,"i1051":2,"i1052":2,"i1053":2,"i1054":2,"i1055":2,"i1056":2,"i1057":1,"i1058":2,"i1059":1,"i1060":2,"i1061":2,"i1062":2,"i1063":2,"i1064":1,"i1065":2,"i1066":2,"i1067":32,"i1068":2,"i1069":2,"i1070":2,"i1071":1,"i1072":1,"i1073":2,"i1074":32,"i1075":1,"i1076":2,"i1077":2,"i1078":1,"i1079":2,"i1080":2,"i1081":2,"i1082":1,"i1083":2,"i1084":1,"i1085":2,"i1086":1,"i1087":2,"i1088":1,"i1089":2,"i1090":2,"i1091":1,"i1092":32,"i1093":2,"i1094":32,"i1095":1,"i1096":2,"i1097":2,"i1098":1,"i1099":32,"i1100":2,"i1101":2,"i1102":2,"i1103":2,"i1104":2,"i1105":8,"i1106":32,"i1107":8,"i1108":8,"i1109":32,"i1110":2,"i1111":2,"i1112":2,"i1113":2,"i1114":2,"i1115":2,"i1116":2,"i1117":2,"i1118":2,"i1119":2,"i1120":1,"i1121":1,"i1122":2,"i1123":1,"i1124":1,"i1125":2,"i1126":2,"i1127":2,"i1128":2,"i1129":2,"i1130":2,"i1131":2,"i1132":2,"i1133":2,"i1134":8,"i1135":2,"i1136":2,"i1137":2,"i1138":2,"i1139":2,"i1140":2,"i1141":2,"i1142":32,"i1143":32,"i1144":2,"i1145":2,"i1146":2,"i1147":2,"i1148":2,"i1149":2,"i1150":2,"i1151":2,"i1152":1,"i1153":2}; +var data = {"i0":2,"i1":32,"i2":2,"i3":2,"i4":2,"i5":2,"i6":2,"i7":2,"i8":32,"i9":2,"i10":2,"i11":2,"i12":2,"i13":2,"i14":2,"i15":2,"i16":2,"i17":2,"i18":2,"i19":2,"i20":2,"i21":2,"i22":2,"i23":2,"i24":2,"i25":2,"i26":2,"i27":2,"i28":2,"i29":2,"i30":2,"i31":2,"i32":2,"i33":2,"i34":2,"i35":2,"i36":2,"i37":2,"i38":2,"i39":2,"i40":2,"i41":2,"i42":2,"i43":2,"i44":2,"i45":1,"i46":2,"i47":2,"i48":1,"i49":2,"i50":2,"i51":1,"i52":2,"i53":2,"i54":2,"i55":2,"i56":2,"i57":2,"i58":32,"i59":2,"i60":2,"i61":32,"i62":1,"i63":1,"i64":2,"i65":8,"i66":32,"i67":2,"i68":32,"i69":2,"i70":1,"i71":2,"i72":2,"i73":2,"i74":2,"i75":1,"i76":2,"i77":32,"i78":2,"i79":1,"i80":32,"i81":2,"i82":2,"i83":2,"i84":2,"i85":2,"i86":2,"i87":1,"i88":32,"i89":2,"i90":2,"i91":2,"i92":8,"i93":2,"i94":2,"i95":2,"i96":2,"i97":2,"i98":1,"i99":1,"i100":2,"i101":8,"i102":1,"i103":2,"i104":1,"i105":8,"i106":8,"i107":1,"i108":32,"i109":8,"i110":8,"i111":2,"i112":2,"i113":1,"i114":1,"i115":2,"i116":2,"i117":2,"i118":2,"i119":2,"i120":2,"i121":2,"i122":2,"i123":2,"i124":2,"i125":2,"i126":2,"i127":8,"i128":2,"i129":2,"i130":2,"i131":2,"i132":2,"i133":1,"i134":2,"i135":1,"i136":2,"i137":1,"i138":1,"i139":2,"i140":2,"i141":2,"i142":2,"i143":2,"i144":2,"i145":2,"i146":2,"i147":2,"i148":32,"i149":32,"i150":32,"i151":32,"i152":32,"i153":32,"i154":32,"i155":32,"i156":32,"i157":32,"i158":32,"i159":32,"i160":32,"i161":32,"i162":32,"i163":32,"i164":32,"i165":32,"i166":32,"i167":32,"i168":32,"i169":32,"i170":32,"i171":32,"i172":32,"i173":32,"i174":32,"i175":32,"i176":32,"i177":1,"i178":8,"i179":1,"i180":2,"i181":2,"i182":2,"i183":8,"i184":2,"i185":2,"i186":32,"i187":1,"i188":2,"i189":32,"i190":2,"i191":1,"i192":1,"i193":2,"i194":2,"i195":1,"i196":1,"i197":2,"i198":2,"i199":32,"i200":2,"i201":2,"i202":2,"i203":2,"i204":2,"i205":2,"i206":2,"i207":2,"i208":2,"i209":1,"i210":1,"i211":1,"i212":2,"i213":2,"i214":2,"i215":1,"i216":1,"i217":2,"i218":2,"i219":8,"i220":32,"i221":1,"i222":2,"i223":2,"i224":2,"i225":2,"i226":2,"i227":2,"i228":1,"i229":2,"i230":2,"i231":2,"i232":1,"i233":2,"i234":2,"i235":8,"i236":1,"i237":2,"i238":2,"i239":2,"i240":2,"i241":8,"i242":2,"i243":2,"i244":2,"i245":1,"i246":8,"i247":2,"i248":2,"i249":32,"i250":2,"i251":32,"i252":32,"i253":32,"i254":2,"i255":2,"i256":1,"i257":1,"i258":2,"i259":2,"i260":2,"i261":2,"i262":8,"i263":2,"i264":2,"i265":1,"i266":2,"i267":2,"i268":8,"i269":1,"i270":2,"i271":1,"i272":2,"i273":1,"i274":1,"i275":1,"i276":1,"i277":2,"i278":2,"i279":2,"i280":2,"i281":8,"i282":2,"i283":2,"i284":2,"i285":2,"i286":32,"i287":32,"i288":2,"i289":1,"i290":2,"i291":2,"i292":2,"i293":8,"i294":2,"i295":32,"i296":8,"i297":2,"i298":1,"i299":2,"i300":32,"i301":32,"i302":2,"i303":2,"i304":2,"i305":1,"i306":2,"i307":8,"i308":32,"i309":2,"i310":2,"i311":2,"i312":2,"i313":2,"i314":2,"i315":2,"i316":2,"i317":2,"i318":2,"i319":2,"i320":2,"i321":2,"i322":2,"i323":2,"i324":2,"i325":2,"i326":8,"i327":32,"i328":2,"i329":2,"i330":2,"i331":2,"i332":2,"i333":2,"i334":2,"i335":2,"i336":2,"i337":2,"i338":2,"i339":2,"i340":2,"i341":2,"i342":2,"i343":2,"i344":2,"i345":2,"i346":2,"i347":1,"i348":2,"i349":2,"i350":32,"i351":2,"i352":2,"i353":2,"i354":2,"i355":2,"i356":2,"i357":2,"i358":2,"i359":2,"i360":2,"i361":2,"i362":2,"i363":2,"i364":2,"i365":2,"i366":32,"i367":2,"i368":2,"i369":32,"i370":2,"i371":2,"i372":32,"i373":32,"i374":2,"i375":1,"i376":1,"i377":1,"i378":1,"i379":8,"i380":2,"i381":1,"i382":8,"i383":1,"i384":2,"i385":1,"i386":2,"i387":2,"i388":2,"i389":2,"i390":8,"i391":2,"i392":2,"i393":2,"i394":1,"i395":8,"i396":32,"i397":1,"i398":2,"i399":1,"i400":1,"i401":1,"i402":2,"i403":32,"i404":2,"i405":2,"i406":2,"i407":2,"i408":2,"i409":2,"i410":1,"i411":2,"i412":2,"i413":2,"i414":2,"i415":1,"i416":2,"i417":2,"i418":2,"i419":1,"i420":32,"i421":2,"i422":8,"i423":32,"i424":1,"i425":1,"i426":2,"i427":1,"i428":2,"i429":2,"i430":2,"i431":2,"i432":2,"i433":2,"i434":2,"i435":2,"i436":1,"i437":2,"i438":2,"i439":32,"i440":2,"i441":1,"i442":1,"i443":1,"i444":1,"i445":2,"i446":8,"i447":32,"i448":1,"i449":1,"i450":1,"i451":2,"i452":1,"i453":1,"i454":1,"i455":2,"i456":2,"i457":2,"i458":2,"i459":8,"i460":32,"i461":1,"i462":2,"i463":1,"i464":1,"i465":32,"i466":2,"i467":2,"i468":2,"i469":1,"i470":2,"i471":1,"i472":1,"i473":1,"i474":2,"i475":2,"i476":2,"i477":2,"i478":2,"i479":2,"i480":2,"i481":2,"i482":2,"i483":2,"i484":2,"i485":2,"i486":2,"i487":2,"i488":2,"i489":2,"i490":2,"i491":2,"i492":2,"i493":2,"i494":2,"i495":2,"i496":2,"i497":8,"i498":2,"i499":2,"i500":2,"i501":2,"i502":2,"i503":1,"i504":2,"i505":2,"i506":2,"i507":2,"i508":2,"i509":2,"i510":2,"i511":2,"i512":2,"i513":2,"i514":2,"i515":1,"i516":2,"i517":2,"i518":2,"i519":2,"i520":8,"i521":2,"i522":2,"i523":2,"i524":8,"i525":2,"i526":32,"i527":1,"i528":2,"i529":2,"i530":2,"i531":2,"i532":2,"i533":8,"i534":2,"i535":2,"i536":32,"i537":32,"i538":2,"i539":2,"i540":2,"i541":2,"i542":2,"i543":2,"i544":2,"i545":2,"i546":2,"i547":2,"i548":2,"i549":2,"i550":2,"i551":2,"i552":2,"i553":2,"i554":2,"i555":2,"i556":2,"i557":32,"i558":2,"i559":2,"i560":2,"i561":2,"i562":8,"i563":2,"i564":2,"i565":2,"i566":2,"i567":8,"i568":2,"i569":2,"i570":8,"i571":2,"i572":2,"i573":2,"i574":2,"i575":1,"i576":1,"i577":2,"i578":2,"i579":1,"i580":2,"i581":1,"i582":2,"i583":2,"i584":2,"i585":2,"i586":1,"i587":2,"i588":2,"i589":2,"i590":32,"i591":2,"i592":2,"i593":2,"i594":2,"i595":2,"i596":2,"i597":32,"i598":2,"i599":2,"i600":8,"i601":1,"i602":1,"i603":1,"i604":1,"i605":8,"i606":8,"i607":1,"i608":2,"i609":2,"i610":2,"i611":2,"i612":1,"i613":1,"i614":2,"i615":8,"i616":1,"i617":8,"i618":32,"i619":8,"i620":8,"i621":2,"i622":2,"i623":2,"i624":2,"i625":2,"i626":2,"i627":2,"i628":2,"i629":1,"i630":2,"i631":2,"i632":2,"i633":8,"i634":2,"i635":2,"i636":2,"i637":2,"i638":2,"i639":2,"i640":2,"i641":8,"i642":1,"i643":2,"i644":2,"i645":2,"i646":2,"i647":2,"i648":2,"i649":2,"i650":2,"i651":2,"i652":1,"i653":1,"i654":1,"i655":1,"i656":2,"i657":1,"i658":1,"i659":2,"i660":1,"i661":8,"i662":1,"i663":2,"i664":1,"i665":2,"i666":2,"i667":32,"i668":2,"i669":2,"i670":2,"i671":2,"i672":2,"i673":2,"i674":2,"i675":2,"i676":2,"i677":1,"i678":2,"i679":2,"i680":2,"i681":32,"i682":2,"i683":2,"i684":1,"i685":1,"i686":1,"i687":2,"i688":1,"i689":1,"i690":2,"i691":8,"i692":2,"i693":2,"i694":8,"i695":1,"i696":2,"i697":8,"i698":8,"i699":2,"i700":2,"i701":1,"i702":8,"i703":2,"i704":2,"i705":2,"i706":2,"i707":2,"i708":2,"i709":2,"i710":2,"i711":2,"i712":2,"i713":2,"i714":2,"i715":2,"i716":2,"i717":2,"i718":2,"i719":2,"i720":1,"i721":1,"i722":2,"i723":2,"i724":2,"i725":32,"i726":32,"i727":2,"i728":2,"i729":2,"i730":2,"i731":1,"i732":1,"i733":2,"i734":1,"i735":2,"i736":2,"i737":1,"i738":1,"i739":1,"i740":2,"i741":1,"i742":1,"i743":32,"i744":1,"i745":1,"i746":1,"i747":1,"i748":1,"i749":2,"i750":1,"i751":1,"i752":2,"i753":1,"i754":2,"i755":2,"i756":8,"i757":32,"i758":2,"i759":1,"i760":1,"i761":1,"i762":2,"i763":1,"i764":2,"i765":2,"i766":2,"i767":2,"i768":2,"i769":2,"i770":32,"i771":2,"i772":32,"i773":2,"i774":2,"i775":2,"i776":2,"i777":2,"i778":2,"i779":2,"i780":2,"i781":2,"i782":2,"i783":1,"i784":32,"i785":2,"i786":2,"i787":2,"i788":32,"i789":2,"i790":2,"i791":2,"i792":2,"i793":2,"i794":2,"i795":2,"i796":8,"i797":2,"i798":2,"i799":2,"i800":2,"i801":2,"i802":2,"i803":8,"i804":2,"i805":1,"i806":2,"i807":2,"i808":2,"i809":2,"i810":2,"i811":2,"i812":2,"i813":2,"i814":8,"i815":32,"i816":32,"i817":2,"i818":2,"i819":1,"i820":1,"i821":2,"i822":2,"i823":2,"i824":2,"i825":2,"i826":1,"i827":1,"i828":32,"i829":2,"i830":2,"i831":32,"i832":32,"i833":1,"i834":2,"i835":1,"i836":32,"i837":32,"i838":32,"i839":2,"i840":32,"i841":32,"i842":32,"i843":2,"i844":1,"i845":1,"i846":2,"i847":1,"i848":2,"i849":1,"i850":1,"i851":2,"i852":2,"i853":1,"i854":1,"i855":1,"i856":32,"i857":32,"i858":2,"i859":32,"i860":2,"i861":2,"i862":2,"i863":2,"i864":2,"i865":8,"i866":2,"i867":2,"i868":2,"i869":2,"i870":2,"i871":1,"i872":1,"i873":2,"i874":2,"i875":2,"i876":2,"i877":2,"i878":2,"i879":2,"i880":2,"i881":2,"i882":2,"i883":2,"i884":8,"i885":1,"i886":32,"i887":32,"i888":1,"i889":1,"i890":32,"i891":32,"i892":32,"i893":32,"i894":2,"i895":1,"i896":2,"i897":2,"i898":32,"i899":2,"i900":2,"i901":2,"i902":2,"i903":32,"i904":2,"i905":1,"i906":2,"i907":2,"i908":1,"i909":2,"i910":2,"i911":2,"i912":2,"i913":2,"i914":2,"i915":2,"i916":2,"i917":1,"i918":1,"i919":2,"i920":2,"i921":2,"i922":8,"i923":2,"i924":2,"i925":2,"i926":1,"i927":8,"i928":1,"i929":32,"i930":32,"i931":1,"i932":1,"i933":2,"i934":1,"i935":2,"i936":2,"i937":2,"i938":2,"i939":2,"i940":2,"i941":2,"i942":2,"i943":2,"i944":2,"i945":2,"i946":2,"i947":2,"i948":1,"i949":1,"i950":2,"i951":2,"i952":2,"i953":1,"i954":2,"i955":1,"i956":1,"i957":2,"i958":1,"i959":2,"i960":1,"i961":1,"i962":1,"i963":1,"i964":2,"i965":2,"i966":1,"i967":2,"i968":2,"i969":2,"i970":2,"i971":2,"i972":2,"i973":2,"i974":2,"i975":2,"i976":2,"i977":2,"i978":2,"i979":2,"i980":2,"i981":2,"i982":2,"i983":2,"i984":2,"i985":2,"i986":2,"i987":2,"i988":2,"i989":1,"i990":2,"i991":2,"i992":1,"i993":1,"i994":1,"i995":1,"i996":1,"i997":1,"i998":1,"i999":1,"i1000":1,"i1001":2,"i1002":2,"i1003":1,"i1004":2,"i1005":2,"i1006":2,"i1007":2,"i1008":2,"i1009":2,"i1010":2,"i1011":2,"i1012":2,"i1013":1,"i1014":1,"i1015":2,"i1016":2,"i1017":2,"i1018":2,"i1019":2,"i1020":8,"i1021":2,"i1022":2,"i1023":2,"i1024":2,"i1025":2,"i1026":2,"i1027":2,"i1028":2,"i1029":2,"i1030":2,"i1031":2,"i1032":1,"i1033":1,"i1034":1,"i1035":2,"i1036":32,"i1037":2,"i1038":1,"i1039":1,"i1040":8,"i1041":1,"i1042":2,"i1043":2,"i1044":2,"i1045":2,"i1046":32,"i1047":2,"i1048":2,"i1049":2,"i1050":2,"i1051":1,"i1052":2,"i1053":2,"i1054":2,"i1055":2,"i1056":2,"i1057":2,"i1058":2,"i1059":32,"i1060":2,"i1061":32,"i1062":32,"i1063":2,"i1064":1,"i1065":2,"i1066":2,"i1067":1,"i1068":1,"i1069":2,"i1070":2,"i1071":2,"i1072":2,"i1073":2,"i1074":2,"i1075":2,"i1076":1,"i1077":2,"i1078":1,"i1079":2,"i1080":2,"i1081":2,"i1082":2,"i1083":1,"i1084":2,"i1085":2,"i1086":32,"i1087":2,"i1088":2,"i1089":2,"i1090":1,"i1091":1,"i1092":2,"i1093":32,"i1094":1,"i1095":32,"i1096":2,"i1097":2,"i1098":1,"i1099":2,"i1100":2,"i1101":2,"i1102":2,"i1103":2,"i1104":2,"i1105":1,"i1106":2,"i1107":1,"i1108":2,"i1109":1,"i1110":2,"i1111":2,"i1112":2,"i1113":2,"i1114":2,"i1115":1,"i1116":32,"i1117":1,"i1118":2,"i1119":2,"i1120":1,"i1121":32,"i1122":2,"i1123":2,"i1124":32,"i1125":1,"i1126":2,"i1127":2,"i1128":1,"i1129":32,"i1130":2,"i1131":2,"i1132":2,"i1133":2,"i1134":2,"i1135":8,"i1136":32,"i1137":8,"i1138":8,"i1139":32,"i1140":2,"i1141":2,"i1142":2,"i1143":2,"i1144":2,"i1145":2,"i1146":2,"i1147":2,"i1148":1,"i1149":1,"i1150":2,"i1151":1,"i1152":2,"i1153":2,"i1154":2,"i1155":2,"i1156":2,"i1157":2,"i1158":2,"i1159":2,"i1160":2,"i1161":8,"i1162":2,"i1163":2,"i1164":2,"i1165":2,"i1166":2,"i1167":2,"i1168":2,"i1169":32,"i1170":32,"i1171":2,"i1172":2,"i1173":2,"i1174":2,"i1175":2,"i1176":2,"i1177":2,"i1178":2,"i1179":1,"i1180":2}; var tabs = {65535:["t0","All Classes"],1:["t1","Interface Summary"],2:["t2","Class Summary"],8:["t4","Exception Summary"],32:["t6","Annotation Types Summary"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -195,19 +195,19 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.AddMediaItems -

      + Action.ClearMediaItems - + Action.ClearVideoSurface - + @@ -219,7 +219,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.MoveMediaItem - + @@ -238,13 +238,13 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.RemoveMediaItem - + Action.RemoveMediaItems - + @@ -262,19 +262,19 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.SetAudioAttributes - + Action.SetMediaItems - + Action.SetMediaItemsResetPosition - + @@ -299,7 +299,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.SetRepeatMode - + @@ -317,7 +317,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.SetVideoSurface - + @@ -353,27 +353,27 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.WaitForPlaybackState -
      Waits for a specified playback state, returning either immediately or after a call to Player.Listener.onPlaybackStateChanged(int).
      +
      Waits for a specified playback state, returning either immediately or after a call to Player.Listener.onPlaybackStateChanged(int).
      Action.WaitForPlayWhenReady
      Waits for a specified playWhenReady value, returning either immediately or after a call to - Player.Listener.onPlayWhenReadyChanged(boolean, int).
      + Player.Listener.onPlayWhenReadyChanged(boolean, int). Action.WaitForPositionDiscontinuity -
      Waits for Player.Listener.onPositionDiscontinuity(Player.PositionInfo, + Action.WaitForTimelineChanged - + @@ -655,61 +655,61 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); +AssetContentProvider + +
      A ContentProvider for reading asset data.
      + + + AssetDataSource
      A DataSource for reading from a local asset.
      - + AssetDataSource.AssetDataSourceException
      Thrown when an IOException is encountered reading a local asset.
      - + AtomicFile
      A helper class for performing atomic operations on a file by creating a backup file until a write has successfully completed.
      - + AudioAttributes
      Attributes for audio playback, which configure the underlying platform AudioTrack.
      - + AudioAttributes.Builder
      Builder for AudioAttributes.
      - + AudioCapabilities
      Represents the set of audio formats that a device is capable of playing.
      - + AudioCapabilitiesReceiver
      Receives broadcast events indicating changes to the device's audio capabilities, notifying a AudioCapabilitiesReceiver.Listener when audio capability changes occur.
      - + AudioCapabilitiesReceiver.Listener
      Listener notified when audio capabilities change.
      - -AudioListener -Deprecated. - - - AudioProcessor @@ -960,7 +960,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); -BundleableUtils +BundleableUtil
      Utilities for Bundleable.
      @@ -1040,1041 +1040,1089 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); +C.AudioManagerOffloadMode + +
      Playback offload mode.
      + + + C.AudioUsage
      Usage types for audio attributes.
      - + C.BufferFlags
      Flags which can apply to a buffer containing a media sample.
      - + C.ColorRange
      Video color range.
      - + C.ColorSpace
      Video colorspaces.
      - + C.ColorTransfer
      Video color transfer characteristics.
      - + C.ContentType
      Represents a streaming or other media type.
      - + C.CryptoMode
      Crypto modes for a codec.
      - + +C.CryptoType + +
      Types of crypto implementation.
      + + + C.DataType
      Represents a type of data.
      - + C.Encoding
      Represents an audio encoding, or an invalid or unset value.
      - + C.FormatSupport
      Level of renderer support for a format.
      - + C.NetworkType
      Network connection type.
      - + C.PcmEncoding
      Represents a PCM audio encoding, or an invalid or unset value.
      - + C.Projection
      Video projection types.
      - + C.RoleFlags
      Track role flags.
      - + C.SelectionFlags
      Track selection flags.
      - + +C.SelectionReason + +
      Represents a reason for selection.
      + + + C.StereoMode
      The stereo mode for 360/3D/VR videos.
      - + C.StreamType
      Stream types for an AudioTrack.
      - + +C.TrackType + +
      Represents a type of media track.
      + + + +C.VideoChangeFrameRateStrategy + + + + + C.VideoOutputMode
      Video decoder output modes.
      - + C.VideoScalingMode
      Video scaling modes for MediaCodec-based renderers.
      - + C.WakeMode
      Mode specifying whether the player should hold a WakeLock and a WifiLock.
      - + Cache
      A cache that supports partial caching of resources.
      - + Cache.CacheException
      Thrown when an error is encountered when writing data.
      - + Cache.Listener
      Listener of Cache events.
      - + CacheAsserts
      Assertion methods for Cache.
      - + CacheAsserts.RequestSet
      Defines a set of data requests.
      - + CacheDataSink
      Writes data into a cache.
      - + CacheDataSink.CacheDataSinkException
      Thrown when an IOException is encountered when writing data to the sink.
      - + CacheDataSink.Factory - -CacheDataSinkFactory -Deprecated. - - - - + CacheDataSource
      A DataSource that reads and writes a Cache.
      - + CacheDataSource.CacheIgnoredReason
      Reasons the cache may be ignored.
      - + CacheDataSource.EventListener
      Listener of CacheDataSource events.
      - + CacheDataSource.Factory - + CacheDataSource.Flags
      Flags controlling the CacheDataSource's behavior.
      - -CacheDataSourceFactory -Deprecated. - - - - -CachedRegionTracker + +CachedRegionTracker
      Utility class for efficiently tracking regions of data that are stored in a Cache for a given cache key.
      - + CacheEvictor
      Evicts data from a Cache.
      - + CacheKeyFactory
      Factory for cache keys.
      - + CacheSpan
      Defines a span of data that may or may not be cached (as indicated by CacheSpan.isCached).
      - + CacheWriter
      Caching related utility methods.
      - + CacheWriter.ProgressListener
      Receives progress updates during cache operations.
      - + CameraMotionListener
      Listens camera motion.
      - + CameraMotionRenderer
      A Renderer that parses the camera motion track.
      - + CaptionStyleCompat
      A compatibility wrapper for CaptioningManager.CaptionStyle.
      - + CaptionStyleCompat.EdgeType
      The type of edge, which may be none.
      - + CapturingAudioSink
      A ForwardingAudioSink that captures configuration, discontinuity and buffer events.
      - + CapturingRenderersFactory
      A RenderersFactory that captures interactions with the audio and video MediaCodecAdapter instances.
      - + CastPlayer
      Player implementation that communicates with a Cast receiver app.
      - + Cea608Decoder
      A SubtitleDecoder for CEA-608 (also known as "line 21 captions" and "EIA-608").
      - + Cea708Decoder
      A SubtitleDecoder for CEA-708 (also known as "EIA-708").
      - + CeaUtil
      Utility methods for handling CEA-608/708 messages.
      - + ChapterFrame
      Chapter information ID3 frame.
      - + ChapterTocFrame
      Chapter table of contents ID3 frame.
      - + Chunk
      An abstract base class for Loader.Loadable implementations that load chunks of data required for the playback of streams.
      - + ChunkExtractor
      Extracts samples and track Formats from chunks.
      - + ChunkExtractor.Factory
      Creates ChunkExtractor instances.
      - + ChunkExtractor.TrackOutputProvider
      Provides TrackOutput instances to be written to during extraction.
      - + ChunkHolder
      Holds a chunk or an indication that the end of the stream has been reached.
      - + ChunkIndex
      Defines chunks of samples within a media stream.
      - + ChunkSampleStream<T extends ChunkSource>
      A SampleStream that loads media in Chunks, obtained from a ChunkSource.
      - + ChunkSampleStream.ReleaseCallback<T extends ChunkSource>
      A callback to be notified when a sample stream has finished being released.
      - + ChunkSource
      A provider of Chunks for a ChunkSampleStream to load.
      - + ClippingMediaPeriod
      Wraps a MediaPeriod and clips its SampleStreams to provide a subsequence of their samples.
      - + ClippingMediaSource
      MediaSource that wraps a source and clips its timeline based on specified start/end positions.
      - + ClippingMediaSource.IllegalClippingException
      Thrown when a ClippingMediaSource cannot clip its wrapped source.
      - + ClippingMediaSource.IllegalClippingException.Reason
      The reason clipping failed.
      - + Clock
      An interface through which system clocks can be read and HandlerWrappers created.
      - + CodecSpecificDataUtil
      Provides utilities for handling various types of codec-specific data.
      - + ColorInfo
      Stores color info.
      - + ColorParser
      Parser for color expressions found in styling formats, e.g.
      - + CommentFrame
      Comment ID3 frame.
      - + CompositeMediaSource<T>
      Composite MediaSource consisting of multiple child sources.
      - + CompositeSequenceableLoader
      A SequenceableLoader that encapsulates multiple other SequenceableLoaders.
      - + CompositeSequenceableLoaderFactory
      A factory to create composite SequenceableLoaders.
      - + ConcatenatingMediaSource
      Concatenates multiple MediaSources.
      - + ConditionVariable
      An interruptible condition variable.
      - + ConstantBitrateSeekMap
      A SeekMap implementation that assumes the stream has a constant bitrate and consists of multiple independent frames of the same size.
      - + Consumer<T>
      Represents an operation that accepts a single input argument and returns no result.
      - + ContainerMediaChunk
      A BaseMediaChunk that uses an Extractor to decode sample data.
      - + ContentDataSource
      A DataSource for reading from a content URI.
      - + ContentDataSource.ContentDataSourceException
      Thrown when an IOException is encountered reading from a content URI.
      - + ContentMetadata
      Interface for an immutable snapshot of keyed metadata.
      - + ContentMetadataMutations
      Defines multiple mutations on metadata value which are applied atomically.
      - -ControlDispatcher -Deprecated. -
      Use a ForwardingPlayer or configure the player to customize operations.
      - - - + CopyOnWriteMultiset<E>
      An unordered collection of elements that allows duplicates, but also allows access to a set of unique elements.
      - + CronetDataSource
      DataSource without intermediate buffer based on Cronet API set using UrlRequest.
      - + CronetDataSource.Factory - + CronetDataSource.OpenException
      Thrown when an error is encountered when trying to open a CronetDataSource.
      - + CronetDataSourceFactory Deprecated. - + CronetEngineWrapper Deprecated.
      Use CronetEngine directly.
      - + CronetUtil
      Cronet utility methods.
      - -CryptoInfo + +CryptoConfig -
      Compatibility wrapper for MediaCodec.CryptoInfo.
      +
      Configuration for a decoder to allow it to decode encrypted media data.
      - + +CryptoException + +
      Thrown when a non-platform component fails to decrypt data.
      + + + +CryptoInfo + +
      Metadata describing the structure of an encrypted input sample.
      + + + Cue
      Contains information about a specific cue, including textual content and formatting data.
      - + Cue.AnchorType
      The type of anchor, which may be unset.
      - + Cue.Builder
      A builder for Cue objects.
      - + Cue.LineType
      The type of line, which may be unset.
      - + Cue.TextSizeType
      The type of default text size for this cue, which may be unset.
      - + Cue.VerticalType
      The type of vertical layout for this cue, which may be unset (i.e.
      - + +CueDecoder + +
      Decodes data encoded by CueEncoder.
      + + + +CueEncoder + +
      Encodes data that can be decoded by CueDecoder.
      + + + DashChunkSource
      A ChunkSource for DASH streams.
      - + DashChunkSource.Factory
      Factory for DashChunkSources.
      - + DashDownloader
      A downloader for DASH streams.
      - + DashManifest
      Represents a DASH media presentation description (mpd), as defined by ISO/IEC 23009-1:2014 Section 5.3.1.2.
      - + DashManifestParser
      A parser of media presentation description files.
      - + DashManifestParser.RepresentationInfo
      A parsed Representation element.
      - + DashManifestStaleException
      Thrown when a live playback's manifest is stale and a new manifest could not be loaded.
      - + DashMediaSource
      A DASH MediaSource.
      - + DashMediaSource.Factory
      Factory for DashMediaSources.
      - + DashSegmentIndex
      Indexes the segments within a media stream.
      - + DashUtil
      Utility methods for DASH streams.
      - + DashWrappingSegmentIndex
      An implementation of DashSegmentIndex that wraps a ChunkIndex parsed from a media stream.
      - + DatabaseIOException
      An IOException whose cause is an SQLException.
      - + DatabaseProvider -
      Provides SQLiteDatabase instances to ExoPlayer components, which may read and write +
      Provides SQLiteDatabase instances to media library components, which may read and write tables prefixed with DatabaseProvider.TABLE_PREFIX.
      - + DataChunk
      A base class for Chunk implementations where the data should be loaded into a byte[] before being consumed.
      - + DataReader
      Reads bytes from a data stream.
      - + DataSchemeDataSource
      A DataSource for reading data URLs, as defined by RFC 2397.
      - + DataSink
      A component to which streams of data can be written.
      - + DataSink.Factory
      A factory for DataSink instances.
      - + DataSource
      Reads data from URI-identified resources.
      - + DataSource.Factory
      A factory for DataSource instances.
      - + DataSourceContractTest
      A collection of contract tests for DataSource implementations.
      - + DataSourceContractTest.FakeTransferListener
      A TransferListener that only keeps track of the transferred bytes.
      - + DataSourceContractTest.TestResource
      Information about a resource that can be used to test the DataSource instance.
      - + DataSourceContractTest.TestResource.Builder - + DataSourceException
      Used to specify reason of a DataSource error.
      - + DataSourceInputStream
      Allows data corresponding to a given DataSpec to be read from a DataSource and consumed through an InputStream.
      - + +DataSourceUtil + +
      Utility methods for DataSource.
      + + + DataSpec
      Defines a region of data in a resource.
      - + DataSpec.Builder
      Builds DataSpec instances.
      - + DataSpec.Flags
      The flags that apply to any request for data.
      - + DataSpec.HttpMethod
      HTTP methods supported by ExoPlayer HttpDataSources.
      - + DebugTextViewHelper
      A helper class for periodically updating a TextView with debug information obtained from - a SimpleExoPlayer.
      + an ExoPlayer.
      - + Decoder<I,​O,​E extends DecoderException>
      A media decoder.
      - -DecoderAudioRenderer<T extends Decoder<DecoderInputBuffer,​? extends SimpleOutputBuffer,​? extends DecoderException>> + +DecoderAudioRenderer<T extends Decoder<DecoderInputBuffer,​? extends SimpleDecoderOutputBuffer,​? extends DecoderException>>
      Decodes and renders audio using a Decoder.
      - + DecoderCounters
      Maintains decoder event counts, for debugging purposes only.
      - + DecoderCountersUtil
      Assertions for DecoderCounters.
      - + DecoderException
      Thrown when a Decoder error occurs.
      - + DecoderInputBuffer
      Holds input for a decoder.
      - + DecoderInputBuffer.BufferReplacementMode
      The buffer replacement mode.
      - + DecoderInputBuffer.InsufficientCapacityException
      Thrown when an attempt is made to write into a DecoderInputBuffer whose DecoderInputBuffer.bufferReplacementMode is DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED and who DecoderInputBuffer.data capacity is smaller than required.
      - + +DecoderOutputBuffer + +
      Output buffer decoded by a Decoder.
      + + + +DecoderOutputBuffer.Owner<S extends DecoderOutputBuffer> + +
      Buffer owner.
      + + + DecoderReuseEvaluation
      The result of an evaluation to determine whether a decoder can be reused for a new input format.
      - + DecoderReuseEvaluation.DecoderDiscardReasons
      Possible reasons why reuse is not possible.
      - + DecoderReuseEvaluation.DecoderReuseResult
      Possible outcomes of the evaluation.
      - + DecoderVideoRenderer
      Decodes and renders video using a Decoder.
      - -DecryptionException - -
      Thrown when a non-platform component fails to decrypt data.
      - - - + DefaultAllocator
      Default implementation of Allocator.
      - + DefaultAudioSink
      Plays audio data.
      - + DefaultAudioSink.AudioProcessorChain
      Provides a chain of audio processors, which are used for any user-defined processing and applying playback parameters (if supported).
      - + DefaultAudioSink.DefaultAudioProcessorChain
      The default audio processor chain, which applies a (possibly empty) chain of user-defined audio processors followed by SilenceSkippingAudioProcessor and SonicAudioProcessor.
      - + DefaultAudioSink.InvalidAudioTrackTimestampException
      Thrown when the audio track has provided a spurious timestamp, if DefaultAudioSink.failOnSpuriousAudioTimestamp is set.
      - + DefaultAudioSink.OffloadMode
      Audio offload mode configuration.
      - + DefaultBandwidthMeter
      Estimates bandwidth by listening to data transfers.
      - + DefaultBandwidthMeter.Builder
      Builder for a bandwidth meter.
      - + DefaultCastOptionsProvider
      A convenience OptionsProvider to target the default cast receiver app.
      - + DefaultCompositeSequenceableLoaderFactory
      Default implementation of CompositeSequenceableLoaderFactory.
      - + DefaultContentMetadata
      Default implementation of ContentMetadata.
      - -DefaultControlDispatcher -Deprecated. -
      Use a ForwardingPlayer or configure the player to customize operations.
      - - - + DefaultDashChunkSource
      A default DashChunkSource implementation.
      - + DefaultDashChunkSource.Factory   - + DefaultDashChunkSource.RepresentationHolder
      Holds information about a snapshot of a single Representation.
      - + DefaultDashChunkSource.RepresentationSegmentIterator - + DefaultDatabaseProvider
      A DatabaseProvider that provides instances obtained from a SQLiteOpenHelper.
      - + DefaultDataSource
      A DataSource that supports multiple URI schemes.
      - -DefaultDataSourceFactory + +DefaultDataSource.Factory -
      A DataSource.Factory that produces DefaultDataSource instances that delegate to DefaultHttpDataSources for non-file/asset/content URIs.
      + - + +DefaultDataSourceFactory +Deprecated. + + + + DefaultDownloaderFactory
      Default DownloaderFactory, supporting creation of progressive, DASH, HLS and SmoothStreaming downloaders.
      - + DefaultDownloadIndex
      A DownloadIndex that uses SQLite to persist Downloads.
      - + DefaultDrmSessionManager
      A DrmSessionManager that supports playbacks using ExoMediaDrm.
      - + DefaultDrmSessionManager.Builder
      Builder for DefaultDrmSessionManager instances.
      - + DefaultDrmSessionManager.MissingSchemeDataException - + DefaultDrmSessionManager.Mode
      Determines the action to be done after a session acquired.
      - + DefaultDrmSessionManagerProvider
      Default implementation of DrmSessionManagerProvider.
      - + DefaultExtractorInput
      An ExtractorInput that wraps a DataReader.
      - + DefaultExtractorsFactory
      An ExtractorsFactory that provides an array of extractors for the following formats: @@ -2099,1745 +2147,1760 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); com.google.android.exoplayer2.ext.flac.FlacExtractor is used.
      - + DefaultHlsDataSourceFactory
      Default implementation of HlsDataSourceFactory.
      - + DefaultHlsExtractorFactory
      Default HlsExtractorFactory implementation.
      - + DefaultHlsPlaylistParserFactory
      Default implementation for HlsPlaylistParserFactory.
      - + DefaultHlsPlaylistTracker
      Default implementation for HlsPlaylistTracker.
      - + DefaultHttpDataSource
      An HttpDataSource that uses Android's HttpURLConnection.
      - + DefaultHttpDataSource.Factory - -DefaultHttpDataSourceFactory -Deprecated. - - - - + DefaultLivePlaybackSpeedControl
      A LivePlaybackSpeedControl that adjusts the playback speed using a proportional controller.
      - + DefaultLivePlaybackSpeedControl.Builder - + DefaultLoadControl
      The default LoadControl implementation.
      - + DefaultLoadControl.Builder
      Builder for DefaultLoadControl.
      - + DefaultLoadErrorHandlingPolicy
      Default implementation of LoadErrorHandlingPolicy.
      - + +DefaultMediaCodecAdapterFactory + + + + + DefaultMediaDescriptionAdapter - + DefaultMediaItemConverter
      Default MediaItemConverter implementation.
      - + DefaultMediaItemConverter
      Default implementation of MediaItemConverter.
      - + DefaultMediaSourceFactory
      The default MediaSourceFactory implementation.
      - + DefaultMediaSourceFactory.AdsLoaderProvider -
      Provides AdsLoader instances for media items that have ad tag URIs.
      +
      Provides AdsLoader instances for media items that have ad tag URIs.
      - + DefaultPlaybackSessionManager
      Default PlaybackSessionManager which instantiates a new session for each window in the timeline and also for each ad within the windows.
      - + DefaultRenderersFactory
      Default RenderersFactory implementation.
      - + DefaultRenderersFactory.ExtensionRendererMode
      Modes for using extension renderers.
      - + DefaultRenderersFactoryAsserts
      Assertions for DefaultRenderersFactory.
      - + DefaultRtpPayloadReaderFactory
      Default RtpPayloadReader.Factory implementation.
      - + DefaultSsChunkSource
      A default SsChunkSource implementation.
      - + DefaultSsChunkSource.Factory   - + DefaultTimeBar
      A time bar that shows a current position, buffered position, duration and ad markers.
      - + DefaultTrackNameProvider - + DefaultTrackSelector
      A default TrackSelector suitable for most use cases.
      - + DefaultTrackSelector.AudioTrackScore
      Represents how well an audio track matches the selection DefaultTrackSelector.Parameters.
      - + DefaultTrackSelector.OtherTrackScore
      Represents how well any other track (non video, audio or text) matches the selection DefaultTrackSelector.Parameters.
      - + DefaultTrackSelector.Parameters
      Extends DefaultTrackSelector.Parameters by adding fields that are specific to DefaultTrackSelector.
      - + DefaultTrackSelector.ParametersBuilder - + DefaultTrackSelector.SelectionOverride
      A track selection override.
      - + DefaultTrackSelector.TextTrackScore
      Represents how well a text track matches the selection DefaultTrackSelector.Parameters.
      - + DefaultTrackSelector.VideoTrackScore
      Represents how well a video track matches the selection DefaultTrackSelector.Parameters.
      - + DefaultTsPayloadReaderFactory
      Default TsPayloadReader.Factory implementation.
      - + DefaultTsPayloadReaderFactory.Flags
      Flags controlling elementary stream readers' behavior.
      - + Descriptor
      A descriptor, as defined by ISO 23009-1, 2nd edition, 5.8.2.
      - -DeviceInfo + +DeviceInfo
      Information about the playback device.
      - -DeviceInfo.PlaybackType + +DeviceInfo.PlaybackType
      Types of playback.
      - -DeviceListener -Deprecated. - - - - + DolbyVisionConfig
      Dolby Vision configuration data.
      - + Download
      Represents state of a download.
      - + Download.FailureReason
      Failure reasons.
      - + Download.State
      Download states.
      - + DownloadBuilder
      Builder for Download.
      - + DownloadCursor
      Provides random read-write access to the result set returned by a database query.
      - + Downloader
      Downloads and removes a piece of content.
      - + Downloader.ProgressListener
      Receives progress updates during download operations.
      - + DownloaderFactory
      Creates Downloaders for given DownloadRequests.
      - + DownloadException
      Thrown on an error during downloading.
      - + DownloadHelper
      A helper for initializing and removing downloads.
      - + DownloadHelper.Callback
      A callback to be notified when the DownloadHelper is prepared.
      - + DownloadHelper.LiveContentUnsupportedException
      Thrown at an attempt to download live content.
      - + DownloadIndex
      An index of Downloads.
      - + DownloadManager
      Manages downloads.
      - + DownloadManager.Listener
      Listener for DownloadManager events.
      - + DownloadNotificationHelper
      Helper for creating download notifications.
      - + DownloadProgress
      Mutable Download progress.
      - + DownloadRequest
      Defines content to be downloaded.
      - + DownloadRequest.Builder
      A builder for download requests.
      - + DownloadRequest.UnsupportedRequestException
      Thrown when the encoded request data belongs to an unsupported request type.
      - + DownloadService
      A Service for downloading media.
      - + DrmInitData
      Initialization data for one or more DRM schemes.
      - + DrmInitData.SchemeData
      Scheme initialization data.
      - + DrmSession
      A DRM session.
      - + DrmSession.DrmSessionException
      Wraps the throwable which is the cause of the error state.
      - + DrmSession.State
      The state of the DRM session.
      - + DrmSessionEventListener
      Listener of DrmSessionManager events.
      - + DrmSessionEventListener.EventDispatcher
      Dispatches events to DrmSessionEventListeners.
      - + DrmSessionManager
      Manages a DRM session.
      - + DrmSessionManager.DrmSessionReference
      Represents a single reference count of a DrmSession, while deliberately not giving access to the underlying session.
      - + DrmSessionManagerProvider
      A provider to obtain a DrmSessionManager suitable for playing the content described by a MediaItem.
      - + DrmUtil
      DRM-related utility methods.
      - + DrmUtil.ErrorSource
      Identifies the operation which caused a DRM-related error.
      - + DtsReader
      Parses a continuous DTS byte stream and extracts individual samples.
      - + DtsUtil
      Utility methods for parsing DTS frames.
      - + DummyDataSource
      A DataSource which provides no data.
      - + DummyExoMediaDrm
      An ExoMediaDrm that does not support any protection schemes.
      - + DummyExtractorOutput
      A fake ExtractorOutput implementation.
      - + DummyMainThread
      Helper class to simulate main/UI thread in tests.
      - + DummyMainThread.TestRunnable
      Runnable variant which can throw a checked exception.
      - + DummySurface
      A dummy Surface.
      - + DummyTrackOutput
      A fake TrackOutput implementation.
      - + DumpableFormat
      Wraps a Format to allow dumping it.
      - + Dumper
      Helper utility to dump field values.
      - + Dumper.Dumpable
      Provides custom dump method.
      - + DumpFileAsserts
      Helper class to enable assertions based on golden-data dump files.
      - + DvbDecoder
      A SimpleSubtitleDecoder for DVB subtitles.
      - + DvbSubtitleReader
      Parses DVB subtitle data and extracts individual frames.
      - + EbmlProcessor
      Defines EBML element IDs/types and processes events.
      - + EbmlProcessor.ElementType
      EBML element types.
      - + EGLSurfaceTexture
      Generates a SurfaceTexture using EGL/GLES functions.
      - + EGLSurfaceTexture.GlException
      A runtime exception to be thrown if some EGL operations failed.
      - + EGLSurfaceTexture.SecureMode
      Secure mode to be used by the EGL surface and context.
      - + EGLSurfaceTexture.TextureImageListener
      Listener to be called when the texture image on SurfaceTexture has been updated.
      - + ElementaryStreamReader
      Extracts individual samples from an elementary media stream, preserving original order.
      - + EmptySampleStream
      An empty SampleStream.
      - + ErrorMessageProvider<T extends Throwable>
      Converts throwables into error codes and user readable error messages.
      - + ErrorStateDrmSession
      A DrmSession that's in a terminal error state.
      - + EventLogger
      Logs events from Player and other core components using Log.
      - + EventMessage
      An Event Message (emsg) as defined in ISO 23009-1.
      - + EventMessageDecoder
      Decodes data encoded by EventMessageEncoder.
      - + EventMessageEncoder
      Encodes data that can be decoded by EventMessageDecoder.
      - + EventStream
      A DASH in-MPD EventStream element, as defined by ISO/IEC 23009-1, 2nd edition, section 5.10.
      - + ExoDatabaseProvider - -
      An SQLiteOpenHelper that provides instances of a standalone ExoPlayer database.
      +Deprecated. + - + ExoHostedTest
      A HostActivity.HostedTest for ExoPlayer playback tests.
      - -ExoMediaCrypto - -
      Enables decoding of encrypted data using keys in a DRM session.
      - - - + ExoMediaDrm
      Used to obtain keys for decrypting protected media streams.
      - + ExoMediaDrm.AppManagedProvider
      Provides an ExoMediaDrm instance owned by the app.
      - + ExoMediaDrm.KeyRequest
      Contains data used to request keys from a license server.
      - + ExoMediaDrm.KeyRequest.RequestType
      Key request types.
      - + ExoMediaDrm.KeyStatus
      Defines the status of a key.
      - + ExoMediaDrm.OnEventListener
      Called when a DRM event occurs.
      - + ExoMediaDrm.OnExpirationUpdateListener
      Called when a session expiration update occurs.
      - + ExoMediaDrm.OnKeyStatusChangeListener
      Called when the keys in a DRM session change state.
      - + ExoMediaDrm.Provider
      Provider for ExoMediaDrm instances.
      - + ExoMediaDrm.ProvisionRequest
      Contains data to request a certificate from a provisioning server.
      - + ExoPlaybackException
      Thrown when a non locally recoverable playback failure occurs.
      - + ExoPlaybackException.Type
      The type of source that produced the error.
      - + ExoPlayer
      An extensible media player that plays MediaSources.
      - + ExoPlayer.AudioComponent - -
      The audio component of an ExoPlayer.
      +Deprecated. +
      Use ExoPlayer, as the ExoPlayer.AudioComponent methods are defined by that + interface.
      - + ExoPlayer.AudioOffloadListener
      A listener for audio offload events.
      - + ExoPlayer.Builder -Deprecated. - + +
      A builder for ExoPlayer instances.
      - + ExoPlayer.DeviceComponent - -
      The device component of an ExoPlayer.
      +Deprecated. +
      Use Player, as the ExoPlayer.DeviceComponent methods are defined by that + interface.
      - -ExoPlayer.MetadataComponent - -
      The metadata component of an ExoPlayer.
      - - - + ExoPlayer.TextComponent - -
      The text component of an ExoPlayer.
      +Deprecated. +
      Use Player, as the ExoPlayer.TextComponent methods are defined by that + interface.
      - + ExoPlayer.VideoComponent - -
      The video component of an ExoPlayer.
      +Deprecated. +
      Use ExoPlayer, as the ExoPlayer.VideoComponent methods are defined by that + interface.
      - + +ExoplayerCuesDecoder + +
      A SubtitleDecoder that decodes subtitle samples of type MimeTypes.TEXT_EXOPLAYER_CUES
      + + + ExoPlayerLibraryInfo -
      Information about the ExoPlayer library.
      +
      Information about the media libraries.
      - + ExoPlayerTestRunner
      Helper class to run an ExoPlayer test.
      - + ExoPlayerTestRunner.Builder -
      Builder to set-up a ExoPlayerTestRunner.
      +
      Builder to set-up an ExoPlayerTestRunner.
      - + ExoTimeoutException
      A timeout of an operation on the ExoPlayer playback thread.
      - + ExoTimeoutException.TimeoutOperation
      The operation which produced the timeout error.
      - + ExoTrackSelection - + ExoTrackSelection.Definition
      Contains of a subset of selected tracks belonging to a TrackGroup.
      - + ExoTrackSelection.Factory
      Factory for ExoTrackSelection instances.
      - + Extractor
      Extracts media data from a container format.
      - + Extractor.ReadResult
      Result values that can be returned by Extractor.read(ExtractorInput, PositionHolder).
      - + ExtractorAsserts
      Assertion methods for Extractor.
      - + ExtractorAsserts.AssertionConfig
      A config for the assertions made (e.g.
      - + ExtractorAsserts.AssertionConfig.Builder
      Builder for ExtractorAsserts.AssertionConfig instances.
      - + ExtractorAsserts.ExtractorFactory
      A factory for Extractor instances.
      - + ExtractorAsserts.SimulationConfig
      A config of different environments to simulate and extractor behaviours to test.
      - + ExtractorInput
      Provides data to be consumed by an Extractor.
      - + ExtractorOutput
      Receives stream level data extracted by an Extractor.
      - + ExtractorsFactory
      Factory for arrays of Extractor instances.
      - + ExtractorUtil
      Extractor related utility methods.
      - + FailOnCloseDataSink
      A DataSink that can simulate caching the bytes being written to it, and then failing to persist them when FailOnCloseDataSink.close() is called.
      - + FailOnCloseDataSink.Factory
      Factory to create a FailOnCloseDataSink.
      - + FakeAdaptiveDataSet
      Fake data set emulating the data of an adaptive media source.
      - + FakeAdaptiveDataSet.Factory
      Factory for FakeAdaptiveDataSets.
      - + FakeAdaptiveDataSet.Iterator
      MediaChunkIterator for the chunks defined by a fake adaptive data set.
      - + FakeAdaptiveMediaPeriod
      Fake MediaPeriod that provides tracks from the given TrackGroupArray.
      - + FakeAdaptiveMediaSource
      Fake MediaSource that provides a given timeline.
      - + FakeAudioRenderer - + FakeChunkSource
      Fake ChunkSource with adaptive media chunks of a given duration.
      - + FakeChunkSource.Factory
      Factory for a FakeChunkSource.
      - + FakeClock
      Fake Clock implementation that allows to advance the time manually to trigger pending timed messages.
      - + +FakeCryptoConfig + + + + + FakeDataSet
      Collection of FakeDataSet.FakeData to be served by a FakeDataSource.
      - + FakeDataSet.FakeData
      Container of fake data to be served by a FakeDataSource.
      - + FakeDataSet.FakeData.Segment
      A segment of FakeDataSet.FakeData.
      - + FakeDataSource
      A fake DataSource capable of simulating various scenarios.
      - + FakeDataSource.Factory
      Factory to create a FakeDataSource.
      - + FakeExoMediaDrm
      A fake implementation of ExoMediaDrm for use in tests.
      - + FakeExoMediaDrm.Builder
      Builder for FakeExoMediaDrm instances.
      - + FakeExoMediaDrm.LicenseServer
      An license server implementation to interact with FakeExoMediaDrm.
      - + FakeExtractorInput
      A fake ExtractorInput capable of simulating various scenarios.
      - + FakeExtractorInput.Builder
      Builder of FakeExtractorInput instances.
      - + FakeExtractorInput.SimulatedIOException
      Thrown when simulating an IOException.
      - + FakeExtractorOutput - + FakeMediaChunk - + FakeMediaChunkIterator - + FakeMediaClockRenderer
      Fake abstract Renderer which is also a MediaClock.
      - + FakeMediaPeriod
      Fake MediaPeriod that provides tracks from the given TrackGroupArray.
      - + FakeMediaPeriod.TrackDataFactory
      A factory to create the test data for a particular track.
      - + FakeMediaSource
      Fake MediaSource that provides a given timeline.
      - + FakeMediaSource.InitialTimeline
      A forwarding timeline to provide an initial timeline for fake multi window sources.
      - + +FakeMediaSourceFactory + +
      Fake MediaSourceFactory that creates a FakeMediaSource.
      + + + +FakeMetadataEntry + + + + + FakeRenderer
      Fake Renderer that supports any format with the matching track type.
      - + FakeSampleStream
      Fake SampleStream that outputs a given Format and any amount of items.
      - + FakeSampleStream.FakeSampleStreamItem - + FakeShuffleOrder
      Fake ShuffleOrder which returns a reverse order.
      - + FakeTimeline
      Fake Timeline which can be setup to return custom FakeTimeline.TimelineWindowDefinitions.
      - + FakeTimeline.TimelineWindowDefinition
      Definition used to define a FakeTimeline.
      - + FakeTrackOutput
      A fake TrackOutput.
      - + FakeTrackOutput.Factory
      Factory for FakeTrackOutput instances.
      - + FakeTrackSelection
      A fake ExoTrackSelection that only returns 1 fixed track, and allows querying the number of calls to its methods.
      - + FakeTrackSelector - + FakeVideoRenderer - + FfmpegAudioRenderer
      Decodes and renders audio using FFmpeg.
      - + FfmpegDecoderException
      Thrown when an FFmpeg decoder error occurs.
      - + FfmpegLibrary
      Configures and queries the underlying native library.
      - + FileDataSource
      A DataSource for reading local files.
      - + FileDataSource.Factory - + FileDataSource.FileDataSourceException
      Thrown when a FileDataSource encounters an error reading a file.
      - -FileDataSourceFactory -Deprecated. - - - - + FileTypes
      Defines common file type constants and helper methods.
      - + FileTypes.Type
      File types.
      - + FilterableManifest<T>
      A manifest that can generate copies of itself including only the streams specified by the given keys.
      - + FilteringHlsPlaylistParserFactory
      A HlsPlaylistParserFactory that includes only the streams identified by the given stream keys.
      - + FilteringManifestParser<T extends FilterableManifest<T>>
      A manifest parser that includes only the streams identified by the given stream keys.
      - + FixedTrackSelection
      A TrackSelection consisting of a single track.
      - -FlacConstants + +FlacConstants
      Defines constants used by the FLAC extractor.
      - + FlacDecoder
      Flac decoder.
      - + FlacDecoderException
      Thrown when an Flac decoder error occurs.
      - + FlacExtractor
      Facilitates the extraction of data from the FLAC container format.
      - + FlacExtractor
      Extracts data from FLAC container format.
      - + FlacExtractor.Flags
      Flags controlling the behavior of the extractor.
      - + FlacExtractor.Flags
      Flags controlling the behavior of the extractor.
      - + FlacFrameReader
      Reads and peeks FLAC frame elements according to the FLAC format specification.
      - + FlacFrameReader.SampleNumberHolder
      Holds a sample number.
      - + FlacLibrary
      Configures and queries the underlying native library.
      - + FlacMetadataReader
      Reads and peeks FLAC stream metadata elements according to the FLAC format specification.
      - + FlacMetadataReader.FlacStreamMetadataHolder - + FlacSeekTableSeekMap
      A SeekMap implementation for FLAC streams that contain a seek table.
      - + FlacStreamMetadata
      Holder for FLAC metadata.
      - + FlacStreamMetadata.SeekTable
      A FLAC seek table.
      - + FlagSet
      A set of integer flags.
      - + FlagSet.Builder
      A builder for FlagSet instances.
      - + FlvExtractor
      Extracts data from the FLV container format.
      - + Format
      Represents a media format.
      - + Format.Builder
      Builds Format instances.
      - + FormatHolder
      Holds a Format.
      - + ForwardingAudioSink
      An overridable AudioSink implementation forwarding all methods to another sink.
      - + ForwardingExtractorInput
      An overridable ExtractorInput implementation forwarding all methods to another input.
      - + ForwardingPlayer
      A Player that forwards operations to another Player.
      - + ForwardingTimeline
      An overridable Timeline implementation forwarding all methods to another timeline.
      - + FragmentedMp4Extractor
      Extracts data from the FMP4 container format.
      - + FragmentedMp4Extractor.Flags
      Flags controlling the behavior of the extractor.
      - -FrameworkMediaCrypto + +FrameworkCryptoConfig -
      An ExoMediaCrypto implementation that contains the necessary information to build or - update a framework MediaCrypto.
      + - + FrameworkMediaDrm
      An ExoMediaDrm implementation that wraps the framework MediaDrm.
      - + GaplessInfoHolder
      Holder for gapless playback information.
      - + Gav1Decoder
      Gav1 decoder.
      - + Gav1DecoderException
      Thrown when a libgav1 decoder error occurs.
      - + Gav1Library
      Configures and queries the underlying native library.
      - + GeobFrame
      GEOB (General Encapsulated Object) ID3 frame.
      - + GlUtil
      GL utilities.
      - + GlUtil.Attribute
      GL attribute, which can be attached to a buffer with GlUtil.Attribute.setBuffer(float[], int).
      - + +GlUtil.GlException + +
      Thrown when an OpenGL error occurs and GlUtil.glAssertionsEnabled is true.
      + + + +GlUtil.Program + +
      GL program.
      + + + GlUtil.Uniform
      GL uniform, which can be attached to a sampler using GlUtil.Uniform.setSamplerTexId(int, int).
      - -GvrAudioProcessor -Deprecated. -
      If you still need this component, please contact us by filing an issue on our issue tracker.
      + +GlUtil.UnsupportedEglVersionException + +
      Thrown when the required EGL version is not supported by the device.
      - + H262Reader
      Parses a continuous H262 byte stream and extracts individual frames.
      - + H263Reader
      Parses an ISO/IEC 14496-2 (MPEG-4 Part 2) or ITU-T Recommendation H.263 byte stream and extracts individual frames.
      - + H264Reader
      Parses a continuous H264 byte stream and extracts individual frames.
      - + H265Reader
      Parses a continuous H.265 byte stream and extracts individual frames.
      - + HandlerWrapper
      An interface to call through to a Handler.
      - + HandlerWrapper.Message
      A message obtained from the handler.
      - + HeartRating
      A rating expressed as "heart" or "no heart".
      - + HevcConfig
      HEVC configuration data.
      - + HlsDataSourceFactory
      Creates DataSources for HLS playlists, encryption and media chunks.
      - + HlsDownloader
      A downloader for HLS streams.
      - + HlsExtractorFactory
      Factory for HLS media chunk extractors.
      - + HlsManifest
      Holds a master playlist along with a snapshot of one of its media playlists.
      - + HlsMasterPlaylist
      Represents an HLS master playlist.
      - + HlsMasterPlaylist.Rendition
      A rendition (i.e.
      - + HlsMasterPlaylist.Variant
      A variant (i.e.
      - + HlsMediaChunkExtractor
      Extracts samples and track Formats from HlsMediaChunks.
      - + HlsMediaPeriod
      A MediaPeriod that loads an HLS stream.
      - + HlsMediaPlaylist
      Represents an HLS media playlist.
      - + HlsMediaPlaylist.Part
      A media part.
      - + HlsMediaPlaylist.PlaylistType
      Type of the playlist, as defined by #EXT-X-PLAYLIST-TYPE.
      - + HlsMediaPlaylist.RenditionReport
      A rendition report for an alternative rendition defined in another media playlist.
      - + HlsMediaPlaylist.Segment
      Media segment reference.
      - + HlsMediaPlaylist.SegmentBase
      The base for a HlsMediaPlaylist.Segment or a HlsMediaPlaylist.Part required for playback.
      - + HlsMediaPlaylist.ServerControl
      Server control attributes.
      - + HlsMediaSource
      An HLS MediaSource.
      - + HlsMediaSource.Factory
      Factory for HlsMediaSources.
      - + HlsMediaSource.MetadataType
      The types of metadata that can be extracted from HLS streams.
      - + HlsPlaylist
      Represents an HLS playlist.
      - + HlsPlaylistParser
      HLS playlists parsing logic.
      - + HlsPlaylistParser.DeltaUpdateException
      Exception thrown when merging a delta update fails.
      - + HlsPlaylistParserFactory
      Factory for HlsPlaylist parsers.
      - + HlsPlaylistTracker
      Tracks playlists associated to an HLS stream and provides snapshots.
      - + HlsPlaylistTracker.Factory
      Factory for HlsPlaylistTracker instances.
      - + HlsPlaylistTracker.PlaylistEventListener
      Called on playlist loading events.
      - + HlsPlaylistTracker.PlaylistResetException
      Thrown when the media sequence of a new snapshot indicates the server has reset.
      - + HlsPlaylistTracker.PlaylistStuckException
      Thrown when a playlist is considered to be stuck due to a server side error.
      - + HlsPlaylistTracker.PrimaryPlaylistListener
      Listener for primary playlist changes.
      - + HlsTrackMetadataEntry
      Holds metadata associated to an HLS media track.
      - + HlsTrackMetadataEntry.VariantInfo
      Holds attributes defined in an EXT-X-STREAM-INF tag.
      - + HorizontalTextInVerticalContextSpan
      A styling span for horizontal text in a vertical context.
      - + HostActivity
      A host activity for performing playback tests.
      - + HostActivity.HostedTest
      Interface for tests that run inside of a HostActivity.
      - + HttpDataSource
      An HTTP DataSource.
      - + HttpDataSource.BaseFactory
      Base implementation of HttpDataSource.Factory that sets default request properties.
      - + HttpDataSource.CleartextNotPermittedException
      Thrown when cleartext HTTP traffic is not permitted.
      - + HttpDataSource.Factory
      A factory for HttpDataSource instances.
      - + HttpDataSource.HttpDataSourceException
      Thrown when an error is encountered when trying to read from a HttpDataSource.
      - + HttpDataSource.HttpDataSourceException.Type
      The type of operation that produced the error.
      - + HttpDataSource.InvalidContentTypeException
      Thrown when the content type is invalid.
      - + HttpDataSource.InvalidResponseCodeException
      Thrown when an attempt to open a connection results in a response code not in the 2xx range.
      - + HttpDataSource.RequestProperties
      Stores HTTP request properties (aka HTTP headers) and provides methods to modify the headers in @@ -3845,330 +3908,324 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); state.
      - + HttpDataSourceTestEnv
      A JUnit Rule that creates test resources for HttpDataSource contract tests.
      - + HttpMediaDrmCallback
      A MediaDrmCallback that makes requests using HttpDataSource instances.
      - + HttpUtil
      Utility methods for HTTP.
      - + IcyDecoder
      Decodes ICY stream information.
      - + IcyHeaders
      ICY headers.
      - + IcyInfo
      ICY in-stream information.
      - + Id3Decoder
      Decodes ID3 tags.
      - + Id3Decoder.FramePredicate
      A predicate for determining whether individual frames should be decoded.
      - + Id3Frame
      Base class for ID3 frames.
      - + Id3Peeker
      Peeks data from the beginning of an ExtractorInput to determine if there is any ID3 tag.
      - + Id3Reader
      Parses ID3 data and extracts individual text information frames.
      - + IllegalSeekPositionException
      Thrown when an attempt is made to seek to a position that does not exist in the player's Timeline.
      - + ImaAdsLoader
      AdsLoader using the IMA SDK.
      - + ImaAdsLoader.Builder
      Builder for ImaAdsLoader.
      - + IndexSeekMap
      A SeekMap implementation based on a mapping between times and positions in the input stream.
      - + InitializationChunk
      A Chunk that uses an Extractor to decode initialization data for single track.
      - + InputReaderAdapterV30
      MediaParser.SeekableInputReader implementation wrapping a DataReader.
      - -IntArrayQueue - -
      Array-based unbounded queue for int primitives with amortized O(1) add and remove.
      - - - + InternalFrame
      Internal ID3 frame that is intended for use by the player.
      - + JpegExtractor
      Extracts JPEG image using the Exif format.
      - + KeysExpiredException
      Thrown when the drm keys loaded into an open session expire.
      - + LanguageFeatureSpan
      Marker interface for span classes that carry language features rather than style information.
      - + LatmReader
      Parses and extracts samples from an AAC/LATM elementary stream.
      - + LeanbackPlayerAdapter
      Leanback PlayerAdapter implementation for Player.
      - + LeastRecentlyUsedCacheEvictor
      Evicts least recently used cache files first.
      - + LibflacAudioRenderer
      Decodes and renders audio using the native Flac decoder.
      - + Libgav1VideoRenderer
      Decodes and renders video using libgav1 decoder.
      - + LibopusAudioRenderer
      Decodes and renders audio using the native Opus decoder.
      - + LibraryLoader
      Configurable loader for native libraries.
      - + LibvpxVideoRenderer
      Decodes and renders video using the native VP9 decoder.
      - -ListenerSet<T> + +ListenerSet<T extends @NonNull Object>
      A set of listeners.
      - + ListenerSet.Event<T>
      An event sent to a listener.
      - + ListenerSet.IterationFinishedEvent<T>
      An event sent to a listener when all other events sent during one Looper message queue iteration were handled by the listener.
      - + LivePlaybackSpeedControl
      Controls the playback speed while playing live content in order to maintain a steady target live offset.
      - + LoadControl
      Controls buffering of media.
      - + Loader
      Manages the background loading of Loader.Loadables.
      - + Loader.Callback<T extends Loader.Loadable>
      A callback to be notified of Loader events.
      - + Loader.Loadable
      An object that can be loaded using a Loader.
      - + Loader.LoadErrorAction - + Loader.ReleaseCallback
      A callback to be notified when a Loader has finished being released.
      - + Loader.UnexpectedLoaderException
      Thrown when an unexpected exception or error is encountered during loading.
      - + LoaderErrorThrower
      Conditionally throws errors affecting a Loader.
      - + LoaderErrorThrower.Dummy
      A LoaderErrorThrower that never throws.
      - + LoadErrorHandlingPolicy
      A policy that defines how load errors are handled.
      - + LoadErrorHandlingPolicy.FallbackOptions
      Holds information about the available fallback options.
      - + LoadErrorHandlingPolicy.FallbackSelection
      A selected fallback option.
      - + LoadErrorHandlingPolicy.FallbackType
      Fallback type.
      - + LoadErrorHandlingPolicy.LoadErrorInfo
      Holds information about a load task error.
      - + LoadEventInfo
      MediaSource load event information.
      - + LocalMediaDrmCallback
      A MediaDrmCallback that provides a fixed response to key requests.
      - + Log
      Wrapper around Log which allows to set the log level.
      - + LongArray
      An append-only, auto-growing long[].
      - + LoopingMediaSource Deprecated. -
      To loop a MediaSource indefinitely, use Player.setRepeatMode(int) +
      To loop a MediaSource indefinitely, use Player.setRepeatMode(int) instead of this class.
      - + MappingTrackSelector
      Base class for TrackSelectors that first establish a mapping between TrackGroups @@ -4176,1667 +4233,1708 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); renderer.
      - + MappingTrackSelector.MappedTrackInfo
      Provides mapped track information for each renderer.
      - + MaskingMediaPeriod
      Media period that defers calling MediaSource.createPeriod(MediaPeriodId, Allocator, long) on a given source until MaskingMediaPeriod.createPeriod(MediaPeriodId) has been called.
      - + MaskingMediaPeriod.PrepareListener
      Listener for preparation events.
      - + MaskingMediaSource
      A MediaSource that masks the Timeline with a placeholder until the actual media structure is known.
      - + MaskingMediaSource.PlaceholderTimeline
      A timeline with one dynamic window with a period of indeterminate duration.
      - + MatroskaExtractor
      Extracts data from the Matroska and WebM container formats.
      - + MatroskaExtractor.Flags
      Flags controlling the behavior of the extractor.
      - + MdtaMetadataEntry
      Stores extensible metadata with handler type 'mdta'.
      - + MediaChunk
      An abstract base class for Chunks that contain media samples.
      - + MediaChunkIterator
      Iterator for media chunk sequences.
      - + MediaClock
      Tracks the progression of media time.
      - + MediaCodecAdapter
      Abstracts MediaCodec operations.
      - + MediaCodecAdapter.Configuration
      Configuration parameters for a MediaCodecAdapter.
      - + MediaCodecAdapter.Factory
      A factory for MediaCodecAdapter instances.
      - + MediaCodecAdapter.OnFrameRenderedListener
      Listener to be called when an output frame has rendered on the output surface.
      - + MediaCodecAudioRenderer
      Decodes and renders audio using MediaCodec and an AudioSink.
      - + MediaCodecDecoderException
      Thrown when a failure occurs in a MediaCodec decoder.
      - + MediaCodecInfo
      Information about a MediaCodec for a given mime type.
      - + MediaCodecRenderer
      An abstract renderer that uses MediaCodec to decode samples for rendering.
      - + MediaCodecRenderer.DecoderInitializationException
      Thrown when a failure occurs instantiating a decoder.
      - + MediaCodecSelector
      Selector of MediaCodec instances.
      - + MediaCodecUtil
      A utility class for querying the available codecs.
      - + MediaCodecUtil.DecoderQueryException
      Thrown when an error occurs querying the device for its underlying media capabilities.
      - + MediaCodecVideoDecoderException
      Thrown when a failure occurs in a MediaCodec video decoder.
      - + MediaCodecVideoRenderer
      Decodes and renders video using MediaCodec.
      - + MediaCodecVideoRenderer.CodecMaxValues   - + MediaDrmCallback
      Performs ExoMediaDrm key and provisioning requests.
      - + MediaDrmCallbackException
      Thrown when an error occurs while executing a DRM key or provisioning request.
      - + MediaFormatUtil
      Helper class containing utility methods for managing MediaFormat instances.
      - + MediaItem
      Representation of a media item.
      - + MediaItem.AdsConfiguration
      Configuration for playing back linear ads with a media item.
      - + +MediaItem.AdsConfiguration.Builder + +
      Builder for MediaItem.AdsConfiguration instances.
      + + + MediaItem.Builder
      A builder for MediaItem instances.
      - -MediaItem.ClippingProperties + +MediaItem.ClippingConfiguration
      Optionally clips the media item to a custom start and end position.
      - + +MediaItem.ClippingConfiguration.Builder + +
      Builder for MediaItem.ClippingConfiguration instances.
      + + + +MediaItem.ClippingProperties +Deprecated. + + + + MediaItem.DrmConfiguration
      DRM configuration for a media item.
      - + +MediaItem.DrmConfiguration.Builder + + + + + MediaItem.LiveConfiguration
      Live playback configuration.
      - -MediaItem.PlaybackProperties + +MediaItem.LiveConfiguration.Builder + +
      Builder for MediaItem.LiveConfiguration instances.
      + + + +MediaItem.LocalConfiguration
      Properties for local playback.
      - + +MediaItem.PlaybackProperties +Deprecated. + + + + MediaItem.Subtitle +Deprecated. + + + + +MediaItem.SubtitleConfiguration
      Properties for a text track.
      - + +MediaItem.SubtitleConfiguration.Builder + +
      Builder for MediaItem.SubtitleConfiguration instances.
      + + + MediaItemConverter
      Converts between MediaItem and the Cast SDK's MediaQueueItem.
      - + MediaItemConverter
      Converts between Media2 MediaItem and ExoPlayer MediaItem.
      - + MediaLoadData
      Descriptor for data being loaded or selected by a MediaSource.
      - + MediaMetadata
      Metadata of a MediaItem, playlist, or a combination of multiple sources of Metadata.
      - + MediaMetadata.Builder
      A builder for MediaMetadata instances.
      - + MediaMetadata.FolderType
      The folder type of the media item.
      - + MediaMetadata.PictureType
      The picture type of the artwork.
      - + MediaParserChunkExtractor
      ChunkExtractor implemented on top of the platform's MediaParser.
      - + MediaParserExtractorAdapter
      ProgressiveMediaExtractor implemented on top of the platform's MediaParser.
      - + MediaParserHlsMediaChunkExtractor
      HlsMediaChunkExtractor implemented on top of the platform's MediaParser.
      - + MediaParserUtil
      Miscellaneous constants and utility methods related to the MediaParser integration.
      - + MediaPeriod
      Loads media corresponding to a Timeline.Period, and allows that media to be read.
      - + MediaPeriod.Callback
      A callback to be notified of MediaPeriod events.
      - + MediaPeriodAsserts
      Assertion methods for MediaPeriod.
      - + MediaPeriodAsserts.FilterableManifestMediaPeriodFactory<T extends FilterableManifest<T>>
      Interface to create media periods for testing based on a FilterableManifest.
      - + MediaPeriodId
      Identifies a specific playback of a Timeline.Period.
      - + MediaSessionConnector
      Connects a MediaSessionCompat to a Player.
      - + MediaSessionConnector.CaptionCallback
      Handles requests for enabling or disabling captions.
      - + MediaSessionConnector.CommandReceiver
      Receiver of media commands sent by a media controller.
      - + MediaSessionConnector.CustomActionProvider
      Provides a PlaybackStateCompat.CustomAction to be published and handles the action when sent by a media controller.
      - + MediaSessionConnector.DefaultMediaMetadataProvider
      Provides a default MediaMetadataCompat with properties and extras taken from the MediaDescriptionCompat of the MediaSessionCompat.QueueItem of the active queue item.
      - + MediaSessionConnector.MediaButtonEventHandler
      Handles a media button event.
      - + MediaSessionConnector.MediaMetadataProvider
      Provides a MediaMetadataCompat for a given player state.
      - + MediaSessionConnector.PlaybackActions
      Playback actions supported by the connector.
      - + MediaSessionConnector.PlaybackPreparer
      Interface to which playback preparation and play actions are delegated.
      - + MediaSessionConnector.QueueEditor
      Handles media session queue edits.
      - + MediaSessionConnector.QueueNavigator
      Handles queue navigation actions, and updates the media session queue by calling MediaSessionCompat.setQueue().
      - + MediaSessionConnector.RatingCallback
      Callback receiving a user rating for the active media item.
      - + MediaSource
      Defines and provides media to be played by an ExoPlayer.
      - + MediaSource.MediaPeriodId
      Identifier for a MediaPeriod.
      - + MediaSource.MediaSourceCaller
      A caller of media sources, which will be notified of source events.
      - + MediaSourceEventListener
      Interface for callbacks to be notified of MediaSource events.
      - + MediaSourceEventListener.EventDispatcher
      Dispatches events to MediaSourceEventListeners.
      - + MediaSourceFactory
      Factory for creating MediaSources from MediaItems.
      - + MediaSourceTestRunner
      A runner for MediaSource tests.
      - + MergingMediaSource
      Merges multiple MediaSources.
      - + MergingMediaSource.IllegalMergeException
      Thrown when a MergingMediaSource cannot merge its sources.
      - + MergingMediaSource.IllegalMergeException.Reason
      The reason the merge failed.
      - + Metadata
      A collection of metadata entries.
      - + Metadata.Entry
      A metadata entry.
      - + MetadataDecoder
      Decodes metadata from binary data.
      - + MetadataDecoderFactory
      A factory for MetadataDecoder instances.
      - + MetadataInputBuffer - + MetadataOutput
      Receives metadata output.
      - + MetadataRenderer
      A renderer for metadata.
      - + MetadataRetriever
      Retrieves the static metadata of MediaItems.
      - + MimeTypes
      Defines common MIME types and helper methods.
      - + MlltFrame
      MPEG location lookup table frame.
      - + MotionPhotoMetadata
      Metadata of a motion photo file.
      - + Mp3Extractor
      Extracts data from the MP3 container format.
      - + Mp3Extractor.Flags
      Flags controlling the behavior of the extractor.
      - + Mp4Extractor
      Extracts data from the MP4 container format.
      - + Mp4Extractor.Flags
      Flags controlling the behavior of the extractor.
      - + Mp4WebvttDecoder
      A SimpleSubtitleDecoder for Webvtt embedded in a Mp4 container file.
      - + MpegAudioReader
      Parses a continuous MPEG Audio byte stream and extracts individual frames.
      - + MpegAudioUtil
      Utility methods for handling MPEG audio streams.
      - + MpegAudioUtil.Header
      Stores the metadata for an MPEG audio frame.
      - + NalUnitUtil
      Utility methods for handling H.264/AVC and H.265/HEVC NAL units.
      - + +NalUnitUtil.H265SpsData + +
      Holds data parsed from a H.265 sequence parameter set NAL unit.
      + + + NalUnitUtil.PpsData
      Holds data parsed from a picture parameter set NAL unit.
      - + NalUnitUtil.SpsData -
      Holds data parsed from a sequence parameter set NAL unit.
      +
      Holds data parsed from a H.264 sequence parameter set NAL unit.
      - + NetworkTypeObserver
      Observer for network type changes.
      - + NetworkTypeObserver.Config
      Configuration for NetworkTypeObserver.
      - + NetworkTypeObserver.Listener
      A listener for network type changes.
      - + NonNullApi
      Annotation to declare all type usages in the annotated instance as Nonnull, unless explicitly marked with a nullable annotation.
      - + NoOpCacheEvictor
      Evictor that doesn't ever evict cache files.
      - + NoSampleRenderer
      A Renderer implementation whose track type is C.TRACK_TYPE_NONE and does not consume data from its SampleStream.
      - + NotificationUtil
      Utility methods for displaying Notifications.
      - + NotificationUtil.Importance
      Notification channel importance levels.
      - + NoUidTimeline
      A timeline which wraps another timeline and overrides all window and period uids to 0.
      - + OfflineLicenseHelper
      Helper class to download, renew and release offline licenses.
      - + OggExtractor
      Extracts data from the Ogg container format.
      - + OkHttpDataSource
      An HttpDataSource that delegates to Square's Call.Factory.
      - + OkHttpDataSource.Factory - + OkHttpDataSourceFactory Deprecated. - + OpusDecoder
      Opus decoder.
      - + OpusDecoderException
      Thrown when an Opus decoder error occurs.
      - + OpusLibrary
      Configures and queries the underlying native library.
      - + OpusUtil
      Utility methods for handling Opus audio streams.
      - -OutputBuffer - -
      Output buffer decoded by a Decoder.
      - - - -OutputBuffer.Owner<S extends OutputBuffer> - -
      Buffer owner.
      - - - + OutputConsumerAdapterV30
      MediaParser.OutputConsumer implementation that redirects output to an ExtractorOutput.
      - + ParsableBitArray
      Wraps a byte array, providing methods that allow it to be read as a bitstream.
      - + ParsableByteArray
      Wraps a byte array, providing a set of methods for parsing data from it.
      - + ParsableNalUnitBitArray
      Wraps a byte array, providing methods that allow it to be read as a NAL unit bitstream.
      - + ParserException
      Thrown when an error occurs parsing media data and metadata.
      - + ParsingLoadable<T>
      A Loader.Loadable for objects that can be parsed from binary data using a ParsingLoadable.Parser.
      - + ParsingLoadable.Parser<T>
      Parses an object from loaded data.
      - + PassthroughSectionPayloadReader
      A SectionPayloadReader that directly outputs the section bytes as sample data.
      - + PercentageRating
      A rating expressed as a percentage.
      - + Period
      Encapsulates media content components over a contiguous period of time.
      - + PesReader
      Parses PES packet data and extracts samples.
      - + PgsDecoder
      A SimpleSubtitleDecoder for PGS subtitles.
      - + PictureFrame
      A picture parsed from a FLAC file.
      - + PlatformScheduler
      A Scheduler that uses JobScheduler.
      - + PlatformScheduler.PlatformSchedulerService
      A JobService that starts the target service if the requirements are met.
      - + PlaybackException
      Thrown when a non locally recoverable playback failure occurs.
      - + PlaybackException.ErrorCode
      Codes that identify causes of player errors.
      - + PlaybackException.FieldNumber
      Identifiers for fields in a Bundle which represents a playback exception.
      - + PlaybackOutput
      Class to capture output from a playback test.
      - + PlaybackParameters
      Parameters that apply to playback, including speed setting.
      - + PlaybackSessionManager
      Manager for active playback sessions.
      - + PlaybackSessionManager.Listener
      A listener for session updates.
      - + PlaybackStats
      Statistics about playbacks.
      - + PlaybackStats.EventTimeAndException
      Stores an exception with the event time at which it occurred.
      - + PlaybackStats.EventTimeAndFormat
      Stores a format with the event time at which it started being used, or null to indicate that no format was used.
      - + PlaybackStats.EventTimeAndPlaybackState
      Stores a playback state with the event time at which it became active.
      - + PlaybackStatsListener
      AnalyticsListener to gather PlaybackStats from the player.
      - + PlaybackStatsListener.Callback
      A listener for PlaybackStats updates.
      - + Player
      A media player interface defining traditional high-level functionality, such as the ability to play, pause, seek and query properties of the currently playing media.
      - + Player.Command
      Commands that can be executed on a Player.
      - + Player.Commands
      A set of commands.
      - + Player.Commands.Builder
      A builder for Player.Commands instances.
      - + Player.DiscontinuityReason
      Reasons for position discontinuities.
      - + Player.Event
      Events that can be reported via Player.Listener.onEvents(Player, Events).
      - + Player.EventListener Deprecated. - + Player.Events
      A set of events.
      - + Player.Listener
      Listener of all changes in the Player.
      - + Player.MediaItemTransitionReason
      Reasons for media item transitions.
      - + Player.PlaybackSuppressionReason
      Reason why playback is suppressed even though Player.getPlayWhenReady() is true.
      - + Player.PlayWhenReadyChangeReason
      Reasons for playWhenReady changes.
      - + Player.PositionInfo
      Position info describing a playback position involved in a discontinuity.
      - + Player.RepeatMode
      Repeat modes for playback.
      - + Player.State
      Playback state.
      - + Player.TimelineChangeReason
      Reasons for timeline changes.
      - + PlayerControlView
      A view for controlling Player instances.
      - + PlayerControlView.ProgressUpdateListener
      Listener to be notified when progress has been updated.
      - + PlayerControlView.VisibilityListener
      Listener to be notified about changes of the visibility of the UI control.
      - + PlayerEmsgHandler
      Handles all emsg messages from all media tracks for the player.
      - + PlayerEmsgHandler.PlayerEmsgCallback
      Callbacks for player emsg events encountered during DASH live stream.
      - + PlayerMessage
      Defines a player message which can be sent with a PlayerMessage.Sender and received by a PlayerMessage.Target.
      - + PlayerMessage.Sender
      A sender for messages.
      - + PlayerMessage.Target
      A target for messages.
      - + PlayerNotificationManager
      Starts, updates and cancels a media style notification reflecting the player state.
      - + PlayerNotificationManager.Builder
      A builder for PlayerNotificationManager instances.
      - + PlayerNotificationManager.CustomActionReceiver
      Defines and handles custom actions.
      - + PlayerNotificationManager.MediaDescriptionAdapter
      An adapter to provide content assets of the media currently playing.
      - + PlayerNotificationManager.NotificationListener
      A listener for changes to the notification.
      - + PlayerNotificationManager.Priority
      Priority of the notification (required for API 25 and lower).
      - + PlayerNotificationManager.Visibility
      Visibility of notification on the lock screen.
      - + PlayerView
      A high level view for Player media playbacks.
      - + PlayerView.ShowBuffering
      Determines when the buffering view is shown.
      - + PositionHolder
      Holds a position in the stream.
      - + PriorityDataSource
      A DataSource that can be used as part of a task registered with a PriorityTaskManager.
      - -PriorityDataSourceFactory + +PriorityDataSource.Factory -
      A DataSource.Factory that produces PriorityDataSource instances.
      + - + +PriorityDataSourceFactory +Deprecated. + + + + PriorityTaskManager
      Allows tasks with associated priorities to control how they proceed relative to one another.
      - + PriorityTaskManager.PriorityTooLowException
      Thrown when task attempts to proceed when another registered task has a higher priority.
      - + PrivateCommand
      Represents a private command as defined in SCTE35, Section 9.3.6.
      - + PrivFrame
      PRIV (Private) ID3 frame.
      - + ProgramInformation
      A parsed program information element.
      - + ProgressHolder
      Holds a progress percentage.
      - + ProgressiveDownloader
      A downloader for progressive media streams.
      - + ProgressiveMediaExtractor
      Extracts the contents of a container file from a progressive media stream.
      - + ProgressiveMediaExtractor.Factory
      Creates ProgressiveMediaExtractor instances.
      - + ProgressiveMediaSource
      Provides one period that loads data from a Uri and extracted using an Extractor.
      - + ProgressiveMediaSource.Factory - + PsExtractor
      Extracts data from the MPEG-2 PS container format.
      - + PsshAtomUtil
      Utility methods for handling PSSH atoms.
      - + RandomizedMp3Decoder
      Generates randomized, but correct amount of data on MP3 audio input.
      - + RandomTrackSelection
      An ExoTrackSelection whose selected track is updated randomly.
      - + RandomTrackSelection.Factory
      Factory for RandomTrackSelection instances.
      - + RangedUri
      Defines a range of data located at a reference uri.
      - + Rating
      A rating for media content.
      - + RawCcExtractor
      Extracts data from the RawCC container format.
      - + RawResourceDataSource
      A DataSource for reading a raw resource inside the APK.
      - + RawResourceDataSource.RawResourceDataSourceException
      Thrown when an IOException is encountered reading from a raw resource.
      - + Renderer
      Renders media read from a SampleStream.
      - + +Renderer.MessageType + +
      Represents a type of message that can be passed to a renderer.
      + + + Renderer.State
      The renderer states.
      - -Renderer.VideoScalingMode -Deprecated. - - - - + Renderer.WakeupListener
      Some renderers can signal when Renderer.render(long, long) should be called.
      - + RendererCapabilities
      Defines the capabilities of a Renderer.
      - + RendererCapabilities.AdaptiveSupport
      Level of renderer support for adaptive format switches.
      - + RendererCapabilities.Capabilities
      Combined renderer capabilities.
      - + RendererCapabilities.FormatSupport Deprecated.
      Use C.FormatSupport instead.
      - + RendererCapabilities.TunnelingSupport
      Level of renderer support for tunneling.
      - + RendererConfiguration
      The configuration of a Renderer.
      - + RenderersFactory -
      Builds Renderer instances for use by a SimpleExoPlayer.
      +
      Builds Renderer instances for use by an ExoPlayer.
      - + RepeatModeActionProvider
      Provides a custom action for toggling repeat modes.
      - + RepeatModeUtil
      Util class for repeat mode handling.
      - + RepeatModeUtil.RepeatToggleModes
      Set of repeat toggle modes.
      - + Representation
      A DASH representation.
      - + Representation.MultiSegmentRepresentation
      A DASH representation consisting of multiple segments.
      - + Representation.SingleSegmentRepresentation
      A DASH representation consisting of a single segment.
      - + Requirements
      Defines a set of device state requirements.
      - + Requirements.RequirementFlags
      Requirement flags.
      - + RequirementsWatcher
      Watches whether the Requirements are met and notifies the RequirementsWatcher.Listener on changes.
      - + RequirementsWatcher.Listener
      Notified when RequirementsWatcher instance first created and on changes whether the Requirements are met.
      - + ResolvingDataSource
      DataSource wrapper allowing just-in-time resolution of DataSpecs.
      - + ResolvingDataSource.Factory - + ResolvingDataSource.Resolver
      Resolves DataSpecs.
      - -ReusableBufferedOutputStream - -
      This is a subclass of BufferedOutputStream with a ReusableBufferedOutputStream.reset(OutputStream) method - that allows an instance to be re-used with another underlying output stream.
      - - - + RobolectricUtil
      Utility methods for Robolectric-based tests.
      - + RtmpDataSource
      A Real-Time Messaging Protocol (RTMP) DataSource.
      - + RtmpDataSource.Factory - + RtmpDataSourceFactory Deprecated. - + RtpAc3Reader
      Parses an AC3 byte stream carried on RTP packets, and extracts AC3 frames.
      - + RtpPacket
      Represents the header and the payload of an RTP packet.
      - + RtpPacket.Builder
      Builder class for an RtpPacket
      - + RtpPayloadFormat
      Represents the payload format used in RTP.
      - + RtpPayloadReader
      Extracts media samples from the payload of received RTP packets.
      - + RtpPayloadReader.Factory
      Factory of RtpPayloadReader instances.
      - + RtpUtils
      Utility methods for RTP.
      - + RtspMediaSource
      An Rtsp MediaSource
      - + RtspMediaSource.Factory
      Factory for RtspMediaSource
      - + RtspMediaSource.RtspPlaybackException
      Thrown when an exception or error is encountered during loading an RTSP stream.
      - + RubySpan
      A styling span for ruby text.
      - + RunnableFutureTask<R,​E extends Exception>
      A RunnableFuture that supports additional uninterruptible operations to query whether execution has started and finished.
      - + SampleQueue
      A queue of media samples.
      - + SampleQueue.UpstreamFormatChangedListener
      A listener for changes to the upstream format.
      - + SampleQueueMappingException
      Thrown when it is not possible to map a TrackGroup to a SampleQueue.
      - + SampleStream
      A stream of media samples (and associated format information).
      - + SampleStream.ReadDataResult - + SampleStream.ReadFlags - + Scheduler
      Schedules a service to be started in the foreground when some Requirements are met.
      - + SectionPayloadReader
      Reads section data.
      - + SectionReader
      Reads section data packets and feeds the whole sections to a given SectionPayloadReader.
      - + SeekMap
      Maps seek positions (in microseconds) to corresponding positions (byte offsets) in the stream.
      - + SeekMap.SeekPoints
      Contains one or two SeekPoints.
      - + SeekMap.Unseekable
      A SeekMap that does not support seeking.
      - + SeekParameters
      Parameters that apply to seeking.
      - + SeekPoint
      Defines a seek point in a media stream.
      - + SegmentBase
      An approximate representation of a SegmentBase manifest element.
      - + SegmentBase.MultiSegmentBase
      A SegmentBase that consists of multiple segments.
      - + SegmentBase.SegmentList
      A SegmentBase.MultiSegmentBase that uses a SegmentList to define its segments.
      - + SegmentBase.SegmentTemplate
      A SegmentBase.MultiSegmentBase that uses a SegmentTemplate to define its segments.
      - + SegmentBase.SegmentTimelineElement
      Represents a timeline segment from the MPD's SegmentTimeline list.
      - + SegmentBase.SingleSegmentBase
      A SegmentBase that defines a single segment.
      - + SegmentDownloader<M extends FilterableManifest<M>>
      Base class for multi segment stream downloaders.
      - + SegmentDownloader.Segment
      Smallest unit of content to be downloaded.
      - + SeiReader
      Consumes SEI buffers, outputting contained CEA-608/708 messages to a TrackOutput.
      - + SequenceableLoader
      A loader that can proceed in approximate synchronization with other loaders.
      - + SequenceableLoader.Callback<T extends SequenceableLoader>
      A callback to be notified of SequenceableLoader events.
      - + ServerSideInsertedAdsMediaSource
      A MediaSource for server-side inserted ad breaks.
      - + ServerSideInsertedAdsUtil
      A static utility class with methods to work with server-side inserted ads.
      - + ServiceDescriptionElement
      Represents a service description element.
      - + SessionAvailabilityListener
      Listener of changes in the cast session availability.
      - + SessionCallbackBuilder
      Builds a MediaSession.SessionCallback with various collaborators.
      - + SessionCallbackBuilder.AllowedCommandProvider
      Provides allowed commands for MediaController.
      - + SessionCallbackBuilder.CustomCommandProvider
      Callbacks for querying what custom commands are supported, and for handling a custom command when a controller sends it.
      - + SessionCallbackBuilder.DefaultAllowedCommandProvider
      Default implementation of SessionCallbackBuilder.AllowedCommandProvider that behaves as follows: @@ -5847,1288 +5945,1356 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Controller is in the same package as the session.
      - + SessionCallbackBuilder.DisconnectedCallback
      Callback for handling controller disconnection.
      - + SessionCallbackBuilder.MediaIdMediaItemProvider
      A SessionCallbackBuilder.MediaItemProvider that creates media items containing only a media ID.
      - + SessionCallbackBuilder.MediaItemProvider
      Provides the MediaItem.
      - + SessionCallbackBuilder.PostConnectCallback
      Callback for handling extra initialization after the connection.
      - + SessionCallbackBuilder.RatingCallback
      Callback receiving a user rating for a specified media id.
      - + SessionCallbackBuilder.SkipCallback
      Callback receiving skip backward and skip forward.
      - + SessionPlayerConnector
      An implementation of SessionPlayer that wraps a given ExoPlayer Player instance.
      - + ShadowMediaCodecConfig
      A JUnit @Rule to configure Roboelectric's ShadowMediaCodec.
      - + ShuffleOrder
      Shuffled order of indices.
      - + ShuffleOrder.DefaultShuffleOrder
      The default ShuffleOrder implementation for random shuffle order.
      - + ShuffleOrder.UnshuffledShuffleOrder
      A ShuffleOrder implementation which does not shuffle.
      - + SilenceMediaSource
      Media source with a single period consisting of silent raw audio of a given duration.
      - + SilenceMediaSource.Factory
      Factory for SilenceMediaSources.
      - + SilenceSkippingAudioProcessor
      An AudioProcessor that skips silence in the input stream.
      - + SimpleCache
      A Cache implementation that maintains an in-memory representation.
      - -SimpleDecoder<I extends DecoderInputBuffer,​O extends OutputBuffer,​E extends DecoderException> + +SimpleDecoder<I extends DecoderInputBuffer,​O extends DecoderOutputBuffer,​E extends DecoderException>
      Base class for Decoders that use their own decode thread and decode each input buffer immediately into a corresponding output buffer.
      - + +SimpleDecoderOutputBuffer + +
      Buffer for SimpleDecoder output.
      + + + SimpleExoPlayer - -
      An ExoPlayer implementation that uses default Renderer components.
      +Deprecated. +
      Use ExoPlayer instead.
      - + SimpleExoPlayer.Builder - -
      A builder for SimpleExoPlayer instances.
      +Deprecated. +
      Use ExoPlayer.Builder instead.
      - + SimpleMetadataDecoder
      A MetadataDecoder base class that validates input buffers and discards any for which Buffer.isDecodeOnly() is true.
      - -SimpleOutputBuffer - -
      Buffer for SimpleDecoder output.
      - - - + SimpleSubtitleDecoder
      Base class for subtitle parsers that use their own decode thread.
      - + SinglePeriodAdTimeline
      A Timeline for sources that have ads.
      - + SinglePeriodTimeline
      A Timeline consisting of a single period and static window.
      - + SingleSampleMediaChunk
      A BaseMediaChunk for chunks consisting of a single raw sample.
      - + SingleSampleMediaSource
      Loads data at a given Uri as a single sample belonging to a single MediaPeriod.
      - + SingleSampleMediaSource.Factory - -SlidingPercentile + +SlidingPercentile
      Calculate any percentile over a sliding window of weighted values.
      - + SlowMotionData
      Holds information about the segments of slow motion playback within a track.
      - + SlowMotionData.Segment
      Holds information about a single segment of slow motion playback within a track.
      - + SmtaMetadataEntry
      Stores metadata from the Samsung smta box.
      - + SntpClient
      Static utility to retrieve the device time offset using SNTP.
      - + SntpClient.InitializationCallback - + SonicAudioProcessor
      An AudioProcessor that uses the Sonic library to modify audio speed/pitch/sample rate.
      - + SpannedSubject
      A Truth Subject for assertions on Spanned instances containing text styling.
      - + SpannedSubject.AbsoluteSized
      Allows assertions about the absolute size of a span.
      - + SpannedSubject.Aligned
      Allows assertions about the alignment of a span.
      - + SpannedSubject.AndSpanFlags
      Allows additional assertions to be made on the flags of matching spans.
      - + SpannedSubject.Colored
      Allows assertions about the color of a span.
      - + SpannedSubject.EmphasizedText
      Allows assertions about a span's text emphasis mark and its position.
      - + SpannedSubject.RelativeSized
      Allows assertions about the relative size of a span.
      - + SpannedSubject.RubyText
      Allows assertions about a span's ruby text and its position.
      - + SpannedSubject.Typefaced
      Allows assertions about the typeface of a span.
      - + SpannedSubject.WithSpanFlags
      Allows additional assertions to be made on the flags of matching spans.
      - + SpanUtil
      Utility methods for Android span styling.
      - + SphericalGLSurfaceView
      Renders a GL scene in a non-VR Activity that is affected by phone orientation and touch input.
      - + SphericalGLSurfaceView.VideoSurfaceListener
      Listener for the Surface to which video frames should be rendered.
      - + SpliceCommand
      Superclass for SCTE35 splice commands.
      - + SpliceInfoDecoder
      Decodes splice info sections and produces splice commands.
      - + SpliceInsertCommand
      Represents a splice insert command defined in SCTE35, Section 9.3.3.
      - + SpliceInsertCommand.ComponentSplice
      Holds splicing information for specific splice insert command components.
      - + SpliceNullCommand
      Represents a splice null command as defined in SCTE35, Section 9.3.1.
      - + SpliceScheduleCommand
      Represents a splice schedule command as defined in SCTE35, Section 9.3.2.
      - + SpliceScheduleCommand.ComponentSplice
      Holds splicing information for specific splice schedule command components.
      - + SpliceScheduleCommand.Event
      Represents a splice event as contained in a SpliceScheduleCommand.
      - + SsaDecoder
      A SimpleSubtitleDecoder for SSA/ASS.
      - + SsChunkSource
      A ChunkSource for SmoothStreaming.
      - + SsChunkSource.Factory
      Factory for SsChunkSources.
      - + SsDownloader
      A downloader for SmoothStreaming streams.
      - + SsManifest
      Represents a SmoothStreaming manifest.
      - + SsManifest.ProtectionElement
      Represents a protection element containing a single header.
      - + SsManifest.StreamElement
      Represents a StreamIndex element.
      - + SsManifestParser
      Parses SmoothStreaming client manifests.
      - + SsManifestParser.MissingFieldException
      Thrown if a required field is missing.
      - + SsMediaSource
      A SmoothStreaming MediaSource.
      - + SsMediaSource.Factory
      Factory for SsMediaSource.
      - + +StandaloneDatabaseProvider + +
      An SQLiteOpenHelper that provides instances of a standalone database.
      + + + StandaloneMediaClock
      A MediaClock whose position advances with real time based on the playback parameters when started.
      - + StarRating
      A rating expressed as a fractional number of stars.
      - + StartOffsetExtractorOutput
      An extractor output that wraps another extractor output and applies a give start byte offset to seek positions.
      - + StatsDataSource
      DataSource wrapper which keeps track of bytes transferred, redirected uris, and response headers.
      - + StreamKey
      A key for a subset of media that can be separately loaded (a "stream").
      - + StubExoPlayer
      An abstract ExoPlayer implementation that throws UnsupportedOperationException from every method.
      - + +StubPlayer + +
      An abstract Player implementation that throws UnsupportedOperationException from + every method.
      + + + StyledPlayerControlView
      A view for controlling Player instances.
      - + StyledPlayerControlView.OnFullScreenModeChangedListener
      Listener to be invoked to inform the fullscreen mode is changed.
      - + StyledPlayerControlView.ProgressUpdateListener
      Listener to be notified when progress has been updated.
      - + StyledPlayerControlView.VisibilityListener
      Listener to be notified about changes of the visibility of the UI control.
      - + StyledPlayerView
      A high level view for Player media playbacks.
      - + StyledPlayerView.ShowBuffering
      Determines when the buffering view is shown.
      - + SubripDecoder
      A SimpleSubtitleDecoder for SubRip.
      - + Subtitle
      A subtitle consisting of timed Cues.
      - + SubtitleDecoder - + SubtitleDecoderException
      Thrown when an error occurs decoding subtitle data.
      - + SubtitleDecoderFactory
      A factory for SubtitleDecoder instances.
      - + +SubtitleExtractor + +
      Generic extractor for extracting subtitles from various subtitle formats.
      + + + SubtitleInputBuffer - + SubtitleOutputBuffer
      Base class for SubtitleDecoder output buffers.
      - + SubtitleView
      A view for displaying subtitle Cues.
      - + SubtitleView.ViewType
      The type of View to use to display subtitles.
      - + SynchronousMediaCodecAdapter
      A MediaCodecAdapter that operates the underlying MediaCodec in synchronous mode.
      - + SynchronousMediaCodecAdapter.Factory
      A factory for SynchronousMediaCodecAdapter instances.
      - + SystemClock
      The standard implementation of Clock, an instance of which is available via Clock.DEFAULT.
      - + TeeAudioProcessor
      Audio processor that outputs its input unmodified and also outputs its input to a given sink.
      - + TeeAudioProcessor.AudioBufferSink
      A sink for audio buffers handled by the audio processor.
      - + TeeAudioProcessor.WavFileAudioBufferSink
      A sink for audio buffers that writes output audio as .wav files with a given path prefix.
      - + TeeDataSource
      Tees data into a DataSink as the data is read.
      - + TestDownloadManagerListener
      Allows tests to block for, and assert properties of, calls from a DownloadManager to its DownloadManager.Listener.
      - + TestExoPlayerBuilder
      A builder of SimpleExoPlayer instances for testing.
      - + TestPlayerRunHelper -
      Helper methods to block the calling thread until the provided SimpleExoPlayer instance - reaches a particular state.
      +
      Helper methods to block the calling thread until the provided ExoPlayer instance reaches + a particular state.
      - + TestUtil
      Utility methods for tests.
      - + TextAnnotation
      Properties of a text annotation (i.e.
      - + TextAnnotation.Position
      The possible positions of the annotation text relative to the base text.
      - + TextEmphasisSpan
      A styling span for text emphasis marks.
      - + TextEmphasisSpan.MarkFill
      The possible mark fills that can be used.
      - + TextEmphasisSpan.MarkShape
      The possible mark shapes that can be used.
      - + TextInformationFrame
      Text information ID3 frame.
      - + TextOutput
      Receives text output.
      - + TextRenderer
      A renderer for text.
      - + ThumbRating
      A rating expressed as "thumbs up" or "thumbs down".
      - + TimeBar
      Interface for time bar views that can display a playback position, buffered position, duration and ad markers, and that have a listener for scrubbing (seeking) events.
      - + TimeBar.OnScrubListener
      Listener for scrubbing events.
      - + TimedValueQueue<V>
      A utility class to keep a queue of values with timestamps.
      - + Timeline
      A flexible representation of the structure of media.
      - + Timeline.Period
      Holds information about a period in a Timeline.
      - + Timeline.RemotableTimeline
      A concrete class of Timeline to restore a Timeline instance from a Bundle sent by another process via IBinder.
      - + Timeline.Window
      Holds information about a window in a Timeline.
      - + TimelineAsserts
      Assertion methods for Timeline.
      - + TimelineQueueEditor - + TimelineQueueEditor.MediaDescriptionConverter
      Converts a MediaDescriptionCompat to a MediaItem.
      - + TimelineQueueEditor.MediaIdEqualityChecker
      Media description comparator comparing the media IDs.
      - + TimelineQueueEditor.QueueDataAdapter
      Adapter to get MediaDescriptionCompat of items in the queue and to notify the application about changes in the queue to sync the data structure backing the MediaSessionConnector.
      - + TimelineQueueNavigator
      An abstract implementation of the MediaSessionConnector.QueueNavigator that maps the windows of a Player's Timeline to the media session queue.
      - + TimeSignalCommand
      Represents a time signal command as defined in SCTE35, Section 9.3.4.
      - + TimestampAdjuster
      Adjusts and offsets sample timestamps.
      - + TimestampAdjusterProvider
      Provides TimestampAdjuster instances for use during HLS playbacks.
      - + TimeToFirstByteEstimator
      Provides an estimate of the time to first byte of a transfer.
      - + TraceUtil
      Calls through to Trace methods on supported API levels.
      - + Track
      Encapsulates information describing an MP4 track.
      - + Track.Transformation
      The transformation to apply to samples in the track, if any.
      - + TrackEncryptionBox
      Encapsulates information parsed from a track encryption (tenc) box or sample group description (sgpd) box in an MP4 stream.
      - + TrackGroup
      Defines an immutable group of tracks identified by their format identity.
      - + TrackGroupArray
      An immutable array of TrackGroups.
      - + TrackNameProvider
      Converts Formats to user readable track names.
      - + TrackOutput
      Receives track level data extracted by an Extractor.
      - + TrackOutput.CryptoData
      Holds data required to decrypt a sample.
      - + TrackOutput.SampleDataPart
      Defines the part of the sample data to which a call to TrackOutput.sampleData(com.google.android.exoplayer2.upstream.DataReader, int, boolean) corresponds.
      - + TrackSelection
      A track selection consisting of a static subset of selected tracks belonging to a TrackGroup.
      - + +TrackSelection.Type + +
      Represents a type track selection.
      + + + TrackSelectionArray
      An array of TrackSelections.
      - + TrackSelectionDialogBuilder
      Builder for a dialog with a TrackSelectionView.
      - + TrackSelectionDialogBuilder.DialogCallback
      Callback which is invoked when a track selection has been made.
      - + +TrackSelectionOverrides + +
      Forces the selection of the specified tracks in TrackGroups.
      + + + +TrackSelectionOverrides.Builder + + + + + +TrackSelectionOverrides.TrackSelectionOverride + + + + + TrackSelectionParameters
      Constraint parameters for track selection.
      - + TrackSelectionParameters.Builder - + TrackSelectionUtil
      Track selection related utility methods.
      - + TrackSelectionUtil.AdaptiveTrackSelectionFactory
      Functional interface to create a single adaptive track selection.
      - + TrackSelectionView
      A view for making track selections.
      - + TrackSelectionView.TrackSelectionListener
      Listener for changes to the selected tracks.
      - + TrackSelector
      The component of an ExoPlayer responsible for selecting tracks to be consumed by each of the player's Renderers.
      - + TrackSelector.InvalidationListener
      Notified when selections previously made by a TrackSelector are no longer valid.
      - + TrackSelectorResult
      The result of a TrackSelector operation.
      - + +TracksInfo + +
      Immutable information (TracksInfo.TrackGroupInfo) about tracks.
      + + + +TracksInfo.TrackGroupInfo + +
      Information about tracks in a TrackGroup: their C.TrackType, if their format is + supported by the player and if they are selected for playback.
      + + + +TranscodingTransformer + +
      A transcoding transformer to transform media inputs.
      + + + +TranscodingTransformer.Builder + +
      A builder for TranscodingTransformer instances.
      + + + +TranscodingTransformer.Listener + +
      A listener for the transformation events.
      + + + +TranscodingTransformer.ProgressState + +
      Progress state.
      + + + TransferListener
      A listener of data transfer events.
      - + Transformer
      A transformer to transform media inputs.
      - + Transformer.Builder
      A builder for Transformer instances.
      - + Transformer.Listener
      A listener for the transformation events.
      - + Transformer.ProgressState
      Progress state.
      - + +TrueHdSampleRechunker + +
      Rechunks TrueHD sample data into groups of Ac3Util.TRUEHD_RECHUNK_SAMPLE_COUNT samples.
      + + + TsExtractor
      Extracts data from the MPEG-2 TS container format.
      - + TsExtractor.Mode
      Modes for the extractor.
      - + TsPayloadReader
      Parses TS packet payload data.
      - + TsPayloadReader.DvbSubtitleInfo
      Holds information about a DVB subtitle, as defined in ETSI EN 300 468 V1.11.1 section 6.2.41.
      - + TsPayloadReader.EsInfo
      Holds information associated with a PMT entry.
      - + TsPayloadReader.Factory
      Factory of TsPayloadReader instances.
      - + TsPayloadReader.Flags
      Contextual flags indicating the presence of indicators in the TS packet or PES packet headers.
      - + TsPayloadReader.TrackIdGenerator
      Generates track ids for initializing TsPayloadReaders' TrackOutputs.
      - + TsUtil
      Utilities method for extracting MPEG-TS streams.
      - + TtmlDecoder
      A SimpleSubtitleDecoder for TTML supporting the DFXP presentation profile.
      - + Tx3gDecoder - + UdpDataSource
      A UDP DataSource.
      - + UdpDataSource.UdpDataSourceException
      Thrown when an error is encountered when trying to read from a UdpDataSource.
      - + UnknownNull
      Annotation for specifying unknown nullness.
      - + UnrecognizedInputFormatException
      Thrown if the input format was not recognized.
      - + UnsupportedDrmException
      Thrown when the requested DRM scheme is not supported.
      - + UnsupportedDrmException.Reason
      The reason for the exception.
      - -UnsupportedMediaCrypto - -
      ExoMediaCrypto type that cannot be used to handle any type of protected content.
      - - - + UriUtil
      Utility methods for manipulating URIs.
      - + UrlLinkFrame
      Url link ID3 frame.
      - + UrlTemplate
      A template from which URLs can be built.
      - + UtcTimingElement
      Represents a UTCTiming element.
      - + Util
      Miscellaneous utility methods.
      - + VersionTable -
      Utility methods for accessing versions of ExoPlayer database components.
      +
      Utility methods for accessing versions of media library database components.
      - + VideoDecoderGLSurfaceView -
      GLSurfaceView implementing VideoDecoderOutputBufferRenderer for rendering VideoDecoderOutputBuffers.
      +
      GLSurfaceView implementing VideoDecoderOutputBufferRenderer for rendering VideoDecoderOutputBuffers.
      - -VideoDecoderInputBuffer - -
      Input buffer to a video decoder.
      - - - -VideoDecoderOutputBuffer + +VideoDecoderOutputBuffer
      Video decoder output buffer containing video frame data.
      - + VideoDecoderOutputBufferRenderer - + - + VideoFrameMetadataListener
      A listener for metadata corresponding to video frames being rendered.
      - + VideoFrameReleaseHelper
      Helps a video Renderer release frames to a Surface.
      - -VideoListener -Deprecated. - - - - + VideoRendererEventListener
      Listener of video Renderer events.
      - + VideoRendererEventListener.EventDispatcher
      Dispatches events to a VideoRendererEventListener.
      - + VideoSize
      Represents the video size.
      - + VorbisBitArray
      Wraps a byte array, providing methods that allow it to be read as a Vorbis bitstream.
      - + VorbisComment
      A vorbis comment.
      - + VorbisUtil
      Utility methods for parsing Vorbis streams.
      - + VorbisUtil.CommentHeader
      Vorbis comment header.
      - + VorbisUtil.Mode
      Vorbis setup header modes.
      - + VorbisUtil.VorbisIdHeader
      Vorbis identification header.
      - + VpxDecoder
      Vpx decoder.
      - + VpxDecoderException
      Thrown when a libvpx decoder error occurs.
      - + VpxLibrary
      Configures and queries the underlying native library.
      - + WavExtractor
      Extracts data from WAV byte streams.
      - + WavUtil
      Utilities for handling WAVE files.
      - + WebServerDispatcher
      A Dispatcher for MockWebServer that allows per-path customisation of the static data served.
      - + WebServerDispatcher.Resource
      A resource served by WebServerDispatcher.
      - + WebServerDispatcher.Resource.Builder - + WebvttCssStyle
      Style object of a Css style block in a Webvtt file.
      - + WebvttCssStyle.FontSizeUnit
      Font size unit enum.
      - + WebvttCssStyle.StyleFlags
      Style flag enum.
      - + WebvttCueInfo
      A representation of a WebVTT cue.
      - + WebvttCueParser
      Parser for WebVTT cues.
      - + WebvttDecoder
      A SimpleSubtitleDecoder for WebVTT.
      - + WebvttExtractor
      A special purpose extractor for WebVTT content in HLS.
      - + WebvttParserUtil
      Utility methods for parsing WebVTT data.
      - + WidevineUtil
      Utility methods for Widevine.
      - + WorkManagerScheduler
      A Scheduler that uses WorkManager.
      - + WorkManagerScheduler.SchedulerWorker
      A Worker that starts the target service if the requirements are met.
      - + WritableDownloadIndex
      A writable index of Downloads.
      - + XmlPullParserUtil
      XmlPullParser utility methods.
      diff --git a/docs/doc/reference/allclasses.html b/docs/doc/reference/allclasses.html index 288afe5bcf..5d8782d8f4 100644 --- a/docs/doc/reference/allclasses.html +++ b/docs/doc/reference/allclasses.html @@ -109,6 +109,7 @@
    • AspectRatioFrameLayout.AspectRatioListener
    • AspectRatioFrameLayout.ResizeMode
    • Assertions
    • +
    • AssetContentProvider
    • AssetDataSource
    • AssetDataSource.AssetDataSourceException
    • AtomicFile
    • @@ -117,7 +118,6 @@
    • AudioCapabilities
    • AudioCapabilitiesReceiver
    • AudioCapabilitiesReceiver.Listener
    • -
    • AudioListener
    • AudioProcessor
    • AudioProcessor.AudioFormat
    • AudioProcessor.UnhandledAudioFormatException
    • @@ -158,7 +158,7 @@
    • Buffer
    • Bundleable
    • Bundleable.Creator
    • -
    • BundleableUtils
    • +
    • BundleableUtil
    • BundledChunkExtractor
    • BundledExtractorsAdapter
    • BundledHlsMediaChunkExtractor
    • @@ -171,6 +171,7 @@
    • C.AudioContentType
    • C.AudioFlags
    • C.AudioFocusGain
    • +
    • C.AudioManagerOffloadMode
    • C.AudioUsage
    • C.BufferFlags
    • C.ColorRange
    • @@ -178,6 +179,7 @@
    • C.ColorTransfer
    • C.ContentType
    • C.CryptoMode
    • +
    • C.CryptoType
    • C.DataType
    • C.Encoding
    • C.FormatSupport
    • @@ -186,8 +188,11 @@
    • C.Projection
    • C.RoleFlags
    • C.SelectionFlags
    • +
    • C.SelectionReason
    • C.StereoMode
    • C.StreamType
    • +
    • C.TrackType
    • +
    • C.VideoChangeFrameRateStrategy
    • C.VideoOutputMode
    • C.VideoScalingMode
    • C.WakeMode
    • @@ -199,14 +204,12 @@
    • CacheDataSink
    • CacheDataSink.CacheDataSinkException
    • CacheDataSink.Factory
    • -
    • CacheDataSinkFactory
    • CacheDataSource
    • CacheDataSource.CacheIgnoredReason
    • CacheDataSource.EventListener
    • CacheDataSource.Factory
    • CacheDataSource.Flags
    • -
    • CacheDataSourceFactory
    • -
    • CachedRegionTracker
    • +
    • CachedRegionTracker
    • CacheEvictor
    • CacheKeyFactory
    • CacheSpan
    • @@ -254,7 +257,6 @@
    • ContentDataSource.ContentDataSourceException
    • ContentMetadata
    • ContentMetadataMutations
    • -
    • ControlDispatcher
    • CopyOnWriteMultiset
    • CronetDataSource
    • CronetDataSource.Factory
    • @@ -262,6 +264,8 @@
    • CronetDataSourceFactory
    • CronetEngineWrapper
    • CronetUtil
    • +
    • CryptoConfig
    • +
    • CryptoException
    • CryptoInfo
    • Cue
    • Cue.AnchorType
    • @@ -269,6 +273,8 @@
    • Cue.LineType
    • Cue.TextSizeType
    • Cue.VerticalType
    • +
    • CueDecoder
    • +
    • CueEncoder
    • DashChunkSource
    • DashChunkSource.Factory
    • DashDownloader
    • @@ -296,6 +302,7 @@
    • DataSourceContractTest.TestResource.Builder
    • DataSourceException
    • DataSourceInputStream
    • +
    • DataSourceUtil
    • DataSpec
    • DataSpec.Builder
    • DataSpec.Flags
    • @@ -309,11 +316,12 @@
    • DecoderInputBuffer
    • DecoderInputBuffer.BufferReplacementMode
    • DecoderInputBuffer.InsufficientCapacityException
    • +
    • DecoderOutputBuffer
    • +
    • DecoderOutputBuffer.Owner
    • DecoderReuseEvaluation
    • DecoderReuseEvaluation.DecoderDiscardReasons
    • DecoderReuseEvaluation.DecoderReuseResult
    • DecoderVideoRenderer
    • -
    • DecryptionException
    • DefaultAllocator
    • DefaultAudioSink
    • DefaultAudioSink.AudioProcessorChain
    • @@ -325,13 +333,13 @@
    • DefaultCastOptionsProvider
    • DefaultCompositeSequenceableLoaderFactory
    • DefaultContentMetadata
    • -
    • DefaultControlDispatcher
    • DefaultDashChunkSource
    • DefaultDashChunkSource.Factory
    • DefaultDashChunkSource.RepresentationHolder
    • DefaultDashChunkSource.RepresentationSegmentIterator
    • DefaultDatabaseProvider
    • DefaultDataSource
    • +
    • DefaultDataSource.Factory
    • DefaultDataSourceFactory
    • DefaultDownloaderFactory
    • DefaultDownloadIndex
    • @@ -348,12 +356,12 @@
    • DefaultHlsPlaylistTracker
    • DefaultHttpDataSource
    • DefaultHttpDataSource.Factory
    • -
    • DefaultHttpDataSourceFactory
    • DefaultLivePlaybackSpeedControl
    • DefaultLivePlaybackSpeedControl.Builder
    • DefaultLoadControl
    • DefaultLoadControl.Builder
    • DefaultLoadErrorHandlingPolicy
    • +
    • DefaultMediaCodecAdapterFactory
    • DefaultMediaDescriptionAdapter
    • DefaultMediaItemConverter
    • DefaultMediaItemConverter
    • @@ -379,9 +387,8 @@
    • DefaultTsPayloadReaderFactory
    • DefaultTsPayloadReaderFactory.Flags
    • Descriptor
    • -
    • DeviceInfo
    • -
    • DeviceInfo.PlaybackType
    • -
    • DeviceListener
    • +
    • DeviceInfo
    • +
    • DeviceInfo.PlaybackType
    • DolbyVisionConfig
    • Download
    • Download.FailureReason
    • @@ -448,7 +455,6 @@
    • EventStream
    • ExoDatabaseProvider
    • ExoHostedTest
    • -
    • ExoMediaCrypto
    • ExoMediaDrm
    • ExoMediaDrm.AppManagedProvider
    • ExoMediaDrm.KeyRequest
    • @@ -466,9 +472,9 @@
    • ExoPlayer.AudioOffloadListener
    • ExoPlayer.Builder
    • ExoPlayer.DeviceComponent
    • -
    • ExoPlayer.MetadataComponent
    • ExoPlayer.TextComponent
    • ExoPlayer.VideoComponent
    • +
    • ExoplayerCuesDecoder
    • ExoPlayerLibraryInfo
    • ExoPlayerTestRunner
    • ExoPlayerTestRunner.Builder
    • @@ -499,6 +505,7 @@
    • FakeChunkSource
    • FakeChunkSource.Factory
    • FakeClock
    • +
    • FakeCryptoConfig
    • FakeDataSet
    • FakeDataSet.FakeData
    • FakeDataSet.FakeData.Segment
    • @@ -518,6 +525,8 @@
    • FakeMediaPeriod.TrackDataFactory
    • FakeMediaSource
    • FakeMediaSource.InitialTimeline
    • +
    • FakeMediaSourceFactory
    • +
    • FakeMetadataEntry
    • FakeRenderer
    • FakeSampleStream
    • FakeSampleStream.FakeSampleStreamItem
    • @@ -535,14 +544,13 @@
    • FileDataSource
    • FileDataSource.Factory
    • FileDataSource.FileDataSourceException
    • -
    • FileDataSourceFactory
    • FileTypes
    • FileTypes.Type
    • FilterableManifest
    • FilteringHlsPlaylistParserFactory
    • FilteringManifestParser
    • FixedTrackSelection
    • -
    • FlacConstants
    • +
    • FlacConstants
    • FlacDecoder
    • FlacDecoderException
    • FlacExtractor
    • @@ -569,7 +577,7 @@
    • ForwardingTimeline
    • FragmentedMp4Extractor
    • FragmentedMp4Extractor.Flags
    • -
    • FrameworkMediaCrypto
    • +
    • FrameworkCryptoConfig
    • FrameworkMediaDrm
    • GaplessInfoHolder
    • Gav1Decoder
    • @@ -578,8 +586,10 @@
    • GeobFrame
    • GlUtil
    • GlUtil.Attribute
    • +
    • GlUtil.GlException
    • +
    • GlUtil.Program
    • GlUtil.Uniform
    • -
    • GvrAudioProcessor
    • +
    • GlUtil.UnsupportedEglVersionException
    • H262Reader
    • H263Reader
    • H264Reader
    • @@ -648,7 +658,6 @@
    • IndexSeekMap
    • InitializationChunk
    • InputReaderAdapterV30
    • -
    • IntArrayQueue
    • InternalFrame
    • JpegExtractor
    • KeysExpiredException
    • @@ -716,12 +725,20 @@
    • MediaFormatUtil
    • MediaItem
    • MediaItem.AdsConfiguration
    • +
    • MediaItem.AdsConfiguration.Builder
    • MediaItem.Builder
    • +
    • MediaItem.ClippingConfiguration
    • +
    • MediaItem.ClippingConfiguration.Builder
    • MediaItem.ClippingProperties
    • MediaItem.DrmConfiguration
    • +
    • MediaItem.DrmConfiguration.Builder
    • MediaItem.LiveConfiguration
    • +
    • MediaItem.LiveConfiguration.Builder
    • +
    • MediaItem.LocalConfiguration
    • MediaItem.PlaybackProperties
    • MediaItem.Subtitle
    • +
    • MediaItem.SubtitleConfiguration
    • +
    • MediaItem.SubtitleConfiguration.Builder
    • MediaItemConverter
    • MediaItemConverter
    • MediaLoadData
    • @@ -780,6 +797,7 @@
    • MpegAudioUtil
    • MpegAudioUtil.Header
    • NalUnitUtil
    • +
    • NalUnitUtil.H265SpsData
    • NalUnitUtil.PpsData
    • NalUnitUtil.SpsData
    • NetworkTypeObserver
    • @@ -800,8 +818,6 @@
    • OpusDecoderException
    • OpusLibrary
    • OpusUtil
    • -
    • OutputBuffer
    • -
    • OutputBuffer.Owner
    • OutputConsumerAdapterV30
    • ParsableBitArray
    • ParsableByteArray
    • @@ -865,6 +881,7 @@
    • PlayerView.ShowBuffering
    • PositionHolder
    • PriorityDataSource
    • +
    • PriorityDataSource.Factory
    • PriorityDataSourceFactory
    • PriorityTaskManager
    • PriorityTaskManager.PriorityTooLowException
    • @@ -888,8 +905,8 @@
    • RawResourceDataSource
    • RawResourceDataSource.RawResourceDataSourceException
    • Renderer
    • +
    • Renderer.MessageType
    • Renderer.State
    • -
    • Renderer.VideoScalingMode
    • Renderer.WakeupListener
    • RendererCapabilities
    • RendererCapabilities.AdaptiveSupport
    • @@ -911,7 +928,6 @@
    • ResolvingDataSource
    • ResolvingDataSource.Factory
    • ResolvingDataSource.Resolver
    • -
    • ReusableBufferedOutputStream
    • RobolectricUtil
    • RtmpDataSource
    • RtmpDataSource.Factory
    • @@ -977,17 +993,17 @@
    • SilenceSkippingAudioProcessor
    • SimpleCache
    • SimpleDecoder
    • +
    • SimpleDecoderOutputBuffer
    • SimpleExoPlayer
    • SimpleExoPlayer.Builder
    • SimpleMetadataDecoder
    • -
    • SimpleOutputBuffer
    • SimpleSubtitleDecoder
    • SinglePeriodAdTimeline
    • SinglePeriodTimeline
    • SingleSampleMediaChunk
    • SingleSampleMediaSource
    • SingleSampleMediaSource.Factory
    • -
    • SlidingPercentile
    • +
    • SlidingPercentile
    • SlowMotionData
    • SlowMotionData.Segment
    • SmtaMetadataEntry
    • @@ -1026,12 +1042,14 @@
    • SsManifestParser.MissingFieldException
    • SsMediaSource
    • SsMediaSource.Factory
    • +
    • StandaloneDatabaseProvider
    • StandaloneMediaClock
    • StarRating
    • StartOffsetExtractorOutput
    • StatsDataSource
    • StreamKey
    • StubExoPlayer
    • +
    • StubPlayer
    • StyledPlayerControlView
    • StyledPlayerControlView.OnFullScreenModeChangedListener
    • StyledPlayerControlView.ProgressUpdateListener
    • @@ -1043,6 +1061,7 @@
    • SubtitleDecoder
    • SubtitleDecoderException
    • SubtitleDecoderFactory
    • +
    • SubtitleExtractor
    • SubtitleInputBuffer
    • SubtitleOutputBuffer
    • SubtitleView
    • @@ -1095,9 +1114,13 @@
    • TrackOutput.CryptoData
    • TrackOutput.SampleDataPart
    • TrackSelection
    • +
    • TrackSelection.Type
    • TrackSelectionArray
    • TrackSelectionDialogBuilder
    • TrackSelectionDialogBuilder.DialogCallback
    • +
    • TrackSelectionOverrides
    • +
    • TrackSelectionOverrides.Builder
    • +
    • TrackSelectionOverrides.TrackSelectionOverride
    • TrackSelectionParameters
    • TrackSelectionParameters.Builder
    • TrackSelectionUtil
    • @@ -1107,11 +1130,18 @@
    • TrackSelector
    • TrackSelector.InvalidationListener
    • TrackSelectorResult
    • +
    • TracksInfo
    • +
    • TracksInfo.TrackGroupInfo
    • +
    • TranscodingTransformer
    • +
    • TranscodingTransformer.Builder
    • +
    • TranscodingTransformer.Listener
    • +
    • TranscodingTransformer.ProgressState
    • TransferListener
    • Transformer
    • Transformer.Builder
    • Transformer.Listener
    • Transformer.ProgressState
    • +
    • TrueHdSampleRechunker
    • TsExtractor
    • TsExtractor.Mode
    • TsPayloadReader
    • @@ -1129,7 +1159,6 @@
    • UnrecognizedInputFormatException
    • UnsupportedDrmException
    • UnsupportedDrmException.Reason
    • -
    • UnsupportedMediaCrypto
    • UriUtil
    • UrlLinkFrame
    • UrlTemplate
    • @@ -1137,12 +1166,10 @@
    • Util
    • VersionTable
    • VideoDecoderGLSurfaceView
    • -
    • VideoDecoderInputBuffer
    • -
    • VideoDecoderOutputBuffer
    • +
    • VideoDecoderOutputBuffer
    • VideoDecoderOutputBufferRenderer
    • VideoFrameMetadataListener
    • VideoFrameReleaseHelper
    • -
    • VideoListener
    • VideoRendererEventListener
    • VideoRendererEventListener.EventDispatcher
    • VideoSize
    • diff --git a/docs/doc/reference/allpackages-index.html b/docs/doc/reference/allpackages-index.html index b1bd57364a..aa307180e2 100644 --- a/docs/doc/reference/allpackages-index.html +++ b/docs/doc/reference/allpackages-index.html @@ -124,35 +124,27 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));   -com.google.android.exoplayer2.device -  - - com.google.android.exoplayer2.drm   - + com.google.android.exoplayer2.ext.av1   - + com.google.android.exoplayer2.ext.cast   - + com.google.android.exoplayer2.ext.cronet   - + com.google.android.exoplayer2.ext.ffmpeg   - -com.google.android.exoplayer2.ext.flac -  - -com.google.android.exoplayer2.ext.gvr +com.google.android.exoplayer2.ext.flac   diff --git a/docs/doc/reference/com/google/android/exoplayer2/AbstractConcatenatedTimeline.html b/docs/doc/reference/com/google/android/exoplayer2/AbstractConcatenatedTimeline.html index 460a936697..6dfc96dea1 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/AbstractConcatenatedTimeline.html +++ b/docs/doc/reference/com/google/android/exoplayer2/AbstractConcatenatedTimeline.html @@ -316,8 +316,8 @@ extends T int -getNextWindowIndex​(int windowIndex, - int repeatMode, +getNextWindowIndex​(int windowIndex, + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode, boolean shuffleModeEnabled)
      Returns the index of the window after the window at index windowIndex depending on the @@ -343,8 +343,8 @@ extends T int -getPreviousWindowIndex​(int windowIndex, - int repeatMode, +getPreviousWindowIndex​(int windowIndex, + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode, boolean shuffleModeEnabled)
      Returns the index of the window before the window at index windowIndex depending on the @@ -380,7 +380,7 @@ extends T

      Methods inherited from class com.google.android.exoplayer2.Timeline

      -equals, getNextPeriodIndex, getPeriod, getPeriodCount, getPeriodPosition, getPeriodPosition, getWindow, getWindowCount, hashCode, isEmpty, isLastPeriod, toBundle, toBundle +equals, getNextPeriodIndex, getPeriod, getPeriodCount, getPeriodPosition, getPeriodPosition, getPeriodPositionUs, getPeriodPositionUs, getWindow, getWindowCount, hashCode, isEmpty, isLastPeriod, toBundle, toBundle
    - + - +
  • @@ -254,156 +254,219 @@ implements +boolean +canAdvertiseSession() + +
    Returns whether the player can be used to advertise a media session.
    + + + void clearMediaItems()
    Clears the playlist.
    - + protected Player.Commands getAvailableCommands​(Player.Commands permanentAvailableCommands)
    Returns the Player.Commands available in the player.
    - + int getBufferedPercentage() -
    Returns an estimate of the percentage in the current content window or ad up to which data is +
    Returns an estimate of the percentage in the current content or ad up to which data is buffered, or 0 if no estimate is available.
    - -long -getContentDuration() - -
    If Player.isPlayingAd() returns true, returns the duration of the current content - window in milliseconds, or C.TIME_UNSET if the duration is not known.
    - - long -getCurrentLiveOffset() +getContentDuration() -
    Returns the offset of the current playback position from the live edge in milliseconds, or - C.TIME_UNSET if the current window isn't live or the - offset is unknown.
    +
    If Player.isPlayingAd() returns true, returns the duration of the current content in + milliseconds, or C.TIME_UNSET if the duration is not known.
    +long +getCurrentLiveOffset() + +
    Returns the offset of the current playback position from the live edge in milliseconds, or + C.TIME_UNSET if the current MediaItem Player.isCurrentMediaItemLive() isn't + live} or the offset is unknown.
    + + + Object getCurrentManifest()
    Returns the current manifest.
    - + MediaItem getCurrentMediaItem() -
    Returns the media item of the current window in the timeline.
    +
    Returns the currently playing MediaItem.
    - + +int +getCurrentWindowIndex() + +
    Deprecated.
    + + + MediaItem getMediaItemAt​(int index)
    Returns the MediaItem at the given index.
    - + int getMediaItemCount()
    Returns the number of media items in the playlist.
    - + +int +getNextMediaItemIndex() + +
    Returns the index of the MediaItem that will be played if Player.seekToNextMediaItem() is called, which may depend on the current repeat mode and whether + shuffle mode is enabled.
    + + + int getNextWindowIndex() -
    Returns the index of the window that will be played if Player.seekToNextWindow() is called, - which may depend on the current repeat mode and whether shuffle mode is enabled.
    +
    Deprecated.
    - + +int +getPreviousMediaItemIndex() + +
    Returns the index of the MediaItem that will be played if Player.seekToPreviousMediaItem() is called, which may depend on the current repeat mode and whether + shuffle mode is enabled.
    + + + int getPreviousWindowIndex() -
    Returns the index of the window that will be played if Player.seekToPreviousWindow() is - called, which may depend on the current repeat mode and whether shuffle mode is enabled.
    +
    Deprecated.
    - + boolean hasNext()
    Deprecated.
    - + +boolean +hasNextMediaItem() + +
    Returns whether a next MediaItem exists, which may depend on the current repeat mode + and whether shuffle mode is enabled.
    + + + boolean hasNextWindow() -
    Returns whether a next window exists, which may depend on the current repeat mode and whether - shuffle mode is enabled.
    +
    Deprecated.
    - + boolean hasPrevious()
    Deprecated.
    - + boolean -hasPreviousWindow() +hasPreviousMediaItem() -
    Returns whether a previous window exists, which may depend on the current repeat mode and +
    Returns whether a previous media item exists, which may depend on the current repeat mode and whether shuffle mode is enabled.
    - + boolean -isCommandAvailable​(int command) +hasPreviousWindow() + +
    Deprecated.
    + + + +boolean +isCommandAvailable​(@com.google.android.exoplayer2.Player.Command int command)
    Returns whether the provided Player.Command is available.
    - + +boolean +isCurrentMediaItemDynamic() + +
    Returns whether the current MediaItem is dynamic (may change when the Timeline + is updated), or false if the Timeline is empty.
    + + + +boolean +isCurrentMediaItemLive() + +
    Returns whether the current MediaItem is live, or false if the Timeline + is empty.
    + + + +boolean +isCurrentMediaItemSeekable() + +
    Returns whether the current MediaItem is seekable, or false if the Timeline is empty.
    + + + boolean isCurrentWindowDynamic() -
    Returns whether the current window is dynamic, or false if the Timeline is - empty.
    +
    Deprecated.
    - + boolean isCurrentWindowLive() -
    Returns whether the current window is live, or false if the Timeline is empty.
    +
    Deprecated.
    - + boolean isCurrentWindowSeekable() -
    Returns whether the current window is seekable, or false if the Timeline is - empty.
    +
    Deprecated.
    - + boolean isPlaying()
    Returns whether the player is playing, i.e.
    - + void moveMediaItem​(int currentIndex, int newIndex) @@ -411,107 +474,122 @@ implements Moves the media item at the current index to the new index.
    - + void next()
    Deprecated.
    - + void pause()
    Pauses playback.
    - + void play()
    Resumes playback as soon as Player.getPlaybackState() == Player.STATE_READY.
    - + void previous()
    Deprecated.
    - + void removeMediaItem​(int index)
    Removes the media item at the given index of the playlist.
    - + void seekBack() -
    Seeks back in the current window by Player.getSeekBackIncrement() milliseconds.
    +
    Seeks back in the current MediaItem by Player.getSeekBackIncrement() milliseconds.
    - + void seekForward() -
    Seeks forward in the current window by Player.getSeekForwardIncrement() milliseconds.
    +
    Seeks forward in the current MediaItem by Player.getSeekForwardIncrement() + milliseconds.
    - + void seekTo​(long positionMs) -
    Seeks to a position specified in milliseconds in the current window.
    +
    Seeks to a position specified in milliseconds in the current MediaItem.
    - + void seekToDefaultPosition() -
    Seeks to the default position associated with the current window.
    +
    Seeks to the default position associated with the current MediaItem.
    - + void -seekToDefaultPosition​(int windowIndex) +seekToDefaultPosition​(int mediaItemIndex) -
    Seeks to the default position associated with the specified window.
    +
    Seeks to the default position associated with the specified MediaItem.
    - + void seekToNext() -
    Seeks to a later position in the current or next window (if available).
    +
    Seeks to a later position in the current or next MediaItem (if available).
    - + +void +seekToNextMediaItem() + +
    Seeks to the default position of the next MediaItem, which may depend on the current + repeat mode and whether shuffle mode is enabled.
    + + + void seekToNextWindow() -
    Seeks to the default position of the next window, which may depend on the current repeat mode - and whether shuffle mode is enabled.
    +
    Deprecated.
    - + void seekToPrevious() -
    Seeks to an earlier position in the current or previous window (if available).
    +
    Seeks to an earlier position in the current or previous MediaItem (if available).
    - + +void +seekToPreviousMediaItem() + +
    Seeks to the default position of the previous MediaItem, which may depend on the + current repeat mode and whether shuffle mode is enabled.
    + + + void seekToPreviousWindow() -
    Seeks to the default position of the previous window, which may depend on the current repeat - mode and whether shuffle mode is enabled.
    +
    Deprecated.
    - + void setMediaItem​(MediaItem mediaItem) @@ -519,7 +597,7 @@ implements + void setMediaItem​(MediaItem mediaItem, boolean resetPosition) @@ -527,7 +605,7 @@ implements Clears the playlist and adds the specified MediaItem.
    - + void setMediaItem​(MediaItem mediaItem, long startPositionMs) @@ -535,7 +613,7 @@ implements Clears the playlist and adds the specified MediaItem. - + void setMediaItems​(List<MediaItem> mediaItems) @@ -543,20 +621,13 @@ implements + void setPlaybackSpeed​(float speed)
    Changes the rate at which playback occurs.
    - -void -stop() - -
    Stops playback without resetting the player.
    - - @@ -679,7 +750,7 @@ implements Parameters:
    mediaItem - The new MediaItem.
    resetPosition - Whether the playback position should be reset to the default position. If - false, playback will start from the position defined by Player.getCurrentWindowIndex() + false, playback will start from the position defined by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition().
    @@ -808,28 +879,27 @@ implements + @@ -942,13 +1028,13 @@ implements public final void seekTo​(long positionMs) -
    Seeks to a position specified in milliseconds in the current window.
    +
    Seeks to a position specified in milliseconds in the current MediaItem.
    Specified by:
    seekTo in interface Player
    Parameters:
    -
    positionMs - The seek position in the current window, or C.TIME_UNSET to seek to - the window's default position.
    +
    positionMs - The seek position in the current MediaItem, or C.TIME_UNSET + to seek to the media item's default position.
    @@ -960,7 +1046,7 @@ implements public final void seekBack() -
    Seeks back in the current window by Player.getSeekBackIncrement() milliseconds.
    +
    Seeks back in the current MediaItem by Player.getSeekBackIncrement() milliseconds.
    Specified by:
    seekBack in interface Player
    @@ -975,7 +1061,8 @@ implements public final void seekForward() -
    Seeks forward in the current window by Player.getSeekForwardIncrement() milliseconds.
    +
    Seeks forward in the current MediaItem by Player.getSeekForwardIncrement() + milliseconds.
    Specified by:
    seekForward in interface Player
    @@ -1003,9 +1090,24 @@ public final boolean hasPrevious()
    • hasPreviousWindow

      -
      public final boolean hasPreviousWindow()
      -
      Description copied from interface: Player
      -
      Returns whether a previous window exists, which may depend on the current repeat mode and +
      @Deprecated
      +public final boolean hasPreviousWindow()
      +
      Deprecated.
      +
      +
      Specified by:
      +
      hasPreviousWindow in interface Player
      +
      +
    • +
    + + + +
      +
    • +

      hasPreviousMediaItem

      +
      public final boolean hasPreviousMediaItem()
      +
      Description copied from interface: Player
      +
      Returns whether a previous media item exists, which may depend on the current repeat mode and whether shuffle mode is enabled.

      Note: When the repeat mode is Player.REPEAT_MODE_ONE, this method behaves the same as when @@ -1013,7 +1115,7 @@ public final boolean hasPrevious() details.

      Specified by:
      -
      hasPreviousWindow in interface Player
      +
      hasPreviousMediaItem in interface Player
    @@ -1038,18 +1140,32 @@ public final void previous()
    • seekToPreviousWindow

      -
      public final void seekToPreviousWindow()
      -
      Description copied from interface: Player
      -
      Seeks to the default position of the previous window, which may depend on the current repeat - mode and whether shuffle mode is enabled. Does nothing if Player.hasPreviousWindow() is - false. +
      @Deprecated
      +public final void seekToPreviousWindow()
      +
      Deprecated.
      +
      +
      Specified by:
      +
      seekToPreviousWindow in interface Player
      +
      +
    • +
    + + + + @@ -1061,18 +1177,20 @@ public final void previous()

    seekToPrevious

    public final void seekToPrevious()
    Description copied from interface: Player
    -
    Seeks to an earlier position in the current or previous window (if available). More precisely: +
    Seeks to an earlier position in the current or previous MediaItem (if available). More + precisely:
    Specified by:
    @@ -1101,17 +1219,32 @@ public final boolean hasNext()
    • hasNextWindow

      -
      public final boolean hasNextWindow()
      -
      Description copied from interface: Player
      -
      Returns whether a next window exists, which may depend on the current repeat mode and whether - shuffle mode is enabled. +
      @Deprecated
      +public final boolean hasNextWindow()
      +
      Deprecated.
      +
      +
      Specified by:
      +
      hasNextWindow in interface Player
      +
      +
    • +
    + + + + @@ -1136,17 +1269,33 @@ public final void next()
    • seekToNextWindow

      -
      public final void seekToNextWindow()
      -
      Description copied from interface: Player
      -
      Seeks to the default position of the next window, which may depend on the current repeat mode - and whether shuffle mode is enabled. Does nothing if Player.hasNextWindow() is false. +
      @Deprecated
      +public final void seekToNextWindow()
      +
      Deprecated.
      +
      +
      Specified by:
      +
      seekToNextWindow in interface Player
      +
      +
    • +
    + + + + @@ -1158,14 +1307,15 @@ public final void next()

    seekToNext

    public final void seekToNext()
    Description copied from interface: Player
    -
    Seeks to a later position in the current or next window (if available). More precisely: +
    Seeks to a later position in the current or next MediaItem (if available). More + precisely:
    • If the timeline is empty or seeking is not possible, does nothing. -
    • Otherwise, if a next window exists, seeks to the default - position of the next window. -
    • Otherwise, if the current window is live and has not - ended, seeks to the live edge of the current window. +
    • Otherwise, if a next media item exists, seeks to the default + position of the next MediaItem. +
    • Otherwise, if the current MediaItem is live and + has not ended, seeks to the live edge of the current MediaItem.
    • Otherwise, does nothing.
    @@ -1195,26 +1345,18 @@ public final void next()
    - +
    • -

      stop

      -
      public final void stop()
      -
      Description copied from interface: Player
      -
      Stops playback without resetting the player. Use Player.pause() rather than this method if - the intention is to pause playback. - -

      Calling this method will cause the playback state to transition to Player.STATE_IDLE. The - player instance can still be used, and Player.release() must still be called on the player if - it's no longer required. - -

      Calling this method does not clear the playlist, reset the playback position or the playback - error.

      +

      getCurrentWindowIndex

      +
      @Deprecated
      +public final int getCurrentWindowIndex()
      +
      Deprecated.
      Specified by:
      -
      stop in interface Player
      +
      getCurrentWindowIndex in interface Player
    @@ -1224,17 +1366,33 @@ public final void next() + + + + @@ -1244,18 +1402,33 @@ public final void next() + + + + @@ -1268,13 +1441,12 @@ public final void next()
    @Nullable
     public final MediaItem getCurrentMediaItem()
    Description copied from interface: Player
    -
    Returns the media item of the current window in the timeline. May be null if the timeline is - empty.
    +
    Returns the currently playing MediaItem. May be null if the timeline is empty.
    Specified by:
    getCurrentMediaItem in interface Player
    See Also:
    -
    Player.Listener.onMediaItemTransition(MediaItem, int)
    +
    Player.Listener.onMediaItemTransition(MediaItem, int)
    @@ -1332,7 +1504,7 @@ public final public final int getBufferedPercentage() -
    Returns an estimate of the percentage in the current content window or ad up to which data is +
    Returns an estimate of the percentage in the current content or ad up to which data is buffered, or 0 if no estimate is available.
    Specified by:
    @@ -1346,13 +1518,28 @@ public final 
  • isCurrentWindowDynamic

    -
    public final boolean isCurrentWindowDynamic()
    -
    -
    Returns whether the current window is dynamic, or false if the Timeline is - empty.
    +
    @Deprecated
    +public final boolean isCurrentWindowDynamic()
    +
    Deprecated.
    Specified by:
    isCurrentWindowDynamic in interface Player
    +
    +
  • + + + + + + + + + + + + +
    @@ -89,32 +102,26 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); +
    -

    Package com.google.android.exoplayer2.ext.gvr

    + +

    Annotation Type C.AudioManagerOffloadMode

    +
    +
    +
    See Also:
    -
    Constant Field Values
    +
    Constant Field Values
    @@ -356,7 +356,7 @@ implements
  • UNKNOWN

    -
    public static final DeviceInfo UNKNOWN
    +
    public static final DeviceInfo UNKNOWN
    Unknown DeviceInfo.
  • @@ -366,7 +366,7 @@ implements
  • playbackType

    -
    public final @com.google.android.exoplayer2.device.DeviceInfo.PlaybackType int playbackType
    +
    public final @com.google.android.exoplayer2.DeviceInfo.PlaybackType int playbackType
    The type of playback.
  • @@ -396,8 +396,8 @@ implements
  • CREATOR

    -
    public static final Bundleable.Creator<DeviceInfo> CREATOR
    -
    Object that can restore DeviceInfo from a Bundle.
    +
    public static final Bundleable.Creator<DeviceInfo> CREATOR
    +
    Object that can restore DeviceInfo from a Bundle.
  • @@ -410,13 +410,13 @@ implements +
    • DeviceInfo

      -
      public DeviceInfo​(@com.google.android.exoplayer2.device.DeviceInfo.PlaybackType int playbackType,
      +
      public DeviceInfo​(@com.google.android.exoplayer2.DeviceInfo.PlaybackType int playbackType,
                         int minVolume,
                         int maxVolume)
      Creates device information.
      @@ -466,11 +466,11 @@ implements

      toBundle

      public Bundle toBundle()
      -
      Description copied from interface: Bundleable
      +
      Description copied from interface: Bundleable
      Returns a Bundle representing the information stored in this object.
      Specified by:
      -
      toBundle in interface Bundleable
      +
      toBundle in interface Bundleable
    @@ -494,18 +494,18 @@ implements -
  • Overview
  • +
  • Overview
  • Package
  • Tree
  • -
  • Deprecated
  • -
  • Index
  • -
  • Help
  • +
  • Deprecated
  • +
  • Index
  • +
  • Help

  • -
    public static interface ExoPlayer.TextComponent
    -
    The text component of an ExoPlayer.
    +
    @Deprecated
    +public static interface ExoPlayer.TextComponent
    +
    Deprecated. +
    Use Player, as the ExoPlayer.TextComponent methods are defined by that + interface.
    +
    @@ -152,27 +156,11 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Description -void -addTextOutput​(TextOutput listener) - -
    Deprecated. - -
    - - - List<Cue> getCurrentCues() -
    Returns the current Cues.
    - - - -void -removeTextOutput​(TextOutput listener) - @@ -193,50 +181,17 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

    Method Detail

    - - - - - - - - diff --git a/docs/doc/reference/com/google/android/exoplayer2/ExoPlayer.VideoComponent.html b/docs/doc/reference/com/google/android/exoplayer2/ExoPlayer.VideoComponent.html index a0e7a8c2bf..c2f0aecfef 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ExoPlayer.VideoComponent.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ExoPlayer.VideoComponent.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":38,"i1":6,"i2":6,"i3":6,"i4":6,"i5":6,"i6":6,"i7":6,"i8":6,"i9":6,"i10":38,"i11":6,"i12":6,"i13":6,"i14":6,"i15":6,"i16":6,"i17":6}; +var data = {"i0":38,"i1":38,"i2":38,"i3":38,"i4":38,"i5":38,"i6":38,"i7":38,"i8":38,"i9":38,"i10":38,"i11":38,"i12":38,"i13":38,"i14":38,"i15":38,"i16":38,"i17":38}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -129,8 +129,12 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    ExoPlayer

    -
    public static interface ExoPlayer.VideoComponent
    -
    The video component of an ExoPlayer.
    +
    @Deprecated
    +public static interface ExoPlayer.VideoComponent
    +
    Deprecated. +
    Use ExoPlayer, as the ExoPlayer.VideoComponent methods are defined by that + interface.
    +
    @@ -153,137 +157,166 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); void -addVideoListener​(VideoListener listener) +clearCameraMotionListener​(CameraMotionListener listener) void -clearCameraMotionListener​(CameraMotionListener listener) +clearVideoFrameMetadataListener​(VideoFrameMetadataListener listener) -
    Clears the listener which receives camera motion events if it matches the one passed.
    + void -clearVideoFrameMetadataListener​(VideoFrameMetadataListener listener) +clearVideoSurface() -
    Clears the listener which receives video frame metadata events if it matches the one passed.
    +
    Deprecated. + +
    void -clearVideoSurface() +clearVideoSurface​(Surface surface) -
    Clears any Surface, SurfaceHolder, SurfaceView or TextureView - currently set on the player.
    +
    Deprecated. + +
    void -clearVideoSurface​(Surface surface) +clearVideoSurfaceHolder​(SurfaceHolder surfaceHolder) -
    Clears the Surface onto which video is being rendered if it matches the one passed.
    + void -clearVideoSurfaceHolder​(SurfaceHolder surfaceHolder) +clearVideoSurfaceView​(SurfaceView surfaceView) -
    Clears the SurfaceHolder that holds the Surface onto which video is being - rendered if it matches the one passed.
    +
    Deprecated. + +
    void -clearVideoSurfaceView​(SurfaceView surfaceView) +clearVideoTextureView​(TextureView textureView) -
    Clears the SurfaceView onto which video is being rendered if it matches the one - passed.
    +
    Deprecated. + +
    -void -clearVideoTextureView​(TextureView textureView) +int +getVideoChangeFrameRateStrategy() -
    Clears the TextureView onto which video is being rendered if it matches the one - passed.
    + int getVideoScalingMode() -
    Returns the C.VideoScalingMode.
    +
    Deprecated. + +
    VideoSize getVideoSize() -
    Gets the size of the video.
    +
    Deprecated. + +
    void -removeVideoListener​(VideoListener listener) +setCameraMotionListener​(CameraMotionListener listener) void -setCameraMotionListener​(CameraMotionListener listener) +setVideoChangeFrameRateStrategy​(int videoChangeFrameRateStrategy) -
    Sets a listener of camera motion events.
    + void setVideoFrameMetadataListener​(VideoFrameMetadataListener listener) -
    Sets a listener to receive video frame metadata events.
    + void setVideoScalingMode​(int videoScalingMode) - +
    Deprecated. + +
    void setVideoSurface​(Surface surface) -
    Sets the Surface onto which video will be rendered.
    +
    Deprecated. + +
    void setVideoSurfaceHolder​(SurfaceHolder surfaceHolder) -
    Sets the SurfaceHolder that holds the Surface onto which video will be - rendered.
    + void setVideoSurfaceView​(SurfaceView surfaceView) -
    Sets the SurfaceView onto which video will be rendered.
    +
    Deprecated. + +
    void setVideoTextureView​(TextureView textureView) -
    Sets the TextureView onto which video will be rendered.
    +
    Deprecated. + +
    @@ -309,13 +342,12 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); @@ -324,45 +356,40 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); - + - + @@ -371,16 +398,12 @@ void removeVideoListener​(
  • setVideoFrameMetadataListener

    -
    void setVideoFrameMetadataListener​(VideoFrameMetadataListener listener)
    -
    Sets a listener to receive video frame metadata events. - -

    This method is intended to be called by the same component that sets the Surface - onto which video will be rendered. If using ExoPlayer's standard UI components, this method - should not be called directly from application code.

    -
    -
    Parameters:
    -
    listener - The listener.
    -
    +
    @Deprecated
    +void setVideoFrameMetadataListener​(VideoFrameMetadataListener listener)
    +
  • @@ -389,13 +412,12 @@ void removeVideoListener​(
  • clearVideoFrameMetadataListener

    -
    void clearVideoFrameMetadataListener​(VideoFrameMetadataListener listener)
    -
    Clears the listener which receives video frame metadata events if it matches the one passed. - Else does nothing.
    -
    -
    Parameters:
    -
    listener - The listener to clear.
    -
    +
    @Deprecated
    +void clearVideoFrameMetadataListener​(VideoFrameMetadataListener listener)
    +
  • @@ -404,12 +426,11 @@ void removeVideoListener​(
  • setCameraMotionListener

    -
    void setCameraMotionListener​(CameraMotionListener listener)
    -
    Sets a listener of camera motion events.
    -
    -
    Parameters:
    -
    listener - The listener.
    -
    +
    @Deprecated
    +void setCameraMotionListener​(CameraMotionListener listener)
    +
  • @@ -418,13 +439,11 @@ void removeVideoListener​(
  • clearCameraMotionListener

    -
    void clearCameraMotionListener​(CameraMotionListener listener)
    -
    Clears the listener which receives camera motion events if it matches the one passed. Else - does nothing.
    -
    -
    Parameters:
    -
    listener - The listener to clear.
    -
    +
    @Deprecated
    +void clearCameraMotionListener​(CameraMotionListener listener)
    +
  • @@ -433,9 +452,11 @@ void removeVideoListener​(
  • clearVideoSurface

    -
    void clearVideoSurface()
    -
    Clears any Surface, SurfaceHolder, SurfaceView or TextureView - currently set on the player.
    +
    @Deprecated
    +void clearVideoSurface()
    +
    Deprecated. + +
  • @@ -444,14 +465,12 @@ void removeVideoListener​(
  • clearVideoSurface

    -
    void clearVideoSurface​(@Nullable
    +
    @Deprecated
    +void clearVideoSurface​(@Nullable
                            Surface surface)
    -
    Clears the Surface onto which video is being rendered if it matches the one passed. - Else does nothing.
    -
    -
    Parameters:
    -
    surface - The surface to clear.
    -
    +
    Deprecated. + +
  • @@ -460,19 +479,12 @@ void removeVideoListener​(
  • setVideoSurface

    -
    void setVideoSurface​(@Nullable
    +
    @Deprecated
    +void setVideoSurface​(@Nullable
                          Surface surface)
    -
    Sets the Surface onto which video will be rendered. The caller is responsible for - tracking the lifecycle of the surface, and must clear the surface by calling - setVideoSurface(null) if the surface is destroyed. - -

    If the surface is held by a SurfaceView, TextureView or SurfaceHolder then it's recommended to use setVideoSurfaceView(SurfaceView), setVideoTextureView(TextureView) or setVideoSurfaceHolder(SurfaceHolder) rather - than this method, since passing the holder allows the player to track the lifecycle of the - surface automatically.

    -
    -
    Parameters:
    -
    surface - The Surface.
    -
    +
    Deprecated. + +
  • @@ -481,17 +493,12 @@ void removeVideoListener​(
  • setVideoSurfaceHolder

    -
    void setVideoSurfaceHolder​(@Nullable
    +
    @Deprecated
    +void setVideoSurfaceHolder​(@Nullable
                                SurfaceHolder surfaceHolder)
    -
    Sets the SurfaceHolder that holds the Surface onto which video will be - rendered. The player will track the lifecycle of the surface automatically. - -

    The thread that calls the SurfaceHolder.Callback methods must be the thread - associated with Player.getApplicationLooper().

    -
    -
    Parameters:
    -
    surfaceHolder - The surface holder.
    -
    +
  • @@ -500,14 +507,12 @@ void removeVideoListener​(
  • clearVideoSurfaceHolder

    -
    void clearVideoSurfaceHolder​(@Nullable
    +
    @Deprecated
    +void clearVideoSurfaceHolder​(@Nullable
                                  SurfaceHolder surfaceHolder)
    -
    Clears the SurfaceHolder that holds the Surface onto which video is being - rendered if it matches the one passed. Else does nothing.
    -
    -
    Parameters:
    -
    surfaceHolder - The surface holder to clear.
    -
    +
  • @@ -516,17 +521,12 @@ void removeVideoListener​(
  • setVideoSurfaceView

    -
    void setVideoSurfaceView​(@Nullable
    +
    @Deprecated
    +void setVideoSurfaceView​(@Nullable
                              SurfaceView surfaceView)
    -
    Sets the SurfaceView onto which video will be rendered. The player will track the - lifecycle of the surface automatically. - -

    The thread that calls the SurfaceHolder.Callback methods must be the thread - associated with Player.getApplicationLooper().

    -
    -
    Parameters:
    -
    surfaceView - The surface view.
    -
    +
    Deprecated. + +
  • @@ -535,14 +535,12 @@ void removeVideoListener​(
  • clearVideoSurfaceView

    -
    void clearVideoSurfaceView​(@Nullable
    +
    @Deprecated
    +void clearVideoSurfaceView​(@Nullable
                                SurfaceView surfaceView)
    -
    Clears the SurfaceView onto which video is being rendered if it matches the one - passed. Else does nothing.
    -
    -
    Parameters:
    -
    surfaceView - The texture view to clear.
    -
    +
    Deprecated. + +
  • @@ -551,17 +549,12 @@ void removeVideoListener​(
  • setVideoTextureView

    -
    void setVideoTextureView​(@Nullable
    +
    @Deprecated
    +void setVideoTextureView​(@Nullable
                              TextureView textureView)
    -
    Sets the TextureView onto which video will be rendered. The player will track the - lifecycle of the surface automatically. - -

    The thread that calls the TextureView.SurfaceTextureListener methods must be the - thread associated with Player.getApplicationLooper().

    -
    -
    Parameters:
    -
    textureView - The texture view.
    -
    +
    Deprecated. + +
  • @@ -570,14 +563,12 @@ void removeVideoListener​(
  • clearVideoTextureView

    -
    void clearVideoTextureView​(@Nullable
    +
    @Deprecated
    +void clearVideoTextureView​(@Nullable
                                TextureView textureView)
    -
    Clears the TextureView onto which video is being rendered if it matches the one - passed. Else does nothing.
    -
    -
    Parameters:
    -
    textureView - The texture view to clear.
    -
    +
    Deprecated. + +
  • @@ -586,15 +577,11 @@ void removeVideoListener​(
  • getVideoSize

    -
    VideoSize getVideoSize()
    -
    Gets the size of the video. - -

    The width and height of size could be 0 if there is no video or the size has not been - determined yet.

    -
    -
    See Also:
    -
    VideoListener.onVideoSizeChanged(int, int, int, float)
    -
    +
    @Deprecated
    +VideoSize getVideoSize()
    +
    Deprecated. + +
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/ExoPlayer.html b/docs/doc/reference/com/google/android/exoplayer2/ExoPlayer.html index e8a5fbd7ea..88195ef603 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ExoPlayer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ExoPlayer.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":6,"i1":6,"i2":6,"i3":6,"i4":6,"i5":6,"i6":6,"i7":6,"i8":6,"i9":6,"i10":6,"i11":6,"i12":6,"i13":6,"i14":6,"i15":6,"i16":6,"i17":6,"i18":6,"i19":6,"i20":6,"i21":38,"i22":38,"i23":6,"i24":38,"i25":6,"i26":6,"i27":6,"i28":6,"i29":6,"i30":6,"i31":6,"i32":6,"i33":6,"i34":6}; +var data = {"i0":6,"i1":6,"i2":38,"i3":6,"i4":6,"i5":6,"i6":6,"i7":6,"i8":6,"i9":6,"i10":6,"i11":6,"i12":6,"i13":6,"i14":38,"i15":6,"i16":6,"i17":6,"i18":6,"i19":38,"i20":6,"i21":6,"i22":6,"i23":6,"i24":6,"i25":6,"i26":6,"i27":38,"i28":6,"i29":6,"i30":38,"i31":6,"i32":6,"i33":6,"i34":38,"i35":38,"i36":6,"i37":6,"i38":38,"i39":38,"i40":6,"i41":6,"i42":6,"i43":6,"i44":6,"i45":6,"i46":38,"i47":6,"i48":6,"i49":6,"i50":6,"i51":6,"i52":6,"i53":6,"i54":6,"i55":6,"i56":6,"i57":6,"i58":38,"i59":6,"i60":6,"i61":6,"i62":6}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -131,7 +131,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    public interface ExoPlayer
     extends Player
    -
    An extensible media player that plays MediaSources. Instances can be obtained from SimpleExoPlayer.Builder. +
    An extensible media player that plays MediaSources. Instances can be obtained from ExoPlayer.Builder.

    Player components

    @@ -143,9 +143,9 @@ extends
  • MediaSources that define the media to be played, load the media, - and from which the loaded media can be read. MediaSources are created from MediaItems by the MediaSourceFactory injected into the player Builder, or can be added directly by methods - like setMediaSource(MediaSource). The library provides a DefaultMediaSourceFactory for progressive media files, DASH, SmoothStreaming and HLS, - which also includes functionality for side-loading subtitle files and clipping media. + and from which the loaded media can be read. MediaSources are created from MediaItems by the MediaSourceFactory injected into the player Builder, or can be added directly by methods like setMediaSource(MediaSource). The library provides a DefaultMediaSourceFactory for + progressive media files, DASH, SmoothStreaming and HLS, which also includes functionality + for side-loading subtitle files and clipping media.
  • Renderers that render individual components of the media. The library provides default implementations for common media types (MediaCodecVideoRenderer, MediaCodecAudioRenderer, TextRenderer and MetadataRenderer). A @@ -229,7 +229,10 @@ extends static interface  ExoPlayer.AudioComponent -
    The audio component of an ExoPlayer.
    +
    Deprecated. +
    Use ExoPlayer, as the ExoPlayer.AudioComponent methods are defined by that + interface.
    +
    @@ -243,37 +246,37 @@ extends static class  ExoPlayer.Builder -
    Deprecated. - -
    +
    A builder for ExoPlayer instances.
    static interface  ExoPlayer.DeviceComponent -
    The device component of an ExoPlayer.
    +
    Deprecated. +
    Use Player, as the ExoPlayer.DeviceComponent methods are defined by that + interface.
    +
    static interface  -ExoPlayer.MetadataComponent +ExoPlayer.TextComponent -
    The metadata component of an ExoPlayer.
    +
    Deprecated. +
    Use Player, as the ExoPlayer.TextComponent methods are defined by that + interface.
    +
    static interface  -ExoPlayer.TextComponent - -
    The text component of an ExoPlayer.
    - - - -static interface  ExoPlayer.VideoComponent -
    The video component of an ExoPlayer.
    +
    Deprecated. +
    Use ExoPlayer, as the ExoPlayer.VideoComponent methods are defined by that + interface.
    +
    @@ -303,6 +306,13 @@ extends static long +DEFAULT_DETACH_SURFACE_TIMEOUT_MS + +
    The default timeout for detaching a surface from the player, in milliseconds.
    + + + +static long DEFAULT_RELEASE_TIMEOUT_MS
    The default timeout for calls to Player.release() and setForegroundMode(boolean), in @@ -315,7 +325,7 @@ extends

    Fields inherited from interface com.google.android.exoplayer2.Player

    -COMMAND_ADJUST_DEVICE_VOLUME, COMMAND_CHANGE_MEDIA_ITEMS, COMMAND_GET_AUDIO_ATTRIBUTES, COMMAND_GET_CURRENT_MEDIA_ITEM, COMMAND_GET_DEVICE_VOLUME, COMMAND_GET_MEDIA_ITEMS_METADATA, COMMAND_GET_TEXT, COMMAND_GET_TIMELINE, COMMAND_GET_VOLUME, COMMAND_INVALID, COMMAND_PLAY_PAUSE, COMMAND_PREPARE_STOP, COMMAND_SEEK_BACK, COMMAND_SEEK_FORWARD, COMMAND_SEEK_IN_CURRENT_WINDOW, COMMAND_SEEK_TO_DEFAULT_POSITION, COMMAND_SEEK_TO_NEXT, COMMAND_SEEK_TO_NEXT_WINDOW, COMMAND_SEEK_TO_PREVIOUS, COMMAND_SEEK_TO_PREVIOUS_WINDOW, COMMAND_SEEK_TO_WINDOW, COMMAND_SET_DEVICE_VOLUME, COMMAND_SET_MEDIA_ITEMS_METADATA, COMMAND_SET_REPEAT_MODE, COMMAND_SET_SHUFFLE_MODE, COMMAND_SET_SPEED_AND_PITCH, COMMAND_SET_VIDEO_SURFACE, COMMAND_SET_VOLUME, DISCONTINUITY_REASON_AUTO_TRANSITION, DISCONTINUITY_REASON_INTERNAL, DISCONTINUITY_REASON_REMOVE, DISCONTINUITY_REASON_SEEK, DISCONTINUITY_REASON_SEEK_ADJUSTMENT, DISCONTINUITY_REASON_SKIP, EVENT_AVAILABLE_COMMANDS_CHANGED, EVENT_IS_LOADING_CHANGED, EVENT_IS_PLAYING_CHANGED, EVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED, EVENT_MEDIA_ITEM_TRANSITION, EVENT_MEDIA_METADATA_CHANGED, EVENT_PLAY_WHEN_READY_CHANGED, EVENT_PLAYBACK_PARAMETERS_CHANGED, EVENT_PLAYBACK_STATE_CHANGED, EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED, EVENT_PLAYER_ERROR, EVENT_PLAYLIST_METADATA_CHANGED, EVENT_POSITION_DISCONTINUITY, EVENT_REPEAT_MODE_CHANGED, EVENT_SEEK_BACK_INCREMENT_CHANGED, EVENT_SEEK_FORWARD_INCREMENT_CHANGED, EVENT_SHUFFLE_MODE_ENABLED_CHANGED, EVENT_STATIC_METADATA_CHANGED, EVENT_TIMELINE_CHANGED, EVENT_TRACKS_CHANGED, MEDIA_ITEM_TRANSITION_REASON_AUTO, MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED, MEDIA_ITEM_TRANSITION_REASON_REPEAT, MEDIA_ITEM_TRANSITION_REASON_SEEK, PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY, PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS, PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM, PLAY_WHEN_READY_CHANGE_REASON_REMOTE, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, PLAYBACK_SUPPRESSION_REASON_NONE, PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS, REPEAT_MODE_ALL, REPEAT_MODE_OFF, REPEAT_MODE_ONE, STATE_BUFFERING, STATE_ENDED, STATE_IDLE, STATE_READY, TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED, TIMELINE_CHANGE_REASON_SOURCE_UPDATE
  • +COMMAND_ADJUST_DEVICE_VOLUME, COMMAND_CHANGE_MEDIA_ITEMS, COMMAND_GET_AUDIO_ATTRIBUTES, COMMAND_GET_CURRENT_MEDIA_ITEM, COMMAND_GET_DEVICE_VOLUME, COMMAND_GET_MEDIA_ITEMS_METADATA, COMMAND_GET_TEXT, COMMAND_GET_TIMELINE, COMMAND_GET_TRACK_INFOS, COMMAND_GET_VOLUME, COMMAND_INVALID, COMMAND_PLAY_PAUSE, COMMAND_PREPARE, COMMAND_SEEK_BACK, COMMAND_SEEK_FORWARD, COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_IN_CURRENT_WINDOW, COMMAND_SEEK_TO_DEFAULT_POSITION, COMMAND_SEEK_TO_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT, COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT_WINDOW, COMMAND_SEEK_TO_PREVIOUS, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, COMMAND_SEEK_TO_PREVIOUS_WINDOW, COMMAND_SEEK_TO_WINDOW, COMMAND_SET_DEVICE_VOLUME, COMMAND_SET_MEDIA_ITEMS_METADATA, COMMAND_SET_REPEAT_MODE, COMMAND_SET_SHUFFLE_MODE, COMMAND_SET_SPEED_AND_PITCH, COMMAND_SET_TRACK_SELECTION_PARAMETERS, COMMAND_SET_VIDEO_SURFACE, COMMAND_SET_VOLUME, COMMAND_STOP, DISCONTINUITY_REASON_AUTO_TRANSITION, DISCONTINUITY_REASON_INTERNAL, DISCONTINUITY_REASON_REMOVE, DISCONTINUITY_REASON_SEEK, DISCONTINUITY_REASON_SEEK_ADJUSTMENT, DISCONTINUITY_REASON_SKIP, EVENT_AVAILABLE_COMMANDS_CHANGED, EVENT_IS_LOADING_CHANGED, EVENT_IS_PLAYING_CHANGED, EVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED, EVENT_MEDIA_ITEM_TRANSITION, EVENT_MEDIA_METADATA_CHANGED, EVENT_PLAY_WHEN_READY_CHANGED, EVENT_PLAYBACK_PARAMETERS_CHANGED, EVENT_PLAYBACK_STATE_CHANGED, EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED, EVENT_PLAYER_ERROR, EVENT_PLAYLIST_METADATA_CHANGED, EVENT_POSITION_DISCONTINUITY, EVENT_REPEAT_MODE_CHANGED, EVENT_SEEK_BACK_INCREMENT_CHANGED, EVENT_SEEK_FORWARD_INCREMENT_CHANGED, EVENT_SHUFFLE_MODE_ENABLED_CHANGED, EVENT_TIMELINE_CHANGED, EVENT_TRACK_SELECTION_PARAMETERS_CHANGED, EVENT_TRACKS_CHANGED, MEDIA_ITEM_TRANSITION_REASON_AUTO, MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED, MEDIA_ITEM_TRANSITION_REASON_REPEAT, MEDIA_ITEM_TRANSITION_REASON_SEEK, PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY, PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS, PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM, PLAY_WHEN_READY_CHANGE_REASON_REMOTE, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, PLAYBACK_SUPPRESSION_REASON_NONE, PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS, REPEAT_MODE_ALL, REPEAT_MODE_OFF, REPEAT_MODE_ONE, STATE_BUFFERING, STATE_ENDED, STATE_IDLE, STATE_READY, TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED, TIMELINE_CHANGE_REASON_SOURCE_UPDATE @@ -336,12 +346,28 @@ extends void +addAnalyticsListener​(AnalyticsListener listener) + +
    Adds an AnalyticsListener to receive analytics events.
    + + + +void addAudioOffloadListener​(ExoPlayer.AudioOffloadListener listener)
    Adds a listener to receive audio offload events.
    - + +void +addListener​(Player.EventListener listener) + + + + + void addMediaSource​(int index, MediaSource mediaSource) @@ -349,14 +375,14 @@ extends Adds a media source at the given index of the playlist.
    - + void addMediaSource​(MediaSource mediaSource)
    Adds a media source to the end of the playlist.
    - + void addMediaSources​(int index, List<MediaSource> mediaSources) @@ -364,77 +390,125 @@ extends Adds a list of media sources at the given index of the playlist.
    - + void addMediaSources​(List<MediaSource> mediaSources)
    Adds a list of media sources to the end of the playlist.
    - + +void +clearAuxEffectInfo() + +
    Detaches any previously attached auxiliary audio effect from the underlying audio track.
    + + + +void +clearCameraMotionListener​(CameraMotionListener listener) + +
    Clears the listener which receives camera motion events if it matches the one passed.
    + + + +void +clearVideoFrameMetadataListener​(VideoFrameMetadataListener listener) + +
    Clears the listener which receives video frame metadata events if it matches the one passed.
    + + + PlayerMessage createMessage​(PlayerMessage.Target target)
    Creates a message that can be sent to a PlayerMessage.Target.
    - + boolean experimentalIsSleepingForOffload()
    Returns whether the player has paused its main loop to save power in offload scheduling mode.
    - + void experimentalSetOffloadSchedulingEnabled​(boolean offloadSchedulingEnabled)
    Sets whether audio offload scheduling is enabled.
    - + +AnalyticsCollector +getAnalyticsCollector() + +
    Returns the AnalyticsCollector used for collecting analytics events.
    + + + ExoPlayer.AudioComponent getAudioComponent() -
    Returns the component of this player for audio output, or null if audio is not supported.
    +
    Deprecated. +
    Use ExoPlayer, as the ExoPlayer.AudioComponent methods are defined by that + interface.
    +
    - + +DecoderCounters +getAudioDecoderCounters() + +
    Returns DecoderCounters for audio, or null if no audio is being played.
    + + + +Format +getAudioFormat() + +
    Returns the audio format currently being played, or null if no audio is being played.
    + + + +int +getAudioSessionId() + +
    Returns the audio session identifier, or C.AUDIO_SESSION_ID_UNSET if not set.
    + + + Clock getClock()
    Returns the Clock used for playback.
    - + ExoPlayer.DeviceComponent getDeviceComponent() -
    Returns the component of this player for playback device, or null if it's not supported.
    +
    Deprecated. +
    Use Player, as the ExoPlayer.DeviceComponent methods are defined by that + interface.
    +
    - -ExoPlayer.MetadataComponent -getMetadataComponent() - -
    Returns the component of this player for metadata output, or null if metadata is not supported.
    - - - + boolean getPauseAtEndOfMediaItems()
    Returns whether the player pauses playback at the end of each media item.
    - + Looper getPlaybackLooper()
    Returns the Looper associated with the playback thread.
    - + ExoPlaybackException getPlayerError() @@ -442,49 +516,90 @@ extends ExoPlaybackException. - + int getRendererCount()
    Returns the number of renderers.
    - -int + +@com.google.android.exoplayer2.C.TrackType int getRendererType​(int index)
    Returns the track type that the renderer at a given index handles.
    - + SeekParameters getSeekParameters()
    Returns the currently active SeekParameters of the player.
    - + +boolean +getSkipSilenceEnabled() + +
    Returns whether skipping silences in the audio stream is enabled.
    + + + ExoPlayer.TextComponent getTextComponent() -
    Returns the component of this player for text output, or null if text is not supported.
    +
    Deprecated. +
    Use Player, as the ExoPlayer.TextComponent methods are defined by that + interface.
    +
    - + TrackSelector getTrackSelector()
    Returns the track selector that this player uses, or null if track selection is not supported.
    - + +int +getVideoChangeFrameRateStrategy() + + + + + ExoPlayer.VideoComponent getVideoComponent() -
    Returns the component of this player for video output, or null if video is not supported.
    +
    Deprecated. +
    Use ExoPlayer, as the ExoPlayer.VideoComponent methods are defined by that + interface.
    +
    - + +DecoderCounters +getVideoDecoderCounters() + +
    Returns DecoderCounters for video, or null if no video is being played.
    + + + +Format +getVideoFormat() + +
    Returns the video format currently being played, or null if no video is being played.
    + + + +int +getVideoScalingMode() + +
    Returns the C.VideoScalingMode.
    + + + void prepare​(MediaSource mediaSource) @@ -493,7 +608,7 @@ extends - + void prepare​(MediaSource mediaSource, boolean resetPosition, @@ -504,14 +619,30 @@ extends - + +void +removeAnalyticsListener​(AnalyticsListener listener) + +
    Removes an AnalyticsListener.
    + + + void removeAudioOffloadListener​(ExoPlayer.AudioOffloadListener listener)
    Removes a listener of audio offload events.
    - + +void +removeListener​(Player.EventListener listener) + + + + + void retry() @@ -520,7 +651,36 @@ extends - + +void +setAudioAttributes​(AudioAttributes audioAttributes, + boolean handleAudioFocus) + +
    Sets the attributes for audio playback, used by the underlying audio track.
    + + + +void +setAudioSessionId​(int audioSessionId) + +
    Sets the ID of the audio session to attach to the underlying AudioTrack.
    + + + +void +setAuxEffectInfo​(AuxEffectInfo auxEffectInfo) + +
    Sets information on an auxiliary audio effect to attach to the underlying audio track.
    + + + +void +setCameraMotionListener​(CameraMotionListener listener) + +
    Sets a listener of camera motion events.
    + + + void setForegroundMode​(boolean foregroundMode) @@ -528,7 +688,24 @@ extends - + +void +setHandleAudioBecomingNoisy​(boolean handleAudioBecomingNoisy) + +
    Sets whether the player should pause automatically when audio is rerouted from a headset to + device speakers.
    + + + +void +setHandleWakeLock​(boolean handleWakeLock) + +
    Deprecated. +
    Use setWakeMode(int) instead.
    +
    + + + void setMediaSource​(MediaSource mediaSource) @@ -536,7 +713,7 @@ extends - + void setMediaSource​(MediaSource mediaSource, boolean resetPosition) @@ -544,7 +721,7 @@ extends Clears the playlist and adds the specified MediaSource. - + void setMediaSource​(MediaSource mediaSource, long startPositionMs) @@ -552,7 +729,7 @@ extends Clears the playlist and adds the specified MediaSource. - + void setMediaSources​(List<MediaSource> mediaSources) @@ -560,7 +737,7 @@ extends - + void setMediaSources​(List<MediaSource> mediaSources, boolean resetPosition) @@ -568,43 +745,95 @@ extends Clears the playlist and adds the specified MediaSources. - + void setMediaSources​(List<MediaSource> mediaSources, - int startWindowIndex, + int startMediaItemIndex, long startPositionMs)
    Clears the playlist and adds the specified MediaSources.
    - + void setPauseAtEndOfMediaItems​(boolean pauseAtEndOfMediaItems)
    Sets whether to pause playback at the end of each media item.
    - + +void +setPriorityTaskManager​(PriorityTaskManager priorityTaskManager) + +
    Sets a PriorityTaskManager, or null to clear a previously set priority task manager.
    + + + void setSeekParameters​(SeekParameters seekParameters)
    Sets the parameters that control how seek operations are performed.
    - + void setShuffleOrder​(ShuffleOrder shuffleOrder)
    Sets the shuffle order.
    + +void +setSkipSilenceEnabled​(boolean skipSilenceEnabled) + +
    Sets whether skipping silences in the audio stream is enabled.
    + + + +void +setThrowsWhenUsingWrongThread​(boolean throwsWhenUsingWrongThread) + +
    Deprecated. +
    Disabling the enforcement can result in hard-to-detect bugs.
    +
    + + + +void +setVideoChangeFrameRateStrategy​(int videoChangeFrameRateStrategy) + +
    Sets a C.VideoChangeFrameRateStrategy that will be used by the player when provided + with a video output Surface.
    + + + +void +setVideoFrameMetadataListener​(VideoFrameMetadataListener listener) + +
    Sets a listener to receive video frame metadata events.
    + + + +void +setVideoScalingMode​(int videoScalingMode) + + + + + +void +setWakeMode​(@com.google.android.exoplayer2.C.WakeMode int wakeMode) + +
    Sets how the player should keep the device awake for playback when the screen is off.
    + + @@ -625,7 +854,7 @@ extends -
      +
      • DEFAULT_RELEASE_TIMEOUT_MS

        static final long DEFAULT_RELEASE_TIMEOUT_MS
        @@ -637,6 +866,20 @@ extends
      + + + +
        +
      • +

        DEFAULT_DETACH_SURFACE_TIMEOUT_MS

        +
        static final long DEFAULT_DETACH_SURFACE_TIMEOUT_MS
        +
        The default timeout for detaching a surface from the player, in milliseconds.
        +
        +
        See Also:
        +
        Constant Field Values
        +
        +
      • +
    @@ -673,8 +916,12 @@ extends

    getAudioComponent

    @Nullable
    +@Deprecated
     ExoPlayer.AudioComponent getAudioComponent()
    -
    Returns the component of this player for audio output, or null if audio is not supported.
    +
    Deprecated. +
    Use ExoPlayer, as the ExoPlayer.AudioComponent methods are defined by that + interface.
    +
    @@ -684,8 +931,12 @@ extends

    getVideoComponent

    @Nullable
    +@Deprecated
     ExoPlayer.VideoComponent getVideoComponent()
    -
    Returns the component of this player for video output, or null if video is not supported.
    +
    Deprecated. +
    Use ExoPlayer, as the ExoPlayer.VideoComponent methods are defined by that + interface.
    +
    @@ -695,19 +946,12 @@ extends

    getTextComponent

    @Nullable
    +@Deprecated
     ExoPlayer.TextComponent getTextComponent()
    -
    Returns the component of this player for text output, or null if text is not supported.
    - - - - - -
      -
    • -

      getMetadataComponent

      -
      @Nullable
      -ExoPlayer.MetadataComponent getMetadataComponent()
      -
      Returns the component of this player for metadata output, or null if metadata is not supported.
      +
      Deprecated. +
      Use Player, as the ExoPlayer.TextComponent methods are defined by that + interface.
      +
    @@ -717,8 +961,51 @@ extends

    getDeviceComponent

    @Nullable
    +@Deprecated
     ExoPlayer.DeviceComponent getDeviceComponent()
    -
    Returns the component of this player for playback device, or null if it's not supported.
    +
    Deprecated. +
    Use Player, as the ExoPlayer.DeviceComponent methods are defined by that + interface.
    +
    + + + + + + + + + + @@ -749,6 +1036,44 @@ extends + + + + + + + +
      +
    • +

      addAnalyticsListener

      +
      void addAnalyticsListener​(AnalyticsListener listener)
      +
      Adds an AnalyticsListener to receive analytics events.
      +
      +
      Parameters:
      +
      listener - The listener to be added.
      +
      +
    • +
    + + + +
      +
    • +

      removeAnalyticsListener

      +
      void removeAnalyticsListener​(AnalyticsListener listener)
      +
      Removes an AnalyticsListener.
      +
      +
      Parameters:
      +
      listener - The listener to be removed.
      +
      +
    • +
    @@ -765,7 +1090,7 @@ extends
  • getRendererType

    -
    int getRendererType​(int index)
    +
    @com.google.android.exoplayer2.C.TrackType int getRendererType​(int index)
  • @@ -879,7 +1204,7 @@ void prepare​(MediaSources.
    resetPosition - Whether the playback position should be reset to the default position in the first Timeline.Window. If false, playback will start from the position defined - by Player.getCurrentWindowIndex() and Player.getCurrentPosition().
    + by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition(). @@ -890,17 +1215,16 @@ void prepare​(

    setMediaSources

    void setMediaSources​(List<MediaSource> mediaSources,
    -                     int startWindowIndex,
    +                     int startMediaItemIndex,
                          long startPositionMs)
    Clears the playlist and adds the specified MediaSources.
    Parameters:
    mediaSources - The new MediaSources.
    -
    startWindowIndex - The window index to start playback from. If C.INDEX_UNSET is - passed, the current position is not reset.
    -
    startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given window is used. In any case, if - startWindowIndex is set to C.INDEX_UNSET, this parameter is ignored and the - position is not reset at all.
    +
    startMediaItemIndex - The media item index to start playback from. If C.INDEX_UNSET is passed, the current position is not reset.
    +
    startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given media item is used. In any case, + if startMediaItemIndex is set to C.INDEX_UNSET, this parameter is ignored + and the position is not reset at all.
    @@ -948,7 +1272,7 @@ void prepare​(Parameters:
    mediaSource - The new MediaSource.
    resetPosition - Whether the playback position should be reset to the default position. If - false, playback will start from the position defined by Player.getCurrentWindowIndex() + false, playback will start from the position defined by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition().
    @@ -1027,6 +1351,231 @@ void prepare​( + + +
      +
    • +

      setAudioAttributes

      +
      void setAudioAttributes​(AudioAttributes audioAttributes,
      +                        boolean handleAudioFocus)
      +
      Sets the attributes for audio playback, used by the underlying audio track. If not set, the + default audio attributes will be used. They are suitable for general media playback. + +

      Setting the audio attributes during playback may introduce a short gap in audio output as + the audio track is recreated. A new audio session id will also be generated. + +

      If tunneling is enabled by the track selector, the specified audio attributes will be + ignored, but they will take effect if audio is later played without tunneling. + +

      If the device is running a build before platform API version 21, audio attributes cannot be + set directly on the underlying audio track. In this case, the usage will be mapped onto an + equivalent stream type using Util.getStreamTypeForAudioUsage(int). + +

      If audio focus should be handled, the AudioAttributes.usage must be C.USAGE_MEDIA or C.USAGE_GAME. Other usages will throw an IllegalArgumentException.

      +
      +
      Parameters:
      +
      audioAttributes - The attributes to use for audio playback.
      +
      handleAudioFocus - True if the player should handle audio focus, false otherwise.
      +
      +
    • +
    + + + +
      +
    • +

      setAudioSessionId

      +
      void setAudioSessionId​(int audioSessionId)
      +
      Sets the ID of the audio session to attach to the underlying AudioTrack. + +

      The audio session ID can be generated using Util.generateAudioSessionIdV21(Context) + for API 21+.

      +
      +
      Parameters:
      +
      audioSessionId - The audio session ID, or C.AUDIO_SESSION_ID_UNSET if it should be + generated by the framework.
      +
      +
    • +
    + + + +
      +
    • +

      getAudioSessionId

      +
      int getAudioSessionId()
      +
      Returns the audio session identifier, or C.AUDIO_SESSION_ID_UNSET if not set.
      +
    • +
    + + + +
      +
    • +

      setAuxEffectInfo

      +
      void setAuxEffectInfo​(AuxEffectInfo auxEffectInfo)
      +
      Sets information on an auxiliary audio effect to attach to the underlying audio track.
      +
    • +
    + + + +
      +
    • +

      clearAuxEffectInfo

      +
      void clearAuxEffectInfo()
      +
      Detaches any previously attached auxiliary audio effect from the underlying audio track.
      +
    • +
    + + + +
      +
    • +

      setSkipSilenceEnabled

      +
      void setSkipSilenceEnabled​(boolean skipSilenceEnabled)
      +
      Sets whether skipping silences in the audio stream is enabled.
      +
      +
      Parameters:
      +
      skipSilenceEnabled - Whether skipping silences in the audio stream is enabled.
      +
      +
    • +
    + + + +
      +
    • +

      getSkipSilenceEnabled

      +
      boolean getSkipSilenceEnabled()
      +
      Returns whether skipping silences in the audio stream is enabled.
      +
    • +
    + + + + + + + + + + + + + + + + + + + +
      +
    • +

      setVideoFrameMetadataListener

      +
      void setVideoFrameMetadataListener​(VideoFrameMetadataListener listener)
      +
      Sets a listener to receive video frame metadata events. + +

      This method is intended to be called by the same component that sets the Surface + onto which video will be rendered. If using ExoPlayer's standard UI components, this method + should not be called directly from application code.

      +
      +
      Parameters:
      +
      listener - The listener.
      +
      +
    • +
    + + + +
      +
    • +

      clearVideoFrameMetadataListener

      +
      void clearVideoFrameMetadataListener​(VideoFrameMetadataListener listener)
      +
      Clears the listener which receives video frame metadata events if it matches the one passed. + Else does nothing.
      +
      +
      Parameters:
      +
      listener - The listener to clear.
      +
      +
    • +
    + + + +
      +
    • +

      setCameraMotionListener

      +
      void setCameraMotionListener​(CameraMotionListener listener)
      +
      Sets a listener of camera motion events.
      +
      +
      Parameters:
      +
      listener - The listener.
      +
      +
    • +
    + + + +
      +
    • +

      clearCameraMotionListener

      +
      void clearCameraMotionListener​(CameraMotionListener listener)
      +
      Clears the listener which receives camera motion events if it matches the one passed. Else does + nothing.
      +
      +
      Parameters:
      +
      listener - The listener to clear.
      +
      +
    • +
    @@ -1037,8 +1586,8 @@ void prepare​(Creates a message that can be sent to a PlayerMessage.Target. By default, the message will be delivered immediately without blocking on the playback thread. The default PlayerMessage.getType() is 0 and the default PlayerMessage.getPayload() is null. If a position is specified with PlayerMessage.setPosition(long), the message will be - delivered at this position in the current window defined by Player.getCurrentWindowIndex(). - Alternatively, the message can be sent at a specific window using PlayerMessage.setPosition(int, long). + delivered at this position in the current media item defined by Player.getCurrentMediaItemIndex(). Alternatively, the message can be sent at a specific mediaItem + using PlayerMessage.setPosition(int, long). @@ -1112,7 +1661,7 @@ void prepare​(void setPauseAtEndOfMediaItems​(boolean pauseAtEndOfMediaItems) +

    This means the player will pause at the end of each window in the current timeline. Listeners will be informed by a call to Player.Listener.onPlayWhenReadyChanged(boolean, int) with the reason Player.PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM when this happens.

    Parameters:
    pauseAtEndOfMediaItems - Whether to pause playback at the end of each media item.
    @@ -1133,6 +1682,143 @@ void prepare​( + + +
      +
    • +

      getAudioFormat

      +
      @Nullable
      +Format getAudioFormat()
      +
      Returns the audio format currently being played, or null if no audio is being played.
      +
    • +
    + + + +
      +
    • +

      getVideoFormat

      +
      @Nullable
      +Format getVideoFormat()
      +
      Returns the video format currently being played, or null if no video is being played.
      +
    • +
    + + + +
      +
    • +

      getAudioDecoderCounters

      +
      @Nullable
      +DecoderCounters getAudioDecoderCounters()
      +
      Returns DecoderCounters for audio, or null if no audio is being played.
      +
    • +
    + + + +
      +
    • +

      getVideoDecoderCounters

      +
      @Nullable
      +DecoderCounters getVideoDecoderCounters()
      +
      Returns DecoderCounters for video, or null if no video is being played.
      +
    • +
    + + + +
      +
    • +

      setHandleAudioBecomingNoisy

      +
      void setHandleAudioBecomingNoisy​(boolean handleAudioBecomingNoisy)
      +
      Sets whether the player should pause automatically when audio is rerouted from a headset to + device speakers. See the audio + becoming noisy documentation for more information.
      +
      +
      Parameters:
      +
      handleAudioBecomingNoisy - Whether the player should pause automatically when audio is + rerouted from a headset to device speakers.
      +
      +
    • +
    + + + +
      +
    • +

      setHandleWakeLock

      +
      @Deprecated
      +void setHandleWakeLock​(boolean handleWakeLock)
      +
      Deprecated. +
      Use setWakeMode(int) instead.
      +
      +
    • +
    + + + +
      +
    • +

      setWakeMode

      +
      void setWakeMode​(@WakeMode
      +                 @com.google.android.exoplayer2.C.WakeMode int wakeMode)
      +
      Sets how the player should keep the device awake for playback when the screen is off. + +

      Enabling this feature requires the Manifest.permission.WAKE_LOCK permission. + It should be used together with a foreground Service for use cases where + playback occurs and the screen is off (e.g. background audio playback). It is not useful when + the screen will be kept on during playback (e.g. foreground video playback). + +

      When enabled, the locks (PowerManager.WakeLock / WifiManager.WifiLock) will be held whenever the player is in the Player.STATE_READY or Player.STATE_BUFFERING states with playWhenReady = true. The locks + held depends on the specified C.WakeMode.

      +
      +
      Parameters:
      +
      wakeMode - The C.WakeMode option to keep the device awake during playback.
      +
      +
    • +
    + + + +
      +
    • +

      setPriorityTaskManager

      +
      void setPriorityTaskManager​(@Nullable
      +                            PriorityTaskManager priorityTaskManager)
      +
      Sets a PriorityTaskManager, or null to clear a previously set priority task manager. + +

      The priority C.PRIORITY_PLAYBACK will be set while the player is loading.

      +
      +
      Parameters:
      +
      priorityTaskManager - The PriorityTaskManager, or null to clear a previously set + priority task manager.
      +
      +
    • +
    + + + +
      +
    • +

      setThrowsWhenUsingWrongThread

      +
      @Deprecated
      +void setThrowsWhenUsingWrongThread​(boolean throwsWhenUsingWrongThread)
      +
      Deprecated. +
      Disabling the enforcement can result in hard-to-detect bugs. Do not use this method + except to ease the transition while wrong thread access problems are fixed.
      +
      +
      Sets whether the player should throw an IllegalStateException when methods are called + from a thread other than the one associated with Player.getApplicationLooper(). + +

      The default is true and this method will be removed in the future.

      +
      +
      Parameters:
      +
      throwsWhenUsingWrongThread - Whether to throw when methods are called from a wrong thread.
      +
      +
    • +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/ExoPlayerLibraryInfo.html b/docs/doc/reference/com/google/android/exoplayer2/ExoPlayerLibraryInfo.html index b191655a6c..a5f9f4b29b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ExoPlayerLibraryInfo.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ExoPlayerLibraryInfo.html @@ -131,7 +131,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    public final class ExoPlayerLibraryInfo
     extends Object
    -
    Information about the ExoPlayer library.
    +
    Information about the media libraries.
    @@ -156,24 +156,7 @@ extends static boolean ASSERTIONS_ENABLED -
    Whether the library was compiled with Assertions - checks enabled.
    - - - -static String -DEFAULT_USER_AGENT - -
    Deprecated. -
    ExoPlayer now uses the user agent of the underlying network stack by default.
    -
    - - - -static boolean -GL_ASSERTIONS_ENABLED - -
    Whether an exception should be thrown in case of an OpenGl error.
    +
    Whether the library was compiled with Assertions checks enabled.
    @@ -187,8 +170,7 @@ extends static boolean TRACE_ENABLED -
    Whether the library was compiled with TraceUtil - trace enabled.
    +
    Whether the library was compiled with TraceUtil trace enabled.
    @@ -209,7 +191,7 @@ extends static String VERSION_SLASHY -
    The version of the library expressed as "ExoPlayerLib/" + VERSION.
    +
    The version of the library expressed as TAG + "/" + VERSION.
    @@ -303,7 +285,7 @@ extends

    VERSION_SLASHY

    public static final String VERSION_SLASHY
    -
    The version of the library expressed as "ExoPlayerLib/" + VERSION.
    +
    The version of the library expressed as TAG + "/" + VERSION.
    See Also:
    Constant Field Values
    @@ -328,20 +310,6 @@ extends - - - -
      -
    • -

      DEFAULT_USER_AGENT

      -
      @Deprecated
      -public static final String DEFAULT_USER_AGENT
      -
      Deprecated. -
      ExoPlayer now uses the user agent of the underlying network stack by default.
      -
      -
      The default user agent for requests made by the library.
      -
    • -
    @@ -349,28 +317,13 @@ public static final 

    ASSERTIONS_ENABLED

    public static final boolean ASSERTIONS_ENABLED
    -
    +
    Whether the library was compiled with Assertions checks enabled.
    See Also:
    Constant Field Values
    - - - -
      -
    • -

      GL_ASSERTIONS_ENABLED

      -
      public static final boolean GL_ASSERTIONS_ENABLED
      -
      Whether an exception should be thrown in case of an OpenGl error.
      -
      -
      See Also:
      -
      Constant Field Values
      -
      -
    • -
    @@ -378,8 +331,7 @@ public static final 

    TRACE_ENABLED

    public static final boolean TRACE_ENABLED
    -
    +
    Whether the library was compiled with TraceUtil trace enabled.
    See Also:
    Constant Field Values
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/Format.Builder.html b/docs/doc/reference/com/google/android/exoplayer2/Format.Builder.html index a2b33749a8..4dc4edf5dc 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Format.Builder.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Format.Builder.html @@ -234,32 +234,32 @@ extends Format.Builder +setCryptoType​(@com.google.android.exoplayer2.C.CryptoType int cryptoType) + + + + + +Format.Builder setDrmInitData​(DrmInitData drmInitData) - + Format.Builder setEncoderDelay​(int encoderDelay) - + Format.Builder setEncoderPadding​(int encoderPadding) - -Format.Builder -setExoMediaCryptoType​(Class<? extends ExoMediaCrypto> exoMediaCryptoType) - - - - Format.Builder setFrameRate​(float frameRate) @@ -353,7 +353,7 @@ extends Format.Builder -setRoleFlags​(int roleFlags) +setRoleFlags​(@com.google.android.exoplayer2.C.RoleFlags int roleFlags) @@ -381,7 +381,7 @@ extends Format.Builder -setSelectionFlags​(int selectionFlags) +setSelectionFlags​(@com.google.android.exoplayer2.C.SelectionFlags int selectionFlags) @@ -519,14 +519,14 @@ extends - +
    • setSelectionFlags

      public Format.Builder setSelectionFlags​(@SelectionFlags
      -                                        int selectionFlags)
      + @com.google.android.exoplayer2.C.SelectionFlags int selectionFlags)
      Sets Format.selectionFlags. The default value is 0.
      Parameters:
      @@ -536,14 +536,14 @@ extends
    - +
    • setRoleFlags

      public Format.Builder setRoleFlags​(@RoleFlags
      -                                   int roleFlags)
      + @com.google.android.exoplayer2.C.RoleFlags int roleFlags)
      Sets Format.roleFlags. The default value is 0.
      Parameters:
      @@ -947,18 +947,17 @@ extends
    - +
    • -

      setExoMediaCryptoType

      -
      public Format.Builder setExoMediaCryptoType​(@Nullable
      -                                            Class<? extends ExoMediaCrypto> exoMediaCryptoType)
      -
      Sets Format.exoMediaCryptoType. The default value is null.
      +

      setCryptoType

      +
      public Format.Builder setCryptoType​(@com.google.android.exoplayer2.C.CryptoType int cryptoType)
      +
      Sets Format.cryptoType. The default value is C.CRYPTO_TYPE_NONE.
      Parameters:
      -
      exoMediaCryptoType - The Format.exoMediaCryptoType.
      +
      cryptoType - The C.CryptoType.
      Returns:
      The builder.
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/Format.html b/docs/doc/reference/com/google/android/exoplayer2/Format.html index 9e78b8eb59..f896e1c926 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Format.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Format.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":42,"i2":42,"i3":10,"i4":42,"i5":42,"i6":42,"i7":42,"i8":42,"i9":42,"i10":42,"i11":42,"i12":41,"i13":41,"i14":41,"i15":41,"i16":41,"i17":41,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":9,"i24":10,"i25":10,"i26":10}; +var data = {"i0":10,"i1":42,"i2":10,"i3":42,"i4":42,"i5":42,"i6":42,"i7":42,"i8":42,"i9":42,"i10":42,"i11":42,"i12":41,"i13":41,"i14":41,"i15":41,"i16":41,"i17":41,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":9,"i24":10,"i25":10}; var tabs = {65535:["t0","All Methods"],1:["t1","Static Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -130,12 +130,12 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    • All Implemented Interfaces:
      -
      Parcelable
      +
      Bundleable

      public final class Format
       extends Object
      -implements Parcelable
      +implements Bundleable
      Represents a media format.

      When building formats, populate all fields whose values are known and relevant to the type of @@ -236,11 +236,11 @@ implements -

    • +
    • -

      Nested classes/interfaces inherited from interface android.os.Parcelable

      -Parcelable.ClassLoaderCreator<T extends Object>, Parcelable.Creator<T extends Object>
    • +

      Nested classes/interfaces inherited from interface com.google.android.exoplayer2.Bundleable

      +Bundleable.Creator<T extends Bundleable>
    @@ -309,18 +309,27 @@ implements -static Parcelable.Creator<Format> +static Bundleable.Creator<Format> CREATOR -  + +
    Object that can restore Format from a Bundle.
    + +@com.google.android.exoplayer2.C.CryptoType int +cryptoType + +
    The type of crypto that must be used to decode samples associated with this format, or C.CRYPTO_TYPE_NONE if the content is not encrypted.
    + + + DrmInitData drmInitData
    DRM initialization data if the stream is protected, or null otherwise.
    - + int encoderDelay @@ -328,21 +337,13 @@ implements + int encoderPadding
    The number of frames to trim from the end of the decoded audio stream, or 0 if not applicable.
    - -Class<? extends ExoMediaCrypto> -exoMediaCryptoType - -
    The type of ExoMediaCrypto that will be associated with the content this format - describes, or null if the content is not encrypted.
    - - float frameRate @@ -444,7 +445,7 @@ implements -int +@com.google.android.exoplayer2.C.RoleFlags int roleFlags
    Track role flags.
    @@ -473,7 +474,7 @@ implements -int +@com.google.android.exoplayer2.C.SelectionFlags int selectionFlags
    Track selection flags.
    @@ -502,13 +503,6 @@ implements -
  • - - -

    Fields inherited from interface android.os.Parcelable

    -CONTENTS_FILE_DESCRIPTOR, PARCELABLE_WRITE_RETURN_VALUE
  • - @@ -544,6 +538,13 @@ implements Format +copyWithCryptoType​(@com.google.android.exoplayer2.C.CryptoType int cryptoType) + +
    Returns a copy of this format with the specified cryptoType.
    + + + +Format copyWithDrmInitData​(DrmInitData drmInitData)
    Deprecated. @@ -551,13 +552,6 @@ implements -Format -copyWithExoMediaCryptoType​(Class<? extends ExoMediaCrypto> exoMediaCryptoType) - -
    Returns a copy of this format with the specified exoMediaCryptoType.
    - - Format copyWithFrameRate​(float frameRate) @@ -634,7 +628,7 @@ implements static Format -createAudioSampleFormat​(String id, +createAudioSampleFormat​(String id, String sampleMimeType, String codecs, int bitrate, @@ -644,7 +638,7 @@ implements List<byte[]> initializationData, DrmInitData drmInitData, - int selectionFlags, + @com.google.android.exoplayer2.C.SelectionFlags int selectionFlags, String language)
    Deprecated. @@ -654,7 +648,7 @@ implements static Format -createAudioSampleFormat​(String id, +createAudioSampleFormat​(String id, String sampleMimeType, String codecs, int bitrate, @@ -663,7 +657,7 @@ implements List<byte[]> initializationData, DrmInitData drmInitData, - int selectionFlags, + @com.google.android.exoplayer2.C.SelectionFlags int selectionFlags, String language)
    Deprecated. @@ -673,14 +667,14 @@ implements static Format -createContainerFormat​(String id, +createContainerFormat​(String id, String label, String containerMimeType, String sampleMimeType, String codecs, int bitrate, - int selectionFlags, - int roleFlags, + @com.google.android.exoplayer2.C.SelectionFlags int selectionFlags, + @com.google.android.exoplayer2.C.RoleFlags int roleFlags, String language)
    Deprecated. @@ -737,16 +731,11 @@ implements -int -describeContents() -  - - boolean equals​(Object obj)   - + int getPixelCount() @@ -754,12 +743,12 @@ implements NO_VALUE otherwise
    - + int hashCode()   - + boolean initializationDataEquals​(Format other) @@ -767,6 +756,13 @@ implements +Bundle +toBundle() + +
    Returns a Bundle representing the information stored in this object.
    + + static String toLogString​(Format format) @@ -784,12 +780,6 @@ implements withManifestFormatInfo​(Format manifestFormat)   - -void -writeToParcel​(Parcel dest, - int flags) -  - @@ -894,7 +884,7 @@ public final int selectionFlags
  • roleFlags

    @RoleFlags
    -public final int roleFlags
    +public final @com.google.android.exoplayer2.C.RoleFlags int roleFlags
    Track role flags.
  • @@ -1197,16 +1187,16 @@ public final int pcmEncoding
    The Accessibility channel, or NO_VALUE if not known or applicable.
    - +
    • -

      exoMediaCryptoType

      -
      @Nullable
      -public final Class<? extends ExoMediaCrypto> exoMediaCryptoType
      -
      The type of ExoMediaCrypto that will be associated with the content this format - describes, or null if the content is not encrypted. Cannot be null if drmInitData is non-null.
      +

      cryptoType

      +
      public final @com.google.android.exoplayer2.C.CryptoType int cryptoType
      +
      The type of crypto that must be used to decode samples associated with this format, or C.CRYPTO_TYPE_NONE if the content is not encrypted. Cannot be C.CRYPTO_TYPE_NONE if + drmInitData is non-null, but may be C.CRYPTO_TYPE_UNSUPPORTED to indicate that + the samples are encrypted using an unsupported crypto type.
    @@ -1215,7 +1205,8 @@ public final 
  • CREATOR

    -
    public static final Parcelable.Creator<Format> CREATOR
    +
    public static final Bundleable.Creator<Format> CREATOR
    +
    Object that can restore Format from a Bundle.
  • @@ -1284,7 +1275,7 @@ public static  + @@ -217,34 +217,27 @@ implements void -addListener​(Player.EventListener listener) +addListener​(Player.Listener listener)
    Deprecated.
    void -addListener​(Player.Listener listener) - -
    Registers a listener to receive all events from the player.
    - - - -void addMediaItem​(int index, MediaItem mediaItem)
    Adds a media item at the given index of the playlist.
    - + void addMediaItem​(MediaItem mediaItem)
    Adds a media item to the end of the playlist.
    - + void addMediaItems​(int index, List<MediaItem> mediaItems) @@ -252,13 +245,20 @@ implements Adds a list of media items at the given index of the playlist.
    - + void addMediaItems​(List<MediaItem> mediaItems)
    Adds a list of media items to the end of the playlist.
    + +boolean +canAdvertiseSession() + +
    Returns whether the player can be used to advertise a media session.
    + + void clearMediaItems() @@ -314,8 +314,7 @@ implements Looper getApplicationLooper() -
    Returns the Looper associated with the application thread that's used to access the - player and on which player events are received.
    +
    Deprecated.
    @@ -336,7 +335,7 @@ implements int getBufferedPercentage() -
    Returns an estimate of the percentage in the current content window or ad up to which data is +
    Returns an estimate of the percentage in the current content or ad up to which data is buffered, or 0 if no estimate is available.
    @@ -344,8 +343,8 @@ implements long getBufferedPosition() -
    Returns an estimate of the position in the current content window or ad up to which data is - buffered, in milliseconds.
    +
    Returns an estimate of the position in the current content or ad up to which data is buffered, + in milliseconds.
    @@ -353,15 +352,15 @@ implements getContentBufferedPosition()
    If Player.isPlayingAd() returns true, returns an estimate of the content position in - the current content window up to which data is buffered, in milliseconds.
    + the current content up to which data is buffered, in milliseconds.
    long getContentDuration() -
    If Player.isPlayingAd() returns true, returns the duration of the current content - window in milliseconds, or C.TIME_UNSET if the duration is not known.
    +
    If Player.isPlayingAd() returns true, returns the duration of the current content in + milliseconds, or C.TIME_UNSET if the duration is not known.
    @@ -399,8 +398,8 @@ implements getCurrentLiveOffset()
    Returns the offset of the current playback position from the live edge in milliseconds, or - C.TIME_UNSET if the current window isn't live or the - offset is unknown.
    + C.TIME_UNSET if the current MediaItem Player.isCurrentMediaItemLive() isn't + live} or the offset is unknown.
    @@ -414,30 +413,30 @@ implements MediaItem getCurrentMediaItem() -
    Returns the media item of the current window in the timeline.
    +
    Returns the currently playing MediaItem.
    int +getCurrentMediaItemIndex() + +
    Returns the index of the current MediaItem in the timeline, or the prospective index if the current timeline is + empty.
    + + + +int getCurrentPeriodIndex()
    Returns the index of the period currently being played.
    - + long getCurrentPosition() -
    Returns the playback position in the current content window or ad, in milliseconds, or the - prospective position in milliseconds if the current timeline is - empty.
    - - - -List<Metadata> -getCurrentStaticMetadata() - -
    Deprecated.
    +
    Returns the playback position in the current content or ad, in milliseconds, or the prospective + position in milliseconds if the current timeline is empty.
    @@ -462,56 +461,63 @@ implements -int -getCurrentWindowIndex() +TracksInfo +getCurrentTracksInfo() -
    Returns the index of the current window in the timeline, or the prospective window index if the current timeline is empty.
    +
    Returns the available tracks, as well as the tracks' support, type, and selection status.
    -DeviceInfo +int +getCurrentWindowIndex() + +
    Deprecated.
    + + + +DeviceInfo getDeviceInfo()
    Gets the device information.
    - + int getDeviceVolume()
    Gets the current volume of the device.
    - + long getDuration() -
    Returns the duration of the current content window or ad in milliseconds, or C.TIME_UNSET if the duration is not known.
    - - - -int -getMaxSeekToPreviousPosition() - -
    Returns the maximum position for which Player.seekToPrevious() seeks to the previous window, - in milliseconds.
    +
    Returns the duration of the current content or ad in milliseconds, or C.TIME_UNSET if + the duration is not known.
    +long +getMaxSeekToPreviousPosition() + +
    Returns the maximum position for which Player.seekToPrevious() seeks to the previous MediaItem, in milliseconds.
    + + + MediaItem getMediaItemAt​(int index)
    Returns the MediaItem at the given index.
    - + int getMediaItemCount()
    Returns the number of media items in the playlist.
    - + MediaMetadata getMediaMetadata() @@ -519,29 +525,36 @@ implements + +int +getNextMediaItemIndex() + +
    Returns the index of the MediaItem that will be played if Player.seekToNextMediaItem() is called, which may depend on the current repeat mode and whether + shuffle mode is enabled.
    + + + int getNextWindowIndex() -
    Returns the index of the window that will be played if Player.seekToNextWindow() is called, - which may depend on the current repeat mode and whether shuffle mode is enabled.
    +
    Deprecated.
    - + PlaybackParameters getPlaybackParameters()
    Returns the currently active playback parameters.
    - + int getPlaybackState()
    Returns the current playback state of the player.
    - + int getPlaybackSuppressionReason() @@ -549,187 +562,236 @@ implements Player.PLAYBACK_SUPPRESSION_REASON_NONE if playback is not suppressed.
    - + PlaybackException getPlayerError()
    Returns the error that caused playback to fail.
    - + MediaMetadata getPlaylistMetadata()
    Returns the playlist MediaMetadata, as set by Player.setPlaylistMetadata(MediaMetadata), or MediaMetadata.EMPTY if not supported.
    - + boolean getPlayWhenReady()
    Whether playback will proceed when Player.getPlaybackState() == Player.STATE_READY.
    - + +int +getPreviousMediaItemIndex() + +
    Returns the index of the MediaItem that will be played if Player.seekToPreviousMediaItem() is called, which may depend on the current repeat mode and whether + shuffle mode is enabled.
    + + + int getPreviousWindowIndex() -
    Returns the index of the window that will be played if Player.seekToPreviousWindow() is - called, which may depend on the current repeat mode and whether shuffle mode is enabled.
    +
    Deprecated.
    - + int getRepeatMode()
    Returns the current Player.RepeatMode used for playback.
    - + long getSeekBackIncrement()
    Returns the Player.seekBack() increment.
    - + long getSeekForwardIncrement()
    Returns the Player.seekForward() increment.
    - + boolean getShuffleModeEnabled() -
    Returns whether shuffling of windows is enabled.
    +
    Returns whether shuffling of media items is enabled.
    - + long getTotalBufferedDuration()
    Returns an estimate of the total buffered duration from the current position, in milliseconds.
    - + +TrackSelectionParameters +getTrackSelectionParameters() + +
    Returns the parameters constraining the track selection.
    + + + VideoSize getVideoSize()
    Gets the size of the video.
    - + float getVolume()
    Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
    - + Player getWrappedPlayer()
    Returns the Player to which operations are forwarded.
    - + boolean hasNext()
    Deprecated.
    - + +boolean +hasNextMediaItem() + +
    Returns whether a next MediaItem exists, which may depend on the current repeat mode + and whether shuffle mode is enabled.
    + + + boolean hasNextWindow() -
    Returns whether a next window exists, which may depend on the current repeat mode and whether - shuffle mode is enabled.
    +
    Deprecated.
    - + boolean hasPrevious()
    Deprecated.
    - + boolean -hasPreviousWindow() +hasPreviousMediaItem() -
    Returns whether a previous window exists, which may depend on the current repeat mode and +
    Returns whether a previous media item exists, which may depend on the current repeat mode and whether shuffle mode is enabled.
    - + +boolean +hasPreviousWindow() + +
    Deprecated.
    + + + void increaseDeviceVolume()
    Increases the volume of the device.
    - + boolean -isCommandAvailable​(int command) +isCommandAvailable​(@com.google.android.exoplayer2.Player.Command int command)
    Returns whether the provided Player.Command is available.
    - + +boolean +isCurrentMediaItemDynamic() + +
    Returns whether the current MediaItem is dynamic (may change when the Timeline + is updated), or false if the Timeline is empty.
    + + + +boolean +isCurrentMediaItemLive() + +
    Returns whether the current MediaItem is live, or false if the Timeline + is empty.
    + + + +boolean +isCurrentMediaItemSeekable() + +
    Returns whether the current MediaItem is seekable, or false if the Timeline is empty.
    + + + boolean isCurrentWindowDynamic() -
    Returns whether the current window is dynamic, or false if the Timeline is - empty.
    +
    Deprecated.
    - + boolean isCurrentWindowLive() -
    Returns whether the current window is live, or false if the Timeline is empty.
    +
    Deprecated.
    - + boolean isCurrentWindowSeekable() -
    Returns whether the current window is seekable, or false if the Timeline is - empty.
    +
    Deprecated.
    - + boolean isDeviceMuted()
    Gets whether the device is muted or not.
    - + boolean isLoading()
    Whether the player is currently loading the source.
    - + boolean isPlaying()
    Returns whether the player is playing, i.e.
    - + boolean isPlayingAd()
    Returns whether the player is currently playing an ad.
    - + void moveMediaItem​(int currentIndex, int newIndex) @@ -737,7 +799,7 @@ implements Moves the media item at the current index to the new index.
    - + void moveMediaItems​(int fromIndex, int toIndex, @@ -746,70 +808,63 @@ implements Moves the media item range to the new index. - + void next()
    Deprecated.
    - + void pause()
    Pauses playback.
    - + void play()
    Resumes playback as soon as Player.getPlaybackState() == Player.STATE_READY.
    - + void prepare()
    Prepares the player.
    - + void previous()
    Deprecated.
    - + void release()
    Releases the player.
    - -void -removeListener​(Player.EventListener listener) - -
    Deprecated.
    - - - + void removeListener​(Player.Listener listener)
    Unregister a listener registered through Player.addListener(Listener).
    - + void removeMediaItem​(int index)
    Removes the media item at the given index of the playlist.
    - + void removeMediaItems​(int fromIndex, int toIndex) @@ -817,94 +872,109 @@ implements Removes a range of media items from the playlist. - + void seekBack() -
    Seeks back in the current window by Player.getSeekBackIncrement() milliseconds.
    - - - -void -seekForward() - -
    Seeks forward in the current window by Player.getSeekForwardIncrement() milliseconds.
    - - - -void -seekTo​(int windowIndex, - long positionMs) - -
    Seeks to a position specified in milliseconds in the specified window.
    - - - -void -seekTo​(long positionMs) - -
    Seeks to a position specified in milliseconds in the current window.
    - - - -void -seekToDefaultPosition() - -
    Seeks to the default position associated with the current window.
    - - - -void -seekToDefaultPosition​(int windowIndex) - -
    Seeks to the default position associated with the specified window.
    - - - -void -seekToNext() - -
    Seeks to a later position in the current or next window (if available).
    - - - -void -seekToNextWindow() - -
    Seeks to the default position of the next window, which may depend on the current repeat mode - and whether shuffle mode is enabled.
    - - - -void -seekToPrevious() - -
    Seeks to an earlier position in the current or previous window (if available).
    +
    Seeks back in the current MediaItem by Player.getSeekBackIncrement() milliseconds.
    void -seekToPreviousWindow() +seekForward() -
    Seeks to the default position of the previous window, which may depend on the current repeat - mode and whether shuffle mode is enabled.
    +
    Seeks forward in the current MediaItem by Player.getSeekForwardIncrement() + milliseconds.
    void +seekTo​(int mediaItemIndex, + long positionMs) + +
    Seeks to a position specified in milliseconds in the specified MediaItem.
    + + + +void +seekTo​(long positionMs) + +
    Seeks to a position specified in milliseconds in the current MediaItem.
    + + + +void +seekToDefaultPosition() + +
    Seeks to the default position associated with the current MediaItem.
    + + + +void +seekToDefaultPosition​(int mediaItemIndex) + +
    Seeks to the default position associated with the specified MediaItem.
    + + + +void +seekToNext() + +
    Seeks to a later position in the current or next MediaItem (if available).
    + + + +void +seekToNextMediaItem() + +
    Seeks to the default position of the next MediaItem, which may depend on the current + repeat mode and whether shuffle mode is enabled.
    + + + +void +seekToNextWindow() + +
    Deprecated.
    + + + +void +seekToPrevious() + +
    Seeks to an earlier position in the current or previous MediaItem (if available).
    + + + +void +seekToPreviousMediaItem() + +
    Seeks to the default position of the previous MediaItem, which may depend on the + current repeat mode and whether shuffle mode is enabled.
    + + + +void +seekToPreviousWindow() + +
    Deprecated.
    + + + +void setDeviceMuted​(boolean muted)
    Sets the mute state of the device.
    - + void setDeviceVolume​(int volume)
    Sets the volume of the device.
    - + void setMediaItem​(MediaItem mediaItem) @@ -912,7 +982,7 @@ implements + void setMediaItem​(MediaItem mediaItem, boolean resetPosition) @@ -920,7 +990,7 @@ implements Clears the playlist and adds the specified MediaItem. - + void setMediaItem​(MediaItem mediaItem, long startPositionMs) @@ -928,7 +998,7 @@ implements Clears the playlist and adds the specified MediaItem. - + void setMediaItems​(List<MediaItem> mediaItems) @@ -936,7 +1006,7 @@ implements + void setMediaItems​(List<MediaItem> mediaItems, boolean resetPosition) @@ -944,65 +1014,72 @@ implements Clears the playlist and adds the specified MediaItems. - + void setMediaItems​(List<MediaItem> mediaItems, - int startWindowIndex, + int startIndex, long startPositionMs)
    Clears the playlist and adds the specified MediaItems.
    - + void setPlaybackParameters​(PlaybackParameters playbackParameters)
    Attempts to set the playback parameters.
    - + void setPlaybackSpeed​(float speed)
    Changes the rate at which playback occurs.
    - + void setPlaylistMetadata​(MediaMetadata mediaMetadata)
    Sets the playlist MediaMetadata.
    - + void setPlayWhenReady​(boolean playWhenReady)
    Sets whether playback should proceed when Player.getPlaybackState() == Player.STATE_READY.
    - + void -setRepeatMode​(int repeatMode) +setRepeatMode​(@com.google.android.exoplayer2.Player.RepeatMode int repeatMode)
    Sets the Player.RepeatMode to be used for playback.
    - + void setShuffleModeEnabled​(boolean shuffleModeEnabled) -
    Sets whether shuffling of windows is enabled.
    +
    Sets whether shuffling of media items is enabled.
    - + +void +setTrackSelectionParameters​(TrackSelectionParameters parameters) + +
    Sets the parameters constraining the track selection.
    + + + void setVideoSurface​(Surface surface)
    Sets the Surface onto which video will be rendered.
    - + void setVideoSurfaceHolder​(SurfaceHolder surfaceHolder) @@ -1010,35 +1087,36 @@ implements + void setVideoSurfaceView​(SurfaceView surfaceView)
    Sets the SurfaceView onto which video will be rendered.
    - + void setVideoTextureView​(TextureView textureView)
    Sets the TextureView onto which video will be rendered.
    - + void -setVolume​(float audioVolume) +setVolume​(float volume) -
    Sets the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
    +
    Sets the audio volume, valid values are between 0 (silence) and 1 (unity gain, signal + unchanged), inclusive.
    - + void stop()
    Stops playback without resetting the player.
    - + void stop​(boolean reset) @@ -1095,7 +1173,9 @@ implements
  • getApplicationLooper

    -
    public Looper getApplicationLooper()
    +
    @Deprecated
    +public Looper getApplicationLooper()
    +
    Deprecated.
    Description copied from interface: Player
    Returns the Looper associated with the application thread that's used to access the player and on which player events are received.
    @@ -1105,42 +1185,19 @@ implements - - -
      -
    • -

      addListener

      -
      @Deprecated
      -public void addListener​(Player.EventListener listener)
      -
      Deprecated.
      -
      Description copied from interface: Player
      -
      Registers a listener to receive events from the player. - -

      The listener's methods will be called on the thread that was used to construct the player. - However, if the thread used to construct the player does not have a Looper, then the - listener will be called on the main thread.

      -
      -
      Specified by:
      -
      addListener in interface Player
      -
      Parameters:
      -
      listener - The listener to register.
      -
      -
    • -
    • addListener

      -
      public void addListener​(Player.Listener listener)
      +
      @Deprecated
      +public void addListener​(Player.Listener listener)
      +
      Deprecated.
      Description copied from interface: Player
      Registers a listener to receive all events from the player. -

      The listener's methods will be called on the thread that was used to construct the player. - However, if the thread used to construct the player does not have a Looper, then the - listener will be called on the main thread.

      +

      The listener's methods will be called on the thread associated with Player.getApplicationLooper().

      Specified by:
      addListener in interface Player
      @@ -1149,26 +1206,6 @@ public void addListener​(
    - - - - @@ -1222,7 +1259,7 @@ public void removeListener​(mediaItems - The new MediaItems.
    resetPosition - Whether the playback position should be reset to the default position in the first Timeline.Window. If false, playback will start from the position defined - by Player.getCurrentWindowIndex() and Player.getCurrentPosition().
    + by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition().
  • @@ -1233,7 +1270,7 @@ public void removeListener​(

    setMediaItems

    public void setMediaItems​(List<MediaItem> mediaItems,
    -                          int startWindowIndex,
    +                          int startIndex,
                               long startPositionMs)
    Description copied from interface: Player
    Clears the playlist and adds the specified MediaItems.
    @@ -1242,11 +1279,11 @@ public void removeListener​(setMediaItems in interface Player
    Parameters:
    mediaItems - The new MediaItems.
    -
    startWindowIndex - The window index to start playback from. If C.INDEX_UNSET is - passed, the current position is not reset.
    -
    startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given window is used. In any case, if - startWindowIndex is set to C.INDEX_UNSET, this parameter is ignored and the - position is not reset at all.
    +
    startIndex - The MediaItem index to start playback from. If C.INDEX_UNSET + is passed, the current position is not reset.
    +
    startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given MediaItem is used. In + any case, if startIndex is set to C.INDEX_UNSET, this parameter is ignored + and the position is not reset at all.
    @@ -1303,7 +1340,7 @@ public void removeListener​(Parameters:
    mediaItem - The new MediaItem.
    resetPosition - Whether the playback position should be reset to the default position. If - false, playback will start from the position defined by Player.getCurrentWindowIndex() + false, playback will start from the position defined by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition().
    @@ -1477,28 +1514,27 @@ public void removeListener​( - + + + + +
      +
    • +

      canAdvertiseSession

      +
      public boolean canAdvertiseSession()
      +
      Description copied from interface: Player
      +
      Returns whether the player can be used to advertise a media session.
      +
      +
      Specified by:
      +
      canAdvertiseSession in interface Player
      +
      +
    • +
    @@ -1521,12 +1572,11 @@ public void removeListener​(The returned Player.Commands are not updated when available commands change. Use Player.Listener.onAvailableCommandsChanged(Commands) to get an update when the available commands change. -

    Executing a command that is not available (for example, calling Player.seekToNextWindow() - if Player.COMMAND_SEEK_TO_NEXT_WINDOW is unavailable) will neither throw an exception nor - generate a Player.getPlayerError() player error}. +

    Executing a command that is not available (for example, calling Player.seekToNextMediaItem() if Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM is unavailable) will + neither throw an exception nor generate a Player.getPlayerError() player error}. -

    Player.COMMAND_SEEK_TO_PREVIOUS_WINDOW and Player.COMMAND_SEEK_TO_NEXT_WINDOW are - unavailable if there is no such MediaItem. +

    Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM and Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM + are unavailable if there is no such MediaItem.

    Specified by:
    getAvailableCommands in interface Player
    @@ -1567,7 +1617,7 @@ public void removeListener​(Returns:
    The current playback state.
    See Also:
    -
    Player.Listener.onPlaybackStateChanged(int)
    +
    Player.Listener.onPlaybackStateChanged(int)
    @@ -1587,7 +1637,7 @@ public void removeListener​(Returns:
    The current playback suppression reason.
    See Also:
    -
    Player.Listener.onPlaybackSuppressionReasonChanged(int)
    +
    Player.Listener.onPlaybackSuppressionReasonChanged(int)
    @@ -1708,23 +1758,23 @@ public Returns:
    Whether playback will proceed when ready.
    See Also:
    -
    Player.Listener.onPlayWhenReadyChanged(boolean, int)
    +
    Player.Listener.onPlayWhenReadyChanged(boolean, int)
    - + @@ -1757,7 +1807,7 @@ public public void setShuffleModeEnabled​(boolean shuffleModeEnabled) -
    Sets whether shuffling of windows is enabled.
    +
    Sets whether shuffling of media items is enabled.
    Specified by:
    setShuffleModeEnabled in interface Player
    @@ -1774,7 +1824,7 @@ public public boolean getShuffleModeEnabled() -
    Returns whether shuffling of windows is enabled.
    +
    Returns whether shuffling of media items is enabled.
    Specified by:
    getShuffleModeEnabled in interface Player
    @@ -1810,9 +1860,9 @@ public public void seekToDefaultPosition() -
    Seeks to the default position associated with the current window. The position can depend on - the type of media being played. For live streams it will typically be the live edge of the - window. For other streams it will typically be the start of the window.
    +
    Seeks to the default position associated with the current MediaItem. The position can + depend on the type of media being played. For live streams it will typically be the live edge. + For other streams it will typically be the start.
    Specified by:
    seekToDefaultPosition in interface Player
    @@ -1825,17 +1875,17 @@ public 
  • seekToDefaultPosition

    -
    public void seekToDefaultPosition​(int windowIndex)
    +
    public void seekToDefaultPosition​(int mediaItemIndex)
    -
    Seeks to the default position associated with the specified window. The position can depend on - the type of media being played. For live streams it will typically be the live edge of the - window. For other streams it will typically be the start of the window.
    +
    Seeks to the default position associated with the specified MediaItem. The position can + depend on the type of media being played. For live streams it will typically be the live edge. + For other streams it will typically be the start.
    Specified by:
    seekToDefaultPosition in interface Player
    Parameters:
    -
    windowIndex - The index of the window whose associated default position should be seeked - to.
    +
    mediaItemIndex - The index of the MediaItem whose associated default position + should be seeked to.
  • @@ -1847,13 +1897,13 @@ public public void seekTo​(long positionMs) -
    Seeks to a position specified in milliseconds in the current window.
    +
    Seeks to a position specified in milliseconds in the current MediaItem.
    Specified by:
    seekTo in interface Player
    Parameters:
    -
    positionMs - The seek position in the current window, or C.TIME_UNSET to seek to - the window's default position.
    +
    positionMs - The seek position in the current MediaItem, or C.TIME_UNSET + to seek to the media item's default position.
    @@ -1863,17 +1913,17 @@ public 
  • seekTo

    -
    public void seekTo​(int windowIndex,
    +
    public void seekTo​(int mediaItemIndex,
                        long positionMs)
    -
    Seeks to a position specified in milliseconds in the specified window.
    +
    Seeks to a position specified in milliseconds in the specified MediaItem.
    Specified by:
    seekTo in interface Player
    Parameters:
    -
    windowIndex - The index of the window.
    -
    positionMs - The seek position in the specified window, or C.TIME_UNSET to seek to - the window's default position.
    +
    mediaItemIndex - The index of the MediaItem.
    +
    positionMs - The seek position in the specified MediaItem, or C.TIME_UNSET + to seek to the media item's default position.
  • @@ -1904,7 +1954,7 @@ public public void seekBack() -
    Seeks back in the current window by Player.getSeekBackIncrement() milliseconds.
    +
    Seeks back in the current MediaItem by Player.getSeekBackIncrement() milliseconds.
    Specified by:
    seekBack in interface Player
    @@ -1938,7 +1988,8 @@ public public void seekForward() -
    Seeks forward in the current window by Player.getSeekForwardIncrement() milliseconds.
    +
    Seeks forward in the current MediaItem by Player.getSeekForwardIncrement() + milliseconds.
    Specified by:
    seekForward in interface Player
    @@ -1966,9 +2017,24 @@ public boolean hasPrevious()
    • hasPreviousWindow

      -
      public boolean hasPreviousWindow()
      -
      Description copied from interface: Player
      -
      Returns whether a previous window exists, which may depend on the current repeat mode and +
      @Deprecated
      +public boolean hasPreviousWindow()
      +
      Deprecated.
      +
      +
      Specified by:
      +
      hasPreviousWindow in interface Player
      +
      +
    • +
    + + + +
      +
    • +

      hasPreviousMediaItem

      +
      public boolean hasPreviousMediaItem()
      +
      Description copied from interface: Player
      +
      Returns whether a previous media item exists, which may depend on the current repeat mode and whether shuffle mode is enabled.

      Note: When the repeat mode is Player.REPEAT_MODE_ONE, this method behaves the same as when @@ -1976,7 +2042,7 @@ public boolean hasPrevious() details.

      Specified by:
      -
      hasPreviousWindow in interface Player
      +
      hasPreviousMediaItem in interface Player
    @@ -2001,18 +2067,32 @@ public void previous()
    • seekToPreviousWindow

      -
      public void seekToPreviousWindow()
      -
      Description copied from interface: Player
      -
      Seeks to the default position of the previous window, which may depend on the current repeat - mode and whether shuffle mode is enabled. Does nothing if Player.hasPreviousWindow() is - false. +
      @Deprecated
      +public void seekToPreviousWindow()
      +
      Deprecated.
      +
      +
      Specified by:
      +
      seekToPreviousWindow in interface Player
      +
      +
    • +
    + + + + @@ -2024,18 +2104,20 @@ public void previous()

    seekToPrevious

    public void seekToPrevious()
    Description copied from interface: Player
    -
    Seeks to an earlier position in the current or previous window (if available). More precisely: +
    Seeks to an earlier position in the current or previous MediaItem (if available). More + precisely:
    Specified by:
    @@ -2049,17 +2131,16 @@ public void previous() @@ -2084,17 +2165,32 @@ public boolean hasNext()
    • hasNextWindow

      -
      public boolean hasNextWindow()
      -
      Description copied from interface: Player
      -
      Returns whether a next window exists, which may depend on the current repeat mode and whether - shuffle mode is enabled. +
      @Deprecated
      +public boolean hasNextWindow()
      +
      Deprecated.
      +
      +
      Specified by:
      +
      hasNextWindow in interface Player
      +
      +
    • +
    + + + + @@ -2119,17 +2215,33 @@ public void next()
    • seekToNextWindow

      -
      public void seekToNextWindow()
      -
      Description copied from interface: Player
      -
      Seeks to the default position of the next window, which may depend on the current repeat mode - and whether shuffle mode is enabled. Does nothing if Player.hasNextWindow() is false. +
      @Deprecated
      +public void seekToNextWindow()
      +
      Deprecated.
      +
      +
      Specified by:
      +
      seekToNextWindow in interface Player
      +
      +
    • +
    + + + + @@ -2141,14 +2253,15 @@ public void next()

    seekToNext

    public void seekToNext()
    Description copied from interface: Player
    -
    Seeks to a later position in the current or next window (if available). More precisely: +
    Seeks to a later position in the current or next MediaItem (if available). More + precisely:
    • If the timeline is empty or seeking is not possible, does nothing. -
    • Otherwise, if a next window exists, seeks to the default - position of the next window. -
    • Otherwise, if the current window is live and has not - ended, seeks to the live edge of the current window. +
    • Otherwise, if a next media item exists, seeks to the default + position of the next MediaItem. +
    • Otherwise, if the current MediaItem is live and + has not ended, seeks to the live edge of the current MediaItem.
    • Otherwise, does nothing.
    @@ -2283,7 +2396,7 @@ public void stop​(boolean reset)
    Specified by:
    getCurrentTrackGroups in interface Player
    See Also:
    -
    Player.Listener.onTracksChanged(TrackGroupArray, TrackSelectionArray)
    +
    Player.EventListener.onTracksChanged(TrackGroupArray, TrackSelectionArray)
    @@ -2304,22 +2417,70 @@ public void stop​(boolean reset)
    Specified by:
    getCurrentTrackSelections in interface Player
    See Also:
    -
    Player.Listener.onTracksChanged(TrackGroupArray, TrackSelectionArray)
    +
    Player.EventListener.onTracksChanged(TrackGroupArray, TrackSelectionArray)
    - + + + + + + + + +
      +
    • +

      setTrackSelectionParameters

      +
      public void setTrackSelectionParameters​(TrackSelectionParameters parameters)
      +
      Description copied from interface: Player
      +
      Sets the parameters constraining the track selection. + +

      Unsupported parameters will be silently ignored. + +

      Use Player.getTrackSelectionParameters() to retrieve the current parameters. For example, + the following snippet restricts video to SD whilst keep other track selection parameters + unchanged: + +

      
      + player.setTrackSelectionParameters(
      +   player.getTrackSelectionParameters()
      +         .buildUpon()
      +         .setMaxVideoSizeSd()
      +         .build())
      + 
      +
      +
      Specified by:
      +
      setTrackSelectionParameters in interface Player
    @@ -2336,7 +2497,8 @@ public MediaMetadata is a combination of the MediaItem.mediaMetadata and the static and dynamic metadata from the track selections' - formats and MetadataOutput.onMetadata(Metadata).
    + formats
    and Player.Listener.onMetadata(Metadata). If a field is populated in the MediaItem.mediaMetadata, it will be prioritised above the same field coming from static or + dynamic metadata.
    Specified by:
    getMediaMetadata in interface Player
    @@ -2402,7 +2564,7 @@ public Specified by:
    getCurrentTimeline in interface Player
    See Also:
    -
    Player.Listener.onTimelineChanged(Timeline, int)
    +
    Player.Listener.onTimelineChanged(Timeline, int)
    @@ -2427,32 +2589,64 @@ public 
  • getCurrentWindowIndex

    -
    public int getCurrentWindowIndex()
    -
    -
    Returns the index of the current window in the timeline, or the prospective window index if the current timeline is empty.
    +
    @Deprecated
    +public int getCurrentWindowIndex()
    +
    Deprecated.
    Specified by:
    getCurrentWindowIndex in interface Player
  • + + + + + + + + @@ -2462,18 +2656,33 @@ public 
  • getPreviousWindowIndex

    -
    public int getPreviousWindowIndex()
    -
    -
    Returns the index of the window that will be played if Player.seekToPreviousWindow() is - called, which may depend on the current repeat mode and whether shuffle mode is enabled. - Returns C.INDEX_UNSET if Player.hasPreviousWindow() is false. +
    @Deprecated
    +public int getPreviousWindowIndex()
    +
    Deprecated.
    +
    +
    Specified by:
    +
    getPreviousWindowIndex in interface Player
    +
    +
  • + + + + + @@ -2486,13 +2695,12 @@ public @Nullable public MediaItem getCurrentMediaItem()
    Description copied from interface: Player
    -
    Returns the media item of the current window in the timeline. May be null if the timeline is - empty.
    +
    Returns the currently playing MediaItem. May be null if the timeline is empty.
    Specified by:
    getCurrentMediaItem in interface Player
    See Also:
    -
    Player.Listener.onMediaItemTransition(MediaItem, int)
    +
    Player.Listener.onMediaItemTransition(MediaItem, int)
    @@ -2534,7 +2742,8 @@ public public long getDuration() -
    Returns the duration of the current content window or ad in milliseconds, or C.TIME_UNSET if the duration is not known.
    +
    Returns the duration of the current content or ad in milliseconds, or C.TIME_UNSET if + the duration is not known.
    Specified by:
    getDuration in interface Player
    @@ -2549,9 +2758,8 @@ public public long getCurrentPosition() -
    Returns the playback position in the current content window or ad, in milliseconds, or the - prospective position in milliseconds if the current timeline is - empty.
    +
    Returns the playback position in the current content or ad, in milliseconds, or the prospective + position in milliseconds if the current timeline is empty.
    Specified by:
    getCurrentPosition in interface Player
    @@ -2566,8 +2774,8 @@ public public long getBufferedPosition() -
    Returns an estimate of the position in the current content window or ad up to which data is - buffered, in milliseconds.
    +
    Returns an estimate of the position in the current content or ad up to which data is buffered, + in milliseconds.
    Specified by:
    getBufferedPosition in interface Player
    @@ -2582,7 +2790,7 @@ public public int getBufferedPercentage() -
    Returns an estimate of the percentage in the current content window or ad up to which data is +
    Returns an estimate of the percentage in the current content or ad up to which data is buffered, or 0 if no estimate is available.
    Specified by:
    @@ -2599,7 +2807,7 @@ public public long getTotalBufferedDuration()
    Returns an estimate of the total buffered duration from the current position, in milliseconds. - This includes pre-buffered data for subsequent ads and windows.
    + This includes pre-buffered data for subsequent ads and media items.
    Specified by:
    getTotalBufferedDuration in interface Player
    @@ -2612,13 +2820,28 @@ public 
  • isCurrentWindowDynamic

    -
    public boolean isCurrentWindowDynamic()
    -
    -
    Returns whether the current window is dynamic, or false if the Timeline is - empty.
    +
    @Deprecated
    +public boolean isCurrentWindowDynamic()
    +
    Deprecated.
    Specified by:
    isCurrentWindowDynamic in interface Player
    +
    +
  • + + + + + + + + + + + + + @@ -3052,7 +3306,7 @@ public 
  • getDeviceInfo

    -
    public DeviceInfo getDeviceInfo()
    +
    public DeviceInfo getDeviceInfo()
    Description copied from interface: Player
    Gets the device information.
    @@ -3071,12 +3325,12 @@ public Description copied from interface: Player
    Gets the current volume of the device. -

    For devices with local playback, the volume returned +

    For devices with local playback, the volume returned by this method varies according to the current stream type. The stream type is determined by AudioAttributes.usage which can be converted to stream type with - Util.getStreamTypeForAudioUsage(int). + Util.getStreamTypeForAudioUsage(int). -

    For devices with remote playback, the volume of the +

    For devices with remote playback, the volume of the remote device is returned.

    Specified by:
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/upstream/cache/CacheDataSinkFactory.html b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.AdsConfiguration.Builder.html similarity index 60% rename from docs/doc/reference/com/google/android/exoplayer2/upstream/cache/CacheDataSinkFactory.html rename to docs/doc/reference/com/google/android/exoplayer2/MediaItem.AdsConfiguration.Builder.html index 13079461d9..d71987cbca 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/upstream/cache/CacheDataSinkFactory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.AdsConfiguration.Builder.html @@ -2,36 +2,36 @@ -CacheDataSinkFactory (ExoPlayer library) +MediaItem.AdsConfiguration.Builder (ExoPlayer library) - - - - - + + + + + - - + +
  • @@ -255,6 +291,16 @@ public final  + + + @@ -333,7 +379,7 @@ public final 
  • Summary: 
  • -
  • Nested | 
  • +
  • Nested | 
  • Field | 
  • Constr | 
  • Method
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.Builder.html b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.Builder.html index 7a637f2164..2cc26876fd 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.Builder.html +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.Builder.html @@ -25,8 +25,8 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10}; -var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; +var data = {"i0":10,"i1":10,"i2":42,"i3":42,"i4":42,"i5":42,"i6":10,"i7":42,"i8":42,"i9":42,"i10":42,"i11":10,"i12":10,"i13":42,"i14":42,"i15":42,"i16":42,"i17":42,"i18":42,"i19":42,"i20":42,"i21":42,"i22":42,"i23":10,"i24":42,"i25":42,"i26":42,"i27":42,"i28":42,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":42,"i35":10,"i36":10,"i37":10}; +var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; var tableTab = "tableTab"; @@ -173,7 +173,7 @@ extends

    Method Summary

    - + @@ -188,203 +188,273 @@ extends - + - + - + - + - + - + - + - + + + + + + + + + + + - - - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + + + + + + - + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - +
    Deprecated.
    All Methods Instance Methods Concrete Methods All Methods Instance Methods Concrete Methods Deprecated Methods 
    Modifier and Type Method
    MediaItem.BuildersetAdTagUri​(Uri adTagUri)setAdsConfiguration​(MediaItem.AdsConfiguration adsConfiguration) -
    Sets the optional ad tag Uri.
    +
    Sets the optional MediaItem.AdsConfiguration.
    MediaItem.BuildersetAdTagUri​(Uri adTagUri, - Object adsId)setAdTagUri​(Uri adTagUri) -
    Sets the optional ad tag Uri and ads identifier.
    +
    Deprecated. +
    Use setAdsConfiguration(AdsConfiguration) and pass the adTagUri + to Builder(Uri) instead.
    +
    MediaItem.BuildersetAdTagUri​(String adTagUri)setAdTagUri​(Uri adTagUri, + Object adsId) -
    Sets the optional ad tag Uri.
    +
    Deprecated. + +
    MediaItem.BuildersetClipEndPositionMs​(long endPositionMs)setAdTagUri​(String adTagUri) -
    Sets the optional end position in milliseconds which must be a value larger than or equal to - zero, or C.TIME_END_OF_SOURCE to end when playback reaches the end of media (Default: - C.TIME_END_OF_SOURCE).
    +
    Deprecated. +
    Use setAdsConfiguration(AdsConfiguration), parse the adTagUri + with Uri.parse(String) and pass the result to Builder(Uri) instead.
    +
    MediaItem.BuildersetClipRelativeToDefaultPosition​(boolean relativeToDefaultPosition)setClipEndPositionMs​(long endPositionMs) -
    Sets whether the start position and the end position are relative to the default position in - the window (Default: false).
    +
    MediaItem.BuildersetClipRelativeToLiveWindow​(boolean relativeToLiveWindow)setClippingConfiguration​(MediaItem.ClippingConfiguration clippingConfiguration) -
    Sets whether the start/end positions should move with the live window for live streams.
    +
    MediaItem.BuildersetClipStartPositionMs​(long startPositionMs)setClipRelativeToDefaultPosition​(boolean relativeToDefaultPosition) -
    Sets the optional start position in milliseconds which must be a value larger than or equal - to zero (Default: 0).
    +
    MediaItem.BuildersetClipStartsAtKeyFrame​(boolean startsAtKeyFrame)setClipRelativeToLiveWindow​(boolean relativeToLiveWindow) -
    Sets whether the start point is guaranteed to be a key frame.
    +
    MediaItem.BuildersetClipStartPositionMs​(long startPositionMs) + +
    MediaItem.BuildersetClipStartsAtKeyFrame​(boolean startsAtKeyFrame) + +
    MediaItem.Builder setCustomCacheKey​(String customCacheKey)
    Sets the optional custom cache key (only used for progressive streams).
    MediaItem.BuildersetDrmForceDefaultLicenseUri​(boolean forceDefaultLicenseUri) -
    Sets whether to force use the default DRM license server URI even if the media specifies its - own DRM license server URI.
    -
    MediaItem.BuildersetDrmKeySetId​(byte[] keySetId) -
    Sets the key set ID of the offline license.
    -
    MediaItem.BuildersetDrmLicenseRequestHeaders​(Map<String,​String> licenseRequestHeaders)setDrmConfiguration​(MediaItem.DrmConfiguration drmConfiguration) -
    Sets the optional request headers attached to the DRM license request.
    +
    Sets the optional DRM configuration.
    MediaItem.BuildersetDrmLicenseUri​(Uri licenseUri)setDrmForceDefaultLicenseUri​(boolean forceDefaultLicenseUri) -
    Sets the optional default DRM license server URI.
    +
    MediaItem.BuildersetDrmLicenseUri​(String licenseUri)setDrmKeySetId​(byte[] keySetId) -
    Sets the optional default DRM license server URI.
    +
    MediaItem.BuildersetDrmMultiSession​(boolean multiSession)setDrmLicenseRequestHeaders​(Map<String,​String> licenseRequestHeaders) -
    Sets whether the DRM configuration is multi session enabled.
    +
    MediaItem.BuildersetDrmPlayClearContentWithoutKey​(boolean playClearContentWithoutKey)setDrmLicenseUri​(Uri licenseUri) -
    Sets whether clear samples within protected content should be played when keys for the - encrypted part of the content have yet to be loaded.
    +
    MediaItem.BuildersetDrmSessionForClearPeriods​(boolean sessionForClearPeriods)setDrmLicenseUri​(String licenseUri) -
    Sets whether a DRM session should be used for clear tracks of type C.TRACK_TYPE_VIDEO - and C.TRACK_TYPE_AUDIO.
    +
    MediaItem.BuildersetDrmSessionForClearTypes​(List<Integer> sessionForClearTypes)setDrmMultiSession​(boolean multiSession) -
    Sets a list of C.TRACK_TYPE_* constants for which to use a DRM session even - when the tracks are in the clear.
    +
    MediaItem.BuildersetDrmUuid​(UUID uuid)setDrmPlayClearContentWithoutKey​(boolean playClearContentWithoutKey) -
    Sets the UUID of the protection scheme.
    +
    MediaItem.BuildersetLiveMaxOffsetMs​(long liveMaxOffsetMs)setDrmSessionForClearPeriods​(boolean sessionForClearPeriods) -
    Sets the optional maximum offset from the live edge for live streams, in milliseconds.
    +
    MediaItem.BuildersetLiveMaxPlaybackSpeed​(float maxPlaybackSpeed)setDrmSessionForClearTypes​(List<@TrackType Integer> sessionForClearTypes) -
    Sets the optional maximum playback speed for live stream speed adjustment.
    +
    MediaItem.BuildersetLiveMinOffsetMs​(long liveMinOffsetMs)setDrmUuid​(UUID uuid) -
    Sets the optional minimum offset from the live edge for live streams, in milliseconds.
    +
    Deprecated. +
    Use setDrmConfiguration(DrmConfiguration) and pass the uuid to + Builder(UUID) instead.
    +
    MediaItem.BuildersetLiveMinPlaybackSpeed​(float minPlaybackSpeed)setLiveConfiguration​(MediaItem.LiveConfiguration liveConfiguration) -
    Sets the optional minimum playback speed for live stream speed adjustment.
    +
    MediaItem.BuildersetLiveTargetOffsetMs​(long liveTargetOffsetMs)setLiveMaxOffsetMs​(long liveMaxOffsetMs) -
    Sets the optional target offset from the live edge for live streams, in milliseconds.
    +
    MediaItem.BuildersetLiveMaxPlaybackSpeed​(float maxPlaybackSpeed) + +
    MediaItem.BuildersetLiveMinOffsetMs​(long liveMinOffsetMs) + +
    MediaItem.BuildersetLiveMinPlaybackSpeed​(float minPlaybackSpeed) + +
    MediaItem.BuildersetLiveTargetOffsetMs​(long liveTargetOffsetMs) + +
    MediaItem.Builder setMediaId​(String mediaId)
    Sets the optional media ID which identifies the media item.
    MediaItem.Builder setMediaMetadata​(MediaMetadata mediaMetadata)
    Sets the media metadata.
    MediaItem.Builder setMimeType​(String mimeType)
    Sets the optional MIME type.
    MediaItem.Builder setStreamKeys​(List<StreamKey> streamKeys) @@ -392,28 +462,37 @@ extends
    MediaItem.BuildersetSubtitles​(List<MediaItem.Subtitle> subtitles)setSubtitleConfigurations​(List<MediaItem.SubtitleConfiguration> subtitleConfigurations)
    Sets the optional subtitles.
    MediaItem.BuildersetSubtitles​(List<MediaItem.Subtitle> subtitles) +
    Deprecated. + +
    +
    MediaItem.Builder setTag​(Object tag)
    Sets the optional tag for custom attributes.
    MediaItem.Builder setUri​(Uri uri)
    Sets the optional URI.
    MediaItem.Builder setUri​(String uri) @@ -486,8 +565,8 @@ extends String uri)
    Sets the optional URI. -

    If uri is null or unset then no MediaItem.PlaybackProperties object is created - during build() and no other Builder methods that would populate MediaItem.playbackProperties should be called.

    +

    If uri is null or unset then no MediaItem.LocalConfiguration object is created + during build() and no other Builder methods that would populate MediaItem.localConfiguration should be called. @@ -500,8 +579,8 @@ extends Uri uri)

    Sets the optional URI. -

    If uri is null or unset then no MediaItem.PlaybackProperties object is created - during build() and no other Builder methods that would populate MediaItem.playbackProperties should be called.

    +

    If uri is null or unset then no MediaItem.LocalConfiguration object is created + during build() and no other Builder methods that would populate MediaItem.localConfiguration should be called. @@ -523,15 +602,28 @@ extends + + + +

    @@ -540,10 +632,11 @@ extends
  • setClipEndPositionMs

    -
    public MediaItem.Builder setClipEndPositionMs​(long endPositionMs)
    -
    Sets the optional end position in milliseconds which must be a value larger than or equal to - zero, or C.TIME_END_OF_SOURCE to end when playback reaches the end of media (Default: - C.TIME_END_OF_SOURCE).
    +
    @Deprecated
    +public MediaItem.Builder setClipEndPositionMs​(long endPositionMs)
    +
  • @@ -552,10 +645,11 @@ extends
  • setClipRelativeToLiveWindow

    -
    public MediaItem.Builder setClipRelativeToLiveWindow​(boolean relativeToLiveWindow)
    -
    Sets whether the start/end positions should move with the live window for live streams. If - false, live streams end when playback reaches the end position in live window seen - when the media is first loaded (Default: false).
    +
    @Deprecated
    +public MediaItem.Builder setClipRelativeToLiveWindow​(boolean relativeToLiveWindow)
    +
  • @@ -564,9 +658,11 @@ extends
  • setClipRelativeToDefaultPosition

    -
    public MediaItem.Builder setClipRelativeToDefaultPosition​(boolean relativeToDefaultPosition)
    -
    Sets whether the start position and the end position are relative to the default position in - the window (Default: false).
    +
    @Deprecated
    +public MediaItem.Builder setClipRelativeToDefaultPosition​(boolean relativeToDefaultPosition)
    +
  • @@ -575,9 +671,22 @@ extends
  • setClipStartsAtKeyFrame

    -
    public MediaItem.Builder setClipStartsAtKeyFrame​(boolean startsAtKeyFrame)
    -
    Sets whether the start point is guaranteed to be a key frame. If false, the playback - transition into the clip may not be seamless (Default: false).
    +
    @Deprecated
    +public MediaItem.Builder setClipStartsAtKeyFrame​(boolean startsAtKeyFrame)
    + +
  • + + + + + @@ -586,12 +695,12 @@ extends
  • setDrmLicenseUri

    -
    public MediaItem.Builder setDrmLicenseUri​(@Nullable
    +
    @Deprecated
    +public MediaItem.Builder setDrmLicenseUri​(@Nullable
                                               Uri licenseUri)
    -
    Sets the optional default DRM license server URI. If this URI is set, the MediaItem.DrmConfiguration.uuid needs to be specified as well. - -

    This method should only be called if both setUri(java.lang.String) and setDrmUuid(UUID) - are passed non-null values.

    +
  • @@ -600,12 +709,12 @@ extends
  • setDrmLicenseUri

    -
    public MediaItem.Builder setDrmLicenseUri​(@Nullable
    +
    @Deprecated
    +public MediaItem.Builder setDrmLicenseUri​(@Nullable
                                               String licenseUri)
    -
    Sets the optional default DRM license server URI. If this URI is set, the MediaItem.DrmConfiguration.uuid needs to be specified as well. - -

    This method should only be called if both setUri(java.lang.String) and setDrmUuid(UUID) - are passed non-null values.

    +
  • @@ -614,14 +723,13 @@ extends
  • setDrmLicenseRequestHeaders

    -
    public MediaItem.Builder setDrmLicenseRequestHeaders​(@Nullable
    +
    @Deprecated
    +public MediaItem.Builder setDrmLicenseRequestHeaders​(@Nullable
                                                          Map<String,​String> licenseRequestHeaders)
    -
    Sets the optional request headers attached to the DRM license request. - -

    null or an empty Map can be used for a reset. - -

    This method should only be called if both setUri(java.lang.String) and setDrmUuid(UUID) - are passed non-null values.

    +
  • @@ -630,14 +738,13 @@ extends
  • setDrmUuid

    -
    public MediaItem.Builder setDrmUuid​(@Nullable
    +
    @Deprecated
    +public MediaItem.Builder setDrmUuid​(@Nullable
                                         UUID uuid)
    -
    Sets the UUID of the protection scheme. - -

    If uuid is null or unset then no MediaItem.DrmConfiguration object is created during - build() and no other Builder methods that would populate MediaItem.PlaybackProperties.drmConfiguration should be called. - -

    This method should only be called if setUri(java.lang.String) is passed a non-null value.

    +
    Deprecated. +
    Use setDrmConfiguration(DrmConfiguration) and pass the uuid to + Builder(UUID) instead.
    +
  • @@ -646,11 +753,11 @@ extends
  • setDrmMultiSession

    -
    public MediaItem.Builder setDrmMultiSession​(boolean multiSession)
    -
    Sets whether the DRM configuration is multi session enabled. - -

    This method should only be called if both setUri(java.lang.String) and setDrmUuid(UUID) - are passed non-null values.

    +
    @Deprecated
    +public MediaItem.Builder setDrmMultiSession​(boolean multiSession)
    +
  • @@ -659,12 +766,11 @@ extends
  • setDrmForceDefaultLicenseUri

    -
    public MediaItem.Builder setDrmForceDefaultLicenseUri​(boolean forceDefaultLicenseUri)
    -
    Sets whether to force use the default DRM license server URI even if the media specifies its - own DRM license server URI. - -

    This method should only be called if both setUri(java.lang.String) and setDrmUuid(UUID) - are passed non-null values.

    +
    @Deprecated
    +public MediaItem.Builder setDrmForceDefaultLicenseUri​(boolean forceDefaultLicenseUri)
    +
  • @@ -673,12 +779,11 @@ extends
  • setDrmPlayClearContentWithoutKey

    -
    public MediaItem.Builder setDrmPlayClearContentWithoutKey​(boolean playClearContentWithoutKey)
    -
    Sets whether clear samples within protected content should be played when keys for the - encrypted part of the content have yet to be loaded. - -

    This method should only be called if both setUri(java.lang.String) and setDrmUuid(UUID) - are passed non-null values.

    +
    @Deprecated
    +public MediaItem.Builder setDrmPlayClearContentWithoutKey​(boolean playClearContentWithoutKey)
    +
  • @@ -687,14 +792,11 @@ extends
  • setDrmSessionForClearPeriods

    -
    public MediaItem.Builder setDrmSessionForClearPeriods​(boolean sessionForClearPeriods)
    -
    Sets whether a DRM session should be used for clear tracks of type C.TRACK_TYPE_VIDEO - and C.TRACK_TYPE_AUDIO. - -

    This method overrides what has been set by previously calling setDrmSessionForClearTypes(List). - -

    This method should only be called if both setUri(java.lang.String) and setDrmUuid(UUID) - are passed non-null values.

    +
    @Deprecated
    +public MediaItem.Builder setDrmSessionForClearPeriods​(boolean sessionForClearPeriods)
    +
  • @@ -703,19 +805,13 @@ extends
  • setDrmSessionForClearTypes

    -
    public MediaItem.Builder setDrmSessionForClearTypes​(@Nullable
    -                                                    List<Integer> sessionForClearTypes)
    -
    Sets a list of C.TRACK_TYPE_* constants for which to use a DRM session even - when the tracks are in the clear. - -

    For the common case of using a DRM session for C.TRACK_TYPE_VIDEO and C.TRACK_TYPE_AUDIO the setDrmSessionForClearPeriods(boolean) can be used. - -

    This method overrides what has been set by previously calling setDrmSessionForClearPeriods(boolean). - -

    null or an empty List can be used for a reset. - -

    This method should only be called if both setUri(java.lang.String) and setDrmUuid(UUID) - are passed non-null values.

    +
    @Deprecated
    +public MediaItem.Builder setDrmSessionForClearTypes​(@Nullable
    +                                                    List<@TrackType Integer> sessionForClearTypes)
    +
  • @@ -724,16 +820,12 @@ extends
  • setDrmKeySetId

    -
    public MediaItem.Builder setDrmKeySetId​(@Nullable
    +
    @Deprecated
    +public MediaItem.Builder setDrmKeySetId​(@Nullable
                                             byte[] keySetId)
    -
    Sets the key set ID of the offline license. - -

    The key set ID identifies an offline license. The ID is required to query, renew or - release an existing offline license (see DefaultDrmSessionManager#setMode(int - mode,byte[] offlineLicenseKeySetId)). - -

    This method should only be called if both setUri(java.lang.String) and setDrmUuid(UUID) - are passed non-null values.

    +
  • @@ -750,7 +842,7 @@ extends null or an empty List can be used for a reset.

    If setUri(java.lang.String) is passed a non-null uri, the stream keys are used to create a - MediaItem.PlaybackProperties object. Otherwise they will be ignored. + MediaItem.LocalConfiguration object. Otherwise they will be ignored. @@ -772,11 +864,36 @@ extends

  • setSubtitles

    -
    public MediaItem.Builder setSubtitles​(@Nullable
    +
    @Deprecated
    +public MediaItem.Builder setSubtitles​(@Nullable
                                           List<MediaItem.Subtitle> subtitles)
    +
    Deprecated. +
    Use setSubtitleConfigurations(List) instead. Note that setSubtitleConfigurations(List) doesn't accept null, use an empty list to clear the + contents.
    +
    +
  • + + + + + + + + + @@ -808,19 +919,13 @@ extends
  • setAdTagUri

    -
    public MediaItem.Builder setAdTagUri​(@Nullable
    +
    @Deprecated
    +public MediaItem.Builder setAdTagUri​(@Nullable
                                          Uri adTagUri)
    -
    Sets the optional ad tag Uri. - -

    Media items in the playlist with the same ad tag URI, media ID and ads loader will share - the same ad playback state. To resume ad playback when recreating the playlist on returning - from the background, pass media items with the same ad tag URIs and media IDs to the player. - -

    This method should only be called if setUri(java.lang.String) is passed a non-null value.

    -
    -
    Parameters:
    -
    adTagUri - The ad tag URI to load.
    -
    +
    Deprecated. +
    Use setAdsConfiguration(AdsConfiguration) and pass the adTagUri + to Builder(Uri) instead.
    +
  • @@ -829,25 +934,25 @@ extends
  • setAdTagUri

    -
    public MediaItem.Builder setAdTagUri​(@Nullable
    +
    @Deprecated
    +public MediaItem.Builder setAdTagUri​(@Nullable
                                          Uri adTagUri,
                                          @Nullable
                                          Object adsId)
    -
    Sets the optional ad tag Uri and ads identifier. - -

    Media items in the playlist that have the same ads identifier and ads loader share the - same ad playback state. To resume ad playback when recreating the playlist on returning from - the background, pass the same ads IDs to the player. - -

    This method should only be called if setUri(java.lang.String) is passed a non-null value.

    -
    -
    Parameters:
    -
    adTagUri - The ad tag URI to load.
    -
    adsId - An opaque identifier for ad playback state associated with this item. Ad loading - and playback state is shared among all media items that have the same ads ID (by equality) and ads loader, so it is important to pass the same - identifiers when constructing playlist items each time the player returns to the - foreground.
    -
    +
    Deprecated. + +
    +
  • + + + + + @@ -856,15 +961,11 @@ extends
  • setLiveTargetOffsetMs

    -
    public MediaItem.Builder setLiveTargetOffsetMs​(long liveTargetOffsetMs)
    -
    Sets the optional target offset from the live edge for live streams, in milliseconds. - -

    See Player#getCurrentLiveOffset().

    -
    -
    Parameters:
    -
    liveTargetOffsetMs - The target offset, in milliseconds, or C.TIME_UNSET to use - the media-defined default.
    -
    +
    @Deprecated
    +public MediaItem.Builder setLiveTargetOffsetMs​(long liveTargetOffsetMs)
    +
  • @@ -873,15 +974,11 @@ extends
  • setLiveMinOffsetMs

    -
    public MediaItem.Builder setLiveMinOffsetMs​(long liveMinOffsetMs)
    -
    Sets the optional minimum offset from the live edge for live streams, in milliseconds. - -

    See Player#getCurrentLiveOffset().

    -
    -
    Parameters:
    -
    liveMinOffsetMs - The minimum allowed offset, in milliseconds, or C.TIME_UNSET - to use the media-defined default.
    -
    +
    @Deprecated
    +public MediaItem.Builder setLiveMinOffsetMs​(long liveMinOffsetMs)
    +
  • @@ -890,15 +987,11 @@ extends
  • setLiveMaxOffsetMs

    -
    public MediaItem.Builder setLiveMaxOffsetMs​(long liveMaxOffsetMs)
    -
    Sets the optional maximum offset from the live edge for live streams, in milliseconds. - -

    See Player#getCurrentLiveOffset().

    -
    -
    Parameters:
    -
    liveMaxOffsetMs - The maximum allowed offset, in milliseconds, or C.TIME_UNSET - to use the media-defined default.
    -
    +
    @Deprecated
    +public MediaItem.Builder setLiveMaxOffsetMs​(long liveMaxOffsetMs)
    +
  • @@ -907,15 +1000,11 @@ extends
  • setLiveMinPlaybackSpeed

    -
    public MediaItem.Builder setLiveMinPlaybackSpeed​(float minPlaybackSpeed)
    -
    Sets the optional minimum playback speed for live stream speed adjustment. - -

    This value is ignored for other stream types.

    -
    -
    Parameters:
    -
    minPlaybackSpeed - The minimum factor by which playback can be sped up for live streams, - or C.RATE_UNSET to use the media-defined default.
    -
    +
    @Deprecated
    +public MediaItem.Builder setLiveMinPlaybackSpeed​(float minPlaybackSpeed)
    +
  • @@ -924,15 +1013,11 @@ extends
  • setLiveMaxPlaybackSpeed

    -
    public MediaItem.Builder setLiveMaxPlaybackSpeed​(float maxPlaybackSpeed)
    -
    Sets the optional maximum playback speed for live stream speed adjustment. - -

    This value is ignored for other stream types.

    -
    -
    Parameters:
    -
    maxPlaybackSpeed - The maximum factor by which playback can be sped up for live streams, - or C.RATE_UNSET to use the media-defined default.
    -
    +
    @Deprecated
    +public MediaItem.Builder setLiveMaxPlaybackSpeed​(float maxPlaybackSpeed)
    +
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingConfiguration.Builder.html b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingConfiguration.Builder.html new file mode 100644 index 0000000000..09e7bc2dc1 --- /dev/null +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingConfiguration.Builder.html @@ -0,0 +1,434 @@ + + + + +MediaItem.ClippingConfiguration.Builder (ExoPlayer library) + + + + + + + + + + + + + +
    + +
    + +
    +
    + +

    Class MediaItem.ClippingConfiguration.Builder

    +
    +
    +
      +
    • java.lang.Object
    • +
    • +
        +
      • com.google.android.exoplayer2.MediaItem.ClippingConfiguration.Builder
      • +
      +
    • +
    +
    + +
    +
    + +
    +
    +
      +
    • + +
      +
        +
      • + + +

        Constructor Detail

        + + + +
          +
        • +

          Builder

          +
          public Builder()
          +
          Constructs an instance.
          +
        • +
        +
      • +
      +
      + +
      +
        +
      • + + +

        Method Detail

        + + + +
          +
        • +

          setStartPositionMs

          +
          public MediaItem.ClippingConfiguration.Builder setStartPositionMs​(@IntRange(from=0L)
          +                                                                  long startPositionMs)
          +
          Sets the optional start position in milliseconds which must be a value larger than or equal + to zero (Default: 0).
          +
        • +
        + + + + + + + +
          +
        • +

          setRelativeToLiveWindow

          +
          public MediaItem.ClippingConfiguration.Builder setRelativeToLiveWindow​(boolean relativeToLiveWindow)
          +
          Sets whether the start/end positions should move with the live window for live streams. If + false, live streams end when playback reaches the end position in live window seen + when the media is first loaded (Default: false).
          +
        • +
        + + + +
          +
        • +

          setRelativeToDefaultPosition

          +
          public MediaItem.ClippingConfiguration.Builder setRelativeToDefaultPosition​(boolean relativeToDefaultPosition)
          +
          Sets whether the start position and the end position are relative to the default position + in the window (Default: false).
          +
        • +
        + + + +
          +
        • +

          setStartsAtKeyFrame

          +
          public MediaItem.ClippingConfiguration.Builder setStartsAtKeyFrame​(boolean startsAtKeyFrame)
          +
          Sets whether the start point is guaranteed to be a key frame. If false, the + playback transition into the clip may not be seamless (Default: false).
          +
        • +
        + + + + + + + + +
      • +
      +
      +
    • +
    +
    +
    +
    + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingConfiguration.html b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingConfiguration.html new file mode 100644 index 0000000000..b58cccb864 --- /dev/null +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingConfiguration.html @@ -0,0 +1,521 @@ + + + + +MediaItem.ClippingConfiguration (ExoPlayer library) + + + + + + + + + + + + + +
    + +
    + +
    +
    + +

    Class MediaItem.ClippingConfiguration

    +
    +
    +
      +
    • java.lang.Object
    • +
    • +
        +
      • com.google.android.exoplayer2.MediaItem.ClippingConfiguration
      • +
      +
    • +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingProperties.html b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingProperties.html index 4fe4df1dcc..b619bd05a7 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingProperties.html +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.ClippingProperties.html @@ -25,12 +25,6 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10}; -var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; -var altColor = "altColor"; -var rowColor = "rowColor"; -var tableTab = "tableTab"; -var activeTableTab = "activeTableTab"; var pathtoroot = "../../../../"; var useModuleDirectories = false; loadScripts(document, 'script'); @@ -95,7 +89,7 @@ loadScripts(document, 'script');
  • Detail: 
  • Field | 
  • Constr | 
  • -
  • Method
  • +
  • Method
  • @@ -121,10 +115,15 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • java.lang.Object
  • +
  • +
    @@ -155,6 +156,13 @@ implements +
  • + + +

    Nested classes/interfaces inherited from class com.google.android.exoplayer2.MediaItem.ClippingConfiguration

    +MediaItem.ClippingConfiguration.Builder
  • + +
    static Bundleable.Creator<MediaItem.ClippingProperties>CREATORstatic MediaItem.ClippingPropertiesUNSET -
    Object that can restore MediaItem.ClippingProperties from a Bundle.
    -
    longendPositionMs -
    The end position in milliseconds.
    -
    booleanrelativeToDefaultPosition -
    Whether startPositionMs and endPositionMs are relative to the default - position.
    -
    booleanrelativeToLiveWindow -
    Whether the clipping of active media periods moves with a live window.
    -
    longstartPositionMs -
    The start position in milliseconds.
    -
    booleanstartsAtKeyFrame -
    Sets whether the start point is guaranteed to be a key frame.
    -
    + @@ -232,31 +211,13 @@ implements -All Methods Instance Methods Concrete Methods  - -Modifier and Type -Method -Description - - -boolean -equals​(Object obj) -  - - -int -hashCode() -  - - -Bundle -toBundle() - -
    Returns a Bundle representing the information stored in this object.
    - - - +
    • @@ -280,118 +241,14 @@ implements - - -
        -
      • -

        startPositionMs

        -
        public final long startPositionMs
        -
        The start position in milliseconds. This is a value larger than or equal to zero.
        -
      • -
      - - - -
        -
      • -

        endPositionMs

        -
        public final long endPositionMs
        -
        The end position in milliseconds. This is a value larger than or equal to zero or C.TIME_END_OF_SOURCE to play to the end of the stream.
        -
      • -
      - - - -
        -
      • -

        relativeToLiveWindow

        -
        public final boolean relativeToLiveWindow
        -
        Whether the clipping of active media periods moves with a live window. If false, - playback ends when it reaches endPositionMs.
        -
      • -
      - - - -
        -
      • -

        relativeToDefaultPosition

        -
        public final boolean relativeToDefaultPosition
        -
        Whether startPositionMs and endPositionMs are relative to the default - position.
        -
      • -
      - - - -
        -
      • -

        startsAtKeyFrame

        -
        public final boolean startsAtKeyFrame
        -
        Sets whether the start point is guaranteed to be a key frame.
        -
      • -
      - + -
    • -
    - - -
    - diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.DrmConfiguration.Builder.html b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.DrmConfiguration.Builder.html new file mode 100644 index 0000000000..b8bc49adea --- /dev/null +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.DrmConfiguration.Builder.html @@ -0,0 +1,503 @@ + + + + +MediaItem.DrmConfiguration.Builder (ExoPlayer library) + + + + + + + + + + + + + +
    + +
    + +
    +
    + +

    Class MediaItem.DrmConfiguration.Builder

    +
    +
    +
      +
    • java.lang.Object
    • +
    • +
        +
      • com.google.android.exoplayer2.MediaItem.DrmConfiguration.Builder
      • +
      +
    • +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.DrmConfiguration.html b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.DrmConfiguration.html index 962e8326a7..b92180a011 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.DrmConfiguration.html +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.DrmConfiguration.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -86,7 +86,7 @@ loadScripts(document, 'script');
    @@ -121,10 +115,15 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • java.lang.Object
  • +
  • +
    • @@ -133,9 +132,12 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
      MediaItem

    -
    public static final class MediaItem.PlaybackProperties
    -extends Object
    -
    Properties for local playback.
    +
    @Deprecated
    +public static final class MediaItem.PlaybackProperties
    +extends MediaItem.LocalConfiguration
    +
    Deprecated. + +
    @@ -149,70 +151,13 @@ extends

    Field Summary

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Fields 
    Modifier and TypeFieldDescription
    MediaItem.AdsConfigurationadsConfiguration -
    Optional ads configuration.
    -
    StringcustomCacheKey -
    Optional custom cache key (only used for progressive streams).
    -
    MediaItem.DrmConfigurationdrmConfiguration -
    Optional MediaItem.DrmConfiguration for the media.
    -
    StringmimeType -
    The optional MIME type of the item, or null if unspecified.
    -
    List<StreamKey>streamKeys -
    Optional stream keys by which the manifest is filtered.
    -
    List<MediaItem.Subtitle>subtitles -
    Optional subtitles to be sideloaded.
    -
    Objecttag -
    Optional tag for custom attributes.
    -
    Uriuri -
    The Uri.
    -
    + @@ -223,24 +168,13 @@ extends

    Method Summary

    - - - - - - - - - - - - - - - - - -
    All Methods Instance Methods Concrete Methods 
    Modifier and TypeMethodDescription
    booleanequals​(Object obj) 
    inthashCode() 
    + -
    -
      -
    • - -
      -
        -
      • - - -

        Field Detail

        - - - -
          -
        • -

          uri

          -
          public final Uri uri
          -
          The Uri.
          -
        • -
        - - - -
          -
        • -

          mimeType

          -
          @Nullable
          -public final String mimeType
          -
          The optional MIME type of the item, or null if unspecified. - -

          The MIME type can be used to disambiguate media items that have a URI which does not allow - to infer the actual media type.

          -
        • -
        - - - - - - - - - - - -
          -
        • -

          streamKeys

          -
          public final List<StreamKey> streamKeys
          -
          Optional stream keys by which the manifest is filtered.
          -
        • -
        - - - -
          -
        • -

          customCacheKey

          -
          @Nullable
          -public final String customCacheKey
          -
          Optional custom cache key (only used for progressive streams).
          -
        • -
        - - - - - - - -
          -
        • -

          tag

          -
          @Nullable
          -public final Object tag
          -
          Optional tag for custom attributes. The tag for the media source which will be published in - the com.google.android.exoplayer2.Timeline of the source as - com.google.android.exoplayer2.Timeline.Window#tag.
          -
        • -
        -
      • -
      -
      - -
      -
        -
      • - - -

        Method Detail

        - - - -
          -
        • -

          equals

          -
          public boolean equals​(@Nullable
          -                      Object obj)
          -
          -
          Overrides:
          -
          equals in class Object
          -
          -
        • -
        - - - -
          -
        • -

          hashCode

          -
          public int hashCode()
          -
          -
          Overrides:
          -
          hashCode in class Object
          -
          -
        • -
        -
      • -
      -
      -
    • -
    -
    @@ -449,9 +240,9 @@ public final 
  • Detail: 
  • -
  • Field | 
  • +
  • Field | 
  • Constr | 
  • -
  • Method
  • +
  • Method
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.Subtitle.html b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.Subtitle.html index 6f9c93e6b6..22d9d9bfcf 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.Subtitle.html +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.Subtitle.html @@ -25,12 +25,6 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10}; -var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; -var altColor = "altColor"; -var rowColor = "rowColor"; -var tableTab = "tableTab"; -var activeTableTab = "activeTableTab"; var pathtoroot = "../../../../"; var useModuleDirectories = false; loadScripts(document, 'script'); @@ -86,16 +80,16 @@ loadScripts(document, 'script');
    @@ -121,10 +115,15 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • java.lang.Object
  • +
  • +
    • @@ -133,15 +132,35 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
      MediaItem

    -
    public static final class MediaItem.Subtitle
    -extends Object
    -
    Properties for a text track.
    +
    @Deprecated
    +public static final class MediaItem.Subtitle
    +extends MediaItem.SubtitleConfiguration
    +
    Deprecated. + +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.SubtitleConfiguration.Builder.html b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.SubtitleConfiguration.Builder.html new file mode 100644 index 0000000000..b3385dc9c7 --- /dev/null +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.SubtitleConfiguration.Builder.html @@ -0,0 +1,423 @@ + + + + +MediaItem.SubtitleConfiguration.Builder (ExoPlayer library) + + + + + + + + + + + + + +
    + +
    + +
    +
    + +

    Class MediaItem.SubtitleConfiguration.Builder

    +
    +
    +
      +
    • java.lang.Object
    • +
    • +
        +
      • com.google.android.exoplayer2.MediaItem.SubtitleConfiguration.Builder
      • +
      +
    • +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.SubtitleConfiguration.html b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.SubtitleConfiguration.html new file mode 100644 index 0000000000..646cfb4fc5 --- /dev/null +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.SubtitleConfiguration.html @@ -0,0 +1,471 @@ + + + + +MediaItem.SubtitleConfiguration (ExoPlayer library) + + + + + + + + + + + + + +
    + +
    + +
    +
    + +

    Class MediaItem.SubtitleConfiguration

    +
    +
    +
      +
    • java.lang.Object
    • +
    • +
        +
      • com.google.android.exoplayer2.MediaItem.SubtitleConfiguration
      • +
      +
    • +
    +
    +
      +
    • +
      +
      Direct Known Subclasses:
      +
      MediaItem.Subtitle
      +
      +
      +
      Enclosing class:
      +
      MediaItem
      +
      +
      +
      public static class MediaItem.SubtitleConfiguration
      +extends Object
      +
      Properties for a text track.
      +
    • +
    +
    +
    + +
    +
    +
      +
    • + +
      +
        +
      • + + +

        Field Detail

        + + + +
          +
        • +

          uri

          +
          public final Uri uri
          +
          The Uri to the subtitle file.
          +
        • +
        + + + +
          +
        • +

          mimeType

          +
          @Nullable
          +public final String mimeType
          +
          The optional MIME type of the subtitle file, or null if unspecified.
          +
        • +
        + + + +
          +
        • +

          language

          +
          @Nullable
          +public final String language
          +
          The language.
          +
        • +
        + + + +
          +
        • +

          selectionFlags

          +
          @SelectionFlags
          +public final @com.google.android.exoplayer2.C.SelectionFlags int selectionFlags
          +
          The selection flags.
          +
        • +
        + + + +
          +
        • +

          roleFlags

          +
          @RoleFlags
          +public final @com.google.android.exoplayer2.C.RoleFlags int roleFlags
          +
          The role flags.
          +
        • +
        + + + +
          +
        • +

          label

          +
          @Nullable
          +public final String label
          +
          The label.
          +
        • +
        +
      • +
      +
      + +
      + +
      +
    • +
    +
    +
    +
    + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.html b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.html index 9e476679f9..6286401732 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/MediaItem.html +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaItem.html @@ -173,36 +173,63 @@ implements static class  -MediaItem.ClippingProperties +MediaItem.ClippingConfiguration
    Optionally clips the media item to a custom start and end position.
    static class  +MediaItem.ClippingProperties + +
    Deprecated. + +
    + + + +static class  MediaItem.DrmConfiguration
    DRM configuration for a media item.
    - + static class  MediaItem.LiveConfiguration
    Live playback configuration.
    + +static class  +MediaItem.LocalConfiguration + +
    Properties for local playback.
    + + static class  MediaItem.PlaybackProperties -
    Properties for local playback.
    +
    Deprecated. + +
    static class  MediaItem.Subtitle +
    Deprecated. + +
    + + + +static class  +MediaItem.SubtitleConfiguration +
    Properties for a text track.
    @@ -232,40 +259,56 @@ implements Description -MediaItem.ClippingProperties -clippingProperties +MediaItem.ClippingConfiguration +clippingConfiguration
    The clipping properties.
    +MediaItem.ClippingProperties +clippingProperties + +
    Deprecated. + +
    + + + static Bundleable.Creator<MediaItem> CREATOR
    Object that can restore MediaItem from a Bundle.
    - + static String DEFAULT_MEDIA_ID
    The default media ID that is used if the media ID is not explicitly set by MediaItem.Builder.setMediaId(String).
    - + static MediaItem EMPTY
    Empty MediaItem.
    - + MediaItem.LiveConfiguration liveConfiguration
    The live playback configuration.
    + +MediaItem.LocalConfiguration +localConfiguration + +
    Optional configuration for local playback.
    + + String mediaId @@ -284,7 +327,9 @@ implements MediaItem.PlaybackProperties playbackProperties -
    Optional playback properties.
    +
    Deprecated. +
    Use localConfiguration instead.
    +
    @@ -401,15 +446,30 @@ implements Identifies the media item. + + + +
      +
    • +

      localConfiguration

      +
      @Nullable
      +public final MediaItem.LocalConfiguration localConfiguration
      +
      Optional configuration for local playback. May be null if shared over process + boundaries.
      +
    • +
    @@ -432,14 +492,27 @@ public final The media metadata. + + + + @@ -451,7 +524,7 @@ public final Bundleable.Creator<MediaItem> CREATOR
    Object that can restore MediaItem from a Bundle. -

    The playbackProperties of a restored instance will always be null.

    +

    The localConfiguration of a restored instance will always be null. @@ -542,7 +615,7 @@ public final public Bundle toBundle()

    Returns a Bundle representing the information stored in this object. -

    It omits the playbackProperties field. The playbackProperties of an +

    It omits the localConfiguration field. The localConfiguration of an instance restored by CREATOR will always be null.

    Specified by:
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.Builder.html b/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.Builder.html index cceffedcbf..764cb28e27 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.Builder.html +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.Builder.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":42,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":42}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":42,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10,"i36":42}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -186,8 +186,8 @@ extends MediaMetadata.Builder -maybeSetArtworkData​(byte[] artworkData, - int artworkDataType) +maybeSetArtworkData​(byte[] artworkData, + @com.google.android.exoplayer2.MediaMetadata.PictureType int artworkDataType)
    Sets the artwork data as a compressed byte array in the event that the associated MediaMetadata.PictureType is MediaMetadata.PICTURE_TYPE_FRONT_COVER, the existing MediaMetadata.PictureType is not MediaMetadata.PICTURE_TYPE_FRONT_COVER, or the current artworkData is not set.
    @@ -195,239 +195,246 @@ extends MediaMetadata.Builder +populate​(MediaMetadata mediaMetadata) + +
    Populates all the fields from mediaMetadata, provided they are non-null.
    + + + +MediaMetadata.Builder populateFromMetadata​(Metadata metadata)
    Sets all fields supported by the entries within the Metadata.
    - + MediaMetadata.Builder populateFromMetadata​(List<Metadata> metadataList)
    Sets all fields supported by the entries within the list of Metadata.
    - + MediaMetadata.Builder setAlbumArtist​(CharSequence albumArtist)
    Sets the album artist.
    - + MediaMetadata.Builder setAlbumTitle​(CharSequence albumTitle)
    Sets the album title.
    - + MediaMetadata.Builder setArtist​(CharSequence artist)
    Sets the artist.
    - + MediaMetadata.Builder setArtworkData​(byte[] artworkData) - + MediaMetadata.Builder setArtworkData​(byte[] artworkData, - Integer artworkDataType) + @PictureType Integer artworkDataType)
    Sets the artwork data as a compressed byte array with an associated artworkDataType.
    - + MediaMetadata.Builder setArtworkUri​(Uri artworkUri)
    Sets the artwork Uri.
    - + MediaMetadata.Builder setCompilation​(CharSequence compilation)
    Sets the compilation.
    - + MediaMetadata.Builder setComposer​(CharSequence composer)
    Sets the composer.
    - + MediaMetadata.Builder setConductor​(CharSequence conductor)
    Sets the conductor.
    - + MediaMetadata.Builder setDescription​(CharSequence description)
    Sets the description.
    - + MediaMetadata.Builder setDiscNumber​(Integer discNumber)
    Sets the disc number.
    - + MediaMetadata.Builder setDisplayTitle​(CharSequence displayTitle)
    Sets the display title.
    - + MediaMetadata.Builder setExtras​(Bundle extras)
    Sets the extras Bundle.
    - + MediaMetadata.Builder -setFolderType​(Integer folderType) +setFolderType​(@FolderType Integer folderType) - + MediaMetadata.Builder setGenre​(CharSequence genre)
    Sets the genre.
    - + MediaMetadata.Builder setIsPlayable​(Boolean isPlayable)
    Sets whether the media is playable.
    - + MediaMetadata.Builder setMediaUri​(Uri mediaUri)
    Sets the media Uri.
    - + MediaMetadata.Builder setOverallRating​(Rating overallRating)
    Sets the overall Rating.
    - + MediaMetadata.Builder setRecordingDay​(Integer recordingDay)
    Sets the day of the recording date.
    - + MediaMetadata.Builder setRecordingMonth​(Integer recordingMonth)
    Sets the month of the recording date.
    - + MediaMetadata.Builder setRecordingYear​(Integer recordingYear)
    Sets the year of the recording date.
    - + MediaMetadata.Builder setReleaseDay​(Integer releaseDay)
    Sets the day of the release date.
    - + MediaMetadata.Builder setReleaseMonth​(Integer releaseMonth)
    Sets the month of the release date.
    - + MediaMetadata.Builder setReleaseYear​(Integer releaseYear)
    Sets the year of the release date.
    - + MediaMetadata.Builder setSubtitle​(CharSequence subtitle)
    Sets the subtitle.
    - + MediaMetadata.Builder setTitle​(CharSequence title)
    Sets the title.
    - + MediaMetadata.Builder setTotalDiscCount​(Integer totalDiscCount)
    Sets the total number of discs.
    - + MediaMetadata.Builder setTotalTrackCount​(Integer totalTrackCount)
    Sets the total number of tracks.
    - + MediaMetadata.Builder setTrackNumber​(Integer trackNumber)
    Sets the track number.
    - + MediaMetadata.Builder setUserRating​(Rating userRating)
    Sets the user Rating.
    - + MediaMetadata.Builder setWriter​(CharSequence writer)
    Sets the writer.
    - + MediaMetadata.Builder setYear​(Integer year) @@ -601,7 +608,7 @@ extends MediaMetadata.Builder setArtworkData​(@Nullable byte[] artworkData) @@ -614,11 +621,11 @@ public public MediaMetadata.Builder setArtworkData​(@Nullable byte[] artworkData, @Nullable @PictureType - Integer artworkDataType) + @PictureType Integer artworkDataType)
    Sets the artwork data as a compressed byte array with an associated artworkDataType.
    - + @@ -894,6 +901,17 @@ public Metadata.Entry objects within any of the Metadata relate to the same MediaMetadata field, then the last one will be used. + + + +
      +
    • +

      populate

      +
      public MediaMetadata.Builder populate​(@Nullable
      +                                      MediaMetadata mediaMetadata)
      +
      Populates all the fields from mediaMetadata, provided they are non-null.
      +
    • +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.FolderType.html b/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.FolderType.html index 5cf377cb11..c555f2c606 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.FolderType.html +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.FolderType.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    @Documented
     @Retention(SOURCE)
    +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
     public static @interface MediaMetadata.FolderType
    The folder type of the media item. diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.PictureType.html b/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.PictureType.html index 8aa35d1a6e..06dab22929 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.PictureType.html +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.PictureType.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    @Documented
     @Retention(SOURCE)
    +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
     public static @interface MediaMetadata.PictureType
    The picture type of the artwork. diff --git a/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.html b/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.html index a8ce3ba8e0..446b711fa7 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.html +++ b/docs/doc/reference/com/google/android/exoplayer2/MediaMetadata.html @@ -232,7 +232,7 @@ implements -Integer +@PictureType Integer artworkDataType
    Optional MediaMetadata.PictureType of the artwork data.
    @@ -365,7 +365,7 @@ implements -Integer +@FolderType Integer folderType @@ -1196,7 +1196,7 @@ public final byte[] artworkData

    artworkDataType

    @Nullable
     @PictureType
    -public final Integer artworkDataType
    +public final @PictureType Integer artworkDataType
    Optional MediaMetadata.PictureType of the artwork data.
    @@ -1241,7 +1241,7 @@ public final @FolderType -public final Integer folderType +public final @FolderType Integer folderType diff --git a/docs/doc/reference/com/google/android/exoplayer2/NoSampleRenderer.html b/docs/doc/reference/com/google/android/exoplayer2/NoSampleRenderer.html index 36998fa580..038a05ad8e 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/NoSampleRenderer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/NoSampleRenderer.html @@ -156,7 +156,7 @@ implements Renderer -Renderer.State, Renderer.VideoScalingMode, Renderer.WakeupListener +Renderer.MessageType, Renderer.State, Renderer.WakeupListener
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.Commands.Builder.html b/docs/doc/reference/com/google/android/exoplayer2/Player.Commands.Builder.html index ca5c0339c3..80bb720c04 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.Commands.Builder.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.Commands.Builder.html @@ -181,14 +181,14 @@ extends Player.Commands.Builder -add​(int command) +add​(@com.google.android.exoplayer2.Player.Command int command) Player.Commands.Builder -addAll​(int... commands) +addAll​(@com.google.android.exoplayer2.Player.Command int... commands)
    Adds commands.
    @@ -209,7 +209,7 @@ extends Player.Commands.Builder -addIf​(int command, +addIf​(@com.google.android.exoplayer2.Player.Command int command, boolean condition)
    Adds a Player.Command if the provided condition is true.
    @@ -224,21 +224,21 @@ extends Player.Commands.Builder -remove​(int command) +remove​(@com.google.android.exoplayer2.Player.Command int command)
    Removes a Player.Command.
    Player.Commands.Builder -removeAll​(int... commands) +removeAll​(@com.google.android.exoplayer2.Player.Command int... commands)
    Removes commands.
    Player.Commands.Builder -removeIf​(int command, +removeIf​(@com.google.android.exoplayer2.Player.Command int command, boolean condition)
    Removes a Player.Command if the provided condition is true.
    @@ -288,14 +288,14 @@ extends

    Method Detail

    - + - +
    • addIf

      public Player.Commands.Builder addIf​(@Command
      -                                     int command,
      +                                     @com.google.android.exoplayer2.Player.Command int command,
                                            boolean condition)
      Adds a Player.Command if the provided condition is true. Does nothing otherwise.
      @@ -328,14 +328,14 @@ extends
    - + - + - +
    • removeIf

      public Player.Commands.Builder removeIf​(@Command
      -                                        int command,
      +                                        @com.google.android.exoplayer2.Player.Command int command,
                                               boolean condition)
      Removes a Player.Command if the provided condition is true. Does nothing otherwise.
      @@ -421,14 +421,14 @@ extends
    - +
    • removeAll

      public Player.Commands.Builder removeAll​(@Command
      -                                         int... commands)
      + @com.google.android.exoplayer2.Player.Command int... commands)
      Removes commands.
      Parameters:
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.Commands.html b/docs/doc/reference/com/google/android/exoplayer2/Player.Commands.html index 7b79b004ec..545fd32c74 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.Commands.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.Commands.html @@ -236,7 +236,7 @@ implements boolean -contains​(int command) +contains​(@com.google.android.exoplayer2.Player.Command int command)
      Returns whether the set of commands contains the specified Player.Command.
      @@ -247,7 +247,7 @@ implements   -int +@com.google.android.exoplayer2.Player.Command int get​(int index)
      Returns the Player.Command at the given index.
      @@ -336,14 +336,14 @@ implements Returns a Player.Commands.Builder initialized with the values of this instance.
    - +
    • contains

      public boolean contains​(@Command
      -                        int command)
      + @com.google.android.exoplayer2.Player.Command int command)
      Returns whether the set of commands contains the specified Player.Command.
    @@ -364,7 +364,7 @@ implements

    get

    @Command
    -public int get​(int index)
    +public @com.google.android.exoplayer2.Player.Command int get​(int index)
    Returns the Player.Command at the given index.
    Parameters:
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.DiscontinuityReason.html b/docs/doc/reference/com/google/android/exoplayer2/Player.DiscontinuityReason.html index 0fa6ed4600..76879e9080 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.DiscontinuityReason.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.DiscontinuityReason.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    @Documented
     @Retention(SOURCE)
    +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
     public static @interface Player.DiscontinuityReason
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.Event.html b/docs/doc/reference/com/google/android/exoplayer2/Player.Event.html index 51e7f50293..5407eca322 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.Event.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.Event.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    @Documented
     @Retention(SOURCE)
    +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
     public static @interface Player.Event
    Events that can be reported via Player.Listener.onEvents(Player, Events). diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.EventListener.html b/docs/doc/reference/com/google/android/exoplayer2/Player.EventListener.html index 8aadfb108f..f6beaf7e46 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.EventListener.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.EventListener.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":50,"i1":50,"i2":50,"i3":50,"i4":50,"i5":50,"i6":50,"i7":50,"i8":50,"i9":50,"i10":50,"i11":50,"i12":50,"i13":50,"i14":50,"i15":50,"i16":50,"i17":50,"i18":50,"i19":50,"i20":50,"i21":50,"i22":50,"i23":50,"i24":50,"i25":50}; +var data = {"i0":50,"i1":50,"i2":50,"i3":50,"i4":50,"i5":50,"i6":50,"i7":50,"i8":50,"i9":50,"i10":50,"i11":50,"i12":50,"i13":50,"i14":50,"i15":50,"i16":50,"i17":50,"i18":50,"i19":50,"i20":50,"i21":50,"i22":50,"i23":50,"i24":50,"i25":50,"i26":50}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],16:["t5","Default Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -126,7 +126,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    All Known Implementing Classes:
    -
    AnalyticsCollector, DebugTextViewHelper, ExoPlayerTestRunner, ImaAdsLoader
    +
    AnalyticsCollector, DebugTextViewHelper, ExoPlayerTestRunner, ImaAdsLoader, SubtitleView
    Enclosing interface:
    @@ -169,7 +169,7 @@ public static interface Player.EventListener< onAvailableCommandsChanged​(Player.Commands availableCommands)
    Deprecated.
    -
    Called when the value returned from Player.isCommandAvailable(int) changes for at least one +
    Called when the value returned from Player.isCommandAvailable(int) changes for at least one Player.Command.
    @@ -209,7 +209,7 @@ public static interface Player.EventListener< default void -onMaxSeekToPreviousPositionChanged​(int maxSeekToPreviousPositionMs) +onMaxSeekToPreviousPositionChanged​(long maxSeekToPreviousPositionMs)
    Deprecated.
    Called when the value of Player.getMaxSeekToPreviousPosition() changes.
    @@ -217,8 +217,8 @@ public static interface Player.EventListener< default void -onMediaItemTransition​(MediaItem mediaItem, - int reason) +onMediaItemTransition​(MediaItem mediaItem, + @com.google.android.exoplayer2.Player.MediaItemTransitionReason int reason)
    Deprecated.
    Called when playback transitions to a media item or starts repeating a media item according @@ -243,7 +243,7 @@ public static interface Player.EventListener< default void -onPlaybackStateChanged​(int playbackState) +onPlaybackStateChanged​(@com.google.android.exoplayer2.Player.State int playbackState)
    Deprecated.
    Called when the value returned from Player.getPlaybackState() changes.
    @@ -251,7 +251,7 @@ public static interface Player.EventListener< default void -onPlaybackSuppressionReasonChanged​(int playbackSuppressionReason) +onPlaybackSuppressionReasonChanged​(@com.google.android.exoplayer2.Player.PlaybackSuppressionReason int playbackSuppressionReason)
    Deprecated.
    Called when the value returned from Player.getPlaybackSuppressionReason() changes.
    @@ -275,11 +275,11 @@ public static interface Player.EventListener< default void -onPlayerStateChanged​(boolean playWhenReady, - int playbackState) +onPlayerStateChanged​(boolean playWhenReady, + @com.google.android.exoplayer2.Player.State int playbackState) @@ -293,8 +293,8 @@ public static interface Player.EventListener< default void -onPlayWhenReadyChanged​(boolean playWhenReady, - int reason) +onPlayWhenReadyChanged​(boolean playWhenReady, + @com.google.android.exoplayer2.Player.PlayWhenReadyChangeReason int reason)
    Deprecated.
    Called when the value returned from Player.getPlayWhenReady() changes.
    @@ -302,18 +302,18 @@ public static interface Player.EventListener< default void -onPositionDiscontinuity​(int reason) +onPositionDiscontinuity​(@com.google.android.exoplayer2.Player.DiscontinuityReason int reason) default void -onPositionDiscontinuity​(Player.PositionInfo oldPosition, +onPositionDiscontinuity​(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, - int reason) + @com.google.android.exoplayer2.Player.DiscontinuityReason int reason)
    Deprecated.
    Called when a position discontinuity occurs.
    @@ -321,7 +321,7 @@ public static interface Player.EventListener< default void -onRepeatModeChanged​(int repeatMode) +onRepeatModeChanged​(@com.google.android.exoplayer2.Player.RepeatMode int repeatMode)
    Deprecated.
    Called when the value of Player.getRepeatMode() changes.
    @@ -362,29 +362,35 @@ public static interface Player.EventListener< default void -onStaticMetadataChanged​(List<Metadata> metadataList) - -
    Deprecated. -
    Use Player.getMediaMetadata() and onMediaMetadataChanged(MediaMetadata) for access to structured metadata, or access the - raw static metadata directly from the track - selections' formats.
    -
    - - - -default void -onTimelineChanged​(Timeline timeline, - int reason) +onTimelineChanged​(Timeline timeline, + @com.google.android.exoplayer2.Player.TimelineChangeReason int reason)
    Deprecated.
    Called when the timeline has been refreshed.
    - + default void onTracksChanged​(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) +
    Deprecated. + +
    + + + +default void +onTrackSelectionParametersChanged​(TrackSelectionParameters parameters) + +
    Deprecated.
    +
    Called when the value returned from Player.getTrackSelectionParameters() changes.
    + + + +default void +onTracksInfoChanged​(TracksInfo tracksInfo) +
    Deprecated.
    Called when the available or selected tracks change.
    @@ -406,7 +412,7 @@ public static interface Player.EventListener<

    Method Detail

    - +
      @@ -414,12 +420,14 @@ public static interface Player.EventListener<

      onTimelineChanged

      default void onTimelineChanged​(Timeline timeline,
                                      @TimelineChangeReason
      -                               int reason)
      + @com.google.android.exoplayer2.Player.TimelineChangeReason int reason)
      Deprecated.
      Called when the timeline has been refreshed. -

      Note that the current window or period index may change as a result of a timeline change. - If playback can't continue smoothly because of this timeline change, a separate onPositionDiscontinuity(PositionInfo, PositionInfo, int) callback will be triggered. +

      Note that the current MediaItem or playback position may change as a result of a + timeline change. If playback can't continue smoothly because of this timeline change, a + separate onPositionDiscontinuity(PositionInfo, PositionInfo, int) callback will be + triggered.

      onEvents(Player, Events) will also be called to report this event along with other events that happen in the same Looper message queue iteration.

      @@ -430,7 +438,7 @@ public static interface Player.EventListener<
    - +
      @@ -439,7 +447,7 @@ public static interface Player.EventListener<
      default void onMediaItemTransition​(@Nullable
                                          MediaItem mediaItem,
                                          @MediaItemTransitionReason
      -                                   int reason)
      + @com.google.android.exoplayer2.Player.MediaItemTransitionReason int reason)
      Deprecated.
      Called when playback transitions to a media item or starts repeating a media item according to the current repeat mode. @@ -462,9 +470,12 @@ public static interface Player.EventListener<
    - + @@ -506,7 +520,11 @@ default void onStaticMetadataChanged​(MediaMetadata is a combination of the MediaItem.mediaMetadata and the static and dynamic metadata from the track - selections' formats and MetadataOutput.onMetadata(Metadata). + selections' formats and Player.Listener.onMetadata(Metadata). If a field is populated in + the MediaItem.mediaMetadata, it will be prioritised above the same field coming from + static or dynamic metadata. + +

    This method may be called multiple times in quick succession.

    onEvents(Player, Events) will also be called to report this event along with other events that happen in the same Looper message queue iteration. @@ -566,7 +584,7 @@ default void onLoadingChanged​(boolean isLoading)

    onAvailableCommandsChanged

    default void onAvailableCommandsChanged​(Player.Commands availableCommands)
    Deprecated.
    -
    Called when the value returned from Player.isCommandAvailable(int) changes for at least one +
    Called when the value returned from Player.isCommandAvailable(int) changes for at least one Player.Command.

    onEvents(Player, Events) will also be called to report this event along with @@ -577,7 +595,25 @@ default void onLoadingChanged​(boolean isLoading)

    - + + + + + - +
    • onPlaybackStateChanged

      default void onPlaybackStateChanged​(@State
      -                                    int playbackState)
      + @com.google.android.exoplayer2.Player.State int playbackState)
      Deprecated.
      Called when the value returned from Player.getPlaybackState() changes. @@ -611,7 +647,7 @@ default void onPlayerStateChanged​(boolean playWhenReady,
    - +
      @@ -619,7 +655,7 @@ default void onPlayerStateChanged​(boolean playWhenReady,

      onPlayWhenReadyChanged

      default void onPlayWhenReadyChanged​(boolean playWhenReady,
                                           @PlayWhenReadyChangeReason
      -                                    int reason)
      + @com.google.android.exoplayer2.Player.PlayWhenReadyChangeReason int reason)
      Deprecated.
      Called when the value returned from Player.getPlayWhenReady() changes. @@ -632,14 +668,14 @@ default void onPlayerStateChanged​(boolean playWhenReady,
    - +
    • onPlaybackSuppressionReasonChanged

      default void onPlaybackSuppressionReasonChanged​(@PlaybackSuppressionReason
      -                                                int playbackSuppressionReason)
      + @com.google.android.exoplayer2.Player.PlaybackSuppressionReason int playbackSuppressionReason)
      Deprecated.
      Called when the value returned from Player.getPlaybackSuppressionReason() changes. @@ -669,14 +705,14 @@ default void onPlayerStateChanged​(boolean playWhenReady,
    - +
    • onRepeatModeChanged

      default void onRepeatModeChanged​(@RepeatMode
      -                                 int repeatMode)
      + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode)
      Deprecated.
      Called when the value of Player.getRepeatMode() changes. @@ -702,7 +738,7 @@ default void onPlayerStateChanged​(boolean playWhenReady, other events that happen in the same Looper message queue iteration.
      Parameters:
      -
      shuffleModeEnabled - Whether shuffling of windows is enabled.
      +
      shuffleModeEnabled - Whether shuffling of media items is enabled.
    @@ -750,7 +786,7 @@ default void onPlayerStateChanged​(boolean playWhenReady,
    - + - + @@ -419,7 +411,7 @@ extends + - + - +
    • -

      onTracksChanged

      -
      default void onTracksChanged​(TrackGroupArray trackGroups,
      -                             TrackSelectionArray trackSelections)
      -
      Description copied from interface: Player.EventListener
      +

      onTracksInfoChanged

      +
      default void onTracksInfoChanged​(TracksInfo tracksInfo)
      +
      Description copied from interface: Player.EventListener
      Called when the available or selected tracks change.

      Player.EventListener.onEvents(Player, Events) will also be called to report this event along with other events that happen in the same Looper message queue iteration.

      Specified by:
      -
      onTracksChanged in interface Player.EventListener
      +
      onTracksInfoChanged in interface Player.EventListener
      Parameters:
      -
      trackGroups - The available tracks. Never null, but may be of length zero.
      -
      trackSelections - The selected tracks. Never null, but may contain null elements. A - concrete implementation may include null elements if it has a fixed number of renderer - components, wishes to report a TrackSelection for each of them, and has one or more - renderer components that is not assigned any selected tracks.
      +
      tracksInfo - The available tracks information. Never null, but may be of length zero.
    @@ -526,7 +515,7 @@ extends default void onAvailableCommandsChanged​(Player.Commands availableCommands)
    Description copied from interface: Player.EventListener
    -
    Called when the value returned from Player.isCommandAvailable(int) changes for at least one +
    Called when the value returned from Player.isCommandAvailable(int) changes for at least one Player.Command.

    Player.EventListener.onEvents(Player, Events) will also be called to report this event along with @@ -539,28 +528,28 @@ extends +

    - + - +
    @@ -713,7 +702,7 @@ extends + - + @@ -896,12 +868,7 @@ extends default void onDeviceVolumeChanged​(int volume, boolean muted) -
    Called when the device volume or mute state changes.
    -
    -
    Specified by:
    -
    onDeviceVolumeChanged in interface DeviceListener
    -
    @@ -924,15 +891,15 @@ extends Player.EventListener.onPlaybackStateChanged(int) and Player.EventListener.onPlayWhenReadyChanged(boolean, + both Player.EventListener.onPlaybackStateChanged(int) and Player.EventListener.onPlayWhenReadyChanged(boolean, int)).
  • They need access to the Player object to trigger further events (e.g. to call - Player.seekTo(long) after a Player.EventListener.onMediaItemTransition(MediaItem, int)). + Player.seekTo(long) after a Player.EventListener.onMediaItemTransition(MediaItem, int)).
  • They intend to use multiple state values together or in combination with Player - getter methods. For example using Player.getCurrentWindowIndex() with the - timeline provided in Player.EventListener.onTimelineChanged(Timeline, int) is only safe from + getter methods. For example using Player.getCurrentMediaItemIndex() with the + timeline provided in Player.EventListener.onTimelineChanged(Timeline, int) is only safe from within this method. -
  • They are interested in events that logically happened together (e.g Player.EventListener.onPlaybackStateChanged(int) to Player.STATE_BUFFERING because of Player.EventListener.onMediaItemTransition(MediaItem, int)). +
  • They are interested in events that logically happened together (e.g Player.EventListener.onPlaybackStateChanged(int) to Player.STATE_BUFFERING because of Player.EventListener.onMediaItemTransition(MediaItem, int)).
    Specified by:
    @@ -952,11 +919,8 @@ extends

    onVideoSizeChanged

    default void onVideoSizeChanged​(VideoSize videoSize)
    -
    Description copied from interface: VideoListener
    Called each time there's a change in the size of the video being rendered.
    -
    Specified by:
    -
    onVideoSizeChanged in interface VideoListener
    Parameters:
    videoSize - The new size of the video.
    @@ -970,15 +934,12 @@ extends default void onSurfaceSizeChanged​(int width, int height) -
    Called each time there's a change in the size of the surface onto which the video is being rendered.
    -
    Specified by:
    -
    onSurfaceSizeChanged in interface VideoListener
    Parameters:
    -
    width - The surface width in pixels. May be C.LENGTH_UNSET if unknown, or 0 if the - video is not rendered onto a surface.
    +
    width - The surface width in pixels. May be C.LENGTH_UNSET if unknown, or 0 if + the video is not rendered onto a surface.
    height - The surface height in pixels. May be C.LENGTH_UNSET if unknown, or 0 if the video is not rendered onto a surface.
    @@ -991,13 +952,8 @@ extends

    onRenderedFirstFrame

    default void onRenderedFirstFrame()
    -
    Called when a frame is rendered for the first time since setting the surface, or since the renderer was reset, or since the stream being rendered was changed.
    -
    -
    Specified by:
    -
    onRenderedFirstFrame in interface VideoListener
    -
  • @@ -1007,14 +963,11 @@ extends

    onCues

    default void onCues​(List<Cue> cues)
    -
    Description copied from interface: TextOutput
    Called when there is a change in the Cues.

    cues is in ascending order of priority. If any of the cue boxes overlap when displayed, the Cue nearer the end of the list should be shown on top.

    -
    Specified by:
    -
    onCues in interface TextOutput
    Parameters:
    cues - The Cues. May be empty.
    @@ -1027,11 +980,8 @@ extends

    onMetadata

    default void onMetadata​(Metadata metadata)
    -
    Description copied from interface: MetadataOutput
    -
    Called when there is metadata associated with current playback time.
    +
    Called when there is metadata associated with the current playback time.
    -
    Specified by:
    -
    onMetadata in interface MetadataOutput
    Parameters:
    metadata - The metadata.
    @@ -1049,7 +999,11 @@ extends MediaMetadata is a combination of the MediaItem.mediaMetadata and the static and dynamic metadata from the track - selections' formats and MetadataOutput.onMetadata(Metadata). + selections' formats
    and onMetadata(Metadata). If a field is populated in + the MediaItem.mediaMetadata, it will be prioritised above the same field coming from + static or dynamic metadata. + +

    This method may be called multiple times in quick succession.

    Player.EventListener.onEvents(Player, Events) will also be called to report this event along with other events that happen in the same Looper message queue iteration. diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.MediaItemTransitionReason.html b/docs/doc/reference/com/google/android/exoplayer2/Player.MediaItemTransitionReason.html index ca6b2f59b9..9aeb9e8ff3 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.MediaItemTransitionReason.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.MediaItemTransitionReason.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));


    @Documented
     @Retention(SOURCE)
    +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
     public static @interface Player.MediaItemTransitionReason
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.PlayWhenReadyChangeReason.html b/docs/doc/reference/com/google/android/exoplayer2/Player.PlayWhenReadyChangeReason.html index 5727e123a3..c859add3c2 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.PlayWhenReadyChangeReason.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.PlayWhenReadyChangeReason.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    @Documented
     @Retention(SOURCE)
    +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
     public static @interface Player.PlayWhenReadyChangeReason
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.PlaybackSuppressionReason.html b/docs/doc/reference/com/google/android/exoplayer2/Player.PlaybackSuppressionReason.html index adb9d25a81..e9449f426b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.PlaybackSuppressionReason.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.PlaybackSuppressionReason.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    @Documented
     @Retention(SOURCE)
    +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
     public static @interface Player.PlaybackSuppressionReason
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.PositionInfo.html b/docs/doc/reference/com/google/android/exoplayer2/Player.PositionInfo.html index 56aad779c6..14ab0b9589 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.PositionInfo.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.PositionInfo.html @@ -207,6 +207,20 @@ implements +MediaItem +mediaItem + +
    The media item, or null if the timeline is empty.
    + + + +int +mediaItemIndex + +
    The media item index.
    + + + int periodIndex @@ -217,7 +231,7 @@ implements Object periodUid -
    The UID of the period, or null, if the timeline is empty.
    +
    The UID of the period, or null if the timeline is empty.
    @@ -231,14 +245,16 @@ implements int windowIndex -
    The window index.
    +
    Deprecated. +
    Use mediaItemIndex instead.
    +
    Object windowUid -
    The UID of the window, or null, if the timeline is empty.
    +
    The UID of the window, or null if the timeline is empty.
    @@ -259,8 +275,9 @@ implements Description -PositionInfo​(Object windowUid, - int windowIndex, +PositionInfo​(Object windowUid, + int mediaItemIndex, + MediaItem mediaItem, Object periodUid, int periodIndex, long positionMs, @@ -271,6 +288,22 @@ implements Creates an instance. + +PositionInfo​(Object windowUid, + int mediaItemIndex, + Object periodUid, + int periodIndex, + long positionMs, + long contentPositionMs, + int adGroupIndex, + int adIndexInAdGroup) + + + + @@ -338,7 +371,7 @@ implements Object windowUid -
    The UID of the window, or null, if the timeline is empty.
    +
    The UID of the window, or null if the timeline is empty.
    @@ -347,8 +380,32 @@ public final 
  • windowIndex

    -
    public final int windowIndex
    -
    The window index.
    +
    @Deprecated
    +public final int windowIndex
    +
    Deprecated. +
    Use mediaItemIndex instead.
    +
    +
  • + + + + +
      +
    • +

      mediaItemIndex

      +
      public final int mediaItemIndex
      +
      The media item index.
      +
    • +
    + + + +
      +
    • +

      mediaItem

      +
      @Nullable
      +public final MediaItem mediaItem
      +
      The media item, or null if the timeline is empty.
    @@ -359,7 +416,7 @@ public final Object periodUid -
    The UID of the period, or null, if the timeline is empty.
    +
    The UID of the period, or null if the timeline is empty.
    @@ -437,12 +494,37 @@ public final  + + + +
    • PositionInfo

      public PositionInfo​(@Nullable
                           Object windowUid,
      -                    int windowIndex,
      +                    int mediaItemIndex,
      +                    @Nullable
      +                    MediaItem mediaItem,
                           @Nullable
                           Object periodUid,
                           int periodIndex,
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.RepeatMode.html b/docs/doc/reference/com/google/android/exoplayer2/Player.RepeatMode.html
      index 6c7fa3a240..f2c8abd799 100644
      --- a/docs/doc/reference/com/google/android/exoplayer2/Player.RepeatMode.html
      +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.RepeatMode.html
      @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
       
      @Documented
       @Retention(SOURCE)
      +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
       public static @interface Player.RepeatMode
    • diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.State.html b/docs/doc/reference/com/google/android/exoplayer2/Player.State.html index f4758744ae..2e49a77eda 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.State.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.State.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
      @Documented
       @Retention(SOURCE)
      +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
       public static @interface Player.State
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.TimelineChangeReason.html b/docs/doc/reference/com/google/android/exoplayer2/Player.TimelineChangeReason.html index 34514269e3..9972d82602 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.TimelineChangeReason.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.TimelineChangeReason.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
      @Documented
       @Retention(SOURCE)
      +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
       public static @interface Player.TimelineChangeReason
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/Player.html b/docs/doc/reference/com/google/android/exoplayer2/Player.html index 06a5f53fd3..a2e407a755 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/Player.html +++ b/docs/doc/reference/com/google/android/exoplayer2/Player.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":38,"i1":6,"i2":6,"i3":6,"i4":6,"i5":6,"i6":6,"i7":6,"i8":6,"i9":6,"i10":6,"i11":6,"i12":6,"i13":6,"i14":6,"i15":6,"i16":6,"i17":6,"i18":6,"i19":6,"i20":6,"i21":6,"i22":6,"i23":6,"i24":6,"i25":6,"i26":6,"i27":6,"i28":6,"i29":38,"i30":6,"i31":6,"i32":6,"i33":6,"i34":6,"i35":6,"i36":6,"i37":6,"i38":6,"i39":6,"i40":6,"i41":6,"i42":6,"i43":6,"i44":6,"i45":6,"i46":6,"i47":6,"i48":6,"i49":6,"i50":6,"i51":6,"i52":6,"i53":6,"i54":6,"i55":6,"i56":38,"i57":6,"i58":38,"i59":6,"i60":6,"i61":6,"i62":6,"i63":6,"i64":6,"i65":6,"i66":6,"i67":6,"i68":6,"i69":6,"i70":6,"i71":38,"i72":6,"i73":6,"i74":6,"i75":38,"i76":6,"i77":38,"i78":6,"i79":6,"i80":6,"i81":6,"i82":6,"i83":6,"i84":6,"i85":6,"i86":6,"i87":6,"i88":6,"i89":6,"i90":6,"i91":6,"i92":6,"i93":6,"i94":6,"i95":6,"i96":6,"i97":6,"i98":6,"i99":6,"i100":6,"i101":6,"i102":6,"i103":6,"i104":6,"i105":6,"i106":6,"i107":6,"i108":6,"i109":6,"i110":6,"i111":38}; +var data = {"i0":6,"i1":6,"i2":6,"i3":6,"i4":6,"i5":6,"i6":6,"i7":6,"i8":6,"i9":6,"i10":6,"i11":6,"i12":6,"i13":6,"i14":6,"i15":6,"i16":6,"i17":6,"i18":6,"i19":6,"i20":6,"i21":6,"i22":6,"i23":6,"i24":6,"i25":6,"i26":6,"i27":6,"i28":6,"i29":6,"i30":6,"i31":38,"i32":38,"i33":6,"i34":38,"i35":6,"i36":6,"i37":6,"i38":6,"i39":6,"i40":6,"i41":6,"i42":6,"i43":38,"i44":6,"i45":6,"i46":6,"i47":6,"i48":6,"i49":6,"i50":6,"i51":38,"i52":6,"i53":6,"i54":6,"i55":6,"i56":6,"i57":6,"i58":6,"i59":6,"i60":38,"i61":6,"i62":38,"i63":38,"i64":6,"i65":38,"i66":6,"i67":6,"i68":6,"i69":6,"i70":6,"i71":38,"i72":38,"i73":38,"i74":6,"i75":6,"i76":6,"i77":6,"i78":6,"i79":6,"i80":38,"i81":6,"i82":6,"i83":6,"i84":38,"i85":6,"i86":6,"i87":6,"i88":6,"i89":6,"i90":6,"i91":6,"i92":6,"i93":6,"i94":6,"i95":6,"i96":6,"i97":38,"i98":6,"i99":6,"i100":38,"i101":6,"i102":6,"i103":6,"i104":6,"i105":6,"i106":6,"i107":6,"i108":6,"i109":6,"i110":6,"i111":6,"i112":6,"i113":6,"i114":6,"i115":6,"i116":6,"i117":6,"i118":6,"i119":6,"i120":6,"i121":6,"i122":38}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -126,7 +126,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    All Known Implementing Classes:
    -
    BasePlayer, CastPlayer, ForwardingPlayer, SimpleExoPlayer, StubExoPlayer
    +
    BasePlayer, CastPlayer, ForwardingPlayer, SimpleExoPlayer, StubExoPlayer, StubPlayer

    public interface Player
    @@ -143,10 +143,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); @@ -311,7 +309,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); static int COMMAND_GET_CURRENT_MEDIA_ITEM -
    Command to get the MediaItem of the current window.
    +
    Command to get the currently playing MediaItem.
    @@ -344,130 +342,180 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); static int +COMMAND_GET_TRACK_INFOS + +
    Command to get track infos.
    + + + +static int COMMAND_GET_VOLUME
    Command to get the player volume.
    - + static int COMMAND_INVALID
    Represents an invalid Player.Command.
    - + static int COMMAND_PLAY_PAUSE
    Command to start, pause or resume playback.
    + +static int +COMMAND_PREPARE + +
    Command to prepare the player.
    + + static int -COMMAND_PREPARE_STOP +COMMAND_SEEK_BACK -
    Command to prepare the player, stop playback or release the player.
    +
    Command to seek back by a fixed increment into the current MediaItem.
    static int -COMMAND_SEEK_BACK +COMMAND_SEEK_FORWARD -
    Command to seek back by a fixed increment into the current window.
    +
    Command to seek forward by a fixed increment into the current MediaItem.
    static int -COMMAND_SEEK_FORWARD +COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM -
    Command to seek forward by a fixed increment into the current window.
    +
    Command to seek anywhere into the current MediaItem.
    static int COMMAND_SEEK_IN_CURRENT_WINDOW -
    Command to seek anywhere into the current window.
    +
    Deprecated. + +
    static int COMMAND_SEEK_TO_DEFAULT_POSITION -
    Command to seek to the default position of the current window.
    +
    Command to seek to the default position of the current MediaItem.
    static int +COMMAND_SEEK_TO_MEDIA_ITEM + +
    Command to seek anywhere in any MediaItem.
    + + + +static int COMMAND_SEEK_TO_NEXT -
    Command to seek to a later position in the current or next window.
    +
    Command to seek to a later position in the current or next MediaItem.
    + + + +static int +COMMAND_SEEK_TO_NEXT_MEDIA_ITEM + +
    Command to seek to the default position of the next MediaItem.
    static int COMMAND_SEEK_TO_NEXT_WINDOW -
    Command to seek to the default position of the next window.
    +
    Deprecated. + +
    static int COMMAND_SEEK_TO_PREVIOUS -
    Command to seek to an earlier position in the current or previous window.
    +
    Command to seek to an earlier position in the current or previous MediaItem.
    static int -COMMAND_SEEK_TO_PREVIOUS_WINDOW +COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM -
    Command to seek to the default position of the previous window.
    +
    Command to seek to the default position of the previous MediaItem.
    static int -COMMAND_SEEK_TO_WINDOW +COMMAND_SEEK_TO_PREVIOUS_WINDOW -
    Command to seek anywhere in any window.
    +
    Deprecated. + +
    static int +COMMAND_SEEK_TO_WINDOW + +
    Deprecated. + +
    + + + +static int COMMAND_SET_DEVICE_VOLUME
    Command to set the device volume and mute it.
    - + static int COMMAND_SET_MEDIA_ITEMS_METADATA
    Command to set the MediaItems metadata.
    - + static int COMMAND_SET_REPEAT_MODE
    Command to set the repeat mode.
    - + static int COMMAND_SET_SHUFFLE_MODE
    Command to enable shuffling.
    - + static int COMMAND_SET_SPEED_AND_PITCH
    Command to set the playback speed and pitch.
    + +static int +COMMAND_SET_TRACK_SELECTION_PARAMETERS + +
    Command to set the player's track selection parameters.
    + + static int COMMAND_SET_VIDEO_SURFACE @@ -484,33 +532,40 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); static int +COMMAND_STOP + +
    Command to stop playback or release the player.
    + + + +static int DISCONTINUITY_REASON_AUTO_TRANSITION
    Automatic playback transition from one period in the timeline to the next.
    - + static int DISCONTINUITY_REASON_INTERNAL
    Discontinuity introduced internally (e.g.
    - + static int DISCONTINUITY_REASON_REMOVE
    Discontinuity caused by the removal of the current period from the Timeline.
    - + static int DISCONTINUITY_REASON_SEEK
    Seek within the current period or to another period.
    - + static int DISCONTINUITY_REASON_SEEK_ADJUSTMENT @@ -518,141 +573,132 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); permitted to be inexact. - + static int DISCONTINUITY_REASON_SKIP
    Discontinuity introduced by a skipped period (for instance a skipped ad).
    - + static int EVENT_AVAILABLE_COMMANDS_CHANGED -
    isCommandAvailable(int) changed for at least one Player.Command.
    +
    isCommandAvailable(int) changed for at least one Player.Command.
    - + static int EVENT_IS_LOADING_CHANGED
    isLoading() ()} changed.
    - + static int EVENT_IS_PLAYING_CHANGED
    isPlaying() changed.
    - + static int EVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED - + static int EVENT_MEDIA_ITEM_TRANSITION
    getCurrentMediaItem() changed or the player started repeating the current item.
    - + static int EVENT_MEDIA_METADATA_CHANGED - + static int EVENT_PLAY_WHEN_READY_CHANGED - + static int EVENT_PLAYBACK_PARAMETERS_CHANGED - + static int EVENT_PLAYBACK_STATE_CHANGED - + static int EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED - + static int EVENT_PLAYER_ERROR - + static int EVENT_PLAYLIST_METADATA_CHANGED - + static int EVENT_POSITION_DISCONTINUITY
    A position discontinuity occurred.
    - + static int EVENT_REPEAT_MODE_CHANGED - + static int EVENT_SEEK_BACK_INCREMENT_CHANGED - + static int EVENT_SEEK_FORWARD_INCREMENT_CHANGED - + static int EVENT_SHUFFLE_MODE_ENABLED_CHANGED - -static int -EVENT_STATIC_METADATA_CHANGED - -
    Deprecated. -
    Use EVENT_MEDIA_METADATA_CHANGED for structured metadata changes.
    -
    - - static int EVENT_TIMELINE_CHANGED @@ -662,110 +708,117 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); static int -EVENT_TRACKS_CHANGED +EVENT_TRACK_SELECTION_PARAMETERS_CHANGED - + static int +EVENT_TRACKS_CHANGED + + + + + +static int MEDIA_ITEM_TRANSITION_REASON_AUTO
    Playback has automatically transitioned to the next media item.
    - + static int MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED
    The current media item has changed because of a change in the playlist.
    - + static int MEDIA_ITEM_TRANSITION_REASON_REPEAT
    The media item has been repeated.
    - + static int MEDIA_ITEM_TRANSITION_REASON_SEEK
    A seek to another media item has occurred.
    - + static int PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY
    Playback has been paused to avoid becoming noisy.
    - + static int PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS
    Playback has been paused because of a loss of audio focus.
    - + static int PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM
    Playback has been paused at the end of a media item.
    - + static int PLAY_WHEN_READY_CHANGE_REASON_REMOTE
    Playback has been started or paused because of a remote change.
    - + static int PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST
    Playback has been started or paused by a call to setPlayWhenReady(boolean).
    - + static int PLAYBACK_SUPPRESSION_REASON_NONE
    Playback is not suppressed.
    - + static int PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS
    Playback is suppressed due to transient audio focus loss.
    - + static int REPEAT_MODE_ALL
    Repeats the entire timeline infinitely.
    - + static int REPEAT_MODE_OFF
    Normal playback without repetition.
    - + static int REPEAT_MODE_ONE -
    Repeats the currently playing window infinitely during ongoing playback.
    +
    Repeats the currently playing MediaItem infinitely during ongoing playback.
    - + static int STATE_BUFFERING @@ -773,35 +826,35 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); so. - + static int STATE_ENDED
    The player has finished playing the media.
    - + static int STATE_IDLE
    The player is idle, and must be prepared before it will play the media.
    - + static int STATE_READY
    The player is able to immediately play from its current position.
    - + static int TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED
    Timeline changed as a result of a change of the playlist items or the order of the items.
    - + static int TIMELINE_CHANGE_REASON_SOURCE_UPDATE @@ -828,21 +881,12 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); void -addListener​(Player.EventListener listener) - -
    Deprecated. - -
    - - - -void addListener​(Player.Listener listener)
    Registers a listener to receive all events from the player.
    - + void addMediaItem​(int index, MediaItem mediaItem) @@ -850,14 +894,14 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Adds a media item at the given index of the playlist.
    - + void addMediaItem​(MediaItem mediaItem)
    Adds a media item to the end of the playlist.
    - + void addMediaItems​(int index, List<MediaItem> mediaItems) @@ -865,13 +909,20 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Adds a list of media items at the given index of the playlist.
    - + void addMediaItems​(List<MediaItem> mediaItems)
    Adds a list of media items to the end of the playlist.
    + +boolean +canAdvertiseSession() + +
    Returns whether the player can be used to advertise a media session.
    + + void clearMediaItems() @@ -949,7 +1000,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); int getBufferedPercentage() -
    Returns an estimate of the percentage in the current content window or ad up to which data is +
    Returns an estimate of the percentage in the current content or ad up to which data is buffered, or 0 if no estimate is available.
    @@ -957,8 +1008,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); long getBufferedPosition() -
    Returns an estimate of the position in the current content window or ad up to which data is - buffered, in milliseconds.
    +
    Returns an estimate of the position in the current content or ad up to which data is buffered, + in milliseconds.
    @@ -966,15 +1017,15 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); getContentBufferedPosition()
    If isPlayingAd() returns true, returns an estimate of the content position in - the current content window up to which data is buffered, in milliseconds.
    + the current content up to which data is buffered, in milliseconds.
    long getContentDuration() -
    If isPlayingAd() returns true, returns the duration of the current content - window in milliseconds, or C.TIME_UNSET if the duration is not known.
    +
    If isPlayingAd() returns true, returns the duration of the current content in + milliseconds, or C.TIME_UNSET if the duration is not known.
    @@ -1012,8 +1063,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); getCurrentLiveOffset()
    Returns the offset of the current playback position from the live edge in milliseconds, or - C.TIME_UNSET if the current window isn't live or the - offset is unknown.
    + C.TIME_UNSET if the current MediaItem isCurrentMediaItemLive() isn't + live} or the offset is unknown. @@ -1027,34 +1078,30 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); MediaItem getCurrentMediaItem() -
    Returns the media item of the current window in the timeline.
    +
    Returns the currently playing MediaItem.
    int +getCurrentMediaItemIndex() + +
    Returns the index of the current MediaItem in the timeline, or the prospective index if the current timeline is + empty.
    + + + +int getCurrentPeriodIndex()
    Returns the index of the period currently being played.
    - + long getCurrentPosition() -
    Returns the playback position in the current content window or ad, in milliseconds, or the - prospective position in milliseconds if the current timeline is - empty.
    - - - -List<Metadata> -getCurrentStaticMetadata() - -
    Deprecated. -
    Use getMediaMetadata() and Player.Listener.onMediaMetadataChanged(MediaMetadata) for access to structured metadata, or - access the raw static metadata directly from the track - selections' formats.
    -
    +
    Returns the playback position in the current content or ad, in milliseconds, or the prospective + position in milliseconds if the current timeline is empty.
    @@ -1068,67 +1115,80 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); TrackGroupArray getCurrentTrackGroups() -
    Returns the available track groups.
    +
    Deprecated. + +
    TrackSelectionArray getCurrentTrackSelections() -
    Returns the current track selections.
    +
    Deprecated. + +
    -int -getCurrentWindowIndex() +TracksInfo +getCurrentTracksInfo() -
    Returns the index of the current window in the timeline, or the prospective window index if the current timeline is empty.
    +
    Returns the available tracks, as well as the tracks' support, type, and selection status.
    -DeviceInfo +int +getCurrentWindowIndex() + +
    Deprecated. + +
    + + + +DeviceInfo getDeviceInfo()
    Gets the device information.
    - + int getDeviceVolume()
    Gets the current volume of the device.
    - + long getDuration() -
    Returns the duration of the current content window or ad in milliseconds, or C.TIME_UNSET if the duration is not known.
    - - - -int -getMaxSeekToPreviousPosition() - -
    Returns the maximum position for which seekToPrevious() seeks to the previous window, - in milliseconds.
    +
    Returns the duration of the current content or ad in milliseconds, or C.TIME_UNSET if + the duration is not known.
    +long +getMaxSeekToPreviousPosition() + +
    Returns the maximum position for which seekToPrevious() seeks to the previous MediaItem, in milliseconds.
    + + + MediaItem getMediaItemAt​(int index)
    Returns the MediaItem at the given index.
    - + int getMediaItemCount()
    Returns the number of media items in the playlist.
    - + MediaMetadata getMediaMetadata() @@ -1136,214 +1196,284 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); supported. - + +int +getNextMediaItemIndex() + +
    Returns the index of the MediaItem that will be played if seekToNextMediaItem() is called, which may depend on the current repeat mode and whether + shuffle mode is enabled.
    + + + int getNextWindowIndex() -
    Returns the index of the window that will be played if seekToNextWindow() is called, - which may depend on the current repeat mode and whether shuffle mode is enabled.
    +
    Deprecated. + +
    - + PlaybackParameters getPlaybackParameters()
    Returns the currently active playback parameters.
    - -int + +@com.google.android.exoplayer2.Player.State int getPlaybackState()
    Returns the current playback state of the player.
    - -int + +@com.google.android.exoplayer2.Player.PlaybackSuppressionReason int getPlaybackSuppressionReason()
    Returns the reason why playback is suppressed even though getPlayWhenReady() is true, or PLAYBACK_SUPPRESSION_REASON_NONE if playback is not suppressed.
    - + PlaybackException getPlayerError()
    Returns the error that caused playback to fail.
    - + MediaMetadata getPlaylistMetadata()
    Returns the playlist MediaMetadata, as set by setPlaylistMetadata(MediaMetadata), or MediaMetadata.EMPTY if not supported.
    - + boolean getPlayWhenReady()
    Whether playback will proceed when getPlaybackState() == STATE_READY.
    - + +int +getPreviousMediaItemIndex() + +
    Returns the index of the MediaItem that will be played if seekToPreviousMediaItem() is called, which may depend on the current repeat mode and whether + shuffle mode is enabled.
    + + + int getPreviousWindowIndex() -
    Returns the index of the window that will be played if seekToPreviousWindow() is - called, which may depend on the current repeat mode and whether shuffle mode is enabled.
    +
    Deprecated. + +
    - -int + +@com.google.android.exoplayer2.Player.RepeatMode int getRepeatMode()
    Returns the current Player.RepeatMode used for playback.
    - + long getSeekBackIncrement()
    Returns the seekBack() increment.
    - + long getSeekForwardIncrement()
    Returns the seekForward() increment.
    - + boolean getShuffleModeEnabled() -
    Returns whether shuffling of windows is enabled.
    +
    Returns whether shuffling of media items is enabled.
    - + long getTotalBufferedDuration()
    Returns an estimate of the total buffered duration from the current position, in milliseconds.
    - + +TrackSelectionParameters +getTrackSelectionParameters() + +
    Returns the parameters constraining the track selection.
    + + + VideoSize getVideoSize()
    Gets the size of the video.
    - + float getVolume()
    Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
    - + boolean hasNext()
    Deprecated. -
    Use hasNextWindow() instead.
    +
    Use hasNextMediaItem() instead.
    - + +boolean +hasNextMediaItem() + +
    Returns whether a next MediaItem exists, which may depend on the current repeat mode + and whether shuffle mode is enabled.
    + + + boolean hasNextWindow() -
    Returns whether a next window exists, which may depend on the current repeat mode and whether - shuffle mode is enabled.
    +
    Deprecated. +
    Use hasNextMediaItem() instead.
    +
    - + boolean hasPrevious()
    Deprecated. -
    Use hasPreviousWindow() instead.
    +
    - + boolean -hasPreviousWindow() +hasPreviousMediaItem() -
    Returns whether a previous window exists, which may depend on the current repeat mode and +
    Returns whether a previous media item exists, which may depend on the current repeat mode and whether shuffle mode is enabled.
    - + +boolean +hasPreviousWindow() + +
    Deprecated. + +
    + + + void increaseDeviceVolume()
    Increases the volume of the device.
    - + boolean -isCommandAvailable​(int command) +isCommandAvailable​(@com.google.android.exoplayer2.Player.Command int command)
    Returns whether the provided Player.Command is available.
    - + +boolean +isCurrentMediaItemDynamic() + +
    Returns whether the current MediaItem is dynamic (may change when the Timeline + is updated), or false if the Timeline is empty.
    + + + +boolean +isCurrentMediaItemLive() + +
    Returns whether the current MediaItem is live, or false if the Timeline + is empty.
    + + + +boolean +isCurrentMediaItemSeekable() + +
    Returns whether the current MediaItem is seekable, or false if the Timeline is empty.
    + + + boolean isCurrentWindowDynamic() -
    Returns whether the current window is dynamic, or false if the Timeline is - empty.
    +
    Deprecated. + +
    - + boolean isCurrentWindowLive() -
    Returns whether the current window is live, or false if the Timeline is empty.
    +
    Deprecated. + +
    - + boolean isCurrentWindowSeekable() -
    Returns whether the current window is seekable, or false if the Timeline is - empty.
    +
    Deprecated. + +
    - + boolean isDeviceMuted()
    Gets whether the device is muted or not.
    - + boolean isLoading()
    Whether the player is currently loading the source.
    - + boolean isPlaying()
    Returns whether the player is playing, i.e.
    - + boolean isPlayingAd()
    Returns whether the player is currently playing an ad.
    - + void moveMediaItem​(int currentIndex, int newIndex) @@ -1351,7 +1481,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Moves the media item at the current index to the new index.
    - + void moveMediaItems​(int fromIndex, int toIndex, @@ -1360,76 +1490,67 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Moves the media item range to the new index.
    - + void next()
    Deprecated. -
    Use seekToNextWindow() instead.
    +
    - + void pause()
    Pauses playback.
    - + void play()
    Resumes playback as soon as getPlaybackState() == STATE_READY.
    - + void prepare()
    Prepares the player.
    - + void previous()
    Deprecated. - +
    - + void release()
    Releases the player.
    - -void -removeListener​(Player.EventListener listener) - -
    Deprecated. - -
    - - - + void removeListener​(Player.Listener listener)
    Unregister a listener registered through addListener(Listener).
    - + void removeMediaItem​(int index)
    Removes the media item at the given index of the playlist.
    - + void removeMediaItems​(int fromIndex, int toIndex) @@ -1437,94 +1558,113 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Removes a range of media items from the playlist.
    - + void seekBack() -
    Seeks back in the current window by getSeekBackIncrement() milliseconds.
    - - - -void -seekForward() - -
    Seeks forward in the current window by getSeekForwardIncrement() milliseconds.
    - - - -void -seekTo​(int windowIndex, - long positionMs) - -
    Seeks to a position specified in milliseconds in the specified window.
    - - - -void -seekTo​(long positionMs) - -
    Seeks to a position specified in milliseconds in the current window.
    - - - -void -seekToDefaultPosition() - -
    Seeks to the default position associated with the current window.
    - - - -void -seekToDefaultPosition​(int windowIndex) - -
    Seeks to the default position associated with the specified window.
    - - - -void -seekToNext() - -
    Seeks to a later position in the current or next window (if available).
    - - - -void -seekToNextWindow() - -
    Seeks to the default position of the next window, which may depend on the current repeat mode - and whether shuffle mode is enabled.
    - - - -void -seekToPrevious() - -
    Seeks to an earlier position in the current or previous window (if available).
    +
    Seeks back in the current MediaItem by getSeekBackIncrement() milliseconds.
    void -seekToPreviousWindow() +seekForward() -
    Seeks to the default position of the previous window, which may depend on the current repeat - mode and whether shuffle mode is enabled.
    +
    Seeks forward in the current MediaItem by getSeekForwardIncrement() + milliseconds.
    void +seekTo​(int mediaItemIndex, + long positionMs) + +
    Seeks to a position specified in milliseconds in the specified MediaItem.
    + + + +void +seekTo​(long positionMs) + +
    Seeks to a position specified in milliseconds in the current MediaItem.
    + + + +void +seekToDefaultPosition() + +
    Seeks to the default position associated with the current MediaItem.
    + + + +void +seekToDefaultPosition​(int mediaItemIndex) + +
    Seeks to the default position associated with the specified MediaItem.
    + + + +void +seekToNext() + +
    Seeks to a later position in the current or next MediaItem (if available).
    + + + +void +seekToNextMediaItem() + +
    Seeks to the default position of the next MediaItem, which may depend on the current + repeat mode and whether shuffle mode is enabled.
    + + + +void +seekToNextWindow() + +
    Deprecated. + +
    + + + +void +seekToPrevious() + +
    Seeks to an earlier position in the current or previous MediaItem (if available).
    + + + +void +seekToPreviousMediaItem() + +
    Seeks to the default position of the previous MediaItem, which may depend on the + current repeat mode and whether shuffle mode is enabled.
    + + + +void +seekToPreviousWindow() + +
    Deprecated. + +
    + + + +void setDeviceMuted​(boolean muted)
    Sets the mute state of the device.
    - + void setDeviceVolume​(int volume)
    Sets the volume of the device.
    - + void setMediaItem​(MediaItem mediaItem) @@ -1532,7 +1672,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); default position.
    - + void setMediaItem​(MediaItem mediaItem, boolean resetPosition) @@ -1540,7 +1680,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Clears the playlist and adds the specified MediaItem.
    - + void setMediaItem​(MediaItem mediaItem, long startPositionMs) @@ -1548,7 +1688,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Clears the playlist and adds the specified MediaItem.
    - + void setMediaItems​(List<MediaItem> mediaItems) @@ -1556,7 +1696,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); the default position. - + void setMediaItems​(List<MediaItem> mediaItems, boolean resetPosition) @@ -1564,65 +1704,72 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Clears the playlist and adds the specified MediaItems.
    - + void setMediaItems​(List<MediaItem> mediaItems, - int startWindowIndex, + int startIndex, long startPositionMs)
    Clears the playlist and adds the specified MediaItems.
    - + void setPlaybackParameters​(PlaybackParameters playbackParameters)
    Attempts to set the playback parameters.
    - + void setPlaybackSpeed​(float speed)
    Changes the rate at which playback occurs.
    - + void setPlaylistMetadata​(MediaMetadata mediaMetadata)
    Sets the playlist MediaMetadata.
    - + void setPlayWhenReady​(boolean playWhenReady)
    Sets whether playback should proceed when getPlaybackState() == STATE_READY.
    - + void -setRepeatMode​(int repeatMode) +setRepeatMode​(@com.google.android.exoplayer2.Player.RepeatMode int repeatMode)
    Sets the Player.RepeatMode to be used for playback.
    - + void setShuffleModeEnabled​(boolean shuffleModeEnabled) -
    Sets whether shuffling of windows is enabled.
    +
    Sets whether shuffling of media items is enabled.
    - + +void +setTrackSelectionParameters​(TrackSelectionParameters parameters) + +
    Sets the parameters constraining the track selection.
    + + + void setVideoSurface​(Surface surface)
    Sets the Surface onto which video will be rendered.
    - + void setVideoSurfaceHolder​(SurfaceHolder surfaceHolder) @@ -1630,35 +1777,36 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); rendered. - + void setVideoSurfaceView​(SurfaceView surfaceView)
    Sets the SurfaceView onto which video will be rendered.
    - + void setVideoTextureView​(TextureView textureView)
    Sets the TextureView onto which video will be rendered.
    - + void -setVolume​(float audioVolume) +setVolume​(float volume) -
    Sets the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
    +
    Sets the audio volume, valid values are between 0 (silence) and 1 (unity gain, signal + unchanged), inclusive.
    - + void stop()
    Stops playback without resetting the player.
    - + void stop​(boolean reset) @@ -1850,7 +1998,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

    REPEAT_MODE_OFF

    static final int REPEAT_MODE_OFF
    Normal playback without repetition. "Previous" and "Next" actions move to the previous and next - windows respectively, and do nothing when there is no previous or next window to move to.
    + MediaItem respectively, and do nothing when there is no previous or next MediaItem to move to.
    See Also:
    Constant Field Values
    @@ -1864,9 +2012,9 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • REPEAT_MODE_ONE

    static final int REPEAT_MODE_ONE
    -
    Repeats the currently playing window infinitely during ongoing playback. "Previous" and "Next" - actions behave as they do in REPEAT_MODE_OFF, moving to the previous and next windows - respectively, and doing nothing when there is no previous or next window to move to.
    +
    Repeats the currently playing MediaItem infinitely during ongoing playback. "Previous" + and "Next" actions behave as they do in REPEAT_MODE_OFF, moving to the previous and + next MediaItem respectively, and doing nothing when there is no previous or next MediaItem to move to.
    See Also:
    Constant Field Values
    @@ -1882,8 +2030,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    static final int REPEAT_MODE_ALL
    Repeats the entire timeline infinitely. "Previous" and "Next" actions behave as they do in REPEAT_MODE_OFF, but with looping at the ends so that "Previous" when playing the - first window will move to the last window, and "Next" when playing the last window will move to - the first window.
    + first MediaItem will move to the last MediaItem, and "Next" when playing the + last MediaItem will move to the first MediaItem.
    See Also:
    Constant Field Values
    @@ -2108,30 +2256,13 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • EVENT_TRACKS_CHANGED

    static final int EVENT_TRACKS_CHANGED
    - +
    See Also:
    Constant Field Values
  • - - - - @@ -2251,7 +2382,7 @@ static final int EVENT_STATIC_METADATA_CHANGED
  • EVENT_POSITION_DISCONTINUITY

    static final int EVENT_POSITION_DISCONTINUITY
    -
    A position discontinuity occurred. See Player.Listener.onPositionDiscontinuity(PositionInfo, +
    See Also:
    @@ -2280,7 +2411,7 @@ static final int EVENT_STATIC_METADATA_CHANGED
  • EVENT_AVAILABLE_COMMANDS_CHANGED

    static final int EVENT_AVAILABLE_COMMANDS_CHANGED
    -
    isCommandAvailable(int) changed for at least one Player.Command.
    +
    isCommandAvailable(int) changed for at least one Player.Command.
    See Also:
    Constant Field Values
    @@ -2357,6 +2488,20 @@ static final int EVENT_STATIC_METADATA_CHANGED
  • + + + + @@ -2371,17 +2516,31 @@ static final int EVENT_STATIC_METADATA_CHANGED
  • - +
    • -

      COMMAND_PREPARE_STOP

      -
      static final int COMMAND_PREPARE_STOP
      -
      Command to prepare the player, stop playback or release the player.
      +

      COMMAND_PREPARE

      +
      static final int COMMAND_PREPARE
      +
      Command to prepare the player.
      See Also:
      -
      Constant Field Values
      +
      Constant Field Values
      +
      +
    • +
    + + + +
      +
    • +

      COMMAND_STOP

      +
      static final int COMMAND_STOP
      +
      Command to stop playback or release the player.
      +
      +
      See Also:
      +
      Constant Field Values
    @@ -2392,35 +2551,69 @@ static final int EVENT_STATIC_METADATA_CHANGED
  • COMMAND_SEEK_TO_DEFAULT_POSITION

    static final int COMMAND_SEEK_TO_DEFAULT_POSITION
    -
    Command to seek to the default position of the current window.
    +
    Command to seek to the default position of the current MediaItem.
    See Also:
    Constant Field Values
  • + + + +
      +
    • +

      COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM

      +
      static final int COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM
      +
      Command to seek anywhere into the current MediaItem.
      +
      +
      See Also:
      +
      Constant Field Values
      +
      +
    • +
    + + + +
      +
    • +

      COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM

      +
      static final int COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM
      +
      Command to seek to the default position of the previous MediaItem.
      +
      +
      See Also:
      +
      Constant Field Values
      +
      +
    • +
    • COMMAND_SEEK_TO_PREVIOUS_WINDOW

      -
      static final int COMMAND_SEEK_TO_PREVIOUS_WINDOW
      -
      Command to seek to the default position of the previous window.
      +
      @Deprecated
      +static final int COMMAND_SEEK_TO_PREVIOUS_WINDOW
      +
      Deprecated. + +
      See Also:
      Constant Field Values
      @@ -2434,21 +2627,38 @@ static final int EVENT_STATIC_METADATA_CHANGED
    • COMMAND_SEEK_TO_PREVIOUS

      static final int COMMAND_SEEK_TO_PREVIOUS
      -
      Command to seek to an earlier position in the current or previous window.
      +
      Command to seek to an earlier position in the current or previous MediaItem.
      See Also:
      Constant Field Values
    + + + +
      +
    • +

      COMMAND_SEEK_TO_NEXT_MEDIA_ITEM

      +
      static final int COMMAND_SEEK_TO_NEXT_MEDIA_ITEM
      +
      Command to seek to the default position of the next MediaItem.
      +
      +
      See Also:
      +
      Constant Field Values
      +
      +
    • +
    • COMMAND_SEEK_TO_NEXT_WINDOW

      -
      static final int COMMAND_SEEK_TO_NEXT_WINDOW
      -
      Command to seek to the default position of the next window.
      +
      @Deprecated
      +static final int COMMAND_SEEK_TO_NEXT_WINDOW
      +
      Deprecated. + +
      See Also:
      Constant Field Values
      @@ -2462,21 +2672,38 @@ static final int EVENT_STATIC_METADATA_CHANGED
    • COMMAND_SEEK_TO_NEXT

      static final int COMMAND_SEEK_TO_NEXT
      -
      Command to seek to a later position in the current or next window.
      +
      Command to seek to a later position in the current or next MediaItem.
      See Also:
      Constant Field Values
    + + + +
      +
    • +

      COMMAND_SEEK_TO_MEDIA_ITEM

      +
      static final int COMMAND_SEEK_TO_MEDIA_ITEM
      +
      Command to seek anywhere in any MediaItem.
      +
      +
      See Also:
      +
      Constant Field Values
      +
      +
    • +
    • COMMAND_SEEK_TO_WINDOW

      -
      static final int COMMAND_SEEK_TO_WINDOW
      -
      Command to seek anywhere in any window.
      +
      @Deprecated
      +static final int COMMAND_SEEK_TO_WINDOW
      +
      Deprecated. + +
      See Also:
      Constant Field Values
      @@ -2490,7 +2717,7 @@ static final int EVENT_STATIC_METADATA_CHANGED
    • COMMAND_SEEK_BACK

      static final int COMMAND_SEEK_BACK
      -
      Command to seek back by a fixed increment into the current window.
      +
      Command to seek back by a fixed increment into the current MediaItem.
      See Also:
      Constant Field Values
      @@ -2504,7 +2731,7 @@ static final int EVENT_STATIC_METADATA_CHANGED
    • COMMAND_SEEK_FORWARD

      static final int COMMAND_SEEK_FORWARD
      -
      Command to seek forward by a fixed increment into the current window.
      +
      Command to seek forward by a fixed increment into the current MediaItem.
      See Also:
      Constant Field Values
      @@ -2560,7 +2787,7 @@ static final int EVENT_STATIC_METADATA_CHANGED
    • COMMAND_GET_CURRENT_MEDIA_ITEM

      static final int COMMAND_GET_CURRENT_MEDIA_ITEM
      -
      Command to get the MediaItem of the current window.
      +
      Command to get the currently playing MediaItem.
      See Also:
      Constant Field Values
      @@ -2735,6 +2962,34 @@ static final int EVENT_STATIC_METADATA_CHANGED
    + + + +
      +
    • +

      COMMAND_SET_TRACK_SELECTION_PARAMETERS

      +
      static final int COMMAND_SET_TRACK_SELECTION_PARAMETERS
      +
      Command to set the player's track selection parameters.
      +
      +
      See Also:
      +
      Constant Field Values
      +
      +
    • +
    + + + +
      +
    • +

      COMMAND_GET_TRACK_INFOS

      +
      static final int COMMAND_GET_TRACK_INFOS
      +
      Command to get track infos.
      +
      +
      See Also:
      +
      Constant Field Values
      +
      +
    • +
    @@ -2770,28 +3025,6 @@ static final int EVENT_STATIC_METADATA_CHANGED player and on which player events are received.
  • - - - -
      -
    • -

      addListener

      -
      @Deprecated
      -void addListener​(Player.EventListener listener)
      -
      Deprecated. - -
      -
      Registers a listener to receive events from the player. - -

      The listener's methods will be called on the thread that was used to construct the player. - However, if the thread used to construct the player does not have a Looper, then the - listener will be called on the main thread.

      -
      -
      Parameters:
      -
      listener - The listener to register.
      -
      -
    • -
    @@ -2801,34 +3034,13 @@ void addListener​(void addListener​(Player.Listener listener)
    Registers a listener to receive all events from the player. -

    The listener's methods will be called on the thread that was used to construct the player. - However, if the thread used to construct the player does not have a Looper, then the - listener will be called on the main thread.

    +

    The listener's methods will be called on the thread associated with getApplicationLooper().

    Parameters:
    listener - The listener to register.
    - - - - @@ -2873,7 +3085,7 @@ void removeListener​(MediaItems.
    resetPosition - Whether the playback position should be reset to the default position in the first Timeline.Window. If false, playback will start from the position defined - by getCurrentWindowIndex() and getCurrentPosition().
    + by getCurrentMediaItemIndex() and getCurrentPosition().
    @@ -2884,19 +3096,19 @@ void removeListener​(

    setMediaItems

    void setMediaItems​(List<MediaItem> mediaItems,
    -                   int startWindowIndex,
    +                   int startIndex,
                        long startPositionMs)
    Clears the playlist and adds the specified MediaItems.
    Parameters:
    mediaItems - The new MediaItems.
    -
    startWindowIndex - The window index to start playback from. If C.INDEX_UNSET is - passed, the current position is not reset.
    -
    startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given window is used. In any case, if - startWindowIndex is set to C.INDEX_UNSET, this parameter is ignored and the - position is not reset at all.
    +
    startIndex - The MediaItem index to start playback from. If C.INDEX_UNSET + is passed, the current position is not reset.
    +
    startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given MediaItem is used. In + any case, if startIndex is set to C.INDEX_UNSET, this parameter is ignored + and the position is not reset at all.
    Throws:
    -
    IllegalSeekPositionException - If the provided startWindowIndex is not within the +
    IllegalSeekPositionException - If the provided startIndex is not within the bounds of the list of media items.
    @@ -2945,7 +3157,7 @@ void removeListener​(Parameters:
    mediaItem - The new MediaItem.
    resetPosition - Whether the playback position should be reset to the default position. If - false, playback will start from the position defined by getCurrentWindowIndex() + false, playback will start from the position defined by getCurrentMediaItemIndex() and getCurrentPosition().
    @@ -3090,24 +3302,23 @@ void removeListener​(Clears the playlist. - + @@ -3178,14 +3398,14 @@ int getPlaybackState()
  • getPlaybackSuppressionReason

    @PlaybackSuppressionReason
    -int getPlaybackSuppressionReason()
    +@com.google.android.exoplayer2.Player.PlaybackSuppressionReason int getPlaybackSuppressionReason()
    Returns the reason why playback is suppressed even though getPlayWhenReady() is true, or PLAYBACK_SUPPRESSION_REASON_NONE if playback is not suppressed.
    Returns:
    The current playback suppression reason.
    See Also:
    -
    Player.Listener.onPlaybackSuppressionReasonChanged(int)
    +
    Player.Listener.onPlaybackSuppressionReasonChanged(int)
  • @@ -3284,18 +3504,18 @@ int getPlaybackSuppressionReason()
    Returns:
    Whether playback will proceed when ready.
    See Also:
    -
    Player.Listener.onPlayWhenReadyChanged(boolean, int)
    +
    Player.Listener.onPlayWhenReadyChanged(boolean, int)
    - + @@ -3327,7 +3547,7 @@ int getRepeatMode()
  • setShuffleModeEnabled

    void setShuffleModeEnabled​(boolean shuffleModeEnabled)
    -
    Sets whether shuffling of windows is enabled.
    +
    Sets whether shuffling of media items is enabled.
    Parameters:
    shuffleModeEnabled - Whether shuffling is enabled.
    @@ -3341,7 +3561,7 @@ int getRepeatMode()
  • getShuffleModeEnabled

    boolean getShuffleModeEnabled()
    -
    Returns whether shuffling of windows is enabled.
    +
    Returns whether shuffling of media items is enabled.
    See Also:
    Player.Listener.onShuffleModeEnabledChanged(boolean)
    @@ -3371,9 +3591,9 @@ int getRepeatMode()
  • seekToDefaultPosition

    void seekToDefaultPosition()
    -
    Seeks to the default position associated with the current window. The position can depend on - the type of media being played. For live streams it will typically be the live edge of the - window. For other streams it will typically be the start of the window.
    +
    Seeks to the default position associated with the current MediaItem. The position can + depend on the type of media being played. For live streams it will typically be the live edge. + For other streams it will typically be the start.
  • @@ -3382,17 +3602,17 @@ int getRepeatMode() @@ -3403,11 +3623,11 @@ int getRepeatMode()
  • seekTo

    void seekTo​(long positionMs)
    -
    Seeks to a position specified in milliseconds in the current window.
    +
    Seeks to a position specified in milliseconds in the current MediaItem.
    Parameters:
    -
    positionMs - The seek position in the current window, or C.TIME_UNSET to seek to - the window's default position.
    +
    positionMs - The seek position in the current MediaItem, or C.TIME_UNSET + to seek to the media item's default position.
  • @@ -3417,17 +3637,17 @@ int getRepeatMode()
    • seekTo

      -
      void seekTo​(int windowIndex,
      +
      void seekTo​(int mediaItemIndex,
                   long positionMs)
      -
      Seeks to a position specified in milliseconds in the specified window.
      +
      Seeks to a position specified in milliseconds in the specified MediaItem.
      Parameters:
      -
      windowIndex - The index of the window.
      -
      positionMs - The seek position in the specified window, or C.TIME_UNSET to seek to - the window's default position.
      +
      mediaItemIndex - The index of the MediaItem.
      +
      positionMs - The seek position in the specified MediaItem, or C.TIME_UNSET + to seek to the media item's default position.
      Throws:
      IllegalSeekPositionException - If the player has a non-empty timeline and the provided - windowIndex is not within the bounds of the current timeline.
      + mediaItemIndex is not within the bounds of the current timeline.
    @@ -3454,7 +3674,7 @@ int getRepeatMode()
  • seekBack

    void seekBack()
    -
    Seeks back in the current window by getSeekBackIncrement() milliseconds.
    +
    Seeks back in the current MediaItem by getSeekBackIncrement() milliseconds.
  • @@ -3480,7 +3700,8 @@ int getRepeatMode()
  • seekForward

    void seekForward()
    -
    +
    Seeks forward in the current MediaItem by getSeekForwardIncrement() + milliseconds.
  • @@ -3492,7 +3713,7 @@ int getRepeatMode()
    @Deprecated
     boolean hasPrevious()
    Deprecated. -
    Use hasPreviousWindow() instead.
    +
  • @@ -3502,8 +3723,21 @@ boolean hasPrevious()
    • hasPreviousWindow

      -
      boolean hasPreviousWindow()
      -
      Returns whether a previous window exists, which may depend on the current repeat mode and +
      @Deprecated
      +boolean hasPreviousWindow()
      +
      Deprecated. + +
      +
    • +
    + + + +
      +
    • +

      hasPreviousMediaItem

      +
      boolean hasPreviousMediaItem()
      +
      Returns whether a previous media item exists, which may depend on the current repeat mode and whether shuffle mode is enabled.

      Note: When the repeat mode is REPEAT_MODE_ONE, this method behaves the same as when @@ -3520,7 +3754,7 @@ boolean hasPrevious()

      @Deprecated
       void previous()
      Deprecated. - +
    @@ -3530,10 +3764,22 @@ void previous()
    • seekToPreviousWindow

      -
      void seekToPreviousWindow()
      -
      Seeks to the default position of the previous window, which may depend on the current repeat - mode and whether shuffle mode is enabled. Does nothing if hasPreviousWindow() is - false. +
      @Deprecated
      +void seekToPreviousWindow()
      +
      Deprecated. + +
      +
    • +
    + + + + @@ -3588,7 +3835,7 @@ void previous()
    @Deprecated
     boolean hasNext()
    Deprecated. -
    Use hasNextWindow() instead.
    +
    Use hasNextMediaItem() instead.
  • @@ -3598,9 +3845,22 @@ boolean hasNext()
    • hasNextWindow

      -
      boolean hasNextWindow()
      -
      Returns whether a next window exists, which may depend on the current repeat mode and whether - shuffle mode is enabled. +
      @Deprecated
      +boolean hasNextWindow()
      +
      Deprecated. +
      Use hasNextMediaItem() instead.
      +
      +
    • +
    + + + + @@ -3626,9 +3886,23 @@ void next()
    • seekToNextWindow

      -
      void seekToNextWindow()
      -
      Seeks to the default position of the next window, which may depend on the current repeat mode - and whether shuffle mode is enabled. Does nothing if hasNextWindow() is false. +
      @Deprecated
      +void seekToNextWindow()
      +
      Deprecated. + +
      +
    • +
    + + + + @@ -3871,8 +4193,22 @@ void stop​(boolean reset) + + + +
      +
    • +

      getCurrentMediaItemIndex

      +
      int getCurrentMediaItemIndex()
      +
      Returns the index of the current MediaItem in the timeline, or the prospective index if the current timeline is + empty.
    @@ -3881,9 +4217,23 @@ void stop​(boolean reset) + + + + @@ -3959,9 +4322,8 @@ void stop​(boolean reset)
  • getCurrentPosition

    long getCurrentPosition()
    -
    +
    Returns the playback position in the current content or ad, in milliseconds, or the prospective + position in milliseconds if the current timeline is empty.
  • @@ -3971,8 +4333,8 @@ void stop​(boolean reset)
  • getBufferedPosition

    long getBufferedPosition()
    -
    Returns an estimate of the position in the current content window or ad up to which data is - buffered, in milliseconds.
    +
    Returns an estimate of the position in the current content or ad up to which data is buffered, + in milliseconds.
  • @@ -3981,8 +4343,10 @@ void stop​(boolean reset)
    • getBufferedPercentage

      -
      int getBufferedPercentage()
      -
      Returns an estimate of the percentage in the current content window or ad up to which data is +
      @IntRange(from=0L,
      +          to=100L)
      +int getBufferedPercentage()
      +
      Returns an estimate of the percentage in the current content or ad up to which data is buffered, or 0 if no estimate is available.
    @@ -3994,7 +4358,7 @@ void stop​(boolean reset)

    getTotalBufferedDuration

    long getTotalBufferedDuration()
    Returns an estimate of the total buffered duration from the current position, in milliseconds. - This includes pre-buffered data for subsequent ads and windows.
    + This includes pre-buffered data for subsequent ads and
    media items. @@ -4003,9 +4367,22 @@ void stop​(boolean reset) + + + + @@ -155,7 +155,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); TextOutput textRendererOutput, MetadataOutput metadataRendererOutput) -
    Builds the Renderer instances for a SimpleExoPlayer.
    +
    Builds the Renderer instances for an ExoPlayer.
    @@ -186,7 +186,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); AudioRendererEventListener audioRendererEventListener, TextOutput textRendererOutput, MetadataOutput metadataRendererOutput) -
    Builds the Renderer instances for a SimpleExoPlayer.
    +
    Builds the Renderer instances for an ExoPlayer.
    Parameters:
    eventHandler - A handler to use when invoking event listeners and outputs.
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/SimpleExoPlayer.Builder.html b/docs/doc/reference/com/google/android/exoplayer2/SimpleExoPlayer.Builder.html index cb8e403feb..3b18bc8635 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/SimpleExoPlayer.Builder.html +++ b/docs/doc/reference/com/google/android/exoplayer2/SimpleExoPlayer.Builder.html @@ -25,8 +25,8 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10}; -var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; +var data = {"i0":42,"i1":42,"i2":42,"i3":42,"i4":42,"i5":42,"i6":42,"i7":42,"i8":42,"i9":42,"i10":42,"i11":42,"i12":42,"i13":42,"i14":42,"i15":42,"i16":42,"i17":42,"i18":42,"i19":42,"i20":42,"i21":42,"i22":42,"i23":42}; +var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; var tableTab = "tableTab"; @@ -133,11 +133,12 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    SimpleExoPlayer

    -
    public static final class SimpleExoPlayer.Builder
    +
    @Deprecated
    +public static final class SimpleExoPlayer.Builder
     extends Object
    -
    A builder for SimpleExoPlayer instances. - -

    See Builder(Context) for the list of default values.

    +
    Deprecated. +
    Use ExoPlayer.Builder instead.
    +
    @@ -160,21 +161,27 @@ extends Builder​(Context context) -
    Creates a builder.
    +
    Deprecated. +
    Use Builder(Context) instead.
    +
    Builder​(Context context, ExtractorsFactory extractorsFactory) -
    Creates a builder with a custom ExtractorsFactory.
    + Builder​(Context context, RenderersFactory renderersFactory) -
    Creates a builder with a custom RenderersFactory.
    +
    Deprecated. + +
    @@ -182,7 +189,10 @@ extends RenderersFactory renderersFactory, ExtractorsFactory extractorsFactory)
    -
    Creates a builder with a custom RenderersFactory and ExtractorsFactory.
    + @@ -194,7 +204,11 @@ extends BandwidthMeter bandwidthMeter, AnalyticsCollector analyticsCollector) -
    Creates a builder with the specified custom components.
    + @@ -209,7 +223,7 @@ extends

    Method Summary

    - + @@ -219,21 +233,28 @@ extends SimpleExoPlayer @@ -241,144 +262,191 @@ extends setAudioAttributes​(AudioAttributes audioAttributes, boolean handleAudioFocus) - + - + + + + + +
    All Methods Instance Methods Concrete Methods All Methods Instance Methods Concrete Methods Deprecated Methods 
    Modifier and Type Method build() -
    Builds a SimpleExoPlayer instance.
    +
    Deprecated. + +
    SimpleExoPlayer.Builder experimentalSetForegroundModeTimeoutMs​(long timeoutMs) -
    Set a limit on the time a call to SimpleExoPlayer.setForegroundMode(boolean) can spend.
    +
    SimpleExoPlayer.Builder setAnalyticsCollector​(AnalyticsCollector analyticsCollector) -
    Sets the AnalyticsCollector that will collect and forward all player events.
    +
    -
    Sets AudioAttributes that will be used by the player and whether to handle audio - focus.
    +
    SimpleExoPlayer.Builder setBandwidthMeter​(BandwidthMeter bandwidthMeter) -
    Sets the BandwidthMeter that will be used by the player.
    +
    SimpleExoPlayer.Builder setClock​(Clock clock) -
    Sets the Clock that will be used by the player.
    +
    Deprecated. + +
    SimpleExoPlayer.Builder setDetachSurfaceTimeoutMs​(long detachSurfaceTimeoutMs) -
    Sets a timeout for detaching a surface from the player.
    +
    SimpleExoPlayer.Builder setHandleAudioBecomingNoisy​(boolean handleAudioBecomingNoisy) -
    Sets whether the player should pause automatically when audio is rerouted from a headset to - device speakers.
    +
    SimpleExoPlayer.Builder setLivePlaybackSpeedControl​(LivePlaybackSpeedControl livePlaybackSpeedControl) -
    Sets the LivePlaybackSpeedControl that will control the playback speed when playing - live streams, in order to maintain a steady target offset from the live stream edge.
    +
    SimpleExoPlayer.Builder setLoadControl​(LoadControl loadControl) -
    Sets the LoadControl that will be used by the player.
    +
    SimpleExoPlayer.Builder setLooper​(Looper looper) -
    Sets the Looper that must be used for all calls to the player and that is used to - call listeners on.
    +
    Deprecated. + +
    SimpleExoPlayer.Builder setMediaSourceFactory​(MediaSourceFactory mediaSourceFactory) -
    Sets the MediaSourceFactory that will be used by the player.
    +
    SimpleExoPlayer.Builder setPauseAtEndOfMediaItems​(boolean pauseAtEndOfMediaItems) -
    Sets whether to pause playback at the end of each media item.
    +
    SimpleExoPlayer.Builder setPriorityTaskManager​(PriorityTaskManager priorityTaskManager) -
    Sets an PriorityTaskManager that will be used by the player.
    +
    SimpleExoPlayer.Builder setReleaseTimeoutMs​(long releaseTimeoutMs) - +
    SimpleExoPlayer.Builder setSeekBackIncrementMs​(long seekBackIncrementMs) -
    Sets the BasePlayer.seekBack() increment.
    +
    SimpleExoPlayer.Builder setSeekForwardIncrementMs​(long seekForwardIncrementMs) -
    Sets the BasePlayer.seekForward() increment.
    +
    SimpleExoPlayer.Builder setSeekParameters​(SeekParameters seekParameters) -
    Sets the parameters that control how seek operations are performed.
    +
    SimpleExoPlayer.Builder setSkipSilenceEnabled​(boolean skipSilenceEnabled) -
    Sets whether silences silences in the audio stream is enabled.
    +
    SimpleExoPlayer.Builder setTrackSelector​(TrackSelector trackSelector) -
    Sets the TrackSelector that will be used by the player.
    +
    SimpleExoPlayer.Builder setUseLazyPreparation​(boolean useLazyPreparation) -
    Sets whether media sources should be initialized lazily.
    +
    SimpleExoPlayer.BuildersetVideoScalingMode​(int videoScalingMode)setVideoChangeFrameRateStrategy​(int videoChangeFrameRateStrategy) -
    Sets the C.VideoScalingMode that will be used by the player.
    +
    SimpleExoPlayer.BuildersetWakeMode​(int wakeMode)setVideoScalingMode​(int videoScalingMode) -
    Sets the C.WakeMode that will be used by the player.
    +
    Deprecated. + +
    +
    SimpleExoPlayer.BuildersetWakeMode​(@com.google.android.exoplayer2.C.WakeMode int wakeMode) +
    Deprecated. + +
    @@ -411,43 +479,11 @@ extends
  • Builder

    -
    public Builder​(Context context)
    -
    Creates a builder. - -

    Use Builder(Context, RenderersFactory), Builder(Context, - RenderersFactory) or Builder(Context, RenderersFactory, ExtractorsFactory) instead, - if you intend to provide a custom RenderersFactory or a custom ExtractorsFactory. This is to ensure that ProGuard or R8 can remove ExoPlayer's DefaultRenderersFactory and DefaultExtractorsFactory from the APK. - -

    The builder uses the following default values: - -

    -
    -
    Parameters:
    -
    context - A Context.
    -
    +
    @Deprecated
    +public Builder​(Context context)
    +
    Deprecated. +
    Use Builder(Context) instead.
    +
  • @@ -456,17 +492,12 @@ extends
  • Builder

    -
    public Builder​(Context context,
    +
    @Deprecated
    +public Builder​(Context context,
                    RenderersFactory renderersFactory)
    -
    Creates a builder with a custom RenderersFactory. - -

    See Builder(Context) for a list of default values.

    -
    -
    Parameters:
    -
    context - A Context.
    -
    renderersFactory - A factory for creating Renderers to be used by the - player.
    -
    +
    Deprecated. + +
  • @@ -475,17 +506,12 @@ extends
  • Builder

    -
    public Builder​(Context context,
    +
    @Deprecated
    +public Builder​(Context context,
                    ExtractorsFactory extractorsFactory)
    -
    Creates a builder with a custom ExtractorsFactory. - -

    See Builder(Context) for a list of default values.

    -
    -
    Parameters:
    -
    context - A Context.
    -
    extractorsFactory - An ExtractorsFactory used to extract progressive media from - its container.
    -
    +
  • @@ -494,20 +520,14 @@ extends
  • Builder

    -
    public Builder​(Context context,
    +
    @Deprecated
    +public Builder​(Context context,
                    RenderersFactory renderersFactory,
                    ExtractorsFactory extractorsFactory)
    -
    Creates a builder with a custom RenderersFactory and ExtractorsFactory. - -

    See Builder(Context) for a list of default values.

    -
    -
    Parameters:
    -
    context - A Context.
    -
    renderersFactory - A factory for creating Renderers to be used by the - player.
    -
    extractorsFactory - An ExtractorsFactory used to extract progressive media from - its container.
    -
    +
  • @@ -516,28 +536,19 @@ extends
  • Builder

    -
    public Builder​(Context context,
    +
    @Deprecated
    +public Builder​(Context context,
                    RenderersFactory renderersFactory,
                    TrackSelector trackSelector,
                    MediaSourceFactory mediaSourceFactory,
                    LoadControl loadControl,
                    BandwidthMeter bandwidthMeter,
                    AnalyticsCollector analyticsCollector)
    -
    Creates a builder with the specified custom components. - -

    Note that this constructor is only useful to try and ensure that ExoPlayer's default - components can be removed by ProGuard or R8.

    -
    -
    Parameters:
    -
    context - A Context.
    -
    renderersFactory - A factory for creating Renderers to be used by the - player.
    -
    trackSelector - A TrackSelector.
    -
    mediaSourceFactory - A MediaSourceFactory.
    -
    loadControl - A LoadControl.
    -
    bandwidthMeter - A BandwidthMeter.
    -
    analyticsCollector - An AnalyticsCollector.
    -
    +
  • @@ -556,15 +567,12 @@ extends
  • experimentalSetForegroundModeTimeoutMs

    -
    public SimpleExoPlayer.Builder experimentalSetForegroundModeTimeoutMs​(long timeoutMs)
    -
    Set a limit on the time a call to SimpleExoPlayer.setForegroundMode(boolean) can spend. If a call to SimpleExoPlayer.setForegroundMode(boolean) takes more than timeoutMs milliseconds to complete, the player - will raise an error via Player.Listener.onPlayerError(com.google.android.exoplayer2.PlaybackException). - -

    This method is experimental, and will be renamed or removed in a future release.

    -
    -
    Parameters:
    -
    timeoutMs - The time limit in milliseconds.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder experimentalSetForegroundModeTimeoutMs​(long timeoutMs)
    +
  • @@ -573,16 +581,11 @@ extends
  • setTrackSelector

    -
    public SimpleExoPlayer.Builder setTrackSelector​(TrackSelector trackSelector)
    -
    Sets the TrackSelector that will be used by the player.
    -
    -
    Parameters:
    -
    trackSelector - A TrackSelector.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setTrackSelector​(TrackSelector trackSelector)
    +
  • @@ -591,16 +594,11 @@ extends
  • setMediaSourceFactory

    -
    public SimpleExoPlayer.Builder setMediaSourceFactory​(MediaSourceFactory mediaSourceFactory)
    -
    Sets the MediaSourceFactory that will be used by the player.
    -
    -
    Parameters:
    -
    mediaSourceFactory - A MediaSourceFactory.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setMediaSourceFactory​(MediaSourceFactory mediaSourceFactory)
    +
  • @@ -609,16 +607,11 @@ extends
  • setLoadControl

    -
    public SimpleExoPlayer.Builder setLoadControl​(LoadControl loadControl)
    -
    Sets the LoadControl that will be used by the player.
    -
    -
    Parameters:
    -
    loadControl - A LoadControl.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setLoadControl​(LoadControl loadControl)
    +
  • @@ -627,16 +620,11 @@ extends
  • setBandwidthMeter

    -
    public SimpleExoPlayer.Builder setBandwidthMeter​(BandwidthMeter bandwidthMeter)
    -
    Sets the BandwidthMeter that will be used by the player.
    -
    -
    Parameters:
    -
    bandwidthMeter - A BandwidthMeter.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setBandwidthMeter​(BandwidthMeter bandwidthMeter)
    +
  • @@ -645,17 +633,11 @@ extends
  • setLooper

    -
    public SimpleExoPlayer.Builder setLooper​(Looper looper)
    -
    Sets the Looper that must be used for all calls to the player and that is used to - call listeners on.
    -
    -
    Parameters:
    -
    looper - A Looper.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setLooper​(Looper looper)
    +
    Deprecated. + +
  • @@ -664,16 +646,11 @@ extends
  • setAnalyticsCollector

    -
    public SimpleExoPlayer.Builder setAnalyticsCollector​(AnalyticsCollector analyticsCollector)
    -
    Sets the AnalyticsCollector that will collect and forward all player events.
    -
    -
    Parameters:
    -
    analyticsCollector - An AnalyticsCollector.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setAnalyticsCollector​(AnalyticsCollector analyticsCollector)
    +
  • @@ -682,19 +659,13 @@ extends
  • setPriorityTaskManager

    -
    public SimpleExoPlayer.Builder setPriorityTaskManager​(@Nullable
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setPriorityTaskManager​(@Nullable
                                                           PriorityTaskManager priorityTaskManager)
    -
    Sets an PriorityTaskManager that will be used by the player. - -

    The priority C.PRIORITY_PLAYBACK will be set while the player is loading.

    -
    -
    Parameters:
    -
    priorityTaskManager - A PriorityTaskManager, or null to not use one.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
  • @@ -703,48 +674,27 @@ extends
  • setAudioAttributes

    -
    public SimpleExoPlayer.Builder setAudioAttributes​(AudioAttributes audioAttributes,
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setAudioAttributes​(AudioAttributes audioAttributes,
                                                       boolean handleAudioFocus)
    -
    Sets AudioAttributes that will be used by the player and whether to handle audio - focus. - -

    If audio focus should be handled, the AudioAttributes.usage must be C.USAGE_MEDIA or C.USAGE_GAME. Other usages will throw an IllegalArgumentException.

    -
    -
    Parameters:
    -
    audioAttributes - AudioAttributes.
    -
    handleAudioFocus - Whether the player should handle audio focus.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
  • - + @@ -753,19 +703,11 @@ extends
  • setHandleAudioBecomingNoisy

    -
    public SimpleExoPlayer.Builder setHandleAudioBecomingNoisy​(boolean handleAudioBecomingNoisy)
    -
    Sets whether the player should pause automatically when audio is rerouted from a headset to - device speakers. See the audio - becoming noisy documentation for more information.
    -
    -
    Parameters:
    -
    handleAudioBecomingNoisy - Whether the player should pause automatically when audio is - rerouted from a headset to device speakers.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setHandleAudioBecomingNoisy​(boolean handleAudioBecomingNoisy)
    +
  • @@ -774,16 +716,11 @@ extends
  • setSkipSilenceEnabled

    -
    public SimpleExoPlayer.Builder setSkipSilenceEnabled​(boolean skipSilenceEnabled)
    -
    Sets whether silences silences in the audio stream is enabled.
    -
    -
    Parameters:
    -
    skipSilenceEnabled - Whether skipping silences is enabled.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setSkipSilenceEnabled​(boolean skipSilenceEnabled)
    +
  • @@ -792,19 +729,26 @@ extends
  • setVideoScalingMode

    -
    public SimpleExoPlayer.Builder setVideoScalingMode​(@VideoScalingMode
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setVideoScalingMode​(@VideoScalingMode
                                                        int videoScalingMode)
    -
    Sets the C.VideoScalingMode that will be used by the player. - -

    Note that the scaling mode only applies if a MediaCodec-based video Renderer is enabled and if the output surface is owned by a SurfaceView.

    -
    -
    Parameters:
    -
    videoScalingMode - A C.VideoScalingMode.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    Deprecated. + +
    +
  • + + + + + @@ -813,20 +757,11 @@ extends
  • setUseLazyPreparation

    -
    public SimpleExoPlayer.Builder setUseLazyPreparation​(boolean useLazyPreparation)
    -
    Sets whether media sources should be initialized lazily. - -

    If false, all initial preparation steps (e.g., manifest loads) happen immediately. If - true, these initial preparations are triggered only when the player starts buffering the - media.

    -
    -
    Parameters:
    -
    useLazyPreparation - Whether to use lazy preparation.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setUseLazyPreparation​(boolean useLazyPreparation)
    +
  • @@ -835,16 +770,11 @@ extends
  • setSeekParameters

    -
    public SimpleExoPlayer.Builder setSeekParameters​(SeekParameters seekParameters)
    -
    Sets the parameters that control how seek operations are performed.
    -
    -
    Parameters:
    -
    seekParameters - The SeekParameters.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setSeekParameters​(SeekParameters seekParameters)
    +
  • @@ -853,18 +783,12 @@ extends
  • setSeekBackIncrementMs

    -
    public SimpleExoPlayer.Builder setSeekBackIncrementMs​(@IntRange(from=1L)
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setSeekBackIncrementMs​(@IntRange(from=1L)
                                                           long seekBackIncrementMs)
    -
    Sets the BasePlayer.seekBack() increment.
    -
    -
    Parameters:
    -
    seekBackIncrementMs - The seek back increment, in milliseconds.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalArgumentException - If seekBackIncrementMs is non-positive.
    -
    IllegalStateException - If build() has already been called.
    -
    +
  • @@ -873,18 +797,12 @@ extends
  • setSeekForwardIncrementMs

    -
    public SimpleExoPlayer.Builder setSeekForwardIncrementMs​(@IntRange(from=1L)
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setSeekForwardIncrementMs​(@IntRange(from=1L)
                                                              long seekForwardIncrementMs)
    -
    Sets the BasePlayer.seekForward() increment.
    -
    -
    Parameters:
    -
    seekForwardIncrementMs - The seek forward increment, in milliseconds.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalArgumentException - If seekForwardIncrementMs is non-positive.
    -
    IllegalStateException - If build() has already been called.
    -
    +
  • @@ -893,19 +811,11 @@ extends
  • setReleaseTimeoutMs

    -
    public SimpleExoPlayer.Builder setReleaseTimeoutMs​(long releaseTimeoutMs)
    - -
    -
    Parameters:
    -
    releaseTimeoutMs - The release timeout, in milliseconds.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setReleaseTimeoutMs​(long releaseTimeoutMs)
    +
  • @@ -914,19 +824,11 @@ extends
  • setDetachSurfaceTimeoutMs

    -
    public SimpleExoPlayer.Builder setDetachSurfaceTimeoutMs​(long detachSurfaceTimeoutMs)
    -
    Sets a timeout for detaching a surface from the player. - -

    If detaching a surface or replacing a surface takes more than - detachSurfaceTimeoutMs to complete, the player will report an error via Player.Listener.onPlayerError(com.google.android.exoplayer2.PlaybackException).

    -
    -
    Parameters:
    -
    detachSurfaceTimeoutMs - The timeout for detaching a surface, in milliseconds.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setDetachSurfaceTimeoutMs​(long detachSurfaceTimeoutMs)
    +
  • @@ -935,18 +837,11 @@ extends
  • setPauseAtEndOfMediaItems

    -
    public SimpleExoPlayer.Builder setPauseAtEndOfMediaItems​(boolean pauseAtEndOfMediaItems)
    -
    Sets whether to pause playback at the end of each media item. - -

    This means the player will pause at the end of each window in the current timeline. Listeners will be informed by a call to Player.Listener.onPlayWhenReadyChanged(boolean, int) with the reason Player.PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM when this happens.

    -
    -
    Parameters:
    -
    pauseAtEndOfMediaItems - Whether to pause playback at the end of each media item.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setPauseAtEndOfMediaItems​(boolean pauseAtEndOfMediaItems)
    +
  • @@ -955,17 +850,11 @@ extends
  • setLivePlaybackSpeedControl

    -
    public SimpleExoPlayer.Builder setLivePlaybackSpeedControl​(LivePlaybackSpeedControl livePlaybackSpeedControl)
    -
    Sets the LivePlaybackSpeedControl that will control the playback speed when playing - live streams, in order to maintain a steady target offset from the live stream edge.
    -
    -
    Parameters:
    -
    livePlaybackSpeedControl - The LivePlaybackSpeedControl.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setLivePlaybackSpeedControl​(LivePlaybackSpeedControl livePlaybackSpeedControl)
    +
  • @@ -974,17 +863,11 @@ extends
  • setClock

    -
    public SimpleExoPlayer.Builder setClock​(Clock clock)
    -
    Sets the Clock that will be used by the player. Should only be set for testing - purposes.
    -
    -
    Parameters:
    -
    clock - A Clock.
    -
    Returns:
    -
    This builder.
    -
    Throws:
    -
    IllegalStateException - If build() has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer.Builder setClock​(Clock clock)
    +
    Deprecated. + +
  • @@ -993,12 +876,11 @@ extends
  • build

    -
    public SimpleExoPlayer build()
    -
    Builds a SimpleExoPlayer instance.
    -
    -
    Throws:
    -
    IllegalStateException - If this method has already been called.
    -
    +
    @Deprecated
    +public SimpleExoPlayer build()
    +
    Deprecated. + +
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/SimpleExoPlayer.html b/docs/doc/reference/com/google/android/exoplayer2/SimpleExoPlayer.html index 3471b07a47..f9d5724fe1 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/SimpleExoPlayer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/SimpleExoPlayer.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":42,"i2":10,"i3":42,"i4":42,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":42,"i12":42,"i13":42,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10,"i36":10,"i37":10,"i38":10,"i39":10,"i40":10,"i41":10,"i42":10,"i43":42,"i44":10,"i45":10,"i46":10,"i47":10,"i48":10,"i49":10,"i50":10,"i51":10,"i52":10,"i53":10,"i54":10,"i55":10,"i56":10,"i57":10,"i58":10,"i59":10,"i60":10,"i61":10,"i62":10,"i63":10,"i64":10,"i65":10,"i66":10,"i67":10,"i68":10,"i69":10,"i70":10,"i71":10,"i72":10,"i73":10,"i74":10,"i75":10,"i76":10,"i77":10,"i78":10,"i79":10,"i80":10,"i81":10,"i82":10,"i83":10,"i84":10,"i85":10,"i86":42,"i87":42,"i88":10,"i89":10,"i90":42,"i91":10,"i92":42,"i93":42,"i94":10,"i95":10,"i96":42,"i97":42,"i98":42,"i99":42,"i100":10,"i101":10,"i102":10,"i103":10,"i104":10,"i105":10,"i106":10,"i107":10,"i108":10,"i109":42,"i110":10,"i111":10,"i112":10,"i113":10,"i114":10,"i115":10,"i116":10,"i117":10,"i118":10,"i119":10,"i120":10,"i121":10,"i122":10,"i123":10,"i124":10,"i125":10,"i126":10,"i127":10,"i128":42,"i129":10,"i130":10,"i131":10,"i132":10,"i133":10,"i134":10,"i135":10,"i136":10,"i137":42}; +var data = {"i0":42,"i1":42,"i2":42,"i3":42,"i4":42,"i5":42,"i6":42,"i7":42,"i8":42,"i9":42,"i10":42,"i11":42,"i12":42,"i13":42,"i14":42,"i15":42,"i16":42,"i17":42,"i18":42,"i19":42,"i20":42,"i21":42,"i22":42,"i23":42,"i24":42,"i25":42,"i26":42,"i27":42,"i28":42,"i29":42,"i30":42,"i31":42,"i32":42,"i33":42,"i34":42,"i35":42,"i36":42,"i37":42,"i38":42,"i39":42,"i40":42,"i41":42,"i42":42,"i43":42,"i44":42,"i45":42,"i46":42,"i47":42,"i48":42,"i49":42,"i50":42,"i51":42,"i52":42,"i53":42,"i54":42,"i55":42,"i56":42,"i57":42,"i58":42,"i59":42,"i60":42,"i61":42,"i62":42,"i63":42,"i64":42,"i65":42,"i66":42,"i67":42,"i68":42,"i69":42,"i70":42,"i71":42,"i72":42,"i73":42,"i74":42,"i75":42,"i76":42,"i77":42,"i78":42,"i79":42,"i80":42,"i81":42,"i82":42,"i83":42,"i84":42,"i85":42,"i86":42,"i87":42,"i88":42,"i89":42,"i90":42,"i91":42,"i92":42,"i93":42,"i94":42,"i95":42,"i96":42,"i97":42,"i98":42,"i99":42,"i100":42,"i101":42,"i102":42,"i103":42,"i104":42,"i105":42,"i106":42,"i107":42,"i108":42,"i109":42,"i110":42,"i111":42,"i112":42,"i113":42,"i114":42,"i115":42,"i116":42,"i117":42,"i118":42,"i119":42,"i120":42,"i121":42,"i122":42,"i123":42,"i124":42,"i125":42,"i126":42,"i127":42,"i128":42,"i129":42,"i130":42,"i131":42}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -135,14 +135,16 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • All Implemented Interfaces:
    -
    ExoPlayer, ExoPlayer.AudioComponent, ExoPlayer.DeviceComponent, ExoPlayer.MetadataComponent, ExoPlayer.TextComponent, ExoPlayer.VideoComponent, Player
    +
    ExoPlayer, ExoPlayer.AudioComponent, ExoPlayer.DeviceComponent, ExoPlayer.TextComponent, ExoPlayer.VideoComponent, Player

    -
    public class SimpleExoPlayer
    +
    @Deprecated
    +public class SimpleExoPlayer
     extends BasePlayer
    -implements ExoPlayer, ExoPlayer.AudioComponent, ExoPlayer.VideoComponent, ExoPlayer.TextComponent, ExoPlayer.MetadataComponent, ExoPlayer.DeviceComponent
    -
    An ExoPlayer implementation that uses default Renderer components. Instances can - be obtained from SimpleExoPlayer.Builder.
    +implements ExoPlayer, ExoPlayer.AudioComponent, ExoPlayer.VideoComponent, ExoPlayer.TextComponent, ExoPlayer.DeviceComponent
    +
    Deprecated. +
    Use ExoPlayer instead.
    +
  • @@ -167,7 +169,9 @@ implements static class  SimpleExoPlayer.Builder -
    A builder for SimpleExoPlayer instances.
    +
    Deprecated. +
    Use ExoPlayer.Builder instead.
    +
    @@ -176,7 +180,7 @@ implements ExoPlayer -ExoPlayer.AudioComponent, ExoPlayer.AudioOffloadListener, ExoPlayer.DeviceComponent, ExoPlayer.MetadataComponent, ExoPlayer.TextComponent, ExoPlayer.VideoComponent +ExoPlayer.AudioComponent, ExoPlayer.AudioOffloadListener, ExoPlayer.DeviceComponent, ExoPlayer.TextComponent, ExoPlayer.VideoComponent @@ -267,14 +266,16 @@ implements Looper applicationLooper)
    Deprecated. - +
    protected SimpleExoPlayer​(SimpleExoPlayer.Builder builder) -  + +
    Deprecated.
    +  @@ -298,623 +299,672 @@ implements void addAnalyticsListener​(AnalyticsListener listener) +
    Deprecated.
    Adds an AnalyticsListener to receive analytics events.
    void -addAudioListener​(AudioListener listener) - -
    Deprecated.
    - - - -void addAudioOffloadListener​(ExoPlayer.AudioOffloadListener listener) +
    Deprecated.
    Adds a listener to receive audio offload events.
    - -void -addDeviceListener​(DeviceListener listener) - -
    Deprecated.
    - - - + void addListener​(Player.EventListener listener)
    Deprecated.
    - + void addListener​(Player.Listener listener) +
    Deprecated.
    Registers a listener to receive all events from the player.
    - + void addMediaItems​(int index, List<MediaItem> mediaItems) +
    Deprecated.
    Adds a list of media items at the given index of the playlist.
    - + void addMediaSource​(int index, MediaSource mediaSource) +
    Deprecated.
    Adds a media source at the given index of the playlist.
    - + void addMediaSource​(MediaSource mediaSource) +
    Deprecated.
    Adds a media source to the end of the playlist.
    - + void addMediaSources​(int index, List<MediaSource> mediaSources) +
    Deprecated.
    Adds a list of media sources at the given index of the playlist.
    + +void +addMediaSources​(List<MediaSource> mediaSources) + +
    Deprecated.
    +
    Adds a list of media sources to the end of the playlist.
    + + + +void +clearAuxEffectInfo() + +
    Deprecated.
    +
    Detaches any previously attached auxiliary audio effect from the underlying audio track.
    + + void -addMediaSources​(List<MediaSource> mediaSources) +clearCameraMotionListener​(CameraMotionListener listener) -
    Adds a list of media sources to the end of the playlist.
    +
    Deprecated.
    +
    Clears the listener which receives camera motion events if it matches the one passed.
    void -addMetadataOutput​(MetadataOutput output) +clearVideoFrameMetadataListener​(VideoFrameMetadataListener listener)
    Deprecated.
    +
    Clears the listener which receives video frame metadata events if it matches the one passed.
    void -addTextOutput​(TextOutput listener) - -
    Deprecated.
    - - - -void -addVideoListener​(VideoListener listener) - -
    Deprecated.
    - - - -void -clearAuxEffectInfo() - -
    Detaches any previously attached auxiliary audio effect from the underlying audio track.
    - - - -void -clearCameraMotionListener​(CameraMotionListener listener) - -
    Clears the listener which receives camera motion events if it matches the one passed.
    - - - -void -clearVideoFrameMetadataListener​(VideoFrameMetadataListener listener) - -
    Clears the listener which receives video frame metadata events if it matches the one passed.
    - - - -void clearVideoSurface() +
    Deprecated.
    Clears any Surface, SurfaceHolder, SurfaceView or TextureView currently set on the player.
    - + void clearVideoSurface​(Surface surface) +
    Deprecated.
    Clears the Surface onto which video is being rendered if it matches the one passed.
    - + void clearVideoSurfaceHolder​(SurfaceHolder surfaceHolder) +
    Deprecated.
    Clears the SurfaceHolder that holds the Surface onto which video is being rendered if it matches the one passed.
    - + void clearVideoSurfaceView​(SurfaceView surfaceView) +
    Deprecated.
    Clears the SurfaceView onto which video is being rendered if it matches the one passed.
    - + void clearVideoTextureView​(TextureView textureView) +
    Deprecated.
    Clears the TextureView onto which video is being rendered if it matches the one passed.
    - + PlayerMessage createMessage​(PlayerMessage.Target target) +
    Deprecated.
    Creates a message that can be sent to a PlayerMessage.Target.
    - + void decreaseDeviceVolume() +
    Deprecated.
    Decreases the volume of the device.
    - + boolean experimentalIsSleepingForOffload() +
    Deprecated.
    Returns whether the player has paused its main loop to save power in offload scheduling mode.
    - + void experimentalSetOffloadSchedulingEnabled​(boolean offloadSchedulingEnabled) +
    Deprecated.
    Sets whether audio offload scheduling is enabled.
    - + AnalyticsCollector getAnalyticsCollector() +
    Deprecated.
    Returns the AnalyticsCollector used for collecting analytics events.
    - + Looper getApplicationLooper() +
    Deprecated.
    Returns the Looper associated with the application thread that's used to access the player and on which player events are received.
    - + AudioAttributes getAudioAttributes() +
    Deprecated.
    Returns the attributes for audio playback.
    - + ExoPlayer.AudioComponent getAudioComponent() -
    Returns the component of this player for audio output, or null if audio is not supported.
    - +
    Deprecated.
    +  - + DecoderCounters getAudioDecoderCounters() +
    Deprecated.
    Returns DecoderCounters for audio, or null if no audio is being played.
    - + Format getAudioFormat() +
    Deprecated.
    Returns the audio format currently being played, or null if no audio is being played.
    - + int getAudioSessionId() +
    Deprecated.
    Returns the audio session identifier, or C.AUDIO_SESSION_ID_UNSET if not set.
    - + Player.Commands getAvailableCommands() +
    Deprecated.
    Returns the player's currently available Player.Commands.
    - + long getBufferedPosition() -
    Returns an estimate of the position in the current content window or ad up to which data is - buffered, in milliseconds.
    +
    Deprecated.
    +
    Returns an estimate of the position in the current content or ad up to which data is buffered, + in milliseconds.
    - + Clock getClock() +
    Deprecated.
    Returns the Clock used for playback.
    - + long getContentBufferedPosition() +
    Deprecated.
    If Player.isPlayingAd() returns true, returns an estimate of the content position in - the current content window up to which data is buffered, in milliseconds.
    + the current content up to which data is buffered, in milliseconds. - + long getContentPosition() +
    Deprecated.
    If Player.isPlayingAd() returns true, returns the content position that will be played once all ads in the ad group have finished playing, in milliseconds.
    - + int getCurrentAdGroupIndex() +
    Deprecated.
    If Player.isPlayingAd() returns true, returns the index of the ad group in the period currently being played.
    - + int getCurrentAdIndexInAdGroup() +
    Deprecated.
    If Player.isPlayingAd() returns true, returns the index of the ad in its ad group.
    - + List<Cue> getCurrentCues() +
    Deprecated.
    Returns the current Cues.
    - + int -getCurrentPeriodIndex() +getCurrentMediaItemIndex() -
    Returns the index of the period currently being played.
    - - - -long -getCurrentPosition() - -
    Returns the playback position in the current content window or ad, in milliseconds, or the - prospective position in milliseconds if the current timeline is +
    Deprecated.
    +
    Returns the index of the current MediaItem in the timeline, or the prospective index if the current timeline is empty.
    - -List<Metadata> -getCurrentStaticMetadata() + +int +getCurrentPeriodIndex()
    Deprecated.
    +
    Returns the index of the period currently being played.
    - + +long +getCurrentPosition() + +
    Deprecated.
    +
    Returns the playback position in the current content or ad, in milliseconds, or the prospective + position in milliseconds if the current timeline is empty.
    + + + Timeline getCurrentTimeline() +
    Deprecated.
    Returns the current Timeline.
    - + TrackGroupArray getCurrentTrackGroups() +
    Deprecated.
    Returns the available track groups.
    - + TrackSelectionArray getCurrentTrackSelections() +
    Deprecated.
    Returns the current track selections.
    - -int -getCurrentWindowIndex() + +TracksInfo +getCurrentTracksInfo() -
    Returns the index of the current window in the timeline, or the prospective window index if the current timeline is empty.
    +
    Deprecated.
    +
    Returns the available tracks, as well as the tracks' support, type, and selection status.
    - + ExoPlayer.DeviceComponent getDeviceComponent() -
    Returns the component of this player for playback device, or null if it's not supported.
    - +
    Deprecated.
    +  - -DeviceInfo + +DeviceInfo getDeviceInfo() +
    Deprecated.
    Gets the device information.
    - + int getDeviceVolume() +
    Deprecated.
    Gets the current volume of the device.
    - + long getDuration() -
    Returns the duration of the current content window or ad in milliseconds, or C.TIME_UNSET if the duration is not known.
    +
    Deprecated.
    +
    Returns the duration of the current content or ad in milliseconds, or C.TIME_UNSET if + the duration is not known.
    - -int + +long getMaxSeekToPreviousPosition() -
    Returns the maximum position for which Player.seekToPrevious() seeks to the previous window, - in milliseconds.
    +
    Deprecated.
    +
    Returns the maximum position for which Player.seekToPrevious() seeks to the previous MediaItem, in milliseconds.
    - + MediaMetadata getMediaMetadata() +
    Deprecated.
    Returns the current combined MediaMetadata, or MediaMetadata.EMPTY if not supported.
    - -ExoPlayer.MetadataComponent -getMetadataComponent() - -
    Returns the component of this player for metadata output, or null if metadata is not supported.
    - - - + boolean getPauseAtEndOfMediaItems() +
    Deprecated.
    Returns whether the player pauses playback at the end of each media item.
    - + Looper getPlaybackLooper() +
    Deprecated.
    Returns the Looper associated with the playback thread.
    - + PlaybackParameters getPlaybackParameters() +
    Deprecated.
    Returns the currently active playback parameters.
    - -int + +@com.google.android.exoplayer2.Player.State int getPlaybackState() +
    Deprecated.
    Returns the current playback state of the player.
    - -int + +@com.google.android.exoplayer2.Player.PlaybackSuppressionReason int getPlaybackSuppressionReason() +
    Deprecated.
    Returns the reason why playback is suppressed even though Player.getPlayWhenReady() is true, or Player.PLAYBACK_SUPPRESSION_REASON_NONE if playback is not suppressed.
    - + ExoPlaybackException getPlayerError() +
    Deprecated.
    Equivalent to Player.getPlayerError(), except the exception is guaranteed to be an ExoPlaybackException.
    - + MediaMetadata getPlaylistMetadata() +
    Deprecated.
    Returns the playlist MediaMetadata, as set by Player.setPlaylistMetadata(MediaMetadata), or MediaMetadata.EMPTY if not supported.
    - + boolean getPlayWhenReady() +
    Deprecated.
    Whether playback will proceed when Player.getPlaybackState() == Player.STATE_READY.
    - + int getRendererCount() +
    Deprecated.
    Returns the number of renderers.
    - -int + +@com.google.android.exoplayer2.C.TrackType int getRendererType​(int index) +
    Deprecated.
    Returns the track type that the renderer at a given index handles.
    - -int + +@com.google.android.exoplayer2.Player.RepeatMode int getRepeatMode() +
    Deprecated.
    Returns the current Player.RepeatMode used for playback.
    - + long getSeekBackIncrement() +
    Deprecated.
    Returns the Player.seekBack() increment.
    - + long getSeekForwardIncrement() +
    Deprecated.
    Returns the Player.seekForward() increment.
    - + SeekParameters getSeekParameters() +
    Deprecated.
    Returns the currently active SeekParameters of the player.
    - + boolean getShuffleModeEnabled() -
    Returns whether shuffling of windows is enabled.
    +
    Deprecated.
    +
    Returns whether shuffling of media items is enabled.
    - + boolean getSkipSilenceEnabled() +
    Deprecated.
    Returns whether skipping silences in the audio stream is enabled.
    - + ExoPlayer.TextComponent getTextComponent() -
    Returns the component of this player for text output, or null if text is not supported.
    - +
    Deprecated.
    +  - + long getTotalBufferedDuration() +
    Deprecated.
    Returns an estimate of the total buffered duration from the current position, in milliseconds.
    - + +TrackSelectionParameters +getTrackSelectionParameters() + +
    Deprecated.
    +
    Returns the parameters constraining the track selection.
    + + + TrackSelector getTrackSelector() +
    Deprecated.
    Returns the track selector that this player uses, or null if track selection is not supported.
    - + +int +getVideoChangeFrameRateStrategy() + +
    Deprecated.
    + + + + ExoPlayer.VideoComponent getVideoComponent() -
    Returns the component of this player for video output, or null if video is not supported.
    - +
    Deprecated.
    +  - + DecoderCounters getVideoDecoderCounters() +
    Deprecated.
    Returns DecoderCounters for video, or null if no video is being played.
    - + Format getVideoFormat() +
    Deprecated.
    Returns the video format currently being played, or null if no video is being played.
    - + int getVideoScalingMode() +
    Deprecated.
    Returns the C.VideoScalingMode.
    - + VideoSize getVideoSize() +
    Deprecated.
    Gets the size of the video.
    - + float getVolume() +
    Deprecated.
    Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
    - + void increaseDeviceVolume() +
    Deprecated.
    Increases the volume of the device.
    - + boolean isDeviceMuted() +
    Deprecated.
    Gets whether the device is muted or not.
    - + boolean isLoading() +
    Deprecated.
    Whether the player is currently loading the source.
    - + boolean isPlayingAd() +
    Deprecated.
    Returns whether the player is currently playing an ad.
    - + void moveMediaItems​(int fromIndex, int toIndex, int newIndex) +
    Deprecated.
    Moves the media item range to the new index.
    - + void prepare() +
    Deprecated.
    Prepares the player.
    - + void prepare​(MediaSource mediaSource) @@ -923,7 +973,7 @@ implements + void prepare​(MediaSource mediaSource, boolean resetPosition, @@ -935,85 +985,55 @@ implements + void release() +
    Deprecated.
    Releases the player.
    - + void removeAnalyticsListener​(AnalyticsListener listener) +
    Deprecated.
    Removes an AnalyticsListener.
    - -void -removeAudioListener​(AudioListener listener) - -
    Deprecated.
    - - - + void removeAudioOffloadListener​(ExoPlayer.AudioOffloadListener listener) +
    Deprecated.
    Removes a listener of audio offload events.
    - -void -removeDeviceListener​(DeviceListener listener) - -
    Deprecated.
    - - - + void removeListener​(Player.EventListener listener)
    Deprecated.
    - + void removeListener​(Player.Listener listener) +
    Deprecated.
    Unregister a listener registered through Player.addListener(Listener).
    - + void removeMediaItems​(int fromIndex, int toIndex) +
    Deprecated.
    Removes a range of media items from the playlist.
    - -void -removeMetadataOutput​(MetadataOutput output) - -
    Deprecated.
    - - - -void -removeTextOutput​(TextOutput listener) - -
    Deprecated.
    - - - -void -removeVideoListener​(VideoListener listener) - -
    Deprecated.
    - - - + void retry() @@ -1022,285 +1042,342 @@ implements + void -seekTo​(int windowIndex, +seekTo​(int mediaItemIndex, long positionMs) -
    Seeks to a position specified in milliseconds in the specified window.
    +
    Deprecated.
    +
    Seeks to a position specified in milliseconds in the specified MediaItem.
    - + void setAudioAttributes​(AudioAttributes audioAttributes, boolean handleAudioFocus) +
    Deprecated.
    Sets the attributes for audio playback, used by the underlying audio track.
    - + void setAudioSessionId​(int audioSessionId) +
    Deprecated.
    Sets the ID of the audio session to attach to the underlying AudioTrack.
    - + void setAuxEffectInfo​(AuxEffectInfo auxEffectInfo) +
    Deprecated.
    Sets information on an auxiliary audio effect to attach to the underlying audio track.
    - + void setCameraMotionListener​(CameraMotionListener listener) +
    Deprecated.
    Sets a listener of camera motion events.
    - + void setDeviceMuted​(boolean muted) +
    Deprecated.
    Sets the mute state of the device.
    - + void setDeviceVolume​(int volume) +
    Deprecated.
    Sets the volume of the device.
    - + void setForegroundMode​(boolean foregroundMode) +
    Deprecated.
    Sets whether the player is allowed to keep holding limited resources such as video decoders, even when in the idle state.
    - + void setHandleAudioBecomingNoisy​(boolean handleAudioBecomingNoisy) +
    Deprecated.
    Sets whether the player should pause automatically when audio is rerouted from a headset to device speakers.
    - + void setHandleWakeLock​(boolean handleWakeLock) -
    Deprecated. -
    Use setWakeMode(int) instead.
    -
    +
    Deprecated.
    - + void setMediaItems​(List<MediaItem> mediaItems, boolean resetPosition) +
    Deprecated.
    Clears the playlist and adds the specified MediaItems.
    - + void setMediaItems​(List<MediaItem> mediaItems, - int startWindowIndex, + int startIndex, long startPositionMs) +
    Deprecated.
    Clears the playlist and adds the specified MediaItems.
    - + void setMediaSource​(MediaSource mediaSource) +
    Deprecated.
    Clears the playlist, adds the specified MediaSource and resets the position to the default position.
    - + void setMediaSource​(MediaSource mediaSource, boolean resetPosition) +
    Deprecated.
    Clears the playlist and adds the specified MediaSource.
    - + void setMediaSource​(MediaSource mediaSource, long startPositionMs) +
    Deprecated.
    Clears the playlist and adds the specified MediaSource.
    - + void setMediaSources​(List<MediaSource> mediaSources) +
    Deprecated.
    Clears the playlist, adds the specified MediaSources and resets the position to the default position.
    - + void setMediaSources​(List<MediaSource> mediaSources, boolean resetPosition) +
    Deprecated.
    Clears the playlist and adds the specified MediaSources.
    + +void +setMediaSources​(List<MediaSource> mediaSources, + int startMediaItemIndex, + long startPositionMs) + +
    Deprecated.
    +
    Clears the playlist and adds the specified MediaSources.
    + + + +void +setPauseAtEndOfMediaItems​(boolean pauseAtEndOfMediaItems) + +
    Deprecated.
    +
    Sets whether to pause playback at the end of each media item.
    + + + +void +setPlaybackParameters​(PlaybackParameters playbackParameters) + +
    Deprecated.
    +
    Attempts to set the playback parameters.
    + + + +void +setPlaylistMetadata​(MediaMetadata mediaMetadata) + +
    Deprecated.
    +
    Sets the playlist MediaMetadata.
    + + + +void +setPlayWhenReady​(boolean playWhenReady) + +
    Deprecated.
    +
    Sets whether playback should proceed when Player.getPlaybackState() == Player.STATE_READY.
    + + + +void +setPriorityTaskManager​(PriorityTaskManager priorityTaskManager) + +
    Deprecated.
    +
    Sets a PriorityTaskManager, or null to clear a previously set priority task manager.
    + + + +void +setRepeatMode​(@com.google.android.exoplayer2.Player.RepeatMode int repeatMode) + +
    Deprecated.
    +
    Sets the Player.RepeatMode to be used for playback.
    + + + +void +setSeekParameters​(SeekParameters seekParameters) + +
    Deprecated.
    +
    Sets the parameters that control how seek operations are performed.
    + + + +void +setShuffleModeEnabled​(boolean shuffleModeEnabled) + +
    Deprecated.
    +
    Sets whether shuffling of media items is enabled.
    + + void -setMediaSources​(List<MediaSource> mediaSources, - int startWindowIndex, - long startPositionMs) +setShuffleOrder​(ShuffleOrder shuffleOrder) -
    Clears the playlist and adds the specified MediaSources.
    +
    Deprecated.
    +
    Sets the shuffle order.
    void -setPauseAtEndOfMediaItems​(boolean pauseAtEndOfMediaItems) +setSkipSilenceEnabled​(boolean skipSilenceEnabled) -
    Sets whether to pause playback at the end of each media item.
    +
    Deprecated.
    +
    Sets whether skipping silences in the audio stream is enabled.
    void -setPlaybackParameters​(PlaybackParameters playbackParameters) +setThrowsWhenUsingWrongThread​(boolean throwsWhenUsingWrongThread) -
    Attempts to set the playback parameters.
    +
    Deprecated.
    void -setPlaylistMetadata​(MediaMetadata mediaMetadata) +setTrackSelectionParameters​(TrackSelectionParameters parameters) -
    Sets the playlist MediaMetadata.
    +
    Deprecated.
    +
    Sets the parameters constraining the track selection.
    void -setPlayWhenReady​(boolean playWhenReady) +setVideoChangeFrameRateStrategy​(int videoChangeFrameRateStrategy) -
    Sets whether playback should proceed when Player.getPlaybackState() == Player.STATE_READY.
    +
    Deprecated.
    +
    Sets a C.VideoChangeFrameRateStrategy that will be used by the player when provided + with a video output Surface.
    void -setPriorityTaskManager​(PriorityTaskManager priorityTaskManager) +setVideoFrameMetadataListener​(VideoFrameMetadataListener listener) -
    Sets a PriorityTaskManager, or null to clear a previously set priority task manager.
    +
    Deprecated.
    +
    Sets a listener to receive video frame metadata events.
    void -setRepeatMode​(int repeatMode) +setVideoScalingMode​(int videoScalingMode) -
    Sets the Player.RepeatMode to be used for playback.
    +
    Deprecated.
    + void -setSeekParameters​(SeekParameters seekParameters) +setVideoSurface​(Surface surface) -
    Sets the parameters that control how seek operations are performed.
    +
    Deprecated.
    +
    Sets the Surface onto which video will be rendered.
    void -setShuffleModeEnabled​(boolean shuffleModeEnabled) - -
    Sets whether shuffling of windows is enabled.
    - - - -void -setShuffleOrder​(ShuffleOrder shuffleOrder) - -
    Sets the shuffle order.
    - - - -void -setSkipSilenceEnabled​(boolean skipSilenceEnabled) - -
    Sets whether skipping silences in the audio stream is enabled.
    - - - -void -setThrowsWhenUsingWrongThread​(boolean throwsWhenUsingWrongThread) - -
    Deprecated. -
    Disabling the enforcement can result in hard-to-detect bugs.
    -
    - - - -void -setVideoFrameMetadataListener​(VideoFrameMetadataListener listener) - -
    Sets a listener to receive video frame metadata events.
    - - - -void -setVideoScalingMode​(int videoScalingMode) - -
    Sets the video scaling mode.
    - - - -void -setVideoSurface​(Surface surface) - -
    Sets the Surface onto which video will be rendered.
    - - - -void setVideoSurfaceHolder​(SurfaceHolder surfaceHolder) +
    Deprecated.
    Sets the SurfaceHolder that holds the Surface onto which video will be rendered.
    - + void setVideoSurfaceView​(SurfaceView surfaceView) +
    Deprecated.
    Sets the SurfaceView onto which video will be rendered.
    - + void setVideoTextureView​(TextureView textureView) +
    Deprecated.
    Sets the TextureView onto which video will be rendered.
    - + void -setVolume​(float audioVolume) +setVolume​(float volume) -
    Sets the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
    +
    Deprecated.
    +
    Sets the audio volume, valid values are between 0 (silence) and 1 (unity gain, signal + unchanged), inclusive.
    - + void -setWakeMode​(int wakeMode) +setWakeMode​(@com.google.android.exoplayer2.C.WakeMode int wakeMode) +
    Deprecated.
    Sets how the player should keep the device awake for playback when the screen is off.
    - + +void +stop() + +
    Deprecated.
    +
    Stops playback without resetting the player.
    + + + void stop​(boolean reset) @@ -1313,7 +1390,7 @@ implements BasePlayer -addMediaItem, addMediaItem, addMediaItems, clearMediaItems, getAvailableCommands, getBufferedPercentage, getContentDuration, getCurrentLiveOffset, getCurrentManifest, getCurrentMediaItem, getMediaItemAt, getMediaItemCount, getNextWindowIndex, getPreviousWindowIndex, hasNext, hasNextWindow, hasPrevious, hasPreviousWindow, isCommandAvailable, isCurrentWindowDynamic, isCurrentWindowLive, isCurrentWindowSeekable, isPlaying, moveMediaItem, next, pause, play, previous, removeMediaItem, seekBack, seekForward, seekTo, seekToDefaultPosition, seekToDefaultPosition, seekToNext, seekToNextWindow, seekToPrevious, seekToPreviousWindow, setMediaItem, setMediaItem, setMediaItem, setMediaItems, setPlaybackSpeed, stop +addMediaItem, addMediaItem, addMediaItems, canAdvertiseSession, clearMediaItems, getAvailableCommands, getBufferedPercentage, getContentDuration, getCurrentLiveOffset, getCurrentManifest, getCurrentMediaItem, getCurrentWindowIndex, getMediaItemAt, getMediaItemCount, getNextMediaItemIndex, getNextWindowIndex, getPreviousMediaItemIndex, getPreviousWindowIndex, hasNext, hasNextMediaItem, hasNextWindow, hasPrevious, hasPreviousMediaItem, hasPreviousWindow, isCommandAvailable, isCurrentMediaItemDynamic, isCurrentMediaItemLive, isCurrentMediaItemSeekable, isCurrentWindowDynamic, isCurrentWindowLive, isCurrentWindowSeekable, isPlaying, moveMediaItem, next, pause, play, previous, removeMediaItem, seekBack, seekForward, seekTo, seekToDefaultPosition, seekToDefaultPosition, seekToNext, seekToNextMediaItem, seekToNextWindow, seekToPrevious, seekToPreviousMediaItem, seekToPreviousWindow, setMediaItem, setMediaItem, setMediaItem, setMediaItems, setPlaybackSpeed @@ -1345,20 +1422,6 @@ implements - - -
      -
    • -

      DEFAULT_DETACH_SURFACE_TIMEOUT_MS

      -
      public static final long DEFAULT_DETACH_SURFACE_TIMEOUT_MS
      -
      The default timeout for detaching a surface from the player, in milliseconds.
      -
      -
      See Also:
      -
      Constant Field Values
      -
      -
    • -
    @@ -1366,6 +1429,7 @@ implements

    renderers

    protected final Renderer[] renderers
    +
    Deprecated.
    @@ -1396,7 +1460,7 @@ protected SimpleExoPlayer​(Clock clock, Looper applicationLooper)
    Deprecated. - +
    @@ -1407,6 +1471,7 @@ protected SimpleExoPlayer​(

    SimpleExoPlayer

    protected SimpleExoPlayer​(SimpleExoPlayer.Builder builder)
    +
    Deprecated.
    Parameters:
    builder - The SimpleExoPlayer.Builder to obtain all construction parameters.
    @@ -1430,6 +1495,7 @@ protected SimpleExoPlayer​(

    experimentalSetOffloadSchedulingEnabled

    public void experimentalSetOffloadSchedulingEnabled​(boolean offloadSchedulingEnabled)
    +
    Deprecated.
    Sets whether audio offload scheduling is enabled. If enabled, ExoPlayer's main loop will run as rarely as possible when playing an audio stream using audio offload. @@ -1476,6 +1542,7 @@ protected SimpleExoPlayer​(

    experimentalIsSleepingForOffload

    public boolean experimentalIsSleepingForOffload()
    +
    Deprecated.
    Returns whether the player has paused its main loop to save power in offload scheduling mode.
    @@ -1495,8 +1562,7 @@ protected SimpleExoPlayer​(@Nullable public ExoPlayer.AudioComponent getAudioComponent() -
    Description copied from interface: ExoPlayer
    -
    Returns the component of this player for audio output, or null if audio is not supported.
    +
    Deprecated.
    Specified by:
    getAudioComponent in interface ExoPlayer
    @@ -1511,8 +1577,7 @@ public @Nullable public ExoPlayer.VideoComponent getVideoComponent() -
    Description copied from interface: ExoPlayer
    -
    Returns the component of this player for video output, or null if video is not supported.
    +
    Deprecated.
    Specified by:
    getVideoComponent in interface ExoPlayer
    @@ -1527,30 +1592,13 @@ public @Nullable public ExoPlayer.TextComponent getTextComponent() -
    Description copied from interface: ExoPlayer
    -
    Returns the component of this player for text output, or null if text is not supported.
    +
    Deprecated.
    Specified by:
    getTextComponent in interface ExoPlayer
    - - - - @@ -1559,8 +1607,7 @@ public @Nullable public ExoPlayer.DeviceComponent getDeviceComponent() -
    Description copied from interface: ExoPlayer
    -
    Returns the component of this player for playback device, or null if it's not supported.
    +
    Deprecated.
    Specified by:
    getDeviceComponent in interface ExoPlayer
    @@ -1575,12 +1622,16 @@ public public void setVideoScalingMode​(@VideoScalingMode int videoScalingMode) -
    Sets the video scaling mode. +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    +
    Sets the C.VideoScalingMode. -

    Note that the scaling mode only applies if a MediaCodec-based video Renderer - is enabled and if the output surface is owned by a SurfaceView.

    +

    The scaling mode only applies if a MediaCodec-based video Renderer is + enabled and if the output surface is owned by a SurfaceView.

    Specified by:
    +
    setVideoScalingMode in interface ExoPlayer
    +
    Specified by:
    setVideoScalingMode in interface ExoPlayer.VideoComponent
    Parameters:
    videoScalingMode - The C.VideoScalingMode.
    @@ -1595,14 +1646,64 @@ public @VideoScalingMode public int getVideoScalingMode() -
    Description copied from interface: ExoPlayer.VideoComponent
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Returns the C.VideoScalingMode.
    Specified by:
    +
    getVideoScalingMode in interface ExoPlayer
    +
    Specified by:
    getVideoScalingMode in interface ExoPlayer.VideoComponent
    + + + + + + + + @@ -1610,6 +1711,7 @@ public int getVideoScalingMode()
  • getVideoSize

    public VideoSize getVideoSize()
    +
    Deprecated.
    Description copied from interface: Player
    Gets the size of the video. @@ -1632,6 +1734,7 @@ public int getVideoScalingMode()
  • clearVideoSurface

    public void clearVideoSurface()
    +
    Deprecated.
    Description copied from interface: Player
    Clears any Surface, SurfaceHolder, SurfaceView or TextureView currently set on the player.
    @@ -1651,6 +1754,7 @@ public int getVideoScalingMode()

    clearVideoSurface

    public void clearVideoSurface​(@Nullable
                                   Surface surface)
    +
    Deprecated.
    Description copied from interface: Player
    Clears the Surface onto which video is being rendered if it matches the one passed. Else does nothing.
    @@ -1672,6 +1776,7 @@ public int getVideoScalingMode()

    setVideoSurface

    public void setVideoSurface​(@Nullable
                                 Surface surface)
    +
    Deprecated.
    Description copied from interface: Player
    Sets the Surface onto which video will be rendered. The caller is responsible for tracking the lifecycle of the surface, and must clear the surface by calling @@ -1698,6 +1803,7 @@ public int getVideoScalingMode()

    setVideoSurfaceHolder

    public void setVideoSurfaceHolder​(@Nullable
                                       SurfaceHolder surfaceHolder)
    +
    Deprecated.
    Description copied from interface: Player
    Sets the SurfaceHolder that holds the Surface onto which video will be rendered. The player will track the lifecycle of the surface automatically. @@ -1722,6 +1828,7 @@ public int getVideoScalingMode()

    clearVideoSurfaceHolder

    public void clearVideoSurfaceHolder​(@Nullable
                                         SurfaceHolder surfaceHolder)
    +
    Deprecated.
    Description copied from interface: Player
    Clears the SurfaceHolder that holds the Surface onto which video is being rendered if it matches the one passed. Else does nothing.
    @@ -1743,6 +1850,7 @@ public int getVideoScalingMode()

    setVideoSurfaceView

    public void setVideoSurfaceView​(@Nullable
                                     SurfaceView surfaceView)
    +
    Deprecated.
    Description copied from interface: Player
    Sets the SurfaceView onto which video will be rendered. The player will track the lifecycle of the surface automatically. @@ -1767,6 +1875,7 @@ public int getVideoScalingMode()

    clearVideoSurfaceView

    public void clearVideoSurfaceView​(@Nullable
                                       SurfaceView surfaceView)
    +
    Deprecated.
    Description copied from interface: Player
    Clears the SurfaceView onto which video is being rendered if it matches the one passed. Else does nothing.
    @@ -1788,6 +1897,7 @@ public int getVideoScalingMode()

    setVideoTextureView

    public void setVideoTextureView​(@Nullable
                                     TextureView textureView)
    +
    Deprecated.
    Description copied from interface: Player
    Sets the TextureView onto which video will be rendered. The player will track the lifecycle of the surface automatically. @@ -1812,6 +1922,7 @@ public int getVideoScalingMode()

    clearVideoTextureView

    public void clearVideoTextureView​(@Nullable
                                       TextureView textureView)
    +
    Deprecated.
    Description copied from interface: Player
    Clears the TextureView onto which video is being rendered if it matches the one passed. Else does nothing.
    @@ -1832,6 +1943,7 @@ public int getVideoScalingMode()
  • addAudioOffloadListener

    public void addAudioOffloadListener​(ExoPlayer.AudioOffloadListener listener)
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Adds a listener to receive audio offload events.
    @@ -1849,6 +1961,7 @@ public int getVideoScalingMode()
  • removeAudioOffloadListener

    public void removeAudioOffloadListener​(ExoPlayer.AudioOffloadListener listener)
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Removes a listener of audio offload events.
    @@ -1859,44 +1972,6 @@ public int getVideoScalingMode()
  • - - - - - - - - @@ -1905,7 +1980,8 @@ public void removeAudioListener​(public void setAudioAttributes​(AudioAttributes audioAttributes, boolean handleAudioFocus) -
    Description copied from interface: ExoPlayer.AudioComponent
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Sets the attributes for audio playback, used by the underlying audio track. If not set, the default audio attributes will be used. They are suitable for general media playback. @@ -1915,13 +1991,15 @@ public void removeAudioListener​(Util.getStreamTypeForAudioUsage(int). +

    If the device is running a build before platform API version 21, audio attributes cannot be + set directly on the underlying audio track. In this case, the usage will be mapped onto an + equivalent stream type using Util.getStreamTypeForAudioUsage(int).

    If audio focus should be handled, the AudioAttributes.usage must be C.USAGE_MEDIA or C.USAGE_GAME. Other usages will throw an IllegalArgumentException.

    Specified by:
    +
    setAudioAttributes in interface ExoPlayer
    +
    Specified by:
    setAudioAttributes in interface ExoPlayer.AudioComponent
    Parameters:
    audioAttributes - The attributes to use for audio playback.
    @@ -1936,6 +2014,7 @@ public void removeAudioListener​(

    getAudioAttributes

    public AudioAttributes getAudioAttributes()
    +
    Deprecated.
    Description copied from interface: Player
    Returns the attributes for audio playback.
    @@ -1953,17 +2032,20 @@ public void removeAudioListener​(

    setAudioSessionId

    public void setAudioSessionId​(int audioSessionId)
    -
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Sets the ID of the audio session to attach to the underlying AudioTrack. -

    The audio session ID can be generated using C.generateAudioSessionIdV21(Context) +

    The audio session ID can be generated using Util.generateAudioSessionIdV21(Context) for API 21+.

    Specified by:
    +
    setAudioSessionId in interface ExoPlayer
    +
    Specified by:
    setAudioSessionId in interface ExoPlayer.AudioComponent
    Parameters:
    -
    audioSessionId - The audio session ID, or C.AUDIO_SESSION_ID_UNSET if it should - be generated by the framework.
    +
    audioSessionId - The audio session ID, or C.AUDIO_SESSION_ID_UNSET if it should be + generated by the framework.
  • @@ -1974,10 +2056,13 @@ public void removeAudioListener​(

    getAudioSessionId

    public int getAudioSessionId()
    -
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Returns the audio session identifier, or C.AUDIO_SESSION_ID_UNSET if not set.
    Specified by:
    +
    getAudioSessionId in interface ExoPlayer
    +
    Specified by:
    getAudioSessionId in interface ExoPlayer.AudioComponent
    @@ -1989,10 +2074,13 @@ public void removeAudioListener​(

    setAuxEffectInfo

    public void setAuxEffectInfo​(AuxEffectInfo auxEffectInfo)
    -
    Description copied from interface: ExoPlayer.AudioComponent
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Sets information on an auxiliary audio effect to attach to the underlying audio track.
    Specified by:
    +
    setAuxEffectInfo in interface ExoPlayer
    +
    Specified by:
    setAuxEffectInfo in interface ExoPlayer.AudioComponent
    @@ -2004,10 +2092,13 @@ public void removeAudioListener​(

    clearAuxEffectInfo

    public void clearAuxEffectInfo()
    -
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Detaches any previously attached auxiliary audio effect from the underlying audio track.
    Specified by:
    +
    clearAuxEffectInfo in interface ExoPlayer
    +
    Specified by:
    clearAuxEffectInfo in interface ExoPlayer.AudioComponent
    @@ -2018,16 +2109,18 @@ public void removeAudioListener​(
  • setVolume

    -
    public void setVolume​(float audioVolume)
    +
    public void setVolume​(float volume)
    +
    Deprecated.
    -
    Sets the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
    +
    Sets the audio volume, valid values are between 0 (silence) and 1 (unity gain, signal + unchanged), inclusive.
    Specified by:
    setVolume in interface ExoPlayer.AudioComponent
    Specified by:
    setVolume in interface Player
    Parameters:
    -
    audioVolume - Linear output gain to apply to all audio channels.
    +
    volume - Linear output gain to apply to all audio channels.
  • @@ -2038,6 +2131,7 @@ public void removeAudioListener​(

    getVolume

    public float getVolume()
    +
    Deprecated.
    Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
    @@ -2057,10 +2151,13 @@ public void removeAudioListener​(

    getSkipSilenceEnabled

    public boolean getSkipSilenceEnabled()
    -
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Returns whether skipping silences in the audio stream is enabled.
    Specified by:
    +
    getSkipSilenceEnabled in interface ExoPlayer
    +
    Specified by:
    getSkipSilenceEnabled in interface ExoPlayer.AudioComponent
    @@ -2072,10 +2169,13 @@ public void removeAudioListener​(

    setSkipSilenceEnabled

    public void setSkipSilenceEnabled​(boolean skipSilenceEnabled)
    -
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Sets whether skipping silences in the audio stream is enabled.
    Specified by:
    +
    setSkipSilenceEnabled in interface ExoPlayer
    +
    Specified by:
    setSkipSilenceEnabled in interface ExoPlayer.AudioComponent
    Parameters:
    skipSilenceEnabled - Whether skipping silences in the audio stream is enabled.
    @@ -2089,7 +2189,13 @@ public void removeAudioListener​(

    getAnalyticsCollector

    public AnalyticsCollector getAnalyticsCollector()
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Returns the AnalyticsCollector used for collecting analytics events.
    +
    +
    Specified by:
    +
    getAnalyticsCollector in interface ExoPlayer
    +
    @@ -2099,8 +2205,12 @@ public void removeAudioListener​(

    addAnalyticsListener

    public void addAnalyticsListener​(AnalyticsListener listener)
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Adds an AnalyticsListener to receive analytics events.
    +
    Specified by:
    +
    addAnalyticsListener in interface ExoPlayer
    Parameters:
    listener - The listener to be added.
    @@ -2113,8 +2223,12 @@ public void removeAudioListener​(

    removeAnalyticsListener

    public void removeAnalyticsListener​(AnalyticsListener listener)
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Removes an AnalyticsListener.
    +
    Specified by:
    +
    removeAnalyticsListener in interface ExoPlayer
    Parameters:
    listener - The listener to be removed.
    @@ -2127,10 +2241,14 @@ public void removeAudioListener​(

    setHandleAudioBecomingNoisy

    public void setHandleAudioBecomingNoisy​(boolean handleAudioBecomingNoisy)
    +
    Deprecated.
    +
    Sets whether the player should pause automatically when audio is rerouted from a headset to device speakers. See the audio becoming noisy documentation for more information.
    +
    Specified by:
    +
    setHandleAudioBecomingNoisy in interface ExoPlayer
    Parameters:
    handleAudioBecomingNoisy - Whether the player should pause automatically when audio is rerouted from a headset to device speakers.
    @@ -2145,10 +2263,14 @@ public void removeAudioListener​(public void setPriorityTaskManager​(@Nullable PriorityTaskManager priorityTaskManager) +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Sets a PriorityTaskManager, or null to clear a previously set priority task manager.

    The priority C.PRIORITY_PLAYBACK will be set while the player is loading.

    +
    Specified by:
    +
    setPriorityTaskManager in interface ExoPlayer
    Parameters:
    priorityTaskManager - The PriorityTaskManager, or null to clear a previously set priority task manager.
    @@ -2163,7 +2285,13 @@ public void removeAudioListener​(@Nullable public Format getVideoFormat() +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Returns the video format currently being played, or null if no video is being played.
    +
    +
    Specified by:
    +
    getVideoFormat in interface ExoPlayer
    +
    @@ -2174,7 +2302,13 @@ public getAudioFormat
    @Nullable
     public Format getAudioFormat()
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Returns the audio format currently being played, or null if no audio is being played.
    +
    +
    Specified by:
    +
    getAudioFormat in interface ExoPlayer
    +
    @@ -2185,7 +2319,13 @@ public getVideoDecoderCounters
    @Nullable
     public DecoderCounters getVideoDecoderCounters()
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Returns DecoderCounters for video, or null if no video is being played.
    +
    +
    Specified by:
    +
    getVideoDecoderCounters in interface ExoPlayer
    +
    @@ -2196,44 +2336,12 @@ public @Nullable public DecoderCounters getAudioDecoderCounters() +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Returns DecoderCounters for audio, or null if no audio is being played.
    - - - - - - - - - - @@ -2244,7 +2352,8 @@ public void removeVideoListener​(

    setVideoFrameMetadataListener

    public void setVideoFrameMetadataListener​(VideoFrameMetadataListener listener)
    -
    Description copied from interface: ExoPlayer.VideoComponent
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Sets a listener to receive video frame metadata events.

    This method is intended to be called by the same component that sets the Surface @@ -2252,6 +2361,8 @@ public void removeVideoListener​(Specified by: +

    setVideoFrameMetadataListener in interface ExoPlayer
    +
    Specified by:
    setVideoFrameMetadataListener in interface ExoPlayer.VideoComponent
    Parameters:
    listener - The listener.
    @@ -2265,11 +2376,14 @@ public void removeVideoListener​(

    clearVideoFrameMetadataListener

    public void clearVideoFrameMetadataListener​(VideoFrameMetadataListener listener)
    -
    Description copied from interface: ExoPlayer.VideoComponent
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Clears the listener which receives video frame metadata events if it matches the one passed. Else does nothing.
    Specified by:
    +
    clearVideoFrameMetadataListener in interface ExoPlayer
    +
    Specified by:
    clearVideoFrameMetadataListener in interface ExoPlayer.VideoComponent
    Parameters:
    listener - The listener to clear.
    @@ -2283,10 +2397,13 @@ public void removeVideoListener​(

    setCameraMotionListener

    public void setCameraMotionListener​(CameraMotionListener listener)
    -
    Description copied from interface: ExoPlayer.VideoComponent
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    Sets a listener of camera motion events.
    Specified by:
    +
    setCameraMotionListener in interface ExoPlayer
    +
    Specified by:
    setCameraMotionListener in interface ExoPlayer.VideoComponent
    Parameters:
    listener - The listener.
    @@ -2300,55 +2417,20 @@ public void removeVideoListener​(

    clearCameraMotionListener

    public void clearCameraMotionListener​(CameraMotionListener listener)
    -
    Description copied from interface: ExoPlayer.VideoComponent
    -
    Clears the listener which receives camera motion events if it matches the one passed. Else - does nothing.
    +
    Deprecated.
    +
    Description copied from interface: ExoPlayer
    +
    Clears the listener which receives camera motion events if it matches the one passed. Else does + nothing.
    Specified by:
    +
    clearCameraMotionListener in interface ExoPlayer
    +
    Specified by:
    clearCameraMotionListener in interface ExoPlayer.VideoComponent
    Parameters:
    listener - The listener to clear.
    - - - - - - - - @@ -2356,6 +2438,7 @@ public void removeTextOutput​(

    getCurrentCues

    public List<Cue> getCurrentCues()
    +
    Deprecated.
    Description copied from interface: Player
    Returns the current Cues. This list may be empty.
    @@ -2366,44 +2449,6 @@ public void removeTextOutput​( - - - - - - - - @@ -2411,6 +2456,7 @@ public void removeMetadataOutput​(

    getPlaybackLooper

    public Looper getPlaybackLooper()
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Returns the Looper associated with the playback thread.
    @@ -2426,6 +2472,7 @@ public void removeMetadataOutput​(

    getApplicationLooper

    public Looper getApplicationLooper()
    +
    Deprecated.
    Description copied from interface: Player
    Returns the Looper associated with the application thread that's used to access the player and on which player events are received.
    @@ -2442,6 +2489,7 @@ public void removeMetadataOutput​(

    getClock

    public Clock getClock()
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Returns the Clock used for playback.
    @@ -2457,12 +2505,11 @@ public void removeMetadataOutput​(

    addListener

    public void addListener​(Player.Listener listener)
    +
    Deprecated.
    Description copied from interface: Player
    Registers a listener to receive all events from the player. -

    The listener's methods will be called on the thread that was used to construct the player. - However, if the thread used to construct the player does not have a Looper, then the - listener will be called on the main thread.

    +

    The listener's methods will be called on the thread associated with Player.getApplicationLooper().

    Specified by:
    addListener in interface Player
    @@ -2480,15 +2527,13 @@ public void removeMetadataOutput​(@Deprecated public void addListener​(Player.EventListener listener)
    Deprecated.
    -
    Description copied from interface: Player
    +
    Description copied from interface: ExoPlayer
    Registers a listener to receive events from the player. -

    The listener's methods will be called on the thread that was used to construct the player. - However, if the thread used to construct the player does not have a Looper, then the - listener will be called on the main thread.

    +

    The listener's methods will be called on the thread associated with Player.getApplicationLooper().

    Specified by:
    -
    addListener in interface Player
    +
    addListener in interface ExoPlayer
    Parameters:
    listener - The listener to register.
    @@ -2501,6 +2546,7 @@ public void addListener​(

    removeListener

    public void removeListener​(Player.Listener listener)
    +
    Deprecated.
    Description copied from interface: Player
    Unregister a listener registered through Player.addListener(Listener). The listener will no longer receive events.
    @@ -2521,12 +2567,12 @@ public void addListener​(@Deprecated public void removeListener​(Player.EventListener listener)
    Deprecated.
    -
    Description copied from interface: Player
    -
    Unregister a listener registered through Player.addListener(EventListener). The listener will +
    Description copied from interface: ExoPlayer
    +
    Unregister a listener registered through ExoPlayer.addListener(EventListener). The listener will no longer receive events from the player.
    Specified by:
    -
    removeListener in interface Player
    +
    removeListener in interface ExoPlayer
    Parameters:
    listener - The listener to unregister.
    @@ -2539,7 +2585,8 @@ public void removeListener​(

    getPlaybackState

    @State
    -public int getPlaybackState()
    +public @com.google.android.exoplayer2.Player.State int getPlaybackState() +
    Deprecated.
    Description copied from interface: Player
    Returns the current playback state of the player.
    @@ -2548,7 +2595,7 @@ public int getPlaybackState()
    Returns:
    The current playback state.
    See Also:
    -
    Player.Listener.onPlaybackStateChanged(int)
    +
    Player.Listener.onPlaybackStateChanged(int)
    @@ -2559,7 +2606,8 @@ public int getPlaybackState()
  • getPlaybackSuppressionReason

    @PlaybackSuppressionReason
    -public int getPlaybackSuppressionReason()
    +public @com.google.android.exoplayer2.Player.PlaybackSuppressionReason int getPlaybackSuppressionReason() +
    Deprecated.
    Description copied from interface: Player
    Returns the reason why playback is suppressed even though Player.getPlayWhenReady() is true, or Player.PLAYBACK_SUPPRESSION_REASON_NONE if playback is not suppressed.
    @@ -2569,7 +2617,7 @@ public int getPlaybackSuppressionReason()
    Returns:
    The current playback suppression reason.
    See Also:
    -
    Player.Listener.onPlaybackSuppressionReasonChanged(int)
    +
    Player.Listener.onPlaybackSuppressionReasonChanged(int)
  • @@ -2581,6 +2629,7 @@ public int getPlaybackSuppressionReason()

    getPlayerError

    @Nullable
     public ExoPlaybackException getPlayerError()
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Equivalent to Player.getPlayerError(), except the exception is guaranteed to be an ExoPlaybackException.
    @@ -2620,18 +2669,18 @@ public void retry()
  • getAvailableCommands

    public Player.Commands getAvailableCommands()
    +
    Deprecated.
    Description copied from interface: Player
    Returns the player's currently available Player.Commands.

    The returned Player.Commands are not updated when available commands change. Use Player.Listener.onAvailableCommandsChanged(Commands) to get an update when the available commands change. -

    Executing a command that is not available (for example, calling Player.seekToNextWindow() - if Player.COMMAND_SEEK_TO_NEXT_WINDOW is unavailable) will neither throw an exception nor - generate a Player.getPlayerError() player error}. +

    Executing a command that is not available (for example, calling Player.seekToNextMediaItem() if Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM is unavailable) will + neither throw an exception nor generate a Player.getPlayerError() player error}. -

    Player.COMMAND_SEEK_TO_PREVIOUS_WINDOW and Player.COMMAND_SEEK_TO_NEXT_WINDOW are - unavailable if there is no such MediaItem.

    +

    Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM and Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM + are unavailable if there is no such MediaItem.

    Specified by:
    getAvailableCommands in interface Player
    @@ -2649,6 +2698,7 @@ public void retry()
  • prepare

    public void prepare()
    +
    Deprecated.
    Description copied from interface: Player
    Prepares the player.
    @@ -2702,6 +2752,7 @@ public void prepare​(public void setMediaItems​(List<MediaItem> mediaItems, boolean resetPosition) +
    Deprecated.
    Description copied from interface: Player
    Clears the playlist and adds the specified MediaItems.
    @@ -2711,7 +2762,7 @@ public void prepare​(MediaItems.
    resetPosition - Whether the playback position should be reset to the default position in the first Timeline.Window. If false, playback will start from the position defined - by Player.getCurrentWindowIndex() and Player.getCurrentPosition().
    + by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition().
  • @@ -2722,8 +2773,9 @@ public void prepare​(

    setMediaItems

    public void setMediaItems​(List<MediaItem> mediaItems,
    -                          int startWindowIndex,
    +                          int startIndex,
                               long startPositionMs)
    +
    Deprecated.
    Description copied from interface: Player
    Clears the playlist and adds the specified MediaItems.
    @@ -2731,11 +2783,11 @@ public void prepare​(setMediaItems in interface Player
    Parameters:
    mediaItems - The new MediaItems.
    -
    startWindowIndex - The window index to start playback from. If C.INDEX_UNSET is - passed, the current position is not reset.
    -
    startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given window is used. In any case, if - startWindowIndex is set to C.INDEX_UNSET, this parameter is ignored and the - position is not reset at all.
    +
    startIndex - The MediaItem index to start playback from. If C.INDEX_UNSET + is passed, the current position is not reset.
    +
    startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given MediaItem is used. In + any case, if startIndex is set to C.INDEX_UNSET, this parameter is ignored + and the position is not reset at all.
  • @@ -2746,6 +2798,7 @@ public void prepare​(

    setMediaSources

    public void setMediaSources​(List<MediaSource> mediaSources)
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Clears the playlist, adds the specified MediaSources and resets the position to the default position.
    @@ -2765,6 +2818,7 @@ public void prepare​(public void setMediaSources​(List<MediaSource> mediaSources, boolean resetPosition) +
    Deprecated.
    Description copied from interface: ExoPlayer
    Clears the playlist and adds the specified MediaSources.
    @@ -2774,7 +2828,7 @@ public void prepare​(MediaSources.
    resetPosition - Whether the playback position should be reset to the default position in the first Timeline.Window. If false, playback will start from the position defined - by Player.getCurrentWindowIndex() and Player.getCurrentPosition().
    + by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition().
    @@ -2785,8 +2839,9 @@ public void prepare​(

    setMediaSources

    public void setMediaSources​(List<MediaSource> mediaSources,
    -                            int startWindowIndex,
    +                            int startMediaItemIndex,
                                 long startPositionMs)
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Clears the playlist and adds the specified MediaSources.
    @@ -2794,11 +2849,10 @@ public void prepare​(setMediaSources in interface ExoPlayer
    Parameters:
    mediaSources - The new MediaSources.
    -
    startWindowIndex - The window index to start playback from. If C.INDEX_UNSET is - passed, the current position is not reset.
    -
    startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given window is used. In any case, if - startWindowIndex is set to C.INDEX_UNSET, this parameter is ignored and the - position is not reset at all.
    +
    startMediaItemIndex - The media item index to start playback from. If C.INDEX_UNSET is passed, the current position is not reset.
    +
    startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given media item is used. In any case, + if startMediaItemIndex is set to C.INDEX_UNSET, this parameter is ignored + and the position is not reset at all.
    @@ -2809,6 +2863,7 @@ public void prepare​(

    setMediaSource

    public void setMediaSource​(MediaSource mediaSource)
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Clears the playlist, adds the specified MediaSource and resets the position to the default position.
    @@ -2828,6 +2883,7 @@ public void prepare​(public void setMediaSource​(MediaSource mediaSource, boolean resetPosition) +
    Deprecated.
    Description copied from interface: ExoPlayer
    Clears the playlist and adds the specified MediaSource.
    @@ -2836,7 +2892,7 @@ public void prepare​(Parameters:
    mediaSource - The new MediaSource.
    resetPosition - Whether the playback position should be reset to the default position. If - false, playback will start from the position defined by Player.getCurrentWindowIndex() + false, playback will start from the position defined by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition().
    @@ -2849,6 +2905,7 @@ public void prepare​(public void setMediaSource​(MediaSource mediaSource, long startPositionMs) +
    Deprecated.
    Description copied from interface: ExoPlayer
    Clears the playlist and adds the specified MediaSource.
    @@ -2868,6 +2925,7 @@ public void prepare​(public void addMediaItems​(int index, List<MediaItem> mediaItems) +
    Deprecated.
    Description copied from interface: Player
    Adds a list of media items at the given index of the playlist.
    @@ -2887,6 +2945,7 @@ public void prepare​(

    addMediaSource

    public void addMediaSource​(MediaSource mediaSource)
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Adds a media source to the end of the playlist.
    @@ -2905,6 +2964,7 @@ public void prepare​(public void addMediaSource​(int index, MediaSource mediaSource) +
    Deprecated.
    Description copied from interface: ExoPlayer
    Adds a media source at the given index of the playlist.
    @@ -2923,6 +2983,7 @@ public void prepare​(

    addMediaSources

    public void addMediaSources​(List<MediaSource> mediaSources)
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Adds a list of media sources to the end of the playlist.
    @@ -2941,6 +3002,7 @@ public void prepare​(public void addMediaSources​(int index, List<MediaSource> mediaSources) +
    Deprecated.
    Description copied from interface: ExoPlayer
    Adds a list of media sources at the given index of the playlist.
    @@ -2961,6 +3023,7 @@ public void prepare​(public void moveMediaItems​(int fromIndex, int toIndex, int newIndex) +
    Deprecated.
    Moves the media item range to the new index.
    @@ -2983,6 +3046,7 @@ public void prepare​(public void removeMediaItems​(int fromIndex, int toIndex) +
    Deprecated.
    Removes a range of media items from the playlist.
    @@ -3002,6 +3066,7 @@ public void prepare​(

    setShuffleOrder

    public void setShuffleOrder​(ShuffleOrder shuffleOrder)
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Sets the shuffle order.
    @@ -3019,6 +3084,7 @@ public void prepare​(

    setPlayWhenReady

    public void setPlayWhenReady​(boolean playWhenReady)
    +
    Deprecated.
    Sets whether playback should proceed when Player.getPlaybackState() == Player.STATE_READY. @@ -3038,6 +3104,7 @@ public void prepare​(

    getPlayWhenReady

    public boolean getPlayWhenReady()
    +
    Deprecated.
    Whether playback will proceed when Player.getPlaybackState() == Player.STATE_READY.
    @@ -3046,7 +3113,7 @@ public void prepare​(Returns:
    Whether playback will proceed when ready.
    See Also:
    -
    Player.Listener.onPlayWhenReadyChanged(boolean, int)
    +
    Player.Listener.onPlayWhenReadyChanged(boolean, int)
    @@ -3057,10 +3124,11 @@ public void prepare​(

    setPauseAtEndOfMediaItems

    public void setPauseAtEndOfMediaItems​(boolean pauseAtEndOfMediaItems)
    +
    Deprecated.
    Sets whether to pause playback at the end of each media item. -

    This means the player will pause at the end of each window in the current timeline. Listeners will be informed by a call to Player.Listener.onPlayWhenReadyChanged(boolean, int) with the reason Player.PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM when this happens.

    +

    This means the player will pause at the end of each window in the current timeline. Listeners will be informed by a call to Player.Listener.onPlayWhenReadyChanged(boolean, int) with the reason Player.PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM when this happens.

    Specified by:
    setPauseAtEndOfMediaItems in interface ExoPlayer
    @@ -3076,6 +3144,7 @@ public void prepare​(

    getPauseAtEndOfMediaItems

    public boolean getPauseAtEndOfMediaItems()
    +
    Deprecated.
    Returns whether the player pauses playback at the end of each media item.
    @@ -3093,7 +3162,8 @@ public void prepare​(

    getRepeatMode

    @RepeatMode
    -public int getRepeatMode()
    +public @com.google.android.exoplayer2.Player.RepeatMode int getRepeatMode() +
    Deprecated.
    Description copied from interface: Player
    Returns the current Player.RepeatMode used for playback.
    @@ -3102,23 +3172,24 @@ public int getRepeatMode()
    Returns:
    The current repeat mode.
    See Also:
    -
    Player.Listener.onRepeatModeChanged(int)
    +
    Player.Listener.onRepeatModeChanged(int)
    - +
    • setRepeatMode

      public void setRepeatMode​(@RepeatMode
      -                          int repeatMode)
      -
      Description copied from interface: Player
      + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode) +
      Deprecated.
      +
      Description copied from interface: Player
      Sets the Player.RepeatMode to be used for playback.
      Specified by:
      -
      setRepeatMode in interface Player
      +
      setRepeatMode in interface Player
      Parameters:
      repeatMode - The repeat mode.
      @@ -3131,8 +3202,9 @@ public int getRepeatMode()
    • setShuffleModeEnabled

      public void setShuffleModeEnabled​(boolean shuffleModeEnabled)
      +
      Deprecated.
      Description copied from interface: Player
      -
      Sets whether shuffling of windows is enabled.
      +
      Sets whether shuffling of media items is enabled.
      Specified by:
      setShuffleModeEnabled in interface Player
      @@ -3148,8 +3220,9 @@ public int getRepeatMode()
    • getShuffleModeEnabled

      public boolean getShuffleModeEnabled()
      +
      Deprecated.
      Description copied from interface: Player
      -
      Returns whether shuffling of windows is enabled.
      +
      Returns whether shuffling of media items is enabled.
      Specified by:
      getShuffleModeEnabled in interface Player
      @@ -3165,6 +3238,7 @@ public int getRepeatMode()
    • isLoading

      public boolean isLoading()
      +
      Deprecated.
      Description copied from interface: Player
      Whether the player is currently loading the source.
      @@ -3183,17 +3257,18 @@ public int getRepeatMode()
      • seekTo

        -
        public void seekTo​(int windowIndex,
        +
        public void seekTo​(int mediaItemIndex,
                            long positionMs)
        +
        Deprecated.
        Description copied from interface: Player
        -
        Seeks to a position specified in milliseconds in the specified window.
        +
        Seeks to a position specified in milliseconds in the specified MediaItem.
        Specified by:
        seekTo in interface Player
        Parameters:
        -
        windowIndex - The index of the window.
        -
        positionMs - The seek position in the specified window, or C.TIME_UNSET to seek to - the window's default position.
        +
        mediaItemIndex - The index of the MediaItem.
        +
        positionMs - The seek position in the specified MediaItem, or C.TIME_UNSET + to seek to the media item's default position.
      @@ -3204,6 +3279,7 @@ public int getRepeatMode()
    • getSeekBackIncrement

      public long getSeekBackIncrement()
      +
      Deprecated.
      Description copied from interface: Player
      Returns the Player.seekBack() increment.
      @@ -3223,6 +3299,7 @@ public int getRepeatMode()
    • getSeekForwardIncrement

      public long getSeekForwardIncrement()
      +
      Deprecated.
      Description copied from interface: Player
      Returns the Player.seekForward() increment.
      @@ -3241,17 +3318,17 @@ public int getRepeatMode() @@ -3262,6 +3339,7 @@ public int getRepeatMode()
    • setPlaybackParameters

      public void setPlaybackParameters​(PlaybackParameters playbackParameters)
      +
      Deprecated.
      Description copied from interface: Player
      Attempts to set the playback parameters. Passing PlaybackParameters.DEFAULT resets the player to the default, which means there is no speed or pitch adjustment. @@ -3283,6 +3361,7 @@ public int getRepeatMode()
    • getPlaybackParameters

      public PlaybackParameters getPlaybackParameters()
      +
      Deprecated.
      Description copied from interface: Player
      Returns the currently active playback parameters.
      @@ -3301,6 +3380,7 @@ public int getRepeatMode()

      setSeekParameters

      public void setSeekParameters​(@Nullable
                                     SeekParameters seekParameters)
      +
      Deprecated.
      Description copied from interface: ExoPlayer
      Sets the parameters that control how seek operations are performed.
      @@ -3318,6 +3398,7 @@ public int getRepeatMode()
    • getSeekParameters

      public SeekParameters getSeekParameters()
      +
      Deprecated.
      Description copied from interface: ExoPlayer
      Returns the currently active SeekParameters of the player.
      @@ -3333,6 +3414,7 @@ public int getRepeatMode()
    • setForegroundMode

      public void setForegroundMode​(boolean foregroundMode)
      +
      Deprecated.
      Description copied from interface: ExoPlayer
      Sets whether the player is allowed to keep holding limited resources such as video decoders, even when in the idle state. By doing so, the player may be able to reduce latency when @@ -3366,6 +3448,30 @@ public int getRepeatMode()
    + + + +
      +
    • +

      stop

      +
      public void stop()
      +
      Deprecated.
      +
      Description copied from interface: Player
      +
      Stops playback without resetting the player. Use Player.pause() rather than this method if + the intention is to pause playback. + +

      Calling this method will cause the playback state to transition to Player.STATE_IDLE. The + player instance can still be used, and Player.release() must still be called on the player if + it's no longer required. + +

      Calling this method does not clear the playlist, reset the playback position or the playback + error.

      +
      +
      Specified by:
      +
      stop in interface Player
      +
      +
    • +
    @@ -3388,6 +3494,7 @@ public void stop​(boolean reset)
  • release

    public void release()
    +
    Deprecated.
    Description copied from interface: Player
    Releases the player. This method must be called when the player is no longer required. The player must not be used after calling this method.
    @@ -3404,12 +3511,13 @@ public void stop​(boolean reset)
  • createMessage

    public PlayerMessage createMessage​(PlayerMessage.Target target)
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Creates a message that can be sent to a PlayerMessage.Target. By default, the message will be delivered immediately without blocking on the playback thread. The default PlayerMessage.getType() is 0 and the default PlayerMessage.getPayload() is null. If a position is specified with PlayerMessage.setPosition(long), the message will be - delivered at this position in the current window defined by Player.getCurrentWindowIndex(). - Alternatively, the message can be sent at a specific window using PlayerMessage.setPosition(int, long).
    + delivered at this position in the current media item defined by Player.getCurrentMediaItemIndex(). Alternatively, the message can be sent at a specific mediaItem + using PlayerMessage.setPosition(int, long).
    Specified by:
    createMessage in interface ExoPlayer
    @@ -3423,6 +3531,7 @@ public void stop​(boolean reset)
  • getRendererCount

    public int getRendererCount()
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Returns the number of renderers.
    @@ -3437,7 +3546,8 @@ public void stop​(boolean reset)
    • getRendererType

      -
      public int getRendererType​(int index)
      +
      public @com.google.android.exoplayer2.C.TrackType int getRendererType​(int index)
      +
      Deprecated.
      Description copied from interface: ExoPlayer
      Returns the track type that the renderer at a given index handles. @@ -3449,7 +3559,7 @@ public void stop​(boolean reset)
      Parameters:
      index - The index of the renderer.
      Returns:
      -
      One of the TRACK_TYPE_* constants defined in C.
      +
      The track type that the renderer handles.
  • @@ -3461,6 +3571,7 @@ public void stop​(boolean reset)

    getTrackSelector

    @Nullable
     public TrackSelector getTrackSelector()
    +
    Deprecated.
    Description copied from interface: ExoPlayer
    Returns the track selector that this player uses, or null if track selection is not supported.
    @@ -3476,13 +3587,14 @@ public 

    getCurrentTrackGroups

    public TrackGroupArray getCurrentTrackGroups()
    +
    Deprecated.
    Description copied from interface: Player
    Returns the available track groups.
    Specified by:
    getCurrentTrackGroups in interface Player
    See Also:
    -
    Player.Listener.onTracksChanged(TrackGroupArray, TrackSelectionArray)
    +
    Player.EventListener.onTracksChanged(TrackGroupArray, TrackSelectionArray)
  • @@ -3493,6 +3605,7 @@ public 

    getCurrentTrackSelections

    public TrackSelectionArray getCurrentTrackSelections()
    +
    Deprecated.
    Description copied from interface: Player
    - + + + + + + + + +
      +
    • +

      setTrackSelectionParameters

      +
      public void setTrackSelectionParameters​(TrackSelectionParameters parameters)
      +
      Deprecated.
      +
      Description copied from interface: Player
      +
      Sets the parameters constraining the track selection. + +

      Unsupported parameters will be silently ignored. + +

      Use Player.getTrackSelectionParameters() to retrieve the current parameters. For example, + the following snippet restricts video to SD whilst keep other track selection parameters + unchanged: + +

      
      + player.setTrackSelectionParameters(
      +   player.getTrackSelectionParameters()
      +         .buildUpon()
      +         .setMaxVideoSizeSd()
      +         .build())
      + 
      +
      +
      Specified by:
      +
      setTrackSelectionParameters in interface Player
    @@ -3529,13 +3693,15 @@ public 

    getMediaMetadata

    public MediaMetadata getMediaMetadata()
    +
    Deprecated.
    Description copied from interface: Player
    Returns the current combined MediaMetadata, or MediaMetadata.EMPTY if not supported.

    This MediaMetadata is a combination of the MediaItem.mediaMetadata and the static and dynamic metadata from the track selections' - formats and MetadataOutput.onMetadata(Metadata).

    + formats and Player.Listener.onMetadata(Metadata). If a field is populated in the MediaItem.mediaMetadata, it will be prioritised above the same field coming from static or + dynamic metadata.
    Specified by:
    getMediaMetadata in interface Player
    @@ -3549,6 +3715,7 @@ public 

    getPlaylistMetadata

    public MediaMetadata getPlaylistMetadata()
    +
    Deprecated.
    Description copied from interface: Player
    Returns the playlist MediaMetadata, as set by Player.setPlaylistMetadata(MediaMetadata), or MediaMetadata.EMPTY if not supported.
    @@ -3564,6 +3731,7 @@ public 

    setPlaylistMetadata

    public void setPlaylistMetadata​(MediaMetadata mediaMetadata)
    +
    Deprecated.
    Description copied from interface: Player
    Sets the playlist MediaMetadata.
    @@ -3579,13 +3747,14 @@ public 

    getCurrentTimeline

    public Timeline getCurrentTimeline()
    +
    Deprecated.
    Description copied from interface: Player
    Returns the current Timeline. Never null, but may be empty.
    Specified by:
    getCurrentTimeline in interface Player
    See Also:
    -
    Player.Listener.onTimelineChanged(Timeline, int)
    +
    Player.Listener.onTimelineChanged(Timeline, int)
    @@ -3596,6 +3765,7 @@ public 

    getCurrentPeriodIndex

    public int getCurrentPeriodIndex()
    +
    Deprecated.
    Returns the index of the period currently being played.
    @@ -3604,18 +3774,20 @@ public  + @@ -3626,8 +3798,10 @@ public 

    getDuration

    public long getDuration()
    +
    Deprecated.
    -
    Returns the duration of the current content window or ad in milliseconds, or C.TIME_UNSET if the duration is not known.
    +
    Returns the duration of the current content or ad in milliseconds, or C.TIME_UNSET if + the duration is not known.
    Specified by:
    getDuration in interface Player
    @@ -3641,10 +3815,10 @@ public 

    getCurrentPosition

    public long getCurrentPosition()
    +
    Deprecated.
    -
    Returns the playback position in the current content window or ad, in milliseconds, or the - prospective position in milliseconds if the current timeline is - empty.
    +
    Returns the playback position in the current content or ad, in milliseconds, or the prospective + position in milliseconds if the current timeline is empty.
    Specified by:
    getCurrentPosition in interface Player
    @@ -3658,9 +3832,10 @@ public 

    getBufferedPosition

    public long getBufferedPosition()
    +
    Deprecated.
    -
    Returns an estimate of the position in the current content window or ad up to which data is - buffered, in milliseconds.
    +
    Returns an estimate of the position in the current content or ad up to which data is buffered, + in milliseconds.
    Specified by:
    getBufferedPosition in interface Player
    @@ -3674,9 +3849,10 @@ public 

    getTotalBufferedDuration

    public long getTotalBufferedDuration()
    +
    Deprecated.
    Returns an estimate of the total buffered duration from the current position, in milliseconds. - This includes pre-buffered data for subsequent ads and windows.
    + This includes pre-buffered data for subsequent ads and media items.
    Specified by:
    getTotalBufferedDuration in interface Player
    @@ -3690,6 +3866,7 @@ public 

    isPlayingAd

    public boolean isPlayingAd()
    +
    Deprecated.
    Returns whether the player is currently playing an ad.
    @@ -3705,6 +3882,7 @@ public 

    getCurrentAdGroupIndex

    public int getCurrentAdGroupIndex()
    +
    Deprecated.
    If Player.isPlayingAd() returns true, returns the index of the ad group in the period currently being played. Returns C.INDEX_UNSET otherwise.
    @@ -3721,6 +3899,7 @@ public 

    getCurrentAdIndexInAdGroup

    public int getCurrentAdIndexInAdGroup()
    +
    Deprecated.
    If Player.isPlayingAd() returns true, returns the index of the ad in its ad group. Returns C.INDEX_UNSET otherwise.
    @@ -3737,6 +3916,7 @@ public 

    getContentPosition

    public long getContentPosition()
    +
    Deprecated.
    If Player.isPlayingAd() returns true, returns the content position that will be played once all ads in the ad group have finished playing, in milliseconds. If there is no ad @@ -3754,10 +3934,11 @@ public 

    getContentBufferedPosition

    public long getContentBufferedPosition()
    +
    Deprecated.
    If Player.isPlayingAd() returns true, returns an estimate of the content position in - the current content window up to which data is buffered, in milliseconds. If there is no ad - playing, the returned position is the same as that returned by Player.getBufferedPosition().
    + the current content up to which data is buffered, in milliseconds. If there is no ad playing, + the returned position is the same as that returned by Player.getBufferedPosition().
    Specified by:
    getContentBufferedPosition in interface Player
    @@ -3772,31 +3953,23 @@ public @Deprecated public void setHandleWakeLock​(boolean handleWakeLock) -
    Deprecated. -
    Use setWakeMode(int) instead.
    -
    -
    Sets whether the player should use a PowerManager.WakeLock to ensure the - device stays awake for playback, even when the screen is off. - -

    Enabling this feature requires the Manifest.permission.WAKE_LOCK permission. - It should be used together with a foreground Service for use cases where - playback can occur when the screen is off (e.g. background audio playback). It is not useful if - the screen will always be on during playback (e.g. foreground video playback).

    +
    Deprecated.
    -
    Parameters:
    -
    handleWakeLock - Whether the player should use a PowerManager.WakeLock - to ensure the device stays awake for playback, even when the screen is off.
    +
    Specified by:
    +
    setHandleWakeLock in interface ExoPlayer
    - + - - - - - - - -
    - + - + @@ -627,7 +654,7 @@ implements Returns the number of windows in the timeline. - +
    @@ -1939,7 +1927,7 @@ public final void onStaticMetadataChanged​( + - - - - @@ -1495,7 +1467,7 @@ static final int EVENT_STATIC_METADATA_CHANGED
  • EVENT_POSITION_DISCONTINUITY

    static final int EVENT_POSITION_DISCONTINUITY
    - +
    See Also:
    Constant Field Values
    @@ -2157,7 +2129,7 @@ static final int EVENT_STATIC_METADATA_CHANGED

    Method Detail

    - + - + @@ -340,7 +340,7 @@ public final int usage
  • allowedCapturePolicy

    @AudioAllowedCapturePolicy
    -public final int allowedCapturePolicy
    +public final @com.google.android.exoplayer2.C.AudioAllowedCapturePolicy int allowedCapturePolicy
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/audio/AudioListener.html b/docs/doc/reference/com/google/android/exoplayer2/audio/AudioListener.html deleted file mode 100644 index 718a4fc3d8..0000000000 --- a/docs/doc/reference/com/google/android/exoplayer2/audio/AudioListener.html +++ /dev/null @@ -1,337 +0,0 @@ - - - - -AudioListener (ExoPlayer library) - - - - - - - - - - - - - -
    - -
    - -
    -
    - -

    Interface AudioListener

    -
    -
    -
    - -
    -
    - -
    -
    -
      -
    • - -
      -
        -
      • - - -

        Method Detail

        - - - -
          -
        • -

          onAudioSessionIdChanged

          -
          default void onAudioSessionIdChanged​(int audioSessionId)
          -
          Deprecated.
          -
          Called when the audio session ID changes.
          -
          -
          Parameters:
          -
          audioSessionId - The audio session ID.
          -
          -
        • -
        - - - -
          -
        • -

          onAudioAttributesChanged

          -
          default void onAudioAttributesChanged​(AudioAttributes audioAttributes)
          -
          Deprecated.
          -
          Called when the audio attributes change.
          -
          -
          Parameters:
          -
          audioAttributes - The audio attributes.
          -
          -
        • -
        - - - -
          -
        • -

          onVolumeChanged

          -
          default void onVolumeChanged​(float volume)
          -
          Deprecated.
          -
          Called when the volume changes.
          -
          -
          Parameters:
          -
          volume - The new volume, with 0 being silence and 1 being unity gain.
          -
          -
        • -
        - - - -
          -
        • -

          onSkipSilenceEnabledChanged

          -
          default void onSkipSilenceEnabledChanged​(boolean skipSilenceEnabled)
          -
          Deprecated.
          -
          Called when skipping silences is enabled or disabled in the audio stream.
          -
          -
          Parameters:
          -
          skipSilenceEnabled - Whether skipping silences in the audio stream is enabled.
          -
          -
        • -
        -
      • -
      -
      -
    • -
    -
    -
    -
    - -
    - -
    - - diff --git a/docs/doc/reference/com/google/android/exoplayer2/audio/AudioProcessor.html b/docs/doc/reference/com/google/android/exoplayer2/audio/AudioProcessor.html index eecefafcb3..2297eca1dd 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/audio/AudioProcessor.html +++ b/docs/doc/reference/com/google/android/exoplayer2/audio/AudioProcessor.html @@ -122,7 +122,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • All Known Implementing Classes:
    -
    BaseAudioProcessor, GvrAudioProcessor, SilenceSkippingAudioProcessor, SonicAudioProcessor, TeeAudioProcessor
    +
    BaseAudioProcessor, SilenceSkippingAudioProcessor, SonicAudioProcessor, TeeAudioProcessor

    public interface AudioProcessor
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/audio/DecoderAudioRenderer.html b/docs/doc/reference/com/google/android/exoplayer2/audio/DecoderAudioRenderer.html index 88fb36940c..1ada9e6afa 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/audio/DecoderAudioRenderer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/audio/DecoderAudioRenderer.html @@ -114,7 +114,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    -

    Class DecoderAudioRenderer<T extends Decoder<DecoderInputBuffer,​? extends SimpleOutputBuffer,​? extends DecoderException>>

    +

    Class DecoderAudioRenderer<T extends Decoder<DecoderInputBuffer,​? extends SimpleDecoderOutputBuffer,​? extends DecoderException>>


  • -
    public abstract class DecoderAudioRenderer<T extends Decoder<DecoderInputBuffer,​? extends SimpleOutputBuffer,​? extends DecoderException>>
    +
    public abstract class DecoderAudioRenderer<T extends Decoder<DecoderInputBuffer,​? extends SimpleDecoderOutputBuffer,​? extends DecoderException>>
     extends BaseRenderer
     implements MediaClock
    Decodes and renders audio using a Decoder. @@ -154,8 +154,8 @@ implements Renderer.MSG_SET_VOLUME to set the volume. The message payload should be a Float with 0 being silence and 1 being unity gain.
  • Message with type Renderer.MSG_SET_AUDIO_ATTRIBUTES to set the audio attributes. The - message payload should be an AudioAttributes - instance that will configure the underlying audio track. + message payload should be an AudioAttributes instance that will configure the + underlying audio track.
  • Message with type Renderer.MSG_SET_AUX_EFFECT_INFO to set the auxiliary effect. The message payload should be an AuxEffectInfo instance that will configure the underlying audio track. @@ -183,7 +183,7 @@ implements Renderer -Renderer.State, Renderer.VideoScalingMode, Renderer.WakeupListener
  • +Renderer.MessageType, Renderer.State, Renderer.WakeupListener
  • - +

    -
    public final class ExoDatabaseProvider
    -extends SQLiteOpenHelper
    -implements DatabaseProvider
    -
    An SQLiteOpenHelper that provides instances of a standalone ExoPlayer database. - -

    Suitable for use by applications that do not already have their own database, or that would - prefer to keep ExoPlayer tables isolated in their own database. Other applications should prefer - to use DefaultDatabaseProvider with their own SQLiteOpenHelper.

    +
    @Deprecated
    +public final class ExoDatabaseProvider
    +extends StandaloneDatabaseProvider
    +
    Deprecated. + +
    @@ -159,21 +156,13 @@ implements -Fields  - -Modifier and Type -Field -Description - - -static String -DATABASE_NAME - -
    The file name used for the standalone ExoPlayer database.
    - - - +
    • @@ -200,8 +189,8 @@ implements ExoDatabaseProvider​(Context context) -
      Provides instances of the database located by passing DATABASE_NAME to Context.getDatabasePath(String).
      - +
      Deprecated.
    • @@ -214,33 +203,13 @@ implements -All Methods Instance Methods Concrete Methods  - -Modifier and Type -Method -Description - - -void -onCreate​(SQLiteDatabase db) -  - - -void -onDowngrade​(SQLiteDatabase db, - int oldVersion, - int newVersion) -  - - -void -onUpgrade​(SQLiteDatabase db, - int oldVersion, - int newVersion) -  - - + diff --git a/docs/doc/reference/com/google/android/exoplayer2/database/package-summary.html b/docs/doc/reference/com/google/android/exoplayer2/database/package-summary.html index b97fa9d159..a21d902eeb 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/database/package-summary.html +++ b/docs/doc/reference/com/google/android/exoplayer2/database/package-summary.html @@ -106,7 +106,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); DatabaseProvider -
      Provides SQLiteDatabase instances to ExoPlayer components, which may read and write +
      Provides SQLiteDatabase instances to media library components, which may read and write tables prefixed with DatabaseProvider.TABLE_PREFIX.
      @@ -129,14 +129,20 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); ExoDatabaseProvider - -
      An SQLiteOpenHelper that provides instances of a standalone ExoPlayer database.
      +Deprecated. + +StandaloneDatabaseProvider + +
      An SQLiteOpenHelper that provides instances of a standalone database.
      + + + VersionTable -
      Utility methods for accessing versions of ExoPlayer database components.
      +
      Utility methods for accessing versions of media library database components.
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/database/package-tree.html b/docs/doc/reference/com/google/android/exoplayer2/database/package-tree.html index f1e892e04c..4e0149de18 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/database/package-tree.html +++ b/docs/doc/reference/com/google/android/exoplayer2/database/package-tree.html @@ -106,7 +106,11 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    • com.google.android.exoplayer2.database.DefaultDatabaseProvider (implements com.google.android.exoplayer2.database.DatabaseProvider)
    • android.database.sqlite.SQLiteOpenHelper (implements java.lang.AutoCloseable)
    • java.lang.Throwable (implements java.io.Serializable) diff --git a/docs/doc/reference/com/google/android/exoplayer2/decoder/Buffer.html b/docs/doc/reference/com/google/android/exoplayer2/decoder/Buffer.html index 0c467e7bf2..9c9d6fa5c1 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/decoder/Buffer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/decoder/Buffer.html @@ -130,7 +130,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    • Direct Known Subclasses:
      -
      DecoderInputBuffer, OutputBuffer
      +
      DecoderInputBuffer, DecoderOutputBuffer

      public abstract class Buffer
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/drm/ExoMediaCrypto.html b/docs/doc/reference/com/google/android/exoplayer2/decoder/CryptoConfig.html
      similarity index 88%
      rename from docs/doc/reference/com/google/android/exoplayer2/drm/ExoMediaCrypto.html
      rename to docs/doc/reference/com/google/android/exoplayer2/decoder/CryptoConfig.html
      index 9e822c4669..618770cff3 100644
      --- a/docs/doc/reference/com/google/android/exoplayer2/drm/ExoMediaCrypto.html
      +++ b/docs/doc/reference/com/google/android/exoplayer2/decoder/CryptoConfig.html
      @@ -2,7 +2,7 @@
       
       
       
      -ExoMediaCrypto (ExoPlayer library)
      +CryptoConfig (ExoPlayer library)
       
       
       
      @@ -19,7 +19,7 @@
       
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - -
      - -
      -
      - -

      Class GvrAudioProcessor

      -
      -
      -
        -
      • java.lang.Object
      • -
      • -
          -
        • com.google.android.exoplayer2.ext.gvr.GvrAudioProcessor
        • -
        -
      • -
      -
      -
        -
      • -
        -
        All Implemented Interfaces:
        -
        AudioProcessor
        -
        -
        -
        @Deprecated
        -public class GvrAudioProcessor
        -extends Object
        -implements AudioProcessor
        -
        Deprecated. -
        If you still need this component, please contact us by filing an issue on our issue tracker.
        -
        -
        An AudioProcessor that uses GvrAudioSurround to provide binaural rendering of - surround sound and ambisonic soundfields.
        -
      • -
      -
      -
      - -
      -
      -
        -
      • - -
        -
          -
        • - - -

          Constructor Detail

          - - - -
            -
          • -

            GvrAudioProcessor

            -
            public GvrAudioProcessor()
            -
            Deprecated.
            -
            Creates a new GVR audio processor.
            -
          • -
          -
        • -
        -
        - -
        -
          -
        • - - -

          Method Detail

          - - - -
            -
          • -

            updateOrientation

            -
            public void updateOrientation​(float w,
            -                              float x,
            -                              float y,
            -                              float z)
            -
            Deprecated.
            -
            Updates the listener head orientation. May be called on any thread. See - GvrAudioSurround.updateNativeOrientation.
            -
            -
            Parameters:
            -
            w - The w component of the quaternion.
            -
            x - The x component of the quaternion.
            -
            y - The y component of the quaternion.
            -
            z - The z component of the quaternion.
            -
            -
          • -
          - - - - - - - -
            -
          • -

            isActive

            -
            public boolean isActive()
            -
            Deprecated.
            -
            Description copied from interface: AudioProcessor
            -
            Returns whether the processor is configured and will process input buffers.
            -
            -
            Specified by:
            -
            isActive in interface AudioProcessor
            -
            -
          • -
          - - - -
            -
          • -

            queueInput

            -
            public void queueInput​(ByteBuffer inputBuffer)
            -
            Deprecated.
            -
            Description copied from interface: AudioProcessor
            -
            Queues audio data between the position and limit of the input buffer for processing. - buffer must be a direct byte buffer with native byte order. Its contents are treated as - read-only. Its position will be advanced by the number of bytes consumed (which may be zero). - The caller retains ownership of the provided buffer. Calling this method invalidates any - previous buffer returned by AudioProcessor.getOutput().
            -
            -
            Specified by:
            -
            queueInput in interface AudioProcessor
            -
            Parameters:
            -
            inputBuffer - The input buffer to process.
            -
            -
          • -
          - - - - - - - -
            -
          • -

            getOutput

            -
            public ByteBuffer getOutput()
            -
            Deprecated.
            -
            Description copied from interface: AudioProcessor
            -
            Returns a buffer containing processed output data between its position and limit. The buffer - will always be a direct byte buffer with native byte order. Calling this method invalidates any - previously returned buffer. The buffer will be empty if no output is available.
            -
            -
            Specified by:
            -
            getOutput in interface AudioProcessor
            -
            Returns:
            -
            A buffer containing processed output data between its position and limit.
            -
            -
          • -
          - - - - - - - -
            -
          • -

            flush

            -
            public void flush()
            -
            Deprecated.
            -
            Description copied from interface: AudioProcessor
            -
            Clears any buffered data and pending output. If the audio processor is active, also prepares - the audio processor to receive a new stream of input in the last configured (pending) format.
            -
            -
            Specified by:
            -
            flush in interface AudioProcessor
            -
            -
          • -
          - - - -
            -
          • -

            reset

            -
            public void reset()
            -
            Deprecated.
            -
            Description copied from interface: AudioProcessor
            -
            Resets the processor to its unconfigured state, releasing any resources.
            -
            -
            Specified by:
            -
            reset in interface AudioProcessor
            -
            -
          • -
          -
        • -
        -
        -
      • -
      -
      -
      -
      - - - - diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/gvr/package-tree.html b/docs/doc/reference/com/google/android/exoplayer2/ext/gvr/package-tree.html deleted file mode 100644 index 3f23cccf8c..0000000000 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/gvr/package-tree.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - -com.google.android.exoplayer2.ext.gvr Class Hierarchy (ExoPlayer library) - - - - - - - - - - - - - -
      - -
      -
      -
      -

      Hierarchy For Package com.google.android.exoplayer2.ext.gvr

      -Package Hierarchies: - -
      -
      -
      -

      Class Hierarchy

      - -
      -
      -
      - - - diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.Builder.html b/docs/doc/reference/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.Builder.html index 4991086e65..6350170170 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.Builder.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.Builder.html @@ -570,7 +570,8 @@ extends
    • setVastLoadTimeoutMs

      -
      public ImaAdsLoader.Builder setVastLoadTimeoutMs​(int vastLoadTimeoutMs)
      +
      public ImaAdsLoader.Builder setVastLoadTimeoutMs​(@IntRange(from=1L)
      +                                                 int vastLoadTimeoutMs)
      Sets the VAST load timeout, in milliseconds.
      Parameters:
      @@ -588,7 +589,8 @@ extends
    • setMediaLoadTimeoutMs

      -
      public ImaAdsLoader.Builder setMediaLoadTimeoutMs​(int mediaLoadTimeoutMs)
      +
      public ImaAdsLoader.Builder setMediaLoadTimeoutMs​(@IntRange(from=1L)
      +                                                  int mediaLoadTimeoutMs)
      Sets the ad media load timeout, in milliseconds.
      Parameters:
      @@ -606,7 +608,8 @@ extends
    • setMaxMediaBitrate

      -
      public ImaAdsLoader.Builder setMaxMediaBitrate​(int bitrate)
      +
      public ImaAdsLoader.Builder setMaxMediaBitrate​(@IntRange(from=1L)
      +                                               int bitrate)
      Sets the media maximum recommended bitrate for ads, in bps.
      Parameters:
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.html b/docs/doc/reference/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.html index 3e436a4b9e..96e20ce38e 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.html @@ -130,7 +130,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    • All Implemented Interfaces:
      -
      AudioListener, DeviceListener, MetadataOutput, Player.EventListener, Player.Listener, AdsLoader, TextOutput, VideoListener
      +
      Player.EventListener, Player.Listener, AdsLoader

      public final class ImaAdsLoader
      @@ -248,16 +248,16 @@ implements 
       void
      -onPositionDiscontinuity​(Player.PositionInfo oldPosition,
      +onPositionDiscontinuity​(Player.PositionInfo oldPosition,
                              Player.PositionInfo newPosition,
      -                       int reason)
      +                       @com.google.android.exoplayer2.Player.DiscontinuityReason int reason)
       
       
      Called when a position discontinuity occurs.
      void -onRepeatModeChanged​(int repeatMode) +onRepeatModeChanged​(@com.google.android.exoplayer2.Player.RepeatMode int repeatMode)
      Called when the value of Player.getRepeatMode() changes.
      @@ -271,8 +271,8 @@ implements void -onTimelineChanged​(Timeline timeline, - int reason) +onTimelineChanged​(Timeline timeline, + @com.google.android.exoplayer2.Player.TimelineChangeReason int reason)
      Called when the timeline has been refreshed.
      @@ -346,21 +346,14 @@ implements Player.EventListener -onLoadingChanged, onMaxSeekToPreviousPositionChanged, onPlayerStateChanged, onPositionDiscontinuity, onSeekProcessed, onStaticMetadataChanged
    • +onLoadingChanged, onMaxSeekToPreviousPositionChanged, onPlayerStateChanged, onPositionDiscontinuity, onSeekProcessed, onTracksChanged, onTrackSelectionParametersChanged
    - @@ -611,7 +604,7 @@ public com.google.ads.interactivemedia.v3.api.AdDisplayContainer getAd
    - + - + - +
    @@ -341,22 +332,6 @@ implements - - -
      -
    • -

      setControlDispatcher

      -
      @Deprecated
      -public void setControlDispatcher​(@Nullable
      -                                 ControlDispatcher controlDispatcher)
      -
      Deprecated. -
      Use a ForwardingPlayer and pass it to the constructor instead. You can also - customize some operations when configuring the player (for example by using - SimpleExoPlayer.Builder#setSeekBackIncrementMs(long)).
      -
      -
    • -
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/media2/SessionPlayerConnector.html b/docs/doc/reference/com/google/android/exoplayer2/ext/media2/SessionPlayerConnector.html index fa266e8b50..a5cdbfe305 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/media2/SessionPlayerConnector.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/media2/SessionPlayerConnector.html @@ -25,8 +25,8 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":42,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10}; -var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10}; +var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; var tableTab = "tableTab"; @@ -226,7 +226,7 @@ extends androidx.media2.common.SessionPlayer

    Method Summary

    - + @@ -359,54 +359,45 @@ extends androidx.media2.common.SessionPlayer - - - - - - + - + - + - + - + - + - + - + @@ -483,21 +474,6 @@ extends androidx.media2.common.SessionPlayer

    Method Detail

    - - - -
      -
    • -

      setControlDispatcher

      -
      @Deprecated
      -public void setControlDispatcher​(ControlDispatcher controlDispatcher)
      -
      Deprecated. -
      Use a ForwardingPlayer and pass it to the constructor instead. You can also - customize some operations when configuring the player (for example by using - SimpleExoPlayer.Builder#setSeekBackIncrementMs(long)).
      -
      -
    • -
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CaptionCallback.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CaptionCallback.html index 0ff56a6951..51355279c2 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CaptionCallback.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CaptionCallback.html @@ -173,7 +173,7 @@ extends MediaSessionConnector.CommandReceiver -onCommand +onCommand diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CommandReceiver.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CommandReceiver.html index b23a996932..1a33f40bc2 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CommandReceiver.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CommandReceiver.html @@ -157,8 +157,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); - @@ -183,15 +182,13 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

    Method Detail

    - +
    • onCommand

      boolean onCommand​(Player player,
      -                  @Deprecated
      -                  ControlDispatcher controlDispatcher,
                         String command,
                         @Nullable
                         Bundle extras,
      @@ -202,10 +199,6 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
       
      Parameters:
      player - The player connected to the media session.
      -
      controlDispatcher - This parameter is deprecated. Use player instead. Operations - can be customized by passing a ForwardingPlayer to MediaSessionConnector.setPlayer(Player), or - when configuring the player (for example by using - SimpleExoPlayer.Builder#setSeekBackIncrementMs(long)).
      command - The command name.
      extras - Optional parameters for the command, may be null.
      cb - A result receiver to which a result may be sent by the command, may be null.
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CustomActionProvider.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CustomActionProvider.html index 548598963a..73b017ab5f 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CustomActionProvider.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.CustomActionProvider.html @@ -163,8 +163,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    - - + @@ -195,32 +195,29 @@ extends - - + + - + - + - - + @@ -291,7 +291,7 @@ extends - - - + - + - - + - - - - - - - + + + + + @@ -226,21 +225,22 @@ extends

    Method Detail

    - +
    • setLibraries

      -
      public static void setLibraries​(Class<? extends ExoMediaCrypto> exoMediaCryptoType,
      +
      public static void setLibraries​(@com.google.android.exoplayer2.C.CryptoType int cryptoType,
                                       String... libraries)
      Override the names of the Vpx native libraries. If an application wishes to call this method, it must do so before calling any other method defined by this class, and before instantiating a LibvpxVideoRenderer instance.
      Parameters:
      -
      exoMediaCryptoType - The ExoMediaCrypto type required for decoding protected - content.
      +
      cryptoType - The C.CryptoType for which the decoder library supports decrypting + protected content, or C.CRYPTO_TYPE_UNSUPPORTED if the library does not support + decryption.
      libraries - The names of the Vpx native libraries.
    • @@ -288,15 +288,14 @@ public static Returns true if the underlying libvpx library supports high bit depth.
    - +
    • -

      matchesExpectedExoMediaCryptoType

      -
      public static boolean matchesExpectedExoMediaCryptoType​(Class<? extends ExoMediaCrypto> exoMediaCryptoType)
      -
      Returns whether the given ExoMediaCrypto type matches the one required for decoding - protected content.
      +

      supportsCryptoType

      +
      public static boolean supportsCryptoType​(@com.google.android.exoplayer2.C.CryptoType int cryptoType)
      +
      Returns whether the library supports the given C.CryptoType.
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/workmanager/WorkManagerScheduler.SchedulerWorker.html b/docs/doc/reference/com/google/android/exoplayer2/ext/workmanager/WorkManagerScheduler.SchedulerWorker.html index 19fe7b10c4..a8562a193b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/workmanager/WorkManagerScheduler.SchedulerWorker.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/workmanager/WorkManagerScheduler.SchedulerWorker.html @@ -223,7 +223,7 @@ extends androidx.work.Worker

    Methods inherited from class androidx.work.ListenableWorker

    -getApplicationContext, getBackgroundExecutor, getId, getInputData, getNetwork, getRunAttemptCount, getTags, getTaskExecutor, getTriggeredContentAuthorities, getTriggeredContentUris, getWorkerFactory, isRunInForeground, isStopped, isUsed, onStopped, setForegroundAsync, setProgressAsync, setUsed, stop +getApplicationContext, getBackgroundExecutor, getForegroundInfoAsync, getId, getInputData, getNetwork, getRunAttemptCount, getTags, getTaskExecutor, getTriggeredContentAuthorities, getTriggeredContentUris, getWorkerFactory, isRunInForeground, isStopped, isUsed, onStopped, setForegroundAsync, setProgressAsync, setRunInForeground, setUsed, stop + + +
    All Methods Instance Methods Concrete Methods Deprecated Methods All Methods Instance Methods Concrete Methods 
    Modifier and Type Method  
    voidsetControlDispatcher​(ControlDispatcher controlDispatcher) -
    Deprecated. -
    Use a ForwardingPlayer and pass it to the constructor instead.
    -
    -
    ListenableFuture<androidx.media2.common.SessionPlayer.PlayerResult> setMediaItem​(androidx.media2.common.MediaItem item)
    ListenableFuture<androidx.media2.common.SessionPlayer.PlayerResult> setPlaybackSpeed​(float playbackSpeed)  
    ListenableFuture<androidx.media2.common.SessionPlayer.PlayerResult> setPlaylist​(List<androidx.media2.common.MediaItem> playlist, androidx.media2.common.MediaMetadata metadata)
    ListenableFuture<androidx.media2.common.SessionPlayer.PlayerResult> setRepeatMode​(int repeatMode)  
    ListenableFuture<androidx.media2.common.SessionPlayer.PlayerResult> setShuffleMode​(int shuffleMode)  
    ListenableFuture<androidx.media2.common.SessionPlayer.PlayerResult> skipToNextPlaylistItem()  
    ListenableFuture<androidx.media2.common.SessionPlayer.PlayerResult> skipToPlaylistItem​(int index)  
    ListenableFuture<androidx.media2.common.SessionPlayer.PlayerResult> skipToPreviousPlaylistItem()  
    ListenableFuture<androidx.media2.common.SessionPlayer.PlayerResult> updatePlaylistMetadata​(androidx.media2.common.MediaMetadata metadata)  
    booleanonCommand​(Player player, - ControlDispatcher controlDispatcher, +onCommand​(Player player, String command, Bundle extras, ResultReceiver cb)
    voidonCustomAction​(Player player, - ControlDispatcher controlDispatcher, +onCustomAction​(Player player, String action, Bundle extras) @@ -188,15 +187,13 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

    Method Detail

    - +
    • onCustomAction

      void onCustomAction​(Player player,
      -                    @Deprecated
      -                    ControlDispatcher controlDispatcher,
                           String action,
                           @Nullable
                           Bundle extras)
      @@ -204,10 +201,6 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
      Parameters:
      player - The player connected to the media session.
      -
      controlDispatcher - This parameter is deprecated. Use player instead. Operations - can be customized by passing a ForwardingPlayer to MediaSessionConnector.setPlayer(Player), or - when configuring the player (for example by using - SimpleExoPlayer.Builder#setSeekBackIncrementMs(long)).
      action - The name of the action which was sent by a media controller.
      extras - Optional extras sent by a media controller, may be null.
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.MediaButtonEventHandler.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.MediaButtonEventHandler.html index 55d05bbd05..83fb0e44cd 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.MediaButtonEventHandler.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.MediaButtonEventHandler.html @@ -149,8 +149,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    booleanonMediaButtonEvent​(Player player, - ControlDispatcher controlDispatcher, +onMediaButtonEvent​(Player player, Intent mediaButtonEvent)
    See MediaSessionCompat.Callback.onMediaButtonEvent(Intent).
    @@ -173,24 +172,18 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

    Method Detail

    - +
    • onMediaButtonEvent

      boolean onMediaButtonEvent​(Player player,
      -                           @Deprecated
      -                           ControlDispatcher controlDispatcher,
                                  Intent mediaButtonEvent)
      See MediaSessionCompat.Callback.onMediaButtonEvent(Intent).
      Parameters:
      player - The Player.
      -
      controlDispatcher - This parameter is deprecated. Use player instead. Operations - can be customized by passing a ForwardingPlayer to MediaSessionConnector.setPlayer(Player), or - when configuring the player (for example by using - SimpleExoPlayer.Builder#setSeekBackIncrementMs(long)).
      mediaButtonEvent - The Intent.
      Returns:
      True if the event was handled, false otherwise.
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.PlaybackPreparer.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.PlaybackPreparer.html index d05eda7543..7c5a3db83c 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.PlaybackPreparer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.PlaybackPreparer.html @@ -222,7 +222,7 @@ extends MediaSessionConnector.CommandReceiver -onCommand
    • +onCommand
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.QueueEditor.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.QueueEditor.html index 3f1f0f90c5..b0f80a763b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.QueueEditor.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.QueueEditor.html @@ -189,7 +189,7 @@ extends MediaSessionConnector.CommandReceiver -onCommand +onCommand diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.QueueNavigator.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.QueueNavigator.html index 907cfdb50d..dcb49e58f5 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.QueueNavigator.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.QueueNavigator.html @@ -25,8 +25,8 @@ catch(err) { } //--> -var data = {"i0":6,"i1":6,"i2":6,"i3":6,"i4":6,"i5":6,"i6":6}; -var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"]}; +var data = {"i0":6,"i1":6,"i2":18,"i3":6,"i4":6,"i5":6,"i6":6}; +var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"],16:["t5","Default Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; var tableTab = "tableTab"; @@ -174,7 +174,7 @@ extends -
    All Methods Instance Methods Abstract Methods All Methods Instance Methods Abstract Methods Default Methods 
    Modifier and Type MethodvoidonCurrentWindowIndexChanged​(Player player)default voidonCurrentMediaItemIndexChanged​(Player player) -
    Called when the current window index changed.
    +
    Called when the current media item index changed.
    voidonSkipToNext​(Player player, - ControlDispatcher controlDispatcher)onSkipToNext​(Player player)
    See MediaSessionCompat.Callback.onSkipToNext().
    voidonSkipToPrevious​(Player player, - ControlDispatcher controlDispatcher)onSkipToPrevious​(Player player)
    See MediaSessionCompat.Callback.onSkipToPrevious().
    voidonSkipToQueueItem​(Player player, - ControlDispatcher controlDispatcher, +onSkipToQueueItem​(Player player, long id)
    See MediaSessionCompat.Callback.onSkipToQueueItem(long).
    @@ -239,7 +236,7 @@ extends MediaSessionConnector.CommandReceiver -onCommand +onCommand @@ -311,14 +308,14 @@ extends +
    • -

      onCurrentWindowIndexChanged

      -
      void onCurrentWindowIndexChanged​(Player player)
      -
      Called when the current window index changed.
      +

      onCurrentMediaItemIndexChanged

      +
      default void onCurrentMediaItemIndexChanged​(Player player)
      +
      Called when the current media item index changed.
      Parameters:
      player - The player connected to the media session.
      @@ -345,64 +342,46 @@ extends +
      • onSkipToPrevious

        -
        void onSkipToPrevious​(Player player,
        -                      @Deprecated
        -                      ControlDispatcher controlDispatcher)
        +
        void onSkipToPrevious​(Player player)
        See MediaSessionCompat.Callback.onSkipToPrevious().
        Parameters:
        player - The player connected to the media session.
        -
        controlDispatcher - This parameter is deprecated. Use player instead. Operations - can be customized by passing a ForwardingPlayer to MediaSessionConnector.setPlayer(Player), or - when configuring the player (for example by using - SimpleExoPlayer.Builder#setSeekBackIncrementMs(long)).
      - +
      • onSkipToQueueItem

        void onSkipToQueueItem​(Player player,
        -                       @Deprecated
        -                       ControlDispatcher controlDispatcher,
                                long id)
        See MediaSessionCompat.Callback.onSkipToQueueItem(long).
        Parameters:
        player - The player connected to the media session.
        -
        controlDispatcher - This parameter is deprecated. Use player instead. Operations - can be customized by passing a ForwardingPlayer to MediaSessionConnector.setPlayer(Player), or - when configuring the player (for example by using - SimpleExoPlayer.Builder#setSeekBackIncrementMs(long)).
      - +
      • onSkipToNext

        -
        void onSkipToNext​(Player player,
        -                  @Deprecated
        -                  ControlDispatcher controlDispatcher)
        +
        void onSkipToNext​(Player player)
        See MediaSessionCompat.Callback.onSkipToNext().
        Parameters:
        player - The player connected to the media session.
        -
        controlDispatcher - This parameter is deprecated. Use player instead. Operations - can be customized by passing a ForwardingPlayer to MediaSessionConnector.setPlayer(Player), or - when configuring the player (for example by using - SimpleExoPlayer.Builder#setSeekBackIncrementMs(long)).
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.RatingCallback.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.RatingCallback.html index c565055f2e..190613ff38 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.RatingCallback.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.RatingCallback.html @@ -175,7 +175,7 @@ extends MediaSessionConnector.CommandReceiver -onCommand
    • +onCommand
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.html index 2fbe4eb63f..295eed1c1b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.html @@ -25,8 +25,8 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":42,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10}; -var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10}; +var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; var tableTab = "tableTab"; @@ -338,7 +338,7 @@ extends

    Method Summary

    - + @@ -381,28 +381,19 @@ extends - - - - - - + - + @@ -410,7 +401,7 @@ extends Sets a custom error on the session. - + - + - + - + - + - + - + - + - + - + - + - + - + - - @@ -480,32 +479,26 @@ implements +
    • onCommand

      public boolean onCommand​(Player player,
      -                         @Deprecated
      -                         ControlDispatcher controlDispatcher,
                                String command,
                                @Nullable
                                Bundle extras,
                                @Nullable
                                ResultReceiver cb)
      -
      Description copied from interface: MediaSessionConnector.CommandReceiver
      +
      Description copied from interface: MediaSessionConnector.CommandReceiver
      See MediaSessionCompat.Callback.onCommand(String, Bundle, ResultReceiver). The receiver may handle the command, but is not required to do so.
      Specified by:
      -
      onCommand in interface MediaSessionConnector.CommandReceiver
      +
      onCommand in interface MediaSessionConnector.CommandReceiver
      Parameters:
      player - The player connected to the media session.
      -
      controlDispatcher - This parameter is deprecated. Use player instead. Operations - can be customized by passing a ForwardingPlayer to MediaSessionConnector.setPlayer(Player), or - when configuring the player (for example by using - SimpleExoPlayer.Builder#setSeekBackIncrementMs(long)).
      command - The command name.
      extras - Optional parameters for the command, may be null.
      cb - A result receiver to which a result may be sent by the command, may be null.
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.html index 35b6029880..a4c81304b2 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.html @@ -242,8 +242,7 @@ implements
    - @@ -253,31 +252,28 @@ implements - + - + - + - + @@ -192,43 +192,34 @@ implements - - - - - - + - + - + - + - + @@ -293,7 +293,7 @@ extends BaseRenderer -createRendererException, createRendererException, disable, enable, getCapabilities, getConfiguration, getFormatHolder, getIndex, getLastResetPositionUs, getReadingPositionUs, getState, getStream, getStreamFormats, getTrackType, hasReadStreamToEnd, isCurrentStreamFinal, isSourceReady, maybeThrowStreamError, onReset, onStreamChanged, readSource, replaceStream, reset, resetPosition, setCurrentStreamFinal, setIndex, skipSource, start, stop, supportsMixedMimeTypeAdaptation +createRendererException, createRendererException, disable, enable, getCapabilities, getConfiguration, getFormatHolder, getIndex, getLastResetPositionUs, getReadingPositionUs, getState, getStream, getStreamFormats, getTrackType, hasReadStreamToEnd, isCurrentStreamFinal, isSourceReady, maybeThrowStreamError, onReset, onStreamChanged, readSource, replaceStream, reset, resetPosition, setCurrentStreamFinal, setIndex, skipSource, start, stop, supportsMixedMimeTypeAdaptation - + - - - - - - - + - + - + + + + +
    All Methods Instance Methods Concrete Methods Deprecated Methods All Methods Instance Methods Concrete Methods 
    Modifier and Type Method
    voidsetControlDispatcher​(ControlDispatcher controlDispatcher) -
    Deprecated. -
    Use a ForwardingPlayer and pass it to setPlayer(Player) instead.
    -
    -
    void setCustomActionProviders​(MediaSessionConnector.CustomActionProvider... customActionProviders)
    Sets custom action providers.
    void setCustomErrorMessage​(CharSequence message)
    Sets a custom error on the session.
    void setCustomErrorMessage​(CharSequence message, int code)
    void setCustomErrorMessage​(CharSequence message, int code, @@ -419,7 +410,7 @@ extends Sets a custom error on the session.
    void setDispatchUnsupportedActionsEnabled​(boolean dispatchUnsupportedActionsEnabled) @@ -427,35 +418,35 @@ extends
    void setEnabledPlaybackActions​(long enabledPlaybackActions)
    Sets the enabled playback actions.
    void setErrorMessageProvider​(ErrorMessageProvider<? super PlaybackException> errorMessageProvider)
    Sets the optional ErrorMessageProvider.
    void setMediaButtonEventHandler​(MediaSessionConnector.MediaButtonEventHandler mediaButtonEventHandler)
    void setMediaMetadataProvider​(MediaSessionConnector.MediaMetadataProvider mediaMetadataProvider)
    Sets a provider of metadata to be published to the media session.
    void setMetadataDeduplicationEnabled​(boolean metadataDeduplicationEnabled) @@ -463,28 +454,28 @@ extends MediaSessionCompat.setMetadata(MediaMetadataCompat).
    void setPlaybackPreparer​(MediaSessionConnector.PlaybackPreparer playbackPreparer)
    void setPlayer​(Player player)
    Sets the player to be connected to the media session.
    void setQueueEditor​(MediaSessionConnector.QueueEditor queueEditor)
    Sets the MediaSessionConnector.QueueEditor to handle queue edits sent by the media controller.
    void setQueueNavigator​(MediaSessionConnector.QueueNavigator queueNavigator) @@ -492,14 +483,14 @@ extends ACTION_SKIP_TO_PREVIOUS and ACTION_SKIP_TO_QUEUE_ITEM.
    void setRatingCallback​(MediaSessionConnector.RatingCallback ratingCallback)
    Sets the MediaSessionConnector.RatingCallback to handle user ratings.
    void unregisterCustomCommandReceiver​(MediaSessionConnector.CommandReceiver commandReceiver) @@ -648,21 +639,6 @@ extends - - - -
      -
    • -

      setControlDispatcher

      -
      @Deprecated
      -public void setControlDispatcher​(ControlDispatcher controlDispatcher)
      -
      Deprecated. -
      Use a ForwardingPlayer and pass it to setPlayer(Player) instead. - You can also customize some operations when configuring the player (for example by using - SimpleExoPlayer.Builder#setSeekBackIncrementMs(long)).
      -
      -
    • -
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.html index 32ee306748..4f7834235b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.html @@ -223,8 +223,7 @@ implements
    voidonCustomAction​(Player player, - ControlDispatcher controlDispatcher, +onCustomAction​(Player player, String action, Bundle extras) @@ -323,29 +322,23 @@ public static final int DEFAULT_REPEAT_TOGGLE_MODES

    Method Detail

    - +
    • onCustomAction

      public void onCustomAction​(Player player,
      -                           @Deprecated
      -                           ControlDispatcher controlDispatcher,
                                  String action,
                                  @Nullable
                                  Bundle extras)
      -
      Description copied from interface: MediaSessionConnector.CustomActionProvider
      +
      Description copied from interface: MediaSessionConnector.CustomActionProvider
      Called when a custom action provided by this provider is sent to the media session.
      Specified by:
      -
      onCustomAction in interface MediaSessionConnector.CustomActionProvider
      +
      onCustomAction in interface MediaSessionConnector.CustomActionProvider
      Parameters:
      player - The player connected to the media session.
      -
      controlDispatcher - This parameter is deprecated. Use player instead. Operations - can be customized by passing a ForwardingPlayer to MediaSessionConnector.setPlayer(Player), or - when configuring the player (for example by using - SimpleExoPlayer.Builder#setSeekBackIncrementMs(long)).
      action - The name of the action which was sent by a media controller.
      extras - Optional extras sent by a media controller, may be null.
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/TimelineQueueEditor.html b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/TimelineQueueEditor.html index d7e91f838e..09fa3b99a6 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/TimelineQueueEditor.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/mediasession/TimelineQueueEditor.html @@ -288,8 +288,7 @@ implements
    booleanonCommand​(Player player, - ControlDispatcher controlDispatcher, +onCommand​(Player player, String command, Bundle extras, ResultReceiver cb) booleanonCommand​(Player player, - ControlDispatcher controlDispatcher, +onCommand​(Player player, String command, Bundle extras, ResultReceiver cb)voidonCurrentWindowIndexChanged​(Player player)onCurrentMediaItemIndexChanged​(Player player) -
    Called when the current window index changed.
    +
    Called when the current media item index changed.
    voidonSkipToNext​(Player player, - ControlDispatcher controlDispatcher)onSkipToNext​(Player player)
    See MediaSessionCompat.Callback.onSkipToNext().
    voidonSkipToPrevious​(Player player, - ControlDispatcher controlDispatcher)onSkipToPrevious​(Player player)
    See MediaSessionCompat.Callback.onSkipToPrevious().
    voidonSkipToQueueItem​(Player player, - ControlDispatcher controlDispatcher, +onSkipToQueueItem​(Player player, long id)
    See MediaSessionCompat.Callback.onSkipToQueueItem(long).
    @@ -442,18 +438,18 @@ implements +
    All Methods Instance Methods Concrete Methods Deprecated Methods All Methods Instance Methods Concrete Methods 
    Modifier and Type MethodHttpDataSource.RequestPropertiesgetDefaultRequestProperties() -
    Deprecated. - -
    -
    OkHttpDataSource.Factory setCacheControl​(okhttp3.CacheControl cacheControl)
    Sets the CacheControl that will be used.
    OkHttpDataSource.Factory setContentTypePredicate​(Predicate<String> contentTypePredicate)
    Sets a content type Predicate.
    OkHttpDataSource.Factory setDefaultRequestProperties​(Map<String,​String> defaultRequestProperties)
    Sets the default request headers for HttpDataSource instances created by the factory.
    OkHttpDataSource.Factory setTransferListener​(TransferListener transferListener)
    Sets the TransferListener that will be used.
    OkHttpDataSource.Factory setUserAgent​(String userAgent) @@ -284,23 +275,6 @@ implements - - - diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.html b/docs/doc/reference/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.html index ce15a16cd4..829907dceb 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.html @@ -238,7 +238,7 @@ extends HttpDataSource.BaseFactory -createDataSource, getDefaultRequestProperties, setDefaultRequestProperties +createDataSource, setDefaultRequestProperties protected OpusDecodercreateDecoder​(Format format, - ExoMediaCrypto mediaCrypto)createDecoder​(Format format, + CryptoConfig cryptoConfig)
    Creates a decoder for the given format.
    OpusDecoder​(int numInputBuffers, +OpusDecoder​(int numInputBuffers, int numOutputBuffers, int initialInputBufferSize, List<byte[]> initializationData, - ExoMediaCrypto exoMediaCrypto, + CryptoConfig cryptoConfig, boolean outputFloat)
    Creates an Opus decoder.
    @@ -225,7 +225,7 @@ extends -
    protected SimpleOutputBufferprotected SimpleDecoderOutputBuffer createOutputBuffer()
    Creates a new output buffer.
    @@ -240,8 +240,8 @@ extends
    protected OpusDecoderExceptiondecode​(DecoderInputBuffer inputBuffer, - SimpleOutputBuffer outputBuffer, +decode​(DecoderInputBuffer inputBuffer, + SimpleDecoderOutputBuffer outputBuffer, boolean reset)
    Decodes the inputBuffer and stores any decoded output in outputBuffer.
    @@ -320,7 +320,7 @@ extends + @@ -397,12 +397,12 @@ extends
  • createOutputBuffer

    -
    protected SimpleOutputBuffer createOutputBuffer()
    +
    protected SimpleDecoderOutputBuffer createOutputBuffer()
    Description copied from class: SimpleDecoder
    Creates a new output buffer.
    Specified by:
    -
    createOutputBuffer in class SimpleDecoder<DecoderInputBuffer,​SimpleOutputBuffer,​OpusDecoderException>
    +
    createOutputBuffer in class SimpleDecoder<DecoderInputBuffer,​SimpleDecoderOutputBuffer,​OpusDecoderException>
  • @@ -417,7 +417,7 @@ extends Creates an exception to propagate for an unexpected decode error.
    Specified by:
    -
    createUnexpectedDecodeException in class SimpleDecoder<DecoderInputBuffer,​SimpleOutputBuffer,​OpusDecoderException>
    +
    createUnexpectedDecodeException in class SimpleDecoder<DecoderInputBuffer,​SimpleDecoderOutputBuffer,​OpusDecoderException>
    Parameters:
    error - The unexpected decode error.
    Returns:
    @@ -425,7 +425,7 @@ extends + diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/opus/OpusLibrary.html b/docs/doc/reference/com/google/android/exoplayer2/ext/opus/OpusLibrary.html index df28b57af1..1444d4d081 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/opus/OpusLibrary.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/opus/OpusLibrary.html @@ -167,31 +167,30 @@ extends
    static booleanmatchesExpectedExoMediaCryptoType​(Class<? extends ExoMediaCrypto> exoMediaCryptoType) -
    Returns whether the given ExoMediaCrypto type matches the one required for decoding - protected content.
    -
    static String opusGetVersion()  
    static boolean opusIsSecureDecodeSupported()  
    static voidsetLibraries​(Class<? extends ExoMediaCrypto> exoMediaCryptoType, +setLibraries​(@com.google.android.exoplayer2.C.CryptoType int cryptoType, String... libraries)
    Override the names of the Opus native libraries.
    static booleansupportsCryptoType​(@com.google.android.exoplayer2.C.CryptoType int cryptoType) +
    Returns whether the library supports the given C.CryptoType.
    +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.html b/docs/doc/reference/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.html index 0ed5d79010..3acae48ed6 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.html @@ -164,7 +164,7 @@ extends Renderer -Renderer.State, Renderer.VideoScalingMode, Renderer.WakeupListener +Renderer.MessageType, Renderer.State, Renderer.WakeupListener
    protected VpxDecodercreateDecoder​(Format format, - ExoMediaCrypto mediaCrypto)createDecoder​(Format format, + CryptoConfig cryptoConfig)
    Creates a decoder for the given format.
    protected voidrenderOutputBufferToSurface​(VideoDecoderOutputBuffer outputBuffer, +renderOutputBufferToSurface​(VideoDecoderOutputBuffer outputBuffer, Surface surface)
    Renders the specified output buffer to the passed surface.
    @@ -317,14 +317,14 @@ extends DecoderVideoRenderer -dropOutputBuffer, flushDecoder, handleMessage, isEnded, isReady, maybeDropBuffersToKeyframe, onDisabled, onEnabled, onInputFormatChanged, onPositionReset, onProcessedOutputBuffer, onQueueInputBuffer, onStarted, onStopped, onStreamChanged, releaseDecoder, render, renderOutputBuffer, setOutput, shouldDropBuffersToKeyframe, shouldDropOutputBuffer, shouldForceRenderOutputBuffer, skipOutputBuffer, updateDroppedBufferCounters +dropOutputBuffer, flushDecoder, handleMessage, isEnded, isReady, maybeDropBuffersToKeyframe, onDisabled, onEnabled, onInputFormatChanged, onPositionReset, onProcessedOutputBuffer, onQueueInputBuffer, onStarted, onStopped, onStreamChanged, releaseDecoder, render, renderOutputBuffer, setOutput, shouldDropBuffersToKeyframe, shouldDropOutputBuffer, shouldForceRenderOutputBuffer, skipOutputBuffer, updateDroppedBufferCounters - + - + @@ -161,10 +161,10 @@ extends Description
    VpxDecoder​(int numInputBuffers, +VpxDecoder​(int numInputBuffers, int numOutputBuffers, int initialInputBufferSize, - ExoMediaCrypto exoMediaCrypto, + CryptoConfig cryptoConfig, int threads)
    Creates a VP9 decoder.
    @@ -189,14 +189,14 @@ extends Description
    protected VideoDecoderInputBufferprotected DecoderInputBuffer createInputBuffer()
    Creates a new input buffer.
    protected VideoDecoderOutputBufferprotected VideoDecoderOutputBuffer createOutputBuffer()
    Creates a new output buffer.
    @@ -211,8 +211,8 @@ extends
    protected VpxDecoderExceptiondecode​(VideoDecoderInputBuffer inputBuffer, - VideoDecoderOutputBuffer outputBuffer, +decode​(DecoderInputBuffer inputBuffer, + VideoDecoderOutputBuffer outputBuffer, boolean reset)
    Decodes the inputBuffer and stores any decoded output in outputBuffer.
    @@ -234,14 +234,14 @@ extends
    protected voidreleaseOutputBuffer​(VideoDecoderOutputBuffer buffer)releaseOutputBuffer​(VideoDecoderOutputBuffer buffer)
    Releases an output buffer back to the decoder.
    voidrenderToSurface​(VideoDecoderOutputBuffer outputBuffer, +renderToSurface​(VideoDecoderOutputBuffer outputBuffer, Surface surface)
    Renders the outputBuffer to the surface.
    @@ -285,7 +285,7 @@ extends + @@ -358,27 +358,27 @@ extends
  • createOutputBuffer

    -
    protected VideoDecoderOutputBuffer createOutputBuffer()
    +
    protected VideoDecoderOutputBuffer createOutputBuffer()
    Description copied from class: SimpleDecoder
    Creates a new output buffer.
    Specified by:
    -
    createOutputBuffer in class SimpleDecoder<VideoDecoderInputBuffer,​VideoDecoderOutputBuffer,​VpxDecoderException>
    +
    createOutputBuffer in class SimpleDecoder<DecoderInputBuffer,​VideoDecoderOutputBuffer,​VpxDecoderException>
  • - +
    static booleanmatchesExpectedExoMediaCryptoType​(Class<? extends ExoMediaCrypto> exoMediaCryptoType) -
    Returns whether the given ExoMediaCrypto type matches the one required for decoding - protected content.
    -
    static voidsetLibraries​(Class<? extends ExoMediaCrypto> exoMediaCryptoType, +setLibraries​(@com.google.android.exoplayer2.C.CryptoType int cryptoType, String... libraries)
    Override the names of the Vpx native libraries.
    static booleansupportsCryptoType​(@com.google.android.exoplayer2.C.CryptoType int cryptoType) +
    Returns whether the library supports the given C.CryptoType.
    +
    static boolean vpxIsSecureDecodeSupported()
    ConstantBitrateSeekMap​(long inputLength, + long firstFrameBytePosition, + int bitrate, + int frameSize, + boolean allowSeeksIfLengthUnknown) +
    Creates an instance.
    @@ -257,14 +267,14 @@ implements - diff --git a/docs/doc/reference/com/google/android/exoplayer2/extractor/amr/AmrExtractor.html b/docs/doc/reference/com/google/android/exoplayer2/extractor/amr/AmrExtractor.html index f288a7c4e8..9788c27ead 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/extractor/amr/AmrExtractor.html +++ b/docs/doc/reference/com/google/android/exoplayer2/extractor/amr/AmrExtractor.html @@ -207,6 +207,14 @@ implements +static int +FLAG_ENABLE_CONSTANT_BITRATE_SEEKING_ALWAYS + +
    Like FLAG_ENABLE_CONSTANT_BITRATE_SEEKING, except that seeking is also enabled in + cases where the content length (and hence the duration of the media) is unknown.
    + + @@ -281,7 +281,7 @@ extends Size of the FLAC stream info block (header included) in bytes.
    See Also:
    -
    Constant Field Values
    +
    Constant Field Values
    @@ -295,7 +295,7 @@ extends Minimum size of a FLAC frame header in bytes.
    See Also:
    -
    Constant Field Values
    +
    Constant Field Values
    @@ -309,7 +309,7 @@ extends Maximum size of a FLAC frame header in bytes.
    See Also:
    -
    Constant Field Values
    +
    Constant Field Values
    @@ -323,7 +323,7 @@ extends Stream info metadata block type.
    See Also:
    -
    Constant Field Values
    +
    Constant Field Values
    @@ -337,7 +337,7 @@ extends Seek table metadata block type.
    See Also:
    -
    Constant Field Values
    +
    Constant Field Values
    @@ -351,7 +351,7 @@ extends Vorbis comment metadata block type.
    See Also:
    -
    Constant Field Values
    +
    Constant Field Values
    @@ -365,7 +365,7 @@ extends Picture metadata block type.
    See Also:
    -
    Constant Field Values
    +
    Constant Field Values
    @@ -389,18 +389,18 @@ extends diff --git a/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.Factory.html b/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.Factory.html index f335fe5099..0efbdc1d72 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.Factory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.Factory.html @@ -122,7 +122,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • All Known Implementing Classes:
    -
    SynchronousMediaCodecAdapter.Factory
    +
    DefaultMediaCodecAdapterFactory, SynchronousMediaCodecAdapter.Factory
    Enclosing interface:
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.html b/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.html index 0487ffd65e..70e564c229 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.html +++ b/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":6,"i1":6,"i2":6,"i3":6,"i4":6,"i5":6,"i6":6,"i7":6,"i8":6,"i9":6,"i10":6,"i11":6,"i12":6,"i13":6,"i14":6,"i15":6}; +var data = {"i0":6,"i1":6,"i2":6,"i3":6,"i4":6,"i5":6,"i6":6,"i7":6,"i8":6,"i9":6,"i10":6,"i11":6,"i12":6,"i13":6,"i14":6,"i15":6,"i16":6,"i17":6}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -218,27 +218,34 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); +Surface +getInputSurface() + +
    Returns the input Surface, or null if the input is not a surface.
    + + + ByteBuffer getOutputBuffer​(int index)
    Returns a read-only ByteBuffer for a dequeued output buffer index.
    - + MediaFormat getOutputFormat()
    Gets the MediaFormat that was output from the MediaCodec.
    - + boolean needsReconfiguration()
    Whether the adapter needs to be reconfigured before it is used.
    - + void queueInputBuffer​(int index, int offset, @@ -249,7 +256,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Submit an input buffer for decoding.
    - + void queueSecureInputBuffer​(int index, int offset, @@ -260,14 +267,14 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Submit an input buffer that is potentially encrypted for decoding.
    - + void release()
    Releases the adapter and the underlying MediaCodec.
    - + void releaseOutputBuffer​(int index, boolean render) @@ -275,7 +282,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Returns the buffer to the MediaCodec.
    - + void releaseOutputBuffer​(int index, long renderTimeStampNs) @@ -284,7 +291,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); it on the output surface. - + void setOnFrameRenderedListener​(MediaCodecAdapter.OnFrameRenderedListener listener, Handler handler) @@ -292,27 +299,34 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    Registers a callback to be invoked when an output frame is rendered on the output surface.
    - + void setOutputSurface​(Surface surface)
    Dynamically sets the output surface of a MediaCodec.
    - + void setParameters​(Bundle params)
    Communicate additional parameter changes to the MediaCodec instance.
    - + void setVideoScalingMode​(int scalingMode)
    Specifies the scaling mode to use, if a surface was specified when the codec was created.
    + +void +signalEndOfInputStream() + +
    Signals the encoder of end-of-stream on input.
    + +
  • @@ -387,6 +401,21 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    + + + + @@ -567,13 +596,29 @@ void setParameters​( -
      +
      • needsReconfiguration

        boolean needsReconfiguration()
        Whether the adapter needs to be reconfigured before it is used.
      + + + +
        +
      • +

        signalEndOfInputStream

        +
        @RequiresApi(18)
        +void signalEndOfInputStream()
        +
        Signals the encoder of end-of-stream on input. The call can only be used when the encoder + receives its input from a surface.
        +
        +
        See Also:
        +
        MediaCodec.signalEndOfInputStream()
        +
        +
      • +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.html b/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.html index 1d886e6561..6c6aa82f26 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":6,"i14":6,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10,"i36":6,"i37":10,"i38":10,"i39":10,"i40":10,"i41":10,"i42":10,"i43":10,"i44":10,"i45":10,"i46":10,"i47":10,"i48":10,"i49":6,"i50":9,"i51":10,"i52":10,"i53":10}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":6,"i11":6,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":6,"i34":10,"i35":10,"i36":10,"i37":10,"i38":10,"i39":10,"i40":10,"i41":10,"i42":10,"i43":10,"i44":10,"i45":10,"i46":6,"i47":9,"i48":10,"i49":10,"i50":10}; var tabs = {65535:["t0","All Methods"],1:["t1","Static Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -178,7 +178,7 @@ extends Renderer -Renderer.State, Renderer.VideoScalingMode, Renderer.WakeupListener +Renderer.MessageType, Renderer.State, Renderer.WakeupListener +
  • com.google.android.exoplayer2.mediacodec.DefaultMediaCodecAdapterFactory (implements com.google.android.exoplayer2.mediacodec.MediaCodecAdapter.Factory)
  • com.google.android.exoplayer2.mediacodec.MediaCodecAdapter.Configuration
  • com.google.android.exoplayer2.mediacodec.MediaCodecInfo
  • com.google.android.exoplayer2.mediacodec.MediaCodecUtil
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/metadata/Metadata.Entry.html b/docs/doc/reference/com/google/android/exoplayer2/metadata/Metadata.Entry.html index 1ca5ab2ed7..c4938c36c7 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/metadata/Metadata.Entry.html +++ b/docs/doc/reference/com/google/android/exoplayer2/metadata/Metadata.Entry.html @@ -126,7 +126,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    All Known Implementing Classes:
    -
    ApicFrame, AppInfoTable, BinaryFrame, ChapterFrame, ChapterTocFrame, CommentFrame, EventMessage, GeobFrame, HlsTrackMetadataEntry, IcyHeaders, IcyInfo, Id3Frame, InternalFrame, MdtaMetadataEntry, MlltFrame, MotionPhotoMetadata, PictureFrame, PrivateCommand, PrivFrame, SlowMotionData, SmtaMetadataEntry, SpliceCommand, SpliceInsertCommand, SpliceNullCommand, SpliceScheduleCommand, TextInformationFrame, TimeSignalCommand, UrlLinkFrame, VorbisComment
    +
    ApicFrame, AppInfoTable, BinaryFrame, ChapterFrame, ChapterTocFrame, CommentFrame, EventMessage, FakeMetadataEntry, GeobFrame, HlsTrackMetadataEntry, IcyHeaders, IcyInfo, Id3Frame, InternalFrame, MdtaMetadataEntry, MlltFrame, MotionPhotoMetadata, PictureFrame, PrivateCommand, PrivFrame, SlowMotionData, SmtaMetadataEntry, SpliceCommand, SpliceInsertCommand, SpliceNullCommand, SpliceScheduleCommand, TextInformationFrame, TimeSignalCommand, UrlLinkFrame, VorbisComment
    Enclosing class:
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/metadata/MetadataInputBuffer.html b/docs/doc/reference/com/google/android/exoplayer2/metadata/MetadataInputBuffer.html index af7bb84d43..aae1d0ef8d 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/metadata/MetadataInputBuffer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/metadata/MetadataInputBuffer.html @@ -186,7 +186,7 @@ extends DecoderInputBuffer -BUFFER_REPLACEMENT_MODE_DIRECT, BUFFER_REPLACEMENT_MODE_DISABLED, BUFFER_REPLACEMENT_MODE_NORMAL, cryptoInfo, data, supplementalData, timeUs, waitingForKeys +BUFFER_REPLACEMENT_MODE_DIRECT, BUFFER_REPLACEMENT_MODE_DISABLED, BUFFER_REPLACEMENT_MODE_NORMAL, cryptoInfo, data, format, supplementalData, timeUs, waitingForKeys diff --git a/docs/doc/reference/com/google/android/exoplayer2/metadata/MetadataOutput.html b/docs/doc/reference/com/google/android/exoplayer2/metadata/MetadataOutput.html index 91cd1db0ad..6e70217434 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/metadata/MetadataOutput.html +++ b/docs/doc/reference/com/google/android/exoplayer2/metadata/MetadataOutput.html @@ -120,14 +120,6 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    - + static void sendAddDownload​(Context context, Class<? extends DownloadService> clazz, @@ -549,7 +532,7 @@ extends Starts the service if not started already and adds a new download. - + static void sendPauseDownloads​(Context context, Class<? extends DownloadService> clazz, @@ -558,7 +541,7 @@ extends Starts the service if not started already and pauses all downloads. - + static void sendRemoveAllDownloads​(Context context, Class<? extends DownloadService> clazz, @@ -567,7 +550,7 @@ extends Starts the service if not started already and removes all downloads. - + static void sendRemoveDownload​(Context context, Class<? extends DownloadService> clazz, @@ -577,7 +560,7 @@ extends Starts the service if not started already and removes a download. - + static void sendResumeDownloads​(Context context, Class<? extends DownloadService> clazz, @@ -586,7 +569,7 @@ extends Starts the service if not started already and resumes all downloads. - + static void sendSetRequirements​(Context context, Class<? extends DownloadService> clazz, @@ -597,7 +580,7 @@ extends + static void sendSetStopReason​(Context context, Class<? extends DownloadService> clazz, @@ -608,7 +591,7 @@ extends Starts the service if not started already and sets the stop reason for one or all downloads. - + static void start​(Context context, Class<? extends DownloadService> clazz) @@ -616,7 +599,7 @@ extends Starts a download service to resume any ongoing downloads. - + static void startForeground​(Context context, Class<? extends DownloadService> clazz) @@ -637,7 +620,7 @@ extends ContextWrapper -bindIsolatedService, bindService, bindService, bindServiceAsUser, checkCallingOrSelfPermission, checkCallingOrSelfUriPermission, checkCallingPermission, checkCallingUriPermission, checkPermission, checkSelfPermission, checkUriPermission, checkUriPermission, clearWallpaper, createAttributionContext, createConfigurationContext, createContextForSplit, createDeviceProtectedStorageContext, createDisplayContext, createPackageContext, createWindowContext, databaseList, deleteDatabase, deleteFile, deleteSharedPreferences, enforceCallingOrSelfPermission, enforceCallingOrSelfUriPermission, enforceCallingPermission, enforceCallingUriPermission, enforcePermission, enforceUriPermission, enforceUriPermission, fileList, getApplicationContext, getApplicationInfo, getAssets, getAttributionTag, getBaseContext, getCacheDir, getClassLoader, getCodeCacheDir, getContentResolver, getDatabasePath, getDataDir, getDir, getDisplay, getExternalCacheDir, getExternalCacheDirs, getExternalFilesDir, getExternalFilesDirs, getExternalMediaDirs, getFilesDir, getFileStreamPath, getMainExecutor, getMainLooper, getNoBackupFilesDir, getObbDir, getObbDirs, getOpPackageName, getPackageCodePath, getPackageManager, getPackageName, getPackageResourcePath, getResources, getSharedPreferences, getSystemService, getSystemServiceName, getTheme, getWallpaper, getWallpaperDesiredMinimumHeight, getWallpaperDesiredMinimumWidth, grantUriPermission, isDeviceProtectedStorage, isRestricted, moveDatabaseFrom, moveSharedPreferencesFrom, openFileInput, openFileOutput, openOrCreateDatabase, openOrCreateDatabase, peekWallpaper, registerReceiver, registerReceiver, registerReceiver, registerReceiver, removeStickyBroadcast, removeStickyBroadcastAsUser, revokeUriPermission, revokeUriPermission, sendBroadcast, sendBroadcast, sendBroadcastAsUser, sendBroadcastAsUser, sendOrderedBroadcast, sendOrderedBroadcast, sendOrderedBroadcast, sendOrderedBroadcast, sendOrderedBroadcastAsUser, sendStickyBroadcast, sendStickyBroadcastAsUser, sendStickyOrderedBroadcast, sendStickyOrderedBroadcastAsUser, setTheme, setWallpaper, setWallpaper, startActivities, startActivities, startActivity, startActivity, startForegroundService, startInstrumentation, startIntentSender, startIntentSender, startService, stopService, unbindService, unregisterReceiver, updateServiceGroup +bindIsolatedService, bindService, bindService, bindServiceAsUser, checkCallingOrSelfPermission, checkCallingOrSelfUriPermission, checkCallingOrSelfUriPermissions, checkCallingPermission, checkCallingUriPermission, checkCallingUriPermissions, checkPermission, checkSelfPermission, checkUriPermission, checkUriPermission, checkUriPermissions, clearWallpaper, createAttributionContext, createConfigurationContext, createContext, createContextForSplit, createDeviceProtectedStorageContext, createDisplayContext, createPackageContext, createWindowContext, createWindowContext, databaseList, deleteDatabase, deleteFile, deleteSharedPreferences, enforceCallingOrSelfPermission, enforceCallingOrSelfUriPermission, enforceCallingPermission, enforceCallingUriPermission, enforcePermission, enforceUriPermission, enforceUriPermission, fileList, getApplicationContext, getApplicationInfo, getAssets, getAttributionSource, getAttributionTag, getBaseContext, getCacheDir, getClassLoader, getCodeCacheDir, getContentResolver, getDatabasePath, getDataDir, getDir, getDisplay, getExternalCacheDir, getExternalCacheDirs, getExternalFilesDir, getExternalFilesDirs, getExternalMediaDirs, getFilesDir, getFileStreamPath, getMainExecutor, getMainLooper, getNoBackupFilesDir, getObbDir, getObbDirs, getOpPackageName, getPackageCodePath, getPackageManager, getPackageName, getPackageResourcePath, getParams, getResources, getSharedPreferences, getSystemService, getSystemServiceName, getTheme, getWallpaper, getWallpaperDesiredMinimumHeight, getWallpaperDesiredMinimumWidth, grantUriPermission, isDeviceProtectedStorage, isRestricted, isUiContext, moveDatabaseFrom, moveSharedPreferencesFrom, openFileInput, openFileOutput, openOrCreateDatabase, openOrCreateDatabase, peekWallpaper, registerReceiver, registerReceiver, registerReceiver, registerReceiver, removeStickyBroadcast, removeStickyBroadcastAsUser, revokeUriPermission, revokeUriPermission, sendBroadcast, sendBroadcast, sendBroadcastAsUser, sendBroadcastAsUser, sendOrderedBroadcast, sendOrderedBroadcast, sendOrderedBroadcast, sendOrderedBroadcast, sendOrderedBroadcastAsUser, sendStickyBroadcast, sendStickyBroadcast, sendStickyBroadcastAsUser, sendStickyOrderedBroadcast, sendStickyOrderedBroadcastAsUser, setTheme, setWallpaper, setWallpaper, startActivities, startActivities, startActivity, startActivity, startForegroundService, startInstrumentation, startIntentSender, startIntentSender, startService, stopService, unbindService, unregisterReceiver, updateServiceGroup
    • @@ -941,8 +924,7 @@ extends Creates a DownloadService.

      If foregroundNotificationId is FOREGROUND_NOTIFICATION_ID_NONE then the - service will only ever run in the background. No foreground notification will be displayed and - getScheduler() will not be called. + service will only ever run in the background, and no foreground notification will be displayed.

      If foregroundNotificationId is not FOREGROUND_NOTIFICATION_ID_NONE then the service will run in the foreground. The foreground notification will be updated at least as @@ -1502,23 +1484,43 @@ public final @Nullable protected abstract Scheduler getScheduler() -

      Returns a Scheduler to restart the service when requirements allowing downloads to take - place are met. If null, the service will only be restarted if the process is still in - memory when the requirements are met. +
      Returns a Scheduler to restart the service when requirements for downloads to continue + are met. -

      This method is not called for services whose foregroundNotificationId is set to - FOREGROUND_NOTIFICATION_ID_NONE. Such services will only be restarted if the process - is still in memory and considered non-idle, meaning that it's either in the foreground or was - backgrounded within the last few minutes.

      +

      This method is not called on all devices or for all service configurations. When it is + called, it's called only once in the life cycle of the process. If a service has unfinished + downloads that cannot make progress due to unmet requirements, it will behave according to the + first matching case below: + +

        +
      • If the service has foregroundNotificationId set to FOREGROUND_NOTIFICATION_ID_NONE, then this method will not be called. The service will + remain in the background until the downloads are able to continue to completion or the + service is killed by the platform. +
      • If the device API level is less than 31, a Scheduler is returned from this + method, and the returned Scheduler supports all of the requirements that have been specified for downloads to continue, + then the service will stop itself and the Scheduler will be used to restart it in + the foreground when the requirements are met. +
      • If the device API level is less than 31 and either null or a Scheduler + that does not support all of the requirements + is returned from this method, then the service will remain in the foreground until the + downloads are able to continue to completion. +
      • If the device API level is 31 or above, then this method will not be called and the + service will remain in the foreground until the downloads are able to continue to + completion. A Scheduler cannot be used for this case due to Android 12 + foreground service launch restrictions. +
      • +
    - +
    @@ -1535,40 +1538,11 @@ protected abstract  - @@ -199,32 +218,15 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

    Interface Hierarchy

    @@ -263,6 +255,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • com.google.android.exoplayer2.C.AudioContentType (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.AudioFlags (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.AudioFocusGain (implements java.lang.annotation.Annotation)
  • +
  • com.google.android.exoplayer2.C.AudioManagerOffloadMode (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.AudioUsage (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.BufferFlags (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.ColorRange (implements java.lang.annotation.Annotation)
  • @@ -270,6 +263,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • com.google.android.exoplayer2.C.ColorTransfer (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.ContentType (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.CryptoMode (implements java.lang.annotation.Annotation)
  • +
  • com.google.android.exoplayer2.C.CryptoType (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.DataType (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.Encoding (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.FormatSupport (implements java.lang.annotation.Annotation)
  • @@ -278,12 +272,16 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • com.google.android.exoplayer2.C.Projection (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.RoleFlags (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.SelectionFlags (implements java.lang.annotation.Annotation)
  • +
  • com.google.android.exoplayer2.C.SelectionReason (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.StereoMode (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.StreamType (implements java.lang.annotation.Annotation)
  • +
  • com.google.android.exoplayer2.C.TrackType (implements java.lang.annotation.Annotation)
  • +
  • com.google.android.exoplayer2.C.VideoChangeFrameRateStrategy (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.VideoOutputMode (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.VideoScalingMode (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.C.WakeMode (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.DefaultRenderersFactory.ExtensionRendererMode (implements java.lang.annotation.Annotation)
  • +
  • com.google.android.exoplayer2.DeviceInfo.PlaybackType (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.ExoPlaybackException.Type (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.ExoTimeoutException.TimeoutOperation (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.MediaMetadata.FolderType (implements java.lang.annotation.Annotation)
  • @@ -299,8 +297,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • com.google.android.exoplayer2.Player.RepeatMode (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.Player.State (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.Player.TimelineChangeReason (implements java.lang.annotation.Annotation)
  • +
  • com.google.android.exoplayer2.Renderer.MessageType (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.Renderer.State (implements java.lang.annotation.Annotation)
  • -
  • com.google.android.exoplayer2.Renderer.VideoScalingMode (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.RendererCapabilities.Capabilities (implements java.lang.annotation.Annotation)
  • com.google.android.exoplayer2.RendererCapabilities.FormatSupport (implements java.lang.annotation.Annotation)
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/robolectric/PlaybackOutput.html b/docs/doc/reference/com/google/android/exoplayer2/robolectric/PlaybackOutput.html index eddeb7b254..9e50aee779 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/robolectric/PlaybackOutput.html +++ b/docs/doc/reference/com/google/android/exoplayer2/robolectric/PlaybackOutput.html @@ -169,7 +169,7 @@ implements static PlaybackOutput -register​(SimpleExoPlayer player, +register​(ExoPlayer player, CapturingRenderersFactory capturingRenderersFactory)
    Create an instance that captures the metadata and text output from player and the audio @@ -200,13 +200,13 @@ implements +
    • register

      -
      public static PlaybackOutput register​(SimpleExoPlayer player,
      +
      public static PlaybackOutput register​(ExoPlayer player,
                                             CapturingRenderersFactory capturingRenderersFactory)
      Create an instance that captures the metadata and text output from player and the audio and video output via capturingRenderersFactory. @@ -215,7 +215,7 @@ implements Parameters: -
      player - The SimpleExoPlayer to capture metadata and text output from.
      +
      player - The ExoPlayer to capture metadata and text output from.
      capturingRenderersFactory - The CapturingRenderersFactory to capture audio and video output from.
      Returns:
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.html b/docs/doc/reference/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.html index 6a48791aee..36b4271a78 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.html +++ b/docs/doc/reference/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.html @@ -131,8 +131,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
      public class TestPlayerRunHelper
       extends Object
      -
      Helper methods to block the calling thread until the provided SimpleExoPlayer instance - reaches a particular state.
      +
      Helper methods to block the calling thread until the provided ExoPlayer instance reaches + a particular state.
    @@ -156,7 +156,7 @@ extends static void playUntilPosition​(ExoPlayer player, - int windowIndex, + int mediaItemIndex, long positionMs)
    Calls Player.play(), runs tasks of the main Looper until the player @@ -165,11 +165,12 @@ extends static void -playUntilStartOfWindow​(ExoPlayer player, - int windowIndex) +playUntilStartOfMediaItem​(ExoPlayer player, + int mediaItemIndex)
    Calls Player.play(), runs tasks of the main Looper until the player - reaches the specified window or a playback error occurs, and then pauses the player.
    + reaches the specified media item or a playback error occurs, and then pauses the + player.
    @@ -189,8 +190,8 @@ extends static void -runUntilPlaybackState​(Player player, - int expectedState) +runUntilPlaybackState​(Player player, + @com.google.android.exoplayer2.Player.State int expectedState)
    Runs tasks of the main Looper until Player.getPlaybackState() matches the expected state or a playback error occurs.
    @@ -207,10 +208,10 @@ extends static void -runUntilPositionDiscontinuity​(Player player, - int expectedReason) +runUntilPositionDiscontinuity​(Player player, + @com.google.android.exoplayer2.Player.DiscontinuityReason int expectedReason) -
    Runs tasks of the main Looper until Player.Listener.onPositionDiscontinuity(Player.PositionInfo, Player.PositionInfo, int) is +
    Runs tasks of the main Looper until Player.Listener.onPositionDiscontinuity(Player.PositionInfo, Player.PositionInfo, int) is called with the specified Player.DiscontinuityReason or a playback error occurs.
    @@ -224,9 +225,9 @@ extends static void -runUntilRenderedFirstFrame​(SimpleExoPlayer player) +runUntilRenderedFirstFrame​(ExoPlayer player) -
    Runs tasks of the main Looper until the VideoListener.onRenderedFirstFrame() +
    Runs tasks of the main Looper until the Player.Listener.onRenderedFirstFrame() callback is called or a playback error occurs.
    @@ -279,7 +280,7 @@ extends

    Method Detail

    - + - + - +
    - +

    public static interface DefaultMediaSourceFactory.AdsLoaderProvider
    -
    Provides AdsLoader instances for media items that have ad tag URIs.
    +
    Provides AdsLoader instances for media items that have ad tag URIs.
    @@ -151,7 +151,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); AdsLoader getAdsLoader​(MediaItem.AdsConfiguration adsConfiguration) -
    Returns an AdsLoader for the given ads configuration, or null if no ads +
    Returns an AdsLoader for the given ads configuration, or null if no ads loader is available for the given ads configuration.
    @@ -180,11 +180,11 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

    getAdsLoader

    @Nullable
     AdsLoader getAdsLoader​(MediaItem.AdsConfiguration adsConfiguration)
    -
    Returns an AdsLoader for the given ads configuration, or null if no ads +
    Returns an AdsLoader for the given ads configuration, or null if no ads loader is available for the given ads configuration.

    This method is called each time a MediaSource is created from a MediaItem - that defines an ads configuration.

    + that defines an ads configuration.
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.html b/docs/doc/reference/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.html index c88e4910f6..cd59556427 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":42}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":42}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -87,7 +87,7 @@ loadScripts(document, 'script'); @@ -142,25 +142,25 @@ implements uri - ends in '.mpd' or if its mimeType field is +
  • DashMediaSource.Factory if the item's uri + ends in '.mpd' or if its mimeType field is explicitly set to MimeTypes.APPLICATION_MPD (Requires the exoplayer-dash module to be added to the app). -
  • HlsMediaSource.Factory if the item's uri - ends in '.m3u8' or if its mimeType field is +
  • HlsMediaSource.Factory if the item's uri + ends in '.m3u8' or if its mimeType field is explicitly set to MimeTypes.APPLICATION_M3U8 (Requires the exoplayer-hls module to be added to the app). -
  • SsMediaSource.Factory if the item's uri - ends in '.ism', '.ism/Manifest' or if its mimeType field is explicitly set to MimeTypes.APPLICATION_SS (Requires the +
  • SsMediaSource.Factory if the item's uri + ends in '.ism', '.ism/Manifest' or if its mimeType field is explicitly set to MimeTypes.APPLICATION_SS (Requires the exoplayer-smoothstreaming module to be added to the app). -
  • ProgressiveMediaSource.Factory serves as a fallback if the item's uri doesn't match one of the above. It tries to infer the +
  • ProgressiveMediaSource.Factory serves as a fallback if the item's uri doesn't match one of the above. It tries to infer the required extractor by using the DefaultExtractorsFactory or the ExtractorsFactory provided in the constructor. An UnrecognizedInputFormatException is thrown if none of the available extractors can read the stream.

    Ad support for media items with ad tag URIs

    -

    To support media items with ads +

    To support media items with ads configuration, setAdsLoaderProvider(com.google.android.exoplayer2.source.DefaultMediaSourceFactory.AdsLoaderProvider) and setAdViewProvider(com.google.android.exoplayer2.ui.AdViewProvider) need to be called to configure the factory with the required providers.

  • @@ -187,13 +187,30 @@ implements static interface  DefaultMediaSourceFactory.AdsLoaderProvider -
    Provides AdsLoader instances for media items that have ad tag URIs.
    +
    Provides AdsLoader instances for media items that have ad tag URIs.
    + +
    + +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/ForwardingTimeline.html b/docs/doc/reference/com/google/android/exoplayer2/source/ForwardingTimeline.html index feb29f196e..c998caf5f3 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/ForwardingTimeline.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/ForwardingTimeline.html @@ -265,8 +265,8 @@ extends int -getNextWindowIndex​(int windowIndex, - int repeatMode, +getNextWindowIndex​(int windowIndex, + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode, boolean shuffleModeEnabled)
    Returns the index of the window after the window at index windowIndex depending on the @@ -291,8 +291,8 @@ extends int -getPreviousWindowIndex​(int windowIndex, - int repeatMode, +getPreviousWindowIndex​(int windowIndex, + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode, boolean shuffleModeEnabled)
    Returns the index of the window before the window at index windowIndex depending on the @@ -328,7 +328,7 @@ extends Timeline -equals, getNextPeriodIndex, getPeriod, getPeriodByUid, getPeriodPosition, getPeriodPosition, getWindow, hashCode, isEmpty, isLastPeriod, toBundle, toBundle +equals, getNextPeriodIndex, getPeriod, getPeriodByUid, getPeriodPosition, getPeriodPosition, getPeriodPositionUs, getPeriodPositionUs, getWindow, hashCode, isEmpty, isLastPeriod, toBundle, toBundle
    - +
      @@ -375,9 +374,10 @@ public final @DataType int dataType, - int trackType, + @com.google.android.exoplayer2.C.TrackType int trackType, @Nullable Format trackFormat, + @SelectionReason int trackSelectionReason, @Nullable Object trackSelectionData, diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/MediaSource.html b/docs/doc/reference/com/google/android/exoplayer2/source/MediaSource.html index ec0395ff23..34102fdef1 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/MediaSource.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/MediaSource.html @@ -126,8 +126,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

    public interface MediaSource
    -
    Defines and provides media to be played by an ExoPlayer. A - MediaSource has two main responsibilities: +
    Defines and provides media to be played by an ExoPlayer. A MediaSource has two main + responsibilities:
    • To provide the player with a Timeline defining the structure of its media, and to @@ -140,8 +140,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); way for the player to load and read the media.
    - All methods are called on the player's internal playback thread, as described in the ExoPlayer Javadoc. They should not be called directly from - application code. Instances can be re-used, but only for one ExoPlayer instance simultaneously.
    + All methods are called on the player's internal playback thread, as described in the ExoPlayer Javadoc. They should not be called directly from application code. Instances can be + re-used, but only for one ExoPlayer instance simultaneously.
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/MediaSourceEventListener.EventDispatcher.html b/docs/doc/reference/com/google/android/exoplayer2/source/MediaSourceEventListener.EventDispatcher.html index 2ea776b688..b06cfc388a 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/MediaSourceEventListener.EventDispatcher.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/MediaSourceEventListener.EventDispatcher.html @@ -221,7 +221,7 @@ extends void -downstreamFormatChanged​(int trackType, +downstreamFormatChanged​(@com.google.android.exoplayer2.C.TrackType int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, @@ -247,9 +247,9 @@ extends void -loadCanceled​(LoadEventInfo loadEventInfo, +loadCanceled​(LoadEventInfo loadEventInfo, int dataType, - int trackType, + @com.google.android.exoplayer2.C.TrackType int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, @@ -277,9 +277,9 @@ extends void -loadCompleted​(LoadEventInfo loadEventInfo, +loadCompleted​(LoadEventInfo loadEventInfo, int dataType, - int trackType, + @com.google.android.exoplayer2.C.TrackType int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, @@ -299,9 +299,9 @@ extends void -loadError​(LoadEventInfo loadEventInfo, +loadError​(LoadEventInfo loadEventInfo, int dataType, - int trackType, + @com.google.android.exoplayer2.C.TrackType int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, @@ -346,9 +346,9 @@ extends void -loadStarted​(LoadEventInfo loadEventInfo, +loadStarted​(LoadEventInfo loadEventInfo, int dataType, - int trackType, + @com.google.android.exoplayer2.C.TrackType int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, @@ -539,7 +539,7 @@ public Dispatches MediaSourceEventListener.onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData). - + - + - + diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html b/docs/doc/reference/com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html index 299689a652..3278ee9cd5 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html @@ -87,7 +87,7 @@ loadScripts(document, 'script'); @@ -147,6 +147,23 @@ implements
    @@ -598,7 +615,7 @@ public Returns:
    The new ProgressiveMediaSource.
    Throws:
    -
    NullPointerException - if MediaItem.playbackProperties is null.
    +
    NullPointerException - if MediaItem.localConfiguration is null.
    @@ -670,7 +687,7 @@ public 
  • Summary: 
  • Nested | 
  • -
  • Field | 
  • +
  • Field | 
  • Constr | 
  • Method
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/SilenceMediaSource.Factory.html b/docs/doc/reference/com/google/android/exoplayer2/source/SilenceMediaSource.Factory.html index bd35fb95ea..9edf514063 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/SilenceMediaSource.Factory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/SilenceMediaSource.Factory.html @@ -195,7 +195,8 @@ extends SilenceMediaSource.Factory setTag​(Object tag) -
    Sets a tag for the media source which will be published in the Timeline of the source as Window#mediaItem.playbackProperties.tag.
    +
    Sets a tag for the media source which will be published in the Timeline of the source + as Window#mediaItem.localConfiguration.tag.
    @@ -247,7 +248,8 @@ extends
  • setDurationUs

    -
    public SilenceMediaSource.Factory setDurationUs​(long durationUs)
    +
    public SilenceMediaSource.Factory setDurationUs​(@IntRange(from=1L)
    +                                                long durationUs)
    Sets the duration of the silent audio. The value needs to be a positive value.
    Parameters:
    @@ -265,7 +267,8 @@ extends setTag
    public SilenceMediaSource.Factory setTag​(@Nullable
                                              Object tag)
    -
    Sets a tag for the media source which will be published in the Timeline of the source as Window#mediaItem.playbackProperties.tag.
    +
    Sets a tag for the media source which will be published in the Timeline of the source + as Window#mediaItem.localConfiguration.tag.
    Parameters:
    tag - A tag for the media source.
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/SinglePeriodTimeline.html b/docs/doc/reference/com/google/android/exoplayer2/source/SinglePeriodTimeline.html index c657561f8c..9052d5822d 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/SinglePeriodTimeline.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/SinglePeriodTimeline.html @@ -387,7 +387,7 @@ extends Timeline -equals, getFirstWindowIndex, getLastWindowIndex, getNextPeriodIndex, getNextWindowIndex, getPeriod, getPeriodByUid, getPeriodPosition, getPeriodPosition, getPreviousWindowIndex, getWindow, hashCode, isEmpty, isLastPeriod, toBundle, toBundle
  • +equals, getFirstWindowIndex, getLastWindowIndex, getNextPeriodIndex, getNextWindowIndex, getPeriod, getPeriodByUid, getPeriodPosition, getPeriodPosition, getPeriodPositionUs, getPeriodPositionUs, getPreviousWindowIndex, getWindow, hashCode, isEmpty, isLastPeriod, toBundle, toBundle
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/SingleSampleMediaSource.Factory.html b/docs/doc/reference/com/google/android/exoplayer2/source/SingleSampleMediaSource.Factory.html index 90da393734..13f64d6167 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/SingleSampleMediaSource.Factory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/SingleSampleMediaSource.Factory.html @@ -25,8 +25,8 @@ catch(err) { } //--> -var data = {"i0":42,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10}; -var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10}; +var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; var tableTab = "tableTab"; @@ -173,7 +173,7 @@ extends

    Method Summary

    - + @@ -181,46 +181,35 @@ extends - - - - - - - + - + - + - + - + - + @@ -187,13 +189,6 @@ implements -
  • - - -

    Fields inherited from interface android.os.Parcelable

    -CONTENTS_FILE_DESCRIPTOR, PARCELABLE_WRITE_RETURN_VALUE
  • - @@ -212,7 +207,9 @@ implements - +
    All Methods Instance Methods Concrete Methods Deprecated Methods All Methods Instance Methods Concrete Methods 
    Modifier and Type Method
    SingleSampleMediaSourcecreateMediaSource​(Uri uri, - Format format, - long durationUs) - -
    SingleSampleMediaSourcecreateMediaSource​(MediaItem.Subtitle subtitle, +createMediaSource​(MediaItem.SubtitleConfiguration subtitleConfiguration, long durationUs)
    Returns a new SingleSampleMediaSource using the current parameters.
    SingleSampleMediaSource.Factory setLoadErrorHandlingPolicy​(LoadErrorHandlingPolicy loadErrorHandlingPolicy)
    SingleSampleMediaSource.Factory setTag​(Object tag)
    Sets a tag for the media source which will be published in the Timeline of the source - as Window#mediaItem.playbackProperties.tag.
    + as Window#mediaItem.localConfiguration.tag.
    SingleSampleMediaSource.Factory setTrackId​(String trackId)
    Sets an optional track id to be used.
    SingleSampleMediaSource.Factory setTreatLoadErrorsAsEndOfStream​(boolean treatLoadErrorsAsEndOfStream) @@ -286,7 +275,7 @@ extends public SingleSampleMediaSource.Factory setTag​(@Nullable Object tag)
    Sets a tag for the media source which will be published in the Timeline of the source - as Window#mediaItem.playbackProperties.tag.
    + as Window#mediaItem.localConfiguration.tag.
    Parameters:
    tag - A tag for the media source.
    @@ -348,37 +337,22 @@ extends - - - - - + diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/TrackGroup.html b/docs/doc/reference/com/google/android/exoplayer2/source/TrackGroup.html index dff3b570b3..12aa645ca4 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/TrackGroup.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/TrackGroup.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -130,12 +130,12 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • All Implemented Interfaces:
    -
    Parcelable
    +
    Bundleable

    public final class TrackGroup
     extends Object
    -implements Parcelable
    +implements Bundleable
    Defines an immutable group of tracks identified by their format identity.
  • @@ -151,11 +151,11 @@ implements -
  • +
  • -

    Nested classes/interfaces inherited from interface android.os.Parcelable

    -Parcelable.ClassLoaderCreator<T extends Object>, Parcelable.Creator<T extends Object>
  • +

    Nested classes/interfaces inherited from interface com.google.android.exoplayer2.Bundleable

    +Bundleable.Creator<T extends Bundleable> @@ -175,9 +175,11 @@ implements Description
    static Parcelable.Creator<TrackGroup>static Bundleable.Creator<TrackGroup> CREATOR  +
    Object that can restore TrackGroup from a Bundle.
    +
    int TrackGroup​(Format... formats)  +
    Constructs an instance TrackGroup containing the provided formats.
    +
    @@ -233,39 +230,35 @@ implements Description -int -describeContents() -  - - boolean equals​(Object obj)   - + Format getFormat​(int index)
    Returns the format of the track at a given index.
    - + int hashCode()   - + int indexOf​(Format format)
    Returns the index of the track with the given format in the group.
    - -void -writeToParcel​(Parcel dest, - int flags) -  + +Bundle +toBundle() + +
    Returns a Bundle representing the information stored in this object.
    + @@ -327,9 +321,10 @@ implements

    TrackGroup

    public TrackGroup​(Format... formats)
    +
    Constructs an instance TrackGroup containing the provided formats.
    Parameters:
    -
    formats - The track formats. At least one Format must be provided.
    +
    formats - Non empty array of format.
    @@ -404,30 +399,18 @@ implements - - - - + diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/TrackGroupArray.html b/docs/doc/reference/com/google/android/exoplayer2/source/TrackGroupArray.html index 18fb9da3af..ddd782c0ff 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/TrackGroupArray.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/TrackGroupArray.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -130,12 +130,12 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • All Implemented Interfaces:
    -
    Parcelable
    +
    Bundleable

    public final class TrackGroupArray
     extends Object
    -implements Parcelable
    +implements Bundleable
    An immutable array of TrackGroups.
  • @@ -151,11 +151,11 @@ implements -
  • +
  • -

    Nested classes/interfaces inherited from interface android.os.Parcelable

    -Parcelable.ClassLoaderCreator<T extends Object>, Parcelable.Creator<T extends Object>
  • +

    Nested classes/interfaces inherited from interface com.google.android.exoplayer2.Bundleable

    +Bundleable.Creator<T extends Bundleable> @@ -175,9 +175,11 @@ implements Description -static Parcelable.Creator<TrackGroupArray> +static Bundleable.Creator<TrackGroupArray> CREATOR -  + +
    Object that can restores a TrackGroupArray from a Bundle.
    + static TrackGroupArray @@ -194,13 +196,6 @@ implements -
  • - - -

    Fields inherited from interface android.os.Parcelable

    -CONTENTS_FILE_DESCRIPTOR, PARCELABLE_WRITE_RETURN_VALUE
  • - @@ -219,7 +214,9 @@ implements TrackGroupArray​(TrackGroup... trackGroups) -  + +
    Construct a TrackGroupArray from an array of (possibly empty) trackGroups.
    + @@ -240,46 +237,42 @@ implements Description -int -describeContents() -  - - boolean equals​(Object obj)   - + TrackGroup get​(int index)
    Returns the group at a given index.
    - + int hashCode()   - + int indexOf​(TrackGroup group)
    Returns the index of a group within the array.
    - + boolean isEmpty()
    Returns whether this track group array is empty.
    - -void -writeToParcel​(Parcel dest, - int flags) -  + +Bundle +toBundle() + +
    Returns a Bundle representing the information stored in this object.
    + @@ -351,10 +345,7 @@ implements

    TrackGroupArray

    public TrackGroupArray​(TrackGroup... trackGroups)
    -
    -
    Parameters:
    -
    trackGroups - The groups. May be empty.
    -
    +
    Construct a TrackGroupArray from an array of (possibly empty) trackGroups.
    @@ -436,30 +427,18 @@ implements - - - - + diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/ads/AdPlaybackState.AdGroup.html b/docs/doc/reference/com/google/android/exoplayer2/source/ads/AdPlaybackState.AdGroup.html index 69e37b98aa..a31da04f95 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/ads/AdPlaybackState.AdGroup.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/ads/AdPlaybackState.AdGroup.html @@ -228,8 +228,7 @@ implements long timeUs -
    The time of the ad group in the Timeline.Period, in - microseconds, or C.TIME_END_OF_SOURCE to indicate a postroll ad.
    +
    The time of the ad group in the Timeline.Period, in microseconds, or C.TIME_END_OF_SOURCE to indicate a postroll ad.
    @@ -417,8 +416,7 @@ implements

    timeUs

    public final long timeUs
    -
    The time of the ad group in the Timeline.Period, in - microseconds, or C.TIME_END_OF_SOURCE to indicate a postroll ad.
    +
    The time of the ad group in the Timeline.Period, in microseconds, or C.TIME_END_OF_SOURCE to indicate a postroll ad.
    @@ -513,7 +511,8 @@ public final int[] states
    Creates a new ad group with an unspecified number of ads.
    Parameters:
    -
    timeUs - The time of the ad group in the Timeline.Period, in microseconds, or C.TIME_END_OF_SOURCE to indicate a postroll ad.
    +
    timeUs - The time of the ad group in the Timeline.Period, in microseconds, or + C.TIME_END_OF_SOURCE to indicate a postroll ad.
    @@ -544,9 +543,11 @@ public final int[] states
    • getNextAdIndexToPlay

      -
      public int getNextAdIndexToPlay​(int lastPlayedAdIndex)
      +
      public int getNextAdIndexToPlay​(@IntRange(from=-1L)
      +                                int lastPlayedAdIndex)
      Returns the index of the next ad in the ad group that should be played after playing - lastPlayedAdIndex, or count if no later ads should be played.
      + lastPlayedAdIndex
      , or count if no later ads should be played. If no ads have been + played, pass -1 to get the index of the first ad to play.
    @@ -626,6 +627,7 @@ public @CheckResult public AdPlaybackState.AdGroup withAdUri​(Uri uri, + @IntRange(from=0L) int index)
    Returns a new instance with the specified uri set for the specified ad, and the ad marked as AdPlaybackState.AD_STATE_AVAILABLE.
    @@ -640,6 +642,7 @@ public @CheckResult public AdPlaybackState.AdGroup withAdState​(@AdState int state, + @IntRange(from=0L) int index)
    Returns a new instance with the specified ad set to the specified state. The ad specified must currently either be in AdPlaybackState.AD_STATE_UNAVAILABLE or AdPlaybackState.AD_STATE_AVAILABLE. diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/ads/AdPlaybackState.html b/docs/doc/reference/com/google/android/exoplayer2/source/ads/AdPlaybackState.html index 56acc34b48..51526fcf7d 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/ads/AdPlaybackState.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/ads/AdPlaybackState.html @@ -693,8 +693,7 @@ public final Parameters:
    adsId - The opaque identifier for ads with which this instance is associated.
    adGroupTimesUs - The times of ad groups in microseconds, relative to the start of the - Timeline.Period they belong to. A final element with - the value C.TIME_END_OF_SOURCE indicates that there is a postroll ad.
    + Timeline.Period they belong to. A final element with the value C.TIME_END_OF_SOURCE indicates that there is a postroll ad.
    @@ -714,7 +713,8 @@ public final 
  • getAdGroup

    -
    public AdPlaybackState.AdGroup getAdGroup​(int adGroupIndex)
    +
    public AdPlaybackState.AdGroup getAdGroup​(@IntRange(from=0L)
    +                                          int adGroupIndex)
    Returns the specified AdPlaybackState.AdGroup.
  • @@ -769,7 +769,9 @@ public final 
  • isAdInErrorState

    -
    public boolean isAdInErrorState​(int adGroupIndex,
    +
    public boolean isAdInErrorState​(@IntRange(from=0L)
    +                                int adGroupIndex,
    +                                @IntRange(from=0L)
                                     int adIndexInAdGroup)
  • @@ -781,7 +783,8 @@ public final 

    withAdGroupTimeUs

    @CheckResult
    -public AdPlaybackState withAdGroupTimeUs​(int adGroupIndex,
    +public AdPlaybackState withAdGroupTimeUs​(@IntRange(from=0L)
    +                                         int adGroupIndex,
                                              long adGroupTimeUs)
    Returns an instance with the specified ad group time.
    @@ -801,7 +804,8 @@ public 

    withNewAdGroup

    @CheckResult
    -public AdPlaybackState withNewAdGroup​(int adGroupIndex,
    +public AdPlaybackState withNewAdGroup​(@IntRange(from=0L)
    +                                      int adGroupIndex,
                                           long adGroupTimeUs)
    Returns an instance with a new ad group.
    @@ -821,7 +825,9 @@ public 

    withAdCount

    @CheckResult
    -public AdPlaybackState withAdCount​(int adGroupIndex,
    +public AdPlaybackState withAdCount​(@IntRange(from=0L)
    +                                   int adGroupIndex,
    +                                   @IntRange(from=1L)
                                        int adCount)
    Returns an instance with the number of ads in adGroupIndex resolved to adCount. The ad count must be greater than zero.
    @@ -834,7 +840,9 @@ public 

    withAdUri

    @CheckResult
    -public AdPlaybackState withAdUri​(int adGroupIndex,
    +public AdPlaybackState withAdUri​(@IntRange(from=0L)
    +                                 int adGroupIndex,
    +                                 @IntRange(from=0L)
                                      int adIndexInAdGroup,
                                      Uri uri)
    Returns an instance with the specified ad URI.
    @@ -847,7 +855,9 @@ public 

    withPlayedAd

    @CheckResult
    -public AdPlaybackState withPlayedAd​(int adGroupIndex,
    +public AdPlaybackState withPlayedAd​(@IntRange(from=0L)
    +                                    int adGroupIndex,
    +                                    @IntRange(from=0L)
                                         int adIndexInAdGroup)
    Returns an instance with the specified ad marked as played.
    @@ -859,7 +869,9 @@ public 

    withSkippedAd

    @CheckResult
    -public AdPlaybackState withSkippedAd​(int adGroupIndex,
    +public AdPlaybackState withSkippedAd​(@IntRange(from=0L)
    +                                     int adGroupIndex,
    +                                     @IntRange(from=0L)
                                          int adIndexInAdGroup)
    Returns an instance with the specified ad marked as skipped.
    @@ -871,7 +883,9 @@ public 

    withAdLoadError

    @CheckResult
    -public AdPlaybackState withAdLoadError​(int adGroupIndex,
    +public AdPlaybackState withAdLoadError​(@IntRange(from=0L)
    +                                       int adGroupIndex,
    +                                       @IntRange(from=0L)
                                            int adIndexInAdGroup)
    Returns an instance with the specified ad marked as having a load error.
    @@ -883,7 +897,8 @@ public 

    withSkippedAdGroup

    @CheckResult
    -public AdPlaybackState withSkippedAdGroup​(int adGroupIndex)
    +public AdPlaybackState withSkippedAdGroup​(@IntRange(from=0L) + int adGroupIndex)
    Returns an instance with all ads in the specified ad group skipped (except for those already marked as played or in the error state).
    @@ -908,7 +923,8 @@ public 

    withAdDurationsUs

    @CheckResult
    -public AdPlaybackState withAdDurationsUs​(int adGroupIndex,
    +public AdPlaybackState withAdDurationsUs​(@IntRange(from=0L)
    +                                         int adGroupIndex,
                                              long... adDurationsUs)
    Returns an instance with the specified ad durations, in microseconds, in the specified ad group.
    @@ -944,7 +960,8 @@ public 

    withRemovedAdGroupCount

    @CheckResult
    -public AdPlaybackState withRemovedAdGroupCount​(int removedAdGroupCount)
    +public AdPlaybackState withRemovedAdGroupCount​(@IntRange(from=0L) + int removedAdGroupCount)
    Returns an instance with the specified number of removed ad groups. @@ -959,7 +976,8 @@ public 

    withContentResumeOffsetUs

    @CheckResult
    -public AdPlaybackState withContentResumeOffsetUs​(int adGroupIndex,
    +public AdPlaybackState withContentResumeOffsetUs​(@IntRange(from=0L)
    +                                                 int adGroupIndex,
                                                      long contentResumeOffsetUs)
    Returns an instance with the specified AdPlaybackState.AdGroup.contentResumeOffsetUs, in microseconds, for the specified ad group.
    @@ -972,7 +990,8 @@ public 

    withIsServerSideInserted

    @CheckResult
    -public AdPlaybackState withIsServerSideInserted​(int adGroupIndex,
    +public AdPlaybackState withIsServerSideInserted​(@IntRange(from=0L)
    +                                                int adGroupIndex,
                                                     boolean isServerSideInserted)
    Returns an instance with the specified value for AdPlaybackState.AdGroup.isServerSideInserted in the specified ad group.
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/ads/SinglePeriodAdTimeline.html b/docs/doc/reference/com/google/android/exoplayer2/source/ads/SinglePeriodAdTimeline.html index 7bc877dc8c..4a644c4bd8 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/ads/SinglePeriodAdTimeline.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/ads/SinglePeriodAdTimeline.html @@ -253,14 +253,14 @@ extends ForwardingTimeline -getFirstWindowIndex, getIndexOfPeriod, getLastWindowIndex, getNextWindowIndex, getPeriodCount, getPreviousWindowIndex, getUidOfPeriod, getWindow, getWindowCount +getFirstWindowIndex, getIndexOfPeriod, getLastWindowIndex, getNextWindowIndex, getPeriodCount, getPreviousWindowIndex, getUidOfPeriod, getWindow, getWindowCount
    @@ -336,20 +336,20 @@ implements +
    • BundledChunkExtractor

      public BundledChunkExtractor​(Extractor extractor,
      -                             int primaryTrackType,
      +                             @com.google.android.exoplayer2.C.TrackType int primaryTrackType,
                                    Format primaryTrackManifestFormat)
      Creates an instance.
      Parameters:
      extractor - The extractor to wrap.
      -
      primaryTrackType - The type of the primary track. Typically one of the C TRACK_TYPE_* constants.
      +
      primaryTrackType - The type of the primary track.
      primaryTrackManifestFormat - A manifest defined Format whose data should be merged into any sample Format output from the Extractor for the primary track.
      @@ -468,18 +468,17 @@ public public TrackOutput track​(int id, int type) -
      Description copied from interface: ExtractorOutput
      +
      Description copied from interface: ExtractorOutput
      Called by the Extractor to get the TrackOutput for a specific track.

      The same TrackOutput is returned if multiple calls are made with the same id.

      Specified by:
      -
      track in interface ExtractorOutput
      +
      track in interface ExtractorOutput
      Parameters:
      id - A track identifier.
      -
      type - The type of the track. Typically one of the C - TRACK_TYPE_* constants.
      +
      type - The track type.
      Returns:
      The TrackOutput for the given track identifier.
      @@ -494,7 +493,7 @@ public public void endTracks()
      Called when all tracks have been identified, meaning no new trackId values will be - passed to ExtractorOutput.track(int, int).
      + passed to ExtractorOutput.track(int, int).
      Specified by:
      endTracks in interface ExtractorOutput
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/Chunk.html b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/Chunk.html index be9b9b9637..c03339a84d 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/Chunk.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/Chunk.html @@ -215,7 +215,7 @@ implements int trackSelectionReason -
      One of the C SELECTION_REASON_* constants if the chunk belongs to a track.
      +
      One of the selection reasons if the chunk belongs to a track.
      @@ -377,10 +377,10 @@ public final int type
      • trackSelectionReason

        -
        public final int trackSelectionReason
        -
        One of the C SELECTION_REASON_* constants if the chunk belongs to a track. - C.SELECTION_REASON_UNKNOWN if the chunk does not belong to a track, or if the selection - reason is unknown.
        +
        @SelectionReason
        +public final int trackSelectionReason
        +
        One of the selection reasons if the chunk belongs to a track. C.SELECTION_REASON_UNKNOWN if the chunk does not belong to a track, or if the selection reason + is unknown.
      @@ -447,6 +447,7 @@ public final @DataType int type, Format trackFormat, + @SelectionReason int trackSelectionReason, @Nullable Object trackSelectionData, diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkExtractor.Factory.html b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkExtractor.Factory.html index 659df88c70..276103876c 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkExtractor.Factory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkExtractor.Factory.html @@ -149,7 +149,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); ChunkExtractor -createProgressiveMediaExtractor​(int primaryTrackType, +createProgressiveMediaExtractor​(@com.google.android.exoplayer2.C.TrackType int primaryTrackType, Format representationFormat, boolean enableEventMessageTrack, List<Format> closedCaptionFormats, @@ -175,14 +175,14 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

      Method Detail

      - +
      • createProgressiveMediaExtractor

        @Nullable
        -ChunkExtractor createProgressiveMediaExtractor​(int primaryTrackType,
        +ChunkExtractor createProgressiveMediaExtractor​(@com.google.android.exoplayer2.C.TrackType int primaryTrackType,
                                                        Format representationFormat,
                                                        boolean enableEventMessageTrack,
                                                        List<Format> closedCaptionFormats,
        @@ -191,7 +191,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
         
        Returns a new ChunkExtractor instance.
        Parameters:
        -
        primaryTrackType - The type of the primary track. One of C.TRACK_TYPE_*.
        +
        primaryTrackType - The type of the primary track.
        representationFormat - The format of the representation to extract from.
        enableEventMessageTrack - Whether to enable the event message track.
        closedCaptionFormats - The Formats of the Closed-Caption tracks.
        diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkExtractor.TrackOutputProvider.html b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkExtractor.TrackOutputProvider.html index ba08fc5c52..ca99f386b0 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkExtractor.TrackOutputProvider.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkExtractor.TrackOutputProvider.html @@ -153,8 +153,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); TrackOutput -track​(int id, - int type) +track​(int id, + @com.google.android.exoplayer2.C.TrackType int type)
        Called to get the TrackOutput for a specific track.
        @@ -176,14 +176,14 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

        Method Detail

        - +
        • track

          TrackOutput track​(int id,
          -                  int type)
          + @com.google.android.exoplayer2.C.TrackType int type)
        Called to get the TrackOutput for a specific track.

        The same TrackOutput is returned if multiple calls are made with the same @@ -191,8 +191,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

        Parameters:
        id - A track identifier.
        -
        type - The type of the track. Typically one of the C TRACK_TYPE_* - constants.
        +
        type - The type of the track.
        Returns:
        The TrackOutput for the given track identifier.
        diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.html b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.html index 70678ae3e4..0128a190f8 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.html @@ -205,7 +205,7 @@ implements Description -int +@com.google.android.exoplayer2.C.TrackType int primaryTrackType   @@ -234,7 +234,7 @@ implements Description -ChunkSampleStream​(int primaryTrackType, +ChunkSampleStream​(@com.google.android.exoplayer2.C.TrackType int primaryTrackType, int[] embeddedTrackTypes, Format[] embeddedTrackFormats, T chunkSource, @@ -453,7 +453,7 @@ implements
      • primaryTrackType

        -
        public final int primaryTrackType
        +
        public final @com.google.android.exoplayer2.C.TrackType int primaryTrackType
    • @@ -466,15 +466,15 @@ implements + - +
      • ChunkSampleStream

        -
        public ChunkSampleStream​(int primaryTrackType,
        +
        public ChunkSampleStream​(@com.google.android.exoplayer2.C.TrackType int primaryTrackType,
                                  @Nullable
                                  int[] embeddedTrackTypes,
                                  @Nullable
        @@ -490,8 +490,7 @@ implements Constructs an instance.
         
        Parameters:
        -
        primaryTrackType - The type of the primary track. One of the C - TRACK_TYPE_* constants.
        +
        primaryTrackType - The type of the primary track.
        embeddedTrackTypes - The types of any embedded tracks, or null.
        embeddedTrackFormats - The formats of the embedded tracks, or null.
        chunkSource - A ChunkSource from which chunks to load are obtained.
        diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.html b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.html index b875d2f7d9..95ca36b4fc 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.html @@ -317,6 +317,7 @@ extends DataSource dataSource, DataSpec dataSpec, Format trackFormat, + @SelectionReason int trackSelectionReason, @Nullable Object trackSelectionData, diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/DataChunk.html b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/DataChunk.html index 38aacb6ca6..f118ee4cc1 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/DataChunk.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/DataChunk.html @@ -277,6 +277,7 @@ extends @DataType int type, Format trackFormat, + @SelectionReason int trackSelectionReason, @Nullable Object trackSelectionData, diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/InitializationChunk.html b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/InitializationChunk.html index c65a3e6025..1bec691171 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/InitializationChunk.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/InitializationChunk.html @@ -266,6 +266,7 @@ extends DataSource dataSource, DataSpec dataSpec, Format trackFormat, + @SelectionReason int trackSelectionReason, @Nullable Object trackSelectionData, diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/MediaChunk.html b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/MediaChunk.html index 39362613fa..da46a0fc78 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/MediaChunk.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/MediaChunk.html @@ -306,6 +306,7 @@ extends DataSource dataSource, DataSpec dataSpec, Format trackFormat, + @SelectionReason int trackSelectionReason, @Nullable Object trackSelectionData, diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/MediaParserChunkExtractor.html b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/MediaParserChunkExtractor.html index f16a756590..7312e4fa3d 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/MediaParserChunkExtractor.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/MediaParserChunkExtractor.html @@ -198,7 +198,7 @@ implements Description -MediaParserChunkExtractor​(int primaryTrackType, +MediaParserChunkExtractor​(@com.google.android.exoplayer2.C.TrackType int primaryTrackType, Format manifestFormat, List<Format> closedCaptionFormats) @@ -304,20 +304,19 @@ implements +
        • MediaParserChunkExtractor

          -
          public MediaParserChunkExtractor​(int primaryTrackType,
          +
          public MediaParserChunkExtractor​(@com.google.android.exoplayer2.C.TrackType int primaryTrackType,
                                            Format manifestFormat,
                                            List<Format> closedCaptionFormats)
          Creates a new instance.
          Parameters:
          -
          primaryTrackType - The type of the primary track, or C.TRACK_TYPE_NONE if there is - no primary track. Must be one of the C.TRACK_TYPE_* constants.
          +
          primaryTrackType - The type of the primary track. C.TRACK_TYPE_NONE if there is no primary track.
          manifestFormat - The chunks Format as obtained from the manifest.
          closedCaptionFormats - A list containing the Formats of the closed-caption tracks in the chunks.
          diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.html b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.html index 7249fd35c0..806a241073 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.html @@ -202,7 +202,7 @@ extends Description -SingleSampleMediaChunk​(DataSource dataSource, +SingleSampleMediaChunk​(DataSource dataSource, DataSpec dataSpec, Format trackFormat, int trackSelectionReason, @@ -210,7 +210,7 @@ extends Format sampleFormat)   @@ -298,7 +298,7 @@ extends +
            @@ -307,13 +307,14 @@ extends DataSource dataSource, DataSpec dataSpec, Format trackFormat, + @SelectionReason int trackSelectionReason, @Nullable Object trackSelectionData, long startTimeUs, long endTimeUs, long chunkIndex, - int trackType, + @com.google.android.exoplayer2.C.TrackType int trackType, Format sampleFormat)
          Parameters:
          @@ -325,8 +326,7 @@ extends C.INDEX_UNSET if it is not known. -
          trackType - The type of the chunk. Typically one of the C TRACK_TYPE_* - constants.
          +
          trackType - The track type of the chunk.
          sampleFormat - The Format of the sample in the chunk.
        • diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashChunkSource.Factory.html b/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashChunkSource.Factory.html index 4fb04686e4..715a926983 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashChunkSource.Factory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashChunkSource.Factory.html @@ -153,13 +153,13 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); DashChunkSource -createDashChunkSource​(LoaderErrorThrower manifestLoaderErrorThrower, +createDashChunkSource​(LoaderErrorThrower manifestLoaderErrorThrower, DashManifest manifest, BaseUrlExclusionList baseUrlExclusionList, int periodIndex, int[] adaptationSetIndices, ExoTrackSelection trackSelection, - int type, + @com.google.android.exoplayer2.C.TrackType int trackType, long elapsedRealtimeOffsetMs, boolean enableEventMessageTrack, List<Format> closedCaptionFormats, @@ -184,7 +184,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

          Method Detail

          - +
            @@ -196,7 +196,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); int periodIndex, int[] adaptationSetIndices, ExoTrackSelection trackSelection, - int type, + @com.google.android.exoplayer2.C.TrackType int trackType, long elapsedRealtimeOffsetMs, boolean enableEventMessageTrack, List<Format> closedCaptionFormats, @@ -212,9 +212,11 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
            periodIndex - The index of the corresponding period in the manifest.
            adaptationSetIndices - The indices of the corresponding adaptation sets in the period.
            trackSelection - The track selection.
            +
            trackType - The track type.
            elapsedRealtimeOffsetMs - If known, an estimate of the instantaneous difference between server-side unix time and SystemClock.elapsedRealtime() in milliseconds, - specified as the server's unix time minus the local elapsed time. Or C.TIME_UNSET if unknown.
            + specified as the server's unix time minus the local elapsed time. Or C.TIME_UNSET + if unknown.
            enableEventMessageTrack - Whether to output an event message track.
            closedCaptionFormats - The Formats of closed caption tracks to be output.
            transferListener - The transfer listener which should be informed of any data transfers. diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html b/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html index 07374b8fc0..15130b4b64 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html @@ -87,7 +87,7 @@ loadScripts(document, 'script'); @@ -147,6 +147,23 @@ implements
        @@ -553,7 +571,8 @@ public DashMediaSource.Factory setLivePresentationDelayMs​(long livePresentationDelayMs, boolean overridesManifest)
      • @@ -686,7 +705,7 @@ public Returns:
        The new DashMediaSource.
        Throws:
        -
        NullPointerException - if MediaItem.playbackProperties is null.
        +
        NullPointerException - if MediaItem.localConfiguration is null.
    @@ -758,7 +777,7 @@ public 
  • Summary: 
  • Nested | 
  • -
  • Field | 
  • +
  • Field | 
  • Constr | 
  • Method
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashUtil.html b/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashUtil.html index 66e631b456..0426145cf0 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashUtil.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/dash/DashUtil.html @@ -371,7 +371,7 @@ public static Parameters:
    dataSource - The source from which the data should be loaded.
    -
    trackType - The type of the representation. Typically one of the C TRACK_TYPE_* constants.
    +
    trackType - The type of the representation. Typically one of the com.google.android.exoplayer2.C TRACK_TYPE_* constants.
    representation - The representation which initialization chunk belongs to.
    baseUrlIndex - The index of the base URL to be picked from the list of base URLs.
    Returns:
    @@ -398,7 +398,7 @@ public static Parameters:
    dataSource - The source from which the data should be loaded.
    -
    trackType - The type of the representation. Typically one of the C TRACK_TYPE_* constants.
    +
    trackType - The type of the representation. Typically one of the com.google.android.exoplayer2.C TRACK_TYPE_* constants.
    representation - The representation which initialization chunk belongs to.
    Returns:
    the sample Format of the given representation.
    @@ -423,7 +423,7 @@ public static Parameters:
    dataSource - The source from which the data should be loaded.
    -
    trackType - The type of the representation. Typically one of the C TRACK_TYPE_* constants.
    +
    trackType - The type of the representation. Typically one of the com.google.android.exoplayer2.C TRACK_TYPE_* constants.
    representation - The representation which initialization chunk belongs to.
    baseUrlIndex - The index of the base URL with which to resolve the request URI.
    Returns:
    @@ -451,7 +451,7 @@ public static Parameters:
    dataSource - The source from which the data should be loaded.
    -
    trackType - The type of the representation. Typically one of the C TRACK_TYPE_* constants.
    +
    trackType - The type of the representation. Typically one of the com.google.android.exoplayer2.C TRACK_TYPE_* constants.
    representation - The representation which initialization chunk belongs to.
    Returns:
    The ChunkIndex of the given representation, or null if no initialization or diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.Factory.html b/docs/doc/reference/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.Factory.html index 8cfbd412b4..5e3826aff3 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.Factory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.Factory.html @@ -202,13 +202,13 @@ implements DashChunkSource -createDashChunkSource​(LoaderErrorThrower manifestLoaderErrorThrower, +createDashChunkSource​(LoaderErrorThrower manifestLoaderErrorThrower, DashManifest manifest, BaseUrlExclusionList baseUrlExclusionList, int periodIndex, int[] adaptationSetIndices, ExoTrackSelection trackSelection, - int trackType, + @com.google.android.exoplayer2.C.TrackType int trackType, long elapsedRealtimeOffsetMs, boolean enableEventMessageTrack, List<Format> closedCaptionFormats, @@ -278,7 +278,7 @@ implements ChunkExtractor instances to use for extracting chunks.
    dataSourceFactory - Creates the DataSource to use for downloading chunks.
    -
    maxSegmentsPerLoad - See DefaultDashChunkSource(com.google.android.exoplayer2.source.chunk.ChunkExtractor.Factory, com.google.android.exoplayer2.upstream.LoaderErrorThrower, com.google.android.exoplayer2.source.dash.manifest.DashManifest, com.google.android.exoplayer2.source.dash.BaseUrlExclusionList, int, int[], com.google.android.exoplayer2.trackselection.ExoTrackSelection, int, com.google.android.exoplayer2.upstream.DataSource, long, int, boolean, java.util.List<com.google.android.exoplayer2.Format>, com.google.android.exoplayer2.source.dash.PlayerEmsgHandler.PlayerTrackEmsgHandler).
    +
    maxSegmentsPerLoad - See DefaultDashChunkSource(com.google.android.exoplayer2.source.chunk.ChunkExtractor.Factory, com.google.android.exoplayer2.upstream.LoaderErrorThrower, com.google.android.exoplayer2.source.dash.manifest.DashManifest, com.google.android.exoplayer2.source.dash.BaseUrlExclusionList, int, int[], com.google.android.exoplayer2.trackselection.ExoTrackSelection, @com.google.android.exoplayer2.C.TrackType int, com.google.android.exoplayer2.upstream.DataSource, long, int, boolean, java.util.List<com.google.android.exoplayer2.Format>, com.google.android.exoplayer2.source.dash.PlayerEmsgHandler.PlayerTrackEmsgHandler).
    @@ -292,7 +292,7 @@ implements + - + @@ -342,14 +341,14 @@ extends

    Constructor Detail

    - + @@ -1470,8 +1470,8 @@ protected int parseSelectionFlagsFromRoleDescriptors​(

    parseSelectionFlagsFromDashRoleScheme

    @SelectionFlags
    -protected int parseSelectionFlagsFromDashRoleScheme​(@Nullable
    -                                                    String value)
    +protected @com.google.android.exoplayer2.C.SelectionFlags int parseSelectionFlagsFromDashRoleScheme​(@Nullable + String value) @@ -1481,7 +1481,7 @@ protected int parseSelectionFlagsFromDashRoleScheme​(@Nullable
  • parseRoleFlagsFromRoleDescriptors

    @RoleFlags
    -protected int parseRoleFlagsFromRoleDescriptors​(List<Descriptor> roleDescriptors)
    +protected @com.google.android.exoplayer2.C.RoleFlags int parseRoleFlagsFromRoleDescriptors​(List<Descriptor> roleDescriptors)
  • @@ -1491,7 +1491,7 @@ protected int parseRoleFlagsFromRoleDescriptors​(

    parseRoleFlagsFromAccessibilityDescriptors

    @RoleFlags
    -protected int parseRoleFlagsFromAccessibilityDescriptors​(List<Descriptor> accessibilityDescriptors)
    +protected @com.google.android.exoplayer2.C.RoleFlags int parseRoleFlagsFromAccessibilityDescriptors​(List<Descriptor> accessibilityDescriptors) @@ -1501,7 +1501,7 @@ protected int parseRoleFlagsFromAccessibilityDescriptors​(

    parseRoleFlagsFromProperties

    @RoleFlags
    -protected int parseRoleFlagsFromProperties​(List<Descriptor> accessibilityDescriptors)
    +protected @com.google.android.exoplayer2.C.RoleFlags int parseRoleFlagsFromProperties​(List<Descriptor> accessibilityDescriptors) @@ -1511,8 +1511,8 @@ protected int parseRoleFlagsFromProperties​(

    parseRoleFlagsFromDashRoleScheme

    @RoleFlags
    -protected int parseRoleFlagsFromDashRoleScheme​(@Nullable
    -                                               String value)
    +protected @com.google.android.exoplayer2.C.RoleFlags int parseRoleFlagsFromDashRoleScheme​(@Nullable + String value) @@ -1522,8 +1522,8 @@ protected int parseRoleFlagsFromDashRoleScheme​(@Nullable
  • parseTvaAudioPurposeCsValue

    @RoleFlags
    -protected int parseTvaAudioPurposeCsValue​(@Nullable
    -                                          String value)
    +protected @com.google.android.exoplayer2.C.RoleFlags int parseTvaAudioPurposeCsValue​(@Nullable + String value)
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/dash/offline/DashDownloader.html b/docs/doc/reference/com/google/android/exoplayer2/source/dash/offline/DashDownloader.html index 38834cc617..da11d4a0cf 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/dash/offline/DashDownloader.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/dash/offline/DashDownloader.html @@ -149,7 +149,7 @@ extends Description -HlsMediaPeriod​(HlsExtractorFactory extractorFactory, +HlsMediaPeriod​(HlsExtractorFactory extractorFactory, HlsPlaylistTracker playlistTracker, HlsDataSourceFactory dataSourceFactory, TransferListener mediaTransferListener, @@ -185,7 +185,7 @@ implements Allocator allocator, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory, boolean allowChunklessPreparation, - int metadataType, + @com.google.android.exoplayer2.source.hls.HlsMediaSource.MetadataType int metadataType, boolean useSessionKeys)
    Creates an HLS media period.
    @@ -384,7 +384,7 @@ implements +
    @@ -778,7 +794,7 @@ public 
  • Summary: 
  • Nested | 
  • -
  • Field | 
  • +
  • Field | 
  • Constr | 
  • Method
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/hls/HlsMediaSource.MetadataType.html b/docs/doc/reference/com/google/android/exoplayer2/source/hls/HlsMediaSource.MetadataType.html index a7882ab665..e72c27836b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/hls/HlsMediaSource.MetadataType.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/hls/HlsMediaSource.MetadataType.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    @Documented
     @Retention(SOURCE)
    +@Target(TYPE_USE)
     public static @interface HlsMediaSource.MetadataType
    The types of metadata that can be extracted from HLS streams. @@ -125,7 +126,7 @@ public static @interface HlsMediaSource.MetadataTy
  • HlsMediaSource.METADATA_TYPE_EMSG -

    See HlsMediaSource.Factory.setMetadataType(int).

  • +

    See HlsMediaSource.Factory.setMetadataType(int). diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.html b/docs/doc/reference/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.html index 0eb9418bdd..172efd8dad 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.html @@ -149,7 +149,7 @@ extends OutputConsumerAdapterV30() -

    Equivalent to OutputConsumerAdapterV30(primaryTrackManifestFormat= null, primaryTrackType= C.TRACK_TYPE_NONE, + -OutputConsumerAdapterV30​(Format primaryTrackManifestFormat, - int primaryTrackType, +OutputConsumerAdapterV30​(Format primaryTrackManifestFormat, + @com.google.android.exoplayer2.C.TrackType int primaryTrackType, boolean expectDummySeekMap)
    Creates a new instance.
    @@ -324,11 +324,11 @@ implements

    OutputConsumerAdapterV30

    public OutputConsumerAdapterV30()
    -
    Equivalent to OutputConsumerAdapterV30(primaryTrackManifestFormat= null, primaryTrackType= C.TRACK_TYPE_NONE, + - +
      @@ -336,15 +336,14 @@ implements Format primaryTrackManifestFormat, - int primaryTrackType, + @com.google.android.exoplayer2.C.TrackType int primaryTrackType, boolean expectDummySeekMap)
      Creates a new instance.
      Parameters:
      primaryTrackManifestFormat - The manifest-obtained format of the primary track, or null if not applicable.
      -
      primaryTrackType - The type of the primary track, or C.TRACK_TYPE_NONE if there is - no primary track. Must be one of the C.TRACK_TYPE_* constants.
      +
      primaryTrackType - The type of the primary track. C.TRACK_TYPE_NONE if there is no primary track.
      expectDummySeekMap - Whether the output consumer should expect an initial dummy seek map which should be exposed through getDummySeekMap().
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/package-summary.html b/docs/doc/reference/com/google/android/exoplayer2/source/package-summary.html index fae543fbd6..b661f639c0 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/package-summary.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/package-summary.html @@ -112,7 +112,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); DefaultMediaSourceFactory.AdsLoaderProvider -
      Provides AdsLoader instances for media items that have ad tag URIs.
      +
      Provides AdsLoader instances for media items that have ad tag URIs.
      @@ -288,7 +288,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); LoopingMediaSource Deprecated. -
      To loop a MediaSource indefinitely, use Player.setRepeatMode(int) +
      To loop a MediaSource indefinitely, use Player.setRepeatMode(int) instead of this class.
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/package-tree.html b/docs/doc/reference/com/google/android/exoplayer2/source/package-tree.html index 1bc073bbd3..2f64e1f7de 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/package-tree.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/package-tree.html @@ -168,8 +168,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    • com.google.android.exoplayer2.source.SinglePeriodTimeline
    -
  • com.google.android.exoplayer2.source.TrackGroup (implements android.os.Parcelable)
  • -
  • com.google.android.exoplayer2.source.TrackGroupArray (implements android.os.Parcelable)
  • +
  • com.google.android.exoplayer2.source.TrackGroup (implements com.google.android.exoplayer2.Bundleable)
  • +
  • com.google.android.exoplayer2.source.TrackGroupArray (implements com.google.android.exoplayer2.Bundleable)
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.Factory.html b/docs/doc/reference/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.Factory.html index d792cd6754..eca7ec1dff 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.Factory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.Factory.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":42,"i3":42,"i4":10,"i5":42,"i6":10,"i7":10,"i8":10,"i9":10}; +var data = {"i0":10,"i1":10,"i2":10,"i3":42,"i4":42,"i5":10,"i6":42,"i7":10,"i8":10,"i9":10,"i10":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -87,7 +87,7 @@ loadScripts(document, 'script'); @@ -157,6 +157,23 @@ implements
    @@ -515,7 +558,7 @@ public Returns:
    The new RtspMediaSource.
    Throws:
    -
    NullPointerException - if MediaItem.playbackProperties is null.
    +
    NullPointerException - if MediaItem.localConfiguration is null.
    @@ -571,7 +614,7 @@ public 
  • Summary: 
  • Nested | 
  • -
  • Field | 
  • +
  • Field | 
  • Constr | 
  • Method
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.Factory.html b/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.Factory.html index 27e12c8905..d8c91e621b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.Factory.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.Factory.html @@ -87,7 +87,7 @@ loadScripts(document, 'script'); @@ -147,6 +147,23 @@ implements
    @@ -659,7 +676,7 @@ public Returns:
    The new SsMediaSource.
    Throws:
    -
    NullPointerException - if MediaItem.playbackProperties is null.
    +
    NullPointerException - if MediaItem.localConfiguration is null.
    @@ -731,7 +748,7 @@ public 
  • Summary: 
  • Nested | 
  • -
  • Field | 
  • +
  • Field | 
  • Constr | 
  • Method
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifest.StreamElement.html b/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifest.StreamElement.html index 140f5f1b33..d5fe292c2e 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifest.StreamElement.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifest.StreamElement.html @@ -207,7 +207,7 @@ extends   -int +@com.google.android.exoplayer2.C.TrackType int type   @@ -229,9 +229,9 @@ extends Description -StreamElement​(String baseUri, +StreamElement​(String baseUri, String chunkTemplate, - int type, + @com.google.android.exoplayer2.C.TrackType int type, String subType, long timescale, String name, @@ -329,7 +329,7 @@ extends
  • type

    -
    public final int type
    +
    public final @com.google.android.exoplayer2.C.TrackType int type
  • @@ -433,7 +433,7 @@ public final  +
      @@ -441,7 +441,7 @@ public final String baseUri, String chunkTemplate, - int type, + @com.google.android.exoplayer2.C.TrackType int type, String subType, long timescale, String name, diff --git a/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.html b/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.html index 73c741b16a..e4974a23d2 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.html +++ b/docs/doc/reference/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.html @@ -149,7 +149,7 @@ extends
      public static final class Action.AddMediaItems
       extends Action
      - +
    @@ -202,11 +202,11 @@ extends protected void -doActionImpl​(SimpleExoPlayer player, +doActionImpl​(ExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) -
    Called by Action.doActionAndScheduleNextImpl(SimpleExoPlayer, DefaultTrackSelector, Surface, + @@ -216,7 +216,7 @@ extends Action -doActionAndScheduleNext, doActionAndScheduleNextImpl +doActionAndScheduleNext, doActionAndScheduleNextImpl
    @@ -201,11 +201,11 @@ extends protected void -doActionImpl​(SimpleExoPlayer player, +doActionImpl​(ExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) -
    Called by Action.doActionAndScheduleNextImpl(SimpleExoPlayer, DefaultTrackSelector, Surface, + @@ -215,7 +215,7 @@ extends Action -doActionAndScheduleNext, doActionAndScheduleNextImpl +doActionAndScheduleNext, doActionAndScheduleNextImpl
    @@ -201,11 +201,11 @@ extends protected void -doActionImpl​(SimpleExoPlayer player, +doActionImpl​(ExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) -
    Called by Action.doActionAndScheduleNextImpl(SimpleExoPlayer, DefaultTrackSelector, Surface, + @@ -215,7 +215,7 @@ extends Action -doActionAndScheduleNext, doActionAndScheduleNextImpl +doActionAndScheduleNext, doActionAndScheduleNextImpl
    @@ -203,11 +203,11 @@ extends protected void -doActionImpl​(SimpleExoPlayer player, +doActionImpl​(ExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) -
    Called by Action.doActionAndScheduleNextImpl(SimpleExoPlayer, DefaultTrackSelector, Surface, + @@ -217,7 +217,7 @@ extends Action -doActionAndScheduleNext, doActionAndScheduleNextImpl +doActionAndScheduleNext, doActionAndScheduleNextImpl
    @@ -203,11 +203,11 @@ extends protected void -doActionImpl​(SimpleExoPlayer player, +doActionImpl​(ExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) -
    Called by Action.doActionAndScheduleNextImpl(SimpleExoPlayer, DefaultTrackSelector, Surface, + @@ -217,7 +217,7 @@ extends Action -doActionAndScheduleNext, doActionAndScheduleNextImpl +doActionAndScheduleNext, doActionAndScheduleNextImpl
    @@ -203,11 +203,11 @@ extends protected void -doActionImpl​(SimpleExoPlayer player, +doActionImpl​(ExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) -
    Called by Action.doActionAndScheduleNextImpl(SimpleExoPlayer, DefaultTrackSelector, Surface, + @@ -217,7 +217,7 @@ extends Action -doActionAndScheduleNext, doActionAndScheduleNextImpl +doActionAndScheduleNext, doActionAndScheduleNextImpl
    @@ -179,7 +179,7 @@ extends SetMediaItems​(String tag, - int windowIndex, + int mediaItemIndex, long positionMs, MediaSource... mediaSources)   @@ -204,11 +204,11 @@ extends protected void -doActionImpl​(SimpleExoPlayer player, +doActionImpl​(ExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) -
    Called by Action.doActionAndScheduleNextImpl(SimpleExoPlayer, DefaultTrackSelector, Surface, + @@ -218,7 +218,7 @@ extends Action -doActionAndScheduleNext, doActionAndScheduleNextImpl +doActionAndScheduleNext, doActionAndScheduleNextImpl
    @@ -203,11 +203,11 @@ extends protected void -doActionImpl​(SimpleExoPlayer player, +doActionImpl​(ExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) -
    Called by Action.doActionAndScheduleNextImpl(SimpleExoPlayer, DefaultTrackSelector, Surface, + @@ -217,7 +217,7 @@ extends Action -doActionAndScheduleNext, doActionAndScheduleNextImpl +doActionAndScheduleNext, doActionAndScheduleNextImpl
    @@ -178,8 +178,8 @@ extends Description -SetRepeatMode​(String tag, - int repeatMode) +SetRepeatMode​(String tag, + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode)   @@ -202,11 +202,11 @@ extends protected void -doActionImpl​(SimpleExoPlayer player, +doActionImpl​(ExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) -
    Called by Action.doActionAndScheduleNextImpl(SimpleExoPlayer, DefaultTrackSelector, Surface, + @@ -216,7 +216,7 @@ extends Action -doActionAndScheduleNext, doActionAndScheduleNextImpl +doActionAndScheduleNext, doActionAndScheduleNextImpl
    @@ -201,11 +201,11 @@ extends protected void -doActionImpl​(SimpleExoPlayer player, +doActionImpl​(ExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) -
    Called by Action.doActionAndScheduleNextImpl(SimpleExoPlayer, DefaultTrackSelector, Surface, + @@ -215,7 +215,7 @@ extends Action -doActionAndScheduleNext, doActionAndScheduleNextImpl +doActionAndScheduleNext, doActionAndScheduleNextImpl
    Specified by:
    @@ -678,9 +678,9 @@ implements
  • buildExoPlayer

    -
    protected SimpleExoPlayer buildExoPlayer​(HostActivity host,
    -                                         Surface surface,
    -                                         MappingTrackSelector trackSelector)
    +
    protected ExoPlayer buildExoPlayer​(HostActivity host,
    +                                   Surface surface,
    +                                   MappingTrackSelector trackSelector)
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.Builder.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.Builder.html index c672ef49d6..f3208e376e 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.Builder.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.Builder.html @@ -135,7 +135,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    public static final class ExoPlayerTestRunner.Builder
     extends Object
    -
    Builder to set-up a ExoPlayerTestRunner. Default fake implementations will be used for +
    Builder to set-up an ExoPlayerTestRunner. Default fake implementations will be used for unset test properties.
    @@ -187,7 +187,7 @@ extends ExoPlayerTestRunner.Builder -initialSeek​(int windowIndex, +initialSeek​(int mediaItemIndex, long positionMs)
    Seeks before setting the media sources and preparing the player.
    @@ -304,8 +304,7 @@ extends ExoPlayerTestRunner.Builder skipSettingMediaSources() -
    Skips calling ExoPlayer.setMediaSources(List) before - preparing.
    +
    Skips calling ExoPlayer.setMediaSources(List) before preparing.
    @@ -393,12 +392,12 @@ extends
  • initialSeek

    -
    public ExoPlayerTestRunner.Builder initialSeek​(int windowIndex,
    +
    public ExoPlayerTestRunner.Builder initialSeek​(int mediaItemIndex,
                                                    long positionMs)
    Seeks before setting the media sources and preparing the player.
    Parameters:
    -
    windowIndex - The window index to seek to.
    +
    mediaItemIndex - The media item index to seek to.
    positionMs - The position in milliseconds to seek to.
    Returns:
    This builder.
    @@ -448,8 +447,8 @@ extends

    skipSettingMediaSources

    public ExoPlayerTestRunner.Builder skipSettingMediaSources()
    -
    Skips calling ExoPlayer.setMediaSources(List) before - preparing. Calling this method is not allowed after calls to setMediaSources(MediaSource...), setTimeline(Timeline) and/or setManifest(Object).
    +
    Skips calling ExoPlayer.setMediaSources(List) before preparing. Calling this method + is not allowed after calls to setMediaSources(MediaSource...), setTimeline(Timeline) and/or setManifest(Object).
    Returns:
    This builder.
    @@ -585,7 +584,7 @@ extends setActionSchedule
    public ExoPlayerTestRunner.Builder setActionSchedule​(ActionSchedule actionSchedule)
    Sets an ActionSchedule to be run by the test runner. The first action will be - executed immediately before SimpleExoPlayer.prepare().
    + executed immediately before Player.prepare().
  • Parameters:
    actionSchedule - An ActionSchedule to be used by the test runner.
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.html index 998861c593..45d546ed4b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -130,7 +130,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • All Implemented Interfaces:
    -
    AudioListener, DeviceListener, MetadataOutput, Player.EventListener, Player.Listener, ActionSchedule.Callback, TextOutput, VideoListener
    +
    Player.EventListener, Player.Listener, ActionSchedule.Callback

    public final class ExoPlayerTestRunner
    @@ -161,7 +161,7 @@ implements static class 
     ExoPlayerTestRunner.Builder
     
    -
    Builder to set-up a ExoPlayerTestRunner.
    +
    Builder to set-up an ExoPlayerTestRunner.
    @@ -216,150 +216,119 @@ implements void -assertMediaItemsTransitionedSame​(MediaItem... mediaItems) +assertNoPositionDiscontinuities() -
    Asserts that the media items reported by Player.Listener.onMediaItemTransition(MediaItem, int) are the same as the provided media - items.
    + void -assertMediaItemsTransitionReasonsEqual​(Integer... reasons) +assertPlaybackStatesEqual​(Integer... states) -
    Asserts that the media item transition reasons reported by Player.Listener.onMediaItemTransition(MediaItem, int) are the same as the provided reasons.
    +
    Asserts that the playback states reported by Player.Listener.onPlaybackStateChanged(int) are equal to the provided playback states.
    void -assertNoPositionDiscontinuities() - - - - - -void -assertPlaybackStatesEqual​(Integer... states) - -
    Asserts that the playback states reported by Player.Listener.onPlaybackStateChanged(int) are equal to the provided playback states.
    - - - -void assertPlayedPeriodIndices​(Integer... periodIndices)
    Asserts that the indices of played periods is equal to the provided list of periods.
    - + void assertPositionDiscontinuityReasonsEqual​(Integer... discontinuityReasons) -
    Asserts that the discontinuity reasons reported by Player.Listener.onPositionDiscontinuity(Player.PositionInfo, Player.PositionInfo, int) are +
    Asserts that the discontinuity reasons reported by Player.Listener.onPositionDiscontinuity(Player.PositionInfo, Player.PositionInfo, int) are equal to the provided values.
    - + void assertTimelineChangeReasonsEqual​(Integer... reasons) -
    Asserts that the timeline change reasons reported by Player.Listener.onTimelineChanged(Timeline, int) are equal to the provided timeline change +
    Asserts that the timeline change reasons reported by Player.Listener.onTimelineChanged(Timeline, int) are equal to the provided timeline change reasons.
    - + void assertTimelinesSame​(Timeline... timelines) -
    Asserts that the timelines reported by Player.Listener.onTimelineChanged(Timeline, int) +
    Asserts that the timelines reported by Player.Listener.onTimelineChanged(Timeline, int) are the same to the provided timelines.
    - -void -assertTrackGroupsEqual​(TrackGroupArray trackGroupArray) - -
    Asserts that the last track group array reported by Player.Listener.onTracksChanged(TrackGroupArray, TrackSelectionArray) is equal to the provided - track group array.
    - - - + ExoPlayerTestRunner blockUntilActionScheduleFinished​(long timeoutMs)
    Blocks the current thread until the action schedule finished.
    - + ExoPlayerTestRunner blockUntilEnded​(long timeoutMs)
    Blocks the current thread until the test runner finishes.
    - + void onActionScheduleFinished()
    Called when action schedule finished executing all its actions.
    - + void -onMediaItemTransition​(MediaItem mediaItem, - int reason) +onMediaItemTransition​(MediaItem mediaItem, + @com.google.android.exoplayer2.Player.MediaItemTransitionReason int reason)
    Called when playback transitions to a media item or starts repeating a media item according to the current repeat mode.
    - + void -onPlaybackStateChanged​(int playbackState) +onPlaybackStateChanged​(@com.google.android.exoplayer2.Player.State int playbackState)
    Called when the value returned from Player.getPlaybackState() changes.
    - + void onPlayerError​(PlaybackException error)
    Called when an error occurs.
    - + void -onPositionDiscontinuity​(Player.PositionInfo oldPosition, +onPositionDiscontinuity​(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, - int reason) + @com.google.android.exoplayer2.Player.DiscontinuityReason int reason)
    Called when a position discontinuity occurs.
    - + void -onTimelineChanged​(Timeline timeline, - int reason) +onTimelineChanged​(Timeline timeline, + @com.google.android.exoplayer2.Player.TimelineChangeReason int reason)
    Called when the timeline has been refreshed.
    - -void -onTracksChanged​(TrackGroupArray trackGroups, - TrackSelectionArray trackSelections) - -
    Called when the available or selected tracks change.
    - - - + ExoPlayerTestRunner start()
    Starts the test runner on its own thread.
    - + ExoPlayerTestRunner start​(boolean doPrepare) @@ -379,21 +348,14 @@ implements Player.EventListener -onLoadingChanged, onMaxSeekToPreviousPositionChanged, onPlayerStateChanged, onPositionDiscontinuity, onSeekProcessed, onStaticMetadataChanged
  • +onLoadingChanged, onMaxSeekToPreviousPositionChanged, onPlayerStateChanged, onPositionDiscontinuity, onSeekProcessed, onTracksChanged, onTrackSelectionParametersChanged - @@ -526,7 +488,7 @@ implements

    assertTimelinesSame

    public void assertTimelinesSame​(Timeline... timelines)
    -
    Asserts that the timelines reported by Player.Listener.onTimelineChanged(Timeline, int) +
    Asserts that the timelines reported by Player.Listener.onTimelineChanged(Timeline, int) are the same to the provided timelines. This assert differs from testing equality by not comparing period ids which may be different due to id mapping of child source period ids.
    @@ -542,39 +504,10 @@ implements

    assertTimelineChangeReasonsEqual

    public void assertTimelineChangeReasonsEqual​(Integer... reasons)
    -
    Asserts that the timeline change reasons reported by Player.Listener.onTimelineChanged(Timeline, int) are equal to the provided timeline change +
    Asserts that the timeline change reasons reported by Player.Listener.onTimelineChanged(Timeline, int) are equal to the provided timeline change reasons.
    - - - - - - - -
      -
    • -

      assertMediaItemsTransitionReasonsEqual

      -
      public void assertMediaItemsTransitionReasonsEqual​(Integer... reasons)
      -
      Asserts that the media item transition reasons reported by Player.Listener.onMediaItemTransition(MediaItem, int) are the same as the provided reasons.
      -
      -
      Parameters:
      -
      reasons - A list of expected transition reasons.
      -
      -
    • -
    @@ -582,22 +515,7 @@ implements

    assertPlaybackStatesEqual

    public void assertPlaybackStatesEqual​(Integer... states)
    -
    Asserts that the playback states reported by Player.Listener.onPlaybackStateChanged(int) are equal to the provided playback states.
    - - - - - - @@ -607,7 +525,7 @@ implements

    assertNoPositionDiscontinuities

    public void assertNoPositionDiscontinuities()
    -
    Asserts that Player.Listener.onPositionDiscontinuity(Player.PositionInfo, + @@ -618,7 +536,7 @@ implements

    assertPositionDiscontinuityReasonsEqual

    public void assertPositionDiscontinuityReasonsEqual​(Integer... discontinuityReasons)
    -
    Asserts that the discontinuity reasons reported by Player.Listener.onPositionDiscontinuity(Player.PositionInfo, Player.PositionInfo, int) are +
    Asserts that the discontinuity reasons reported by Player.Listener.onPositionDiscontinuity(Player.PositionInfo, Player.PositionInfo, int) are equal to the provided values.
    Parameters:
    @@ -643,7 +561,7 @@ implements + - + - - - -
      -
    • -

      onTracksChanged

      -
      public void onTracksChanged​(TrackGroupArray trackGroups,
      -                            TrackSelectionArray trackSelections)
      -
      Description copied from interface: Player.EventListener
      -
      Called when the available or selected tracks change. - -

      Player.EventListener.onEvents(Player, Events) will also be called to report this event along with - other events that happen in the same Looper message queue iteration.

      -
      -
      Specified by:
      -
      onTracksChanged in interface Player.EventListener
      -
      Specified by:
      -
      onTracksChanged in interface Player.Listener
      -
      Parameters:
      -
      trackGroups - The available tracks. Never null, but may be of length zero.
      -
      trackSelections - The selected tracks. Never null, but may contain null elements. A - concrete implementation may include null elements if it has a fixed number of renderer - components, wishes to report a TrackSelection for each of them, and has one or more - renderer components that is not assigned any selected tracks.
      -
      -
    • -
    - +
    + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExoMediaDrm.LicenseServer.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExoMediaDrm.LicenseServer.html index 66ed5c64c3..c7c54432bd 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExoMediaDrm.LicenseServer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExoMediaDrm.LicenseServer.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":9,"i1":10,"i2":10,"i3":10}; +var data = {"i0":9,"i1":10,"i2":10,"i3":10,"i4":10,"i5":9}; var tabs = {65535:["t0","All Methods"],1:["t1","Static Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -183,10 +183,20 @@ implements +ImmutableList<ImmutableList<Byte>> +getReceivedProvisionRequests() +  + + ImmutableList<ImmutableList<DrmInitData.SchemeData>> getReceivedSchemeDatas()   + +static FakeExoMediaDrm.LicenseServer +requiringProvisioningThenAllowingSchemeDatas​(List<DrmInitData.SchemeData>... schemeDatas) +  + + + + + + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExoMediaDrm.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExoMediaDrm.html index 795140981e..f04c4224c1 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExoMediaDrm.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExoMediaDrm.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -305,17 +305,18 @@ implements -ExoMediaCrypto -createMediaCrypto​(byte[] sessionId) +CryptoConfig +createCryptoConfig​(byte[] sessionId) -
    Creates an ExoMediaCrypto for a given session.
    +
    Creates a CryptoConfig that can be passed to a compatible decoder to allow decryption + of protected content using the specified session.
    -Class<com.google.android.exoplayer2.testutil.FakeExoMediaDrm.FakeExoMediaCrypto> -getExoMediaCryptoType() +@com.google.android.exoplayer2.C.CryptoType int +getCryptoType() - +
    Returns the type of CryptoConfig instances returned by ExoMediaDrm.createCryptoConfig(byte[]).
    @@ -398,6 +399,14 @@ implements +boolean +requiresSecureDecoder​(byte[] sessionId, + String mimeType) + +
    Returns whether the given session requires use of a secure decoder for the given MIME type.
    + + + void resetProvisioning() @@ -405,7 +414,7 @@ implements + void restoreKeys​(byte[] sessionId, byte[] keySetId) @@ -413,28 +422,28 @@ implements Restores persisted offline keys into a session.
    - + void setOnEventListener​(ExoMediaDrm.OnEventListener listener)
    Sets the listener for DRM events.
    - + void setOnExpirationUpdateListener​(ExoMediaDrm.OnExpirationUpdateListener listener)
    Sets the listener for session expiration events.
    - + void setOnKeyStatusChangeListener​(ExoMediaDrm.OnKeyStatusChangeListener listener)
    Sets the listener for key status change events.
    - + void setPropertyByteArray​(String propertyName, byte[] value) @@ -442,7 +451,7 @@ implements Sets the value of a byte array property.
    - + void setPropertyString​(String propertyName, String value) @@ -450,7 +459,7 @@ implements Sets the value of a string property.
    - + void triggerEvent​(Predicate<byte[]> sessionIdPredicate, int event, @@ -744,8 +753,7 @@ public FakeExoMediaDrm​(int maxConcurrentSessions)
    • provideKeyResponse

      -
      @Nullable
      -public byte[] provideKeyResponse​(byte[] scope,
      +
      public byte[] provideKeyResponse​(byte[] scope,
                                        byte[] response)
                                 throws NotProvisionedException,
                                        DeniedByServerException
      @@ -825,6 +833,26 @@ public byte[] provideKeyResponse​(byte[] scope,
    + + + +
      +
    • +

      requiresSecureDecoder

      +
      public boolean requiresSecureDecoder​(byte[] sessionId,
      +                                     String mimeType)
      +
      Description copied from interface: ExoMediaDrm
      +
      Returns whether the given session requires use of a secure decoder for the given MIME type. + Assumes a license policy that requires the highest level of security supported by the session.
      +
      +
      Specified by:
      +
      requiresSecureDecoder in interface ExoMediaDrm
      +
      Parameters:
      +
      sessionId - The ID of the session.
      +
      mimeType - The content MIME type to query.
      +
      +
    • +
    @@ -971,40 +999,41 @@ public  + - + diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExtractorOutput.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExtractorOutput.html index 5d69d2361b..aeaab83381 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExtractorOutput.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeExtractorOutput.html @@ -244,7 +244,7 @@ implements endTracks()
    Called when all tracks have been identified, meaning no new trackId values will be - passed to ExtractorOutput.track(int, int).
    + passed to ExtractorOutput.track(int, int). @@ -368,18 +368,17 @@ implements public FakeTrackOutput track​(int id, int type) -
    Description copied from interface: ExtractorOutput
    +
    Description copied from interface: ExtractorOutput
    Called by the Extractor to get the TrackOutput for a specific track.

    The same TrackOutput is returned if multiple calls are made with the same id.

    Specified by:
    -
    track in interface ExtractorOutput
    +
    track in interface ExtractorOutput
    Parameters:
    id - A track identifier.
    -
    type - The type of the track. Typically one of the C - TRACK_TYPE_* constants.
    +
    type - The track type.
    Returns:
    The TrackOutput for the given track identifier.
    @@ -394,7 +393,7 @@ implements public void endTracks()
    Called when all tracks have been identified, meaning no new trackId values will be - passed to ExtractorOutput.track(int, int).
    + passed to ExtractorOutput.track(int, int).
    Specified by:
    endTracks in interface ExtractorOutput
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeMediaChunk.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeMediaChunk.html index 0bbaea92f4..3432d8ac6a 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeMediaChunk.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeMediaChunk.html @@ -310,6 +310,7 @@ extends Format trackFormat, long startTimeUs, long endTimeUs, + @SelectionReason int selectionReason)
    Creates a fake media chunk.
    @@ -317,7 +318,7 @@ extends Format.
    startTimeUs - The start time of the media, in microseconds.
    endTimeUs - The end time of the media, in microseconds.
    -
    selectionReason - The reason for selecting this format.
    +
    selectionReason - One of the selection reasons.
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.html index 5e9896d0f9..748ddb8f5b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.html @@ -165,7 +165,7 @@ implements Renderer -Renderer.State, Renderer.VideoScalingMode, Renderer.WakeupListener +Renderer.MessageType, Renderer.State, Renderer.WakeupListener + +
    • @@ -139,7 +144,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));

    public class StubExoPlayer
    -extends BasePlayer
    +extends StubPlayer
     implements ExoPlayer
    An abstract ExoPlayer implementation that throws UnsupportedOperationException from every method.
    @@ -161,7 +166,7 @@ implements ExoPlayer -ExoPlayer.AudioComponent, ExoPlayer.AudioOffloadListener, ExoPlayer.Builder, ExoPlayer.DeviceComponent, ExoPlayer.MetadataComponent, ExoPlayer.TextComponent, ExoPlayer.VideoComponent +ExoPlayer.AudioComponent, ExoPlayer.AudioOffloadListener, ExoPlayer.Builder, ExoPlayer.DeviceComponent, ExoPlayer.TextComponent, ExoPlayer.VideoComponent @@ -241,49 +246,41 @@ implements void +addAnalyticsListener​(AnalyticsListener listener) + +
    Adds an AnalyticsListener to receive analytics events.
    + + + +void addAudioOffloadListener​(ExoPlayer.AudioOffloadListener listener)
    Adds a listener to receive audio offload events.
    - + void addListener​(Player.EventListener listener)
    Registers a listener to receive events from the player.
    - -void -addListener​(Player.Listener listener) - -
    Registers a listener to receive all events from the player.
    - - void -addMediaItems​(int index, - List<MediaItem> mediaItems) - -
    Adds a list of media items at the given index of the playlist.
    - - - -void addMediaSource​(int index, MediaSource mediaSource)
    Adds a media source at the given index of the playlist.
    - + void addMediaSource​(MediaSource mediaSource)
    Adds a media source to the end of the playlist.
    - + void addMediaSources​(int index, List<MediaSource> mediaSources) @@ -291,546 +288,276 @@ implements Adds a list of media sources at the given index of the playlist. - + void addMediaSources​(List<MediaSource> mediaSources)
    Adds a list of media sources to the end of the playlist.
    + +void +clearAuxEffectInfo() + +
    Detaches any previously attached auxiliary audio effect from the underlying audio track.
    + + void -clearVideoSurface() +clearCameraMotionListener​(CameraMotionListener listener) -
    Clears any Surface, SurfaceHolder, SurfaceView or TextureView - currently set on the player.
    +
    Clears the listener which receives camera motion events if it matches the one passed.
    void -clearVideoSurface​(Surface surface) +clearVideoFrameMetadataListener​(VideoFrameMetadataListener listener) -
    Clears the Surface onto which video is being rendered if it matches the one passed.
    +
    Clears the listener which receives video frame metadata events if it matches the one passed.
    -void -clearVideoSurfaceHolder​(SurfaceHolder surfaceHolder) - -
    Clears the SurfaceHolder that holds the Surface onto which video is being - rendered if it matches the one passed.
    - - - -void -clearVideoSurfaceView​(SurfaceView surfaceView) - -
    Clears the SurfaceView onto which video is being rendered if it matches the one passed.
    - - - -void -clearVideoTextureView​(TextureView textureView) - -
    Clears the TextureView onto which video is being rendered if it matches the one passed.
    - - - PlayerMessage createMessage​(PlayerMessage.Target target)
    Creates a message that can be sent to a PlayerMessage.Target.
    - -void -decreaseDeviceVolume() - -
    Decreases the volume of the device.
    - - - + boolean experimentalIsSleepingForOffload()
    Returns whether the player has paused its main loop to save power in offload scheduling mode.
    - + void experimentalSetOffloadSchedulingEnabled​(boolean offloadSchedulingEnabled)
    Sets whether audio offload scheduling is enabled.
    - -Looper -getApplicationLooper() + +AnalyticsCollector +getAnalyticsCollector() -
    Returns the Looper associated with the application thread that's used to access the - player and on which player events are received.
    +
    Returns the AnalyticsCollector used for collecting analytics events.
    - -AudioAttributes -getAudioAttributes() - -
    Returns the attributes for audio playback.
    - - - + ExoPlayer.AudioComponent getAudioComponent() -
    Returns the component of this player for audio output, or null if audio is not supported.
    +
    Deprecated.
    - -Player.Commands -getAvailableCommands() + +DecoderCounters +getAudioDecoderCounters() -
    Returns the player's currently available Player.Commands.
    +
    Returns DecoderCounters for audio, or null if no audio is being played.
    - -long -getBufferedPosition() + +Format +getAudioFormat() -
    Returns an estimate of the position in the current content window or ad up to which data is - buffered, in milliseconds.
    +
    Returns the audio format currently being played, or null if no audio is being played.
    - + +int +getAudioSessionId() + +
    Returns the audio session identifier, or C.AUDIO_SESSION_ID_UNSET if not set.
    + + + Clock getClock()
    Returns the Clock used for playback.
    - -long -getContentBufferedPosition() - -
    If Player.isPlayingAd() returns true, returns an estimate of the content position in - the current content window up to which data is buffered, in milliseconds.
    - - - -long -getContentPosition() - -
    If Player.isPlayingAd() returns true, returns the content position that will be - played once all ads in the ad group have finished playing, in milliseconds.
    - - - -int -getCurrentAdGroupIndex() - -
    If Player.isPlayingAd() returns true, returns the index of the ad group in the period - currently being played.
    - - - -int -getCurrentAdIndexInAdGroup() - -
    If Player.isPlayingAd() returns true, returns the index of the ad in its ad group.
    - - - -List<Cue> -getCurrentCues() - -
    Returns the current Cues.
    - - - -int -getCurrentPeriodIndex() - -
    Returns the index of the period currently being played.
    - - - -long -getCurrentPosition() - -
    Returns the playback position in the current content window or ad, in milliseconds, or the - prospective position in milliseconds if the current timeline is - empty.
    - - - -List<Metadata> -getCurrentStaticMetadata() + +ExoPlayer.DeviceComponent +getDeviceComponent()
    Deprecated.
    - -Timeline -getCurrentTimeline() - -
    Returns the current Timeline.
    - - - -TrackGroupArray -getCurrentTrackGroups() - -
    Returns the available track groups.
    - - - -TrackSelectionArray -getCurrentTrackSelections() - -
    Returns the current track selections.
    - - - -int -getCurrentWindowIndex() - -
    Returns the index of the current window in the timeline, or the prospective window index if the current timeline is empty.
    - - - -ExoPlayer.DeviceComponent -getDeviceComponent() - -
    Returns the component of this player for playback device, or null if it's not supported.
    - - - -DeviceInfo -getDeviceInfo() - -
    Gets the device information.
    - - - -int -getDeviceVolume() - -
    Gets the current volume of the device.
    - - - -long -getDuration() - -
    Returns the duration of the current content window or ad in milliseconds, or C.TIME_UNSET if the duration is not known.
    - - - -int -getMaxSeekToPreviousPosition() - -
    Returns the maximum position for which Player.seekToPrevious() seeks to the previous window, - in milliseconds.
    - - - -MediaMetadata -getMediaMetadata() - -
    Returns the current combined MediaMetadata, or MediaMetadata.EMPTY if not - supported.
    - - - -ExoPlayer.MetadataComponent -getMetadataComponent() - -
    Returns the component of this player for metadata output, or null if metadata is not supported.
    - - - + boolean getPauseAtEndOfMediaItems()
    Returns whether the player pauses playback at the end of each media item.
    - + Looper getPlaybackLooper()
    Returns the Looper associated with the playback thread.
    - -PlaybackParameters -getPlaybackParameters() - -
    Returns the currently active playback parameters.
    - - - -int -getPlaybackState() - -
    Returns the current playback state of the player.
    - - - -int -getPlaybackSuppressionReason() - -
    Returns the reason why playback is suppressed even though Player.getPlayWhenReady() is - true, or Player.PLAYBACK_SUPPRESSION_REASON_NONE if playback is not suppressed.
    - - - + ExoPlaybackException getPlayerError() -
    Equivalent to Player.getPlayerError(), except the exception is guaranteed to be an - ExoPlaybackException.
    +
    Returns the error that caused playback to fail.
    - -MediaMetadata -getPlaylistMetadata() - -
    Returns the playlist MediaMetadata, as set by Player.setPlaylistMetadata(MediaMetadata), or MediaMetadata.EMPTY if not supported.
    - - - -boolean -getPlayWhenReady() - -
    Whether playback will proceed when Player.getPlaybackState() == Player.STATE_READY.
    - - - + int getRendererCount()
    Returns the number of renderers.
    - + int getRendererType​(int index)
    Returns the track type that the renderer at a given index handles.
    - -int -getRepeatMode() - -
    Returns the current Player.RepeatMode used for playback.
    - - - -long -getSeekBackIncrement() - -
    Returns the Player.seekBack() increment.
    - - - -long -getSeekForwardIncrement() - -
    Returns the Player.seekForward() increment.
    - - - + SeekParameters getSeekParameters()
    Returns the currently active SeekParameters of the player.
    - + boolean -getShuffleModeEnabled() +getSkipSilenceEnabled() -
    Returns whether shuffling of windows is enabled.
    +
    Returns whether skipping silences in the audio stream is enabled.
    - + ExoPlayer.TextComponent getTextComponent() -
    Returns the component of this player for text output, or null if text is not supported.
    +
    Deprecated.
    - -long -getTotalBufferedDuration() - -
    Returns an estimate of the total buffered duration from the current position, in milliseconds.
    - - - + TrackSelector getTrackSelector()
    Returns the track selector that this player uses, or null if track selection is not supported.
    - + +int +getVideoChangeFrameRateStrategy() + + + + + ExoPlayer.VideoComponent getVideoComponent() -
    Returns the component of this player for video output, or null if video is not supported.
    +
    Deprecated.
    - -VideoSize -getVideoSize() + +DecoderCounters +getVideoDecoderCounters() -
    Gets the size of the video.
    +
    Returns DecoderCounters for video, or null if no video is being played.
    - -float -getVolume() + +Format +getVideoFormat() -
    Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
    +
    Returns the video format currently being played, or null if no video is being played.
    - -void -increaseDeviceVolume() + +int +getVideoScalingMode() -
    Increases the volume of the device.
    +
    Returns the C.VideoScalingMode.
    - -boolean -isDeviceMuted() - -
    Gets whether the device is muted or not.
    - - - -boolean -isLoading() - -
    Whether the player is currently loading the source.
    - - - -boolean -isPlayingAd() - -
    Returns whether the player is currently playing an ad.
    - - - -void -moveMediaItems​(int fromIndex, - int toIndex, - int newIndex) - -
    Moves the media item range to the new index.
    - - - -void -prepare() - -
    Deprecated. - -
    - - - + void prepare​(MediaSource mediaSource) -
    Deprecated. - -
    +
    Deprecated.
    - + void prepare​(MediaSource mediaSource, boolean resetPosition, boolean resetState) -
    Deprecated. - -
    +
    Deprecated.
    - + void -release() +removeAnalyticsListener​(AnalyticsListener listener) -
    Releases the player.
    +
    Removes an AnalyticsListener.
    - + void removeAudioOffloadListener​(ExoPlayer.AudioOffloadListener listener)
    Removes a listener of audio offload events.
    - + void removeListener​(Player.EventListener listener) -
    Unregister a listener registered through Player.addListener(EventListener).
    +
    Unregister a listener registered through ExoPlayer.addListener(EventListener).
    - -void -removeListener​(Player.Listener listener) - -
    Unregister a listener registered through Player.addListener(Listener).
    - - - -void -removeMediaItems​(int fromIndex, - int toIndex) - -
    Removes a range of media items from the playlist.
    - - - + void retry() -
    Deprecated. -
    Use prepare() instead.
    -
    +
    Deprecated.
    - + void -seekTo​(int windowIndex, - long positionMs) +setAudioAttributes​(AudioAttributes audioAttributes, + boolean handleAudioFocus) -
    Seeks to a position specified in milliseconds in the specified window.
    +
    Sets the attributes for audio playback, used by the underlying audio track.
    - + void -setDeviceMuted​(boolean muted) +setAudioSessionId​(int audioSessionId) -
    Sets the mute state of the device.
    +
    Sets the ID of the audio session to attach to the underlying AudioTrack.
    - + void -setDeviceVolume​(int volume) +setAuxEffectInfo​(AuxEffectInfo auxEffectInfo) -
    Sets the volume of the device.
    +
    Sets information on an auxiliary audio effect to attach to the underlying audio track.
    - + +void +setCameraMotionListener​(CameraMotionListener listener) + +
    Sets a listener of camera motion events.
    + + + void setForegroundMode​(boolean foregroundMode) @@ -838,24 +565,22 @@ implements + void -setMediaItems​(List<MediaItem> mediaItems, - boolean resetPosition) +setHandleAudioBecomingNoisy​(boolean handleAudioBecomingNoisy) -
    Clears the playlist and adds the specified MediaItems.
    +
    Sets whether the player should pause automatically when audio is rerouted from a headset to + device speakers.
    - + void -setMediaItems​(List<MediaItem> mediaItems, - int startWindowIndex, - long startPositionMs) +setHandleWakeLock​(boolean handleWakeLock) -
    Clears the playlist and adds the specified MediaItems.
    +
    Deprecated.
    - + void setMediaSource​(MediaSource mediaSource) @@ -863,7 +588,7 @@ implements + void setMediaSource​(MediaSource mediaSource, boolean resetPosition) @@ -871,7 +596,7 @@ implements Clears the playlist and adds the specified MediaSource. - + void setMediaSource​(MediaSource mediaSource, long startPositionMs) @@ -879,7 +604,7 @@ implements Clears the playlist and adds the specified MediaSource. - + void setMediaSources​(List<MediaSource> mediaSources) @@ -887,7 +612,7 @@ implements + void setMediaSources​(List<MediaSource> mediaSources, boolean resetPosition) @@ -895,119 +620,100 @@ implements Clears the playlist and adds the specified MediaSources. - + void setMediaSources​(List<MediaSource> mediaSources, - int startWindowIndex, + int startMediaItemIndex, long startPositionMs)
    Clears the playlist and adds the specified MediaSources.
    - + void setPauseAtEndOfMediaItems​(boolean pauseAtEndOfMediaItems)
    Sets whether to pause playback at the end of each media item.
    - + void -setPlaybackParameters​(PlaybackParameters playbackParameters) +setPriorityTaskManager​(PriorityTaskManager priorityTaskManager) -
    Attempts to set the playback parameters.
    +
    Sets a PriorityTaskManager, or null to clear a previously set priority task manager.
    - -void -setPlaylistMetadata​(MediaMetadata mediaMetadata) - -
    Sets the playlist MediaMetadata.
    - - - -void -setPlayWhenReady​(boolean playWhenReady) - -
    Sets whether playback should proceed when Player.getPlaybackState() == Player.STATE_READY.
    - - - -void -setRepeatMode​(int repeatMode) - -
    Sets the Player.RepeatMode to be used for playback.
    - - - + void setSeekParameters​(SeekParameters seekParameters)
    Sets the parameters that control how seek operations are performed.
    - -void -setShuffleModeEnabled​(boolean shuffleModeEnabled) - -
    Sets whether shuffling of windows is enabled.
    - - - + void setShuffleOrder​(ShuffleOrder shuffleOrder)
    Sets the shuffle order.
    - + void -setVideoSurface​(Surface surface) +setSkipSilenceEnabled​(boolean skipSilenceEnabled) -
    Sets the Surface onto which video will be rendered.
    +
    Sets whether skipping silences in the audio stream is enabled.
    - + void -setVideoSurfaceHolder​(SurfaceHolder surfaceHolder) +setThrowsWhenUsingWrongThread​(boolean throwsWhenUsingWrongThread) -
    Sets the SurfaceHolder that holds the Surface onto which video will be - rendered.
    +
    Deprecated.
    - + void -setVideoSurfaceView​(SurfaceView surfaceView) +setVideoChangeFrameRateStrategy​(int videoChangeFrameRateStrategy) -
    Sets the SurfaceView onto which video will be rendered.
    +
    Sets a C.VideoChangeFrameRateStrategy that will be used by the player when provided + with a video output Surface.
    - + void -setVideoTextureView​(TextureView textureView) +setVideoFrameMetadataListener​(VideoFrameMetadataListener listener) -
    Sets the TextureView onto which video will be rendered.
    +
    Sets a listener to receive video frame metadata events.
    - + void -setVolume​(float audioVolume) +setVideoScalingMode​(int videoScalingMode) -
    Sets the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
    + - + void -stop​(boolean reset) -  +setWakeMode​(int wakeMode) + +
    Sets how the player should keep the device awake for playback when the screen is off.
    + + @@ -1064,9 +770,9 @@ implements
  • getAudioComponent

    -
    public ExoPlayer.AudioComponent getAudioComponent()
    -
    Description copied from interface: ExoPlayer
    -
    Returns the component of this player for audio output, or null if audio is not supported.
    +
    @Deprecated
    +public ExoPlayer.AudioComponent getAudioComponent()
    +
    Deprecated.
    Specified by:
    getAudioComponent in interface ExoPlayer
    @@ -1079,9 +785,9 @@ implements
  • getVideoComponent

    -
    public ExoPlayer.VideoComponent getVideoComponent()
    -
    Description copied from interface: ExoPlayer
    -
    Returns the component of this player for video output, or null if video is not supported.
    +
    @Deprecated
    +public ExoPlayer.VideoComponent getVideoComponent()
    +
    Deprecated.
    Specified by:
    getVideoComponent in interface ExoPlayer
    @@ -1094,39 +800,24 @@ implements
  • getTextComponent

    -
    public ExoPlayer.TextComponent getTextComponent()
    -
    Description copied from interface: ExoPlayer
    -
    Returns the component of this player for text output, or null if text is not supported.
    +
    @Deprecated
    +public ExoPlayer.TextComponent getTextComponent()
    +
    Deprecated.
    Specified by:
    getTextComponent in interface ExoPlayer
  • - - - -
    • getDeviceComponent

      -
      public ExoPlayer.DeviceComponent getDeviceComponent()
      -
      Description copied from interface: ExoPlayer
      -
      Returns the component of this player for playback device, or null if it's not supported.
      +
      @Deprecated
      +public ExoPlayer.DeviceComponent getDeviceComponent()
      +
      Deprecated.
      Specified by:
      getDeviceComponent in interface ExoPlayer
      @@ -1148,22 +839,6 @@ implements - - -
        -
      • -

        getApplicationLooper

        -
        public Looper getApplicationLooper()
        -
        Description copied from interface: Player
        -
        Returns the Looper associated with the application thread that's used to access the - player and on which player events are received.
        -
        -
        Specified by:
        -
        getApplicationLooper in interface Player
        -
        -
      • -
      @@ -1179,27 +854,6 @@ implements - - -
        -
      • -

        addListener

        -
        public void addListener​(Player.Listener listener)
        -
        Description copied from interface: Player
        -
        Registers a listener to receive all events from the player. - -

        The listener's methods will be called on the thread that was used to construct the player. - However, if the thread used to construct the player does not have a Looper, then the - listener will be called on the main thread.

        -
        -
        Specified by:
        -
        addListener in interface Player
        -
        Parameters:
        -
        listener - The listener to register.
        -
        -
      • -
      @@ -1207,38 +861,18 @@ implements

      addListener

      public void addListener​(Player.EventListener listener)
      -
      Description copied from interface: Player
      +
      Description copied from interface: ExoPlayer
      Registers a listener to receive events from the player. -

      The listener's methods will be called on the thread that was used to construct the player. - However, if the thread used to construct the player does not have a Looper, then the - listener will be called on the main thread.

      +

      The listener's methods will be called on the thread associated with Player.getApplicationLooper().

      Specified by:
      -
      addListener in interface Player
      +
      addListener in interface ExoPlayer
      Parameters:
      listener - The listener to register.
    - - - -
      -
    • -

      removeListener

      -
      public void removeListener​(Player.Listener listener)
      -
      Description copied from interface: Player
      -
      Unregister a listener registered through Player.addListener(Listener). The listener will no - longer receive events.
      -
      -
      Specified by:
      -
      removeListener in interface Player
      -
      Parameters:
      -
      listener - The listener to unregister.
      -
      -
    • -
    @@ -1246,12 +880,12 @@ implements

    removeListener

    public void removeListener​(Player.EventListener listener)
    -
    Description copied from interface: Player
    -
    Unregister a listener registered through Player.addListener(EventListener). The listener will +
    Description copied from interface: ExoPlayer
    +
    Unregister a listener registered through ExoPlayer.addListener(EventListener). The listener will no longer receive events from the player.
    Specified by:
    -
    removeListener in interface Player
    +
    removeListener in interface ExoPlayer
    Parameters:
    listener - The listener to unregister.
    @@ -1291,44 +925,52 @@ implements + - + + + + + @@ -1339,14 +981,20 @@ public int getPlaybackSuppressionReason()
  • getPlayerError

    public ExoPlaybackException getPlayerError()
    -
    Description copied from interface: ExoPlayer
    -
    Equivalent to Player.getPlayerError(), except the exception is guaranteed to be an - ExoPlaybackException.
    +
    Description copied from interface: Player
    +
    Returns the error that caused playback to fail. This is the same error that will have been + reported via Player.Listener.onPlayerError(PlaybackException) at the time of failure. It can + be queried using this method until the player is re-prepared. + +

    Note that this method will always return null if Player.getPlaybackState() is not + Player.STATE_IDLE.

    Specified by:
    getPlayerError in interface ExoPlayer
    Specified by:
    getPlayerError in interface Player
    +
    Overrides:
    +
    getPlayerError in class StubPlayer
    Returns:
    The error, or null.
    See Also:
    @@ -1362,34 +1010,13 @@ public int getPlaybackSuppressionReason()

    retry

    @Deprecated
     public void retry()
    -
    Deprecated. -
    Use prepare() instead.
    -
    +
    Deprecated.
    Specified by:
    retry in interface ExoPlayer
  • - - - - @@ -1398,9 +1025,7 @@ public void prepare()

    prepare

    @Deprecated
     public void prepare​(MediaSource mediaSource)
    -
    Deprecated. - -
    +
    Deprecated.
    Specified by:
    prepare in interface ExoPlayer
    @@ -1417,61 +1042,13 @@ public void prepare​(MediaSource mediaSource, boolean resetPosition, boolean resetState) -
    Deprecated. - -
    +
    Deprecated.
    Specified by:
    prepare in interface ExoPlayer
  • - - - - - - - -
      -
    • -

      setMediaItems

      -
      public void setMediaItems​(List<MediaItem> mediaItems,
      -                          int startWindowIndex,
      -                          long startPositionMs)
      -
      Description copied from interface: Player
      -
      Clears the playlist and adds the specified MediaItems.
      -
      -
      Specified by:
      -
      setMediaItems in interface Player
      -
      Parameters:
      -
      mediaItems - The new MediaItems.
      -
      startWindowIndex - The window index to start playback from. If C.INDEX_UNSET is - passed, the current position is not reset.
      -
      startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given window is used. In any case, if - startWindowIndex is set to C.INDEX_UNSET, this parameter is ignored and the - position is not reset at all.
      -
      -
    • -
    @@ -1525,7 +1102,7 @@ public void prepare​(Parameters:
    mediaSource - The new MediaSource.
    resetPosition - Whether the playback position should be reset to the default position. If - false, playback will start from the position defined by Player.getCurrentWindowIndex() + false, playback will start from the position defined by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition().
  • @@ -1565,7 +1142,7 @@ public void prepare​(mediaSources - The new MediaSources.
    resetPosition - Whether the playback position should be reset to the default position in the first Timeline.Window. If false, playback will start from the position defined - by Player.getCurrentWindowIndex() and Player.getCurrentPosition().
    + by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition().
    @@ -1576,7 +1153,7 @@ public void prepare​(

    setMediaSources

    public void setMediaSources​(List<MediaSource> mediaSources,
    -                            int startWindowIndex,
    +                            int startMediaItemIndex,
                                 long startPositionMs)
    Description copied from interface: ExoPlayer
    Clears the playlist and adds the specified MediaSources.
    @@ -1585,31 +1162,10 @@ public void prepare​(setMediaSources in interface ExoPlayer
    Parameters:
    mediaSources - The new MediaSources.
    -
    startWindowIndex - The window index to start playback from. If C.INDEX_UNSET is - passed, the current position is not reset.
    -
    startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given window is used. In any case, if - startWindowIndex is set to C.INDEX_UNSET, this parameter is ignored and the - position is not reset at all.
    -
    - - - - - -
      -
    • -

      addMediaItems

      -
      public void addMediaItems​(int index,
      -                          List<MediaItem> mediaItems)
      -
      Description copied from interface: Player
      -
      Adds a list of media items at the given index of the playlist.
      -
      -
      Specified by:
      -
      addMediaItems in interface Player
      -
      Parameters:
      -
      index - The index at which to add the media items. If the index is larger than the size of - the playlist, the media items are added to the end of the playlist.
      -
      mediaItems - The MediaItems to add.
      +
      startMediaItemIndex - The media item index to start playback from. If C.INDEX_UNSET is passed, the current position is not reset.
      +
      startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given media item is used. In any case, + if startMediaItemIndex is set to C.INDEX_UNSET, this parameter is ignored + and the position is not reset at all.
    @@ -1685,153 +1241,6 @@ public void prepare​( - - - -
      -
    • -

      moveMediaItems

      -
      public void moveMediaItems​(int fromIndex,
      -                           int toIndex,
      -                           int newIndex)
      -
      Description copied from interface: Player
      -
      Moves the media item range to the new index.
      -
      -
      Specified by:
      -
      moveMediaItems in interface Player
      -
      Parameters:
      -
      fromIndex - The start of the range to move.
      -
      toIndex - The first item not to be included in the range (exclusive).
      -
      newIndex - The new index of the first media item of the range. If the new index is larger - than the size of the remaining playlist after removing the range, the range is moved to the - end of the playlist.
      -
      -
    • -
    - - - -
      -
    • -

      removeMediaItems

      -
      public void removeMediaItems​(int fromIndex,
      -                             int toIndex)
      -
      Description copied from interface: Player
      -
      Removes a range of media items from the playlist.
      -
      -
      Specified by:
      -
      removeMediaItems in interface Player
      -
      Parameters:
      -
      fromIndex - The index at which to start removing media items.
      -
      toIndex - The index of the first item to be kept (exclusive). If the index is larger than - the size of the playlist, media items to the end of the playlist are removed.
      -
      -
    • -
    - - - - - - - -
      -
    • -

      setPlayWhenReady

      -
      public void setPlayWhenReady​(boolean playWhenReady)
      -
      Description copied from interface: Player
      -
      Sets whether playback should proceed when Player.getPlaybackState() == Player.STATE_READY. - -

      If the player is already in the ready state then this method pauses and resumes playback.

      -
      -
      Specified by:
      -
      setPlayWhenReady in interface Player
      -
      Parameters:
      -
      playWhenReady - Whether playback should proceed when ready.
      -
      -
    • -
    - - - - - - - -
      -
    • -

      setRepeatMode

      -
      public void setRepeatMode​(@RepeatMode
      -                          int repeatMode)
      -
      Description copied from interface: Player
      -
      Sets the Player.RepeatMode to be used for playback.
      -
      -
      Specified by:
      -
      setRepeatMode in interface Player
      -
      Parameters:
      -
      repeatMode - The repeat mode.
      -
      -
    • -
    - - - - @@ -1849,172 +1258,281 @@ public void prepare​( - +
    • -

      setShuffleModeEnabled

      -
      public void setShuffleModeEnabled​(boolean shuffleModeEnabled)
      -
      Description copied from interface: Player
      -
      Sets whether shuffling of windows is enabled.
      -
      -
      Specified by:
      -
      setShuffleModeEnabled in interface Player
      -
      Parameters:
      -
      shuffleModeEnabled - Whether shuffling is enabled.
      -
      -
    • -
    - - - - - - - - - - - -
      -
    • -

      seekTo

      -
      public void seekTo​(int windowIndex,
      -                   long positionMs)
      -
      Description copied from interface: Player
      -
      Seeks to a position specified in milliseconds in the specified window.
      -
      -
      Specified by:
      -
      seekTo in interface Player
      -
      Parameters:
      -
      windowIndex - The index of the window.
      -
      positionMs - The seek position in the specified window, or C.TIME_UNSET to seek to - the window's default position.
      -
      -
    • -
    - - - - - - - - - - - - - - - -
      -
    • -

      setPlaybackParameters

      -
      public void setPlaybackParameters​(PlaybackParameters playbackParameters)
      -
      Description copied from interface: Player
      -
      Attempts to set the playback parameters. Passing PlaybackParameters.DEFAULT resets the - player to the default, which means there is no speed or pitch adjustment. +

      setAudioAttributes

      +
      public void setAudioAttributes​(AudioAttributes audioAttributes,
      +                               boolean handleAudioFocus)
      +
      Description copied from interface: ExoPlayer
      +
      Sets the attributes for audio playback, used by the underlying audio track. If not set, the + default audio attributes will be used. They are suitable for general media playback. -

      Playback parameters changes may cause the player to buffer. Player.Listener.onPlaybackParametersChanged(PlaybackParameters) will be called whenever the currently - active playback parameters change.

      +

      Setting the audio attributes during playback may introduce a short gap in audio output as + the audio track is recreated. A new audio session id will also be generated. + +

      If tunneling is enabled by the track selector, the specified audio attributes will be + ignored, but they will take effect if audio is later played without tunneling. + +

      If the device is running a build before platform API version 21, audio attributes cannot be + set directly on the underlying audio track. In this case, the usage will be mapped onto an + equivalent stream type using Util.getStreamTypeForAudioUsage(int). + +

      If audio focus should be handled, the AudioAttributes.usage must be C.USAGE_MEDIA or C.USAGE_GAME. Other usages will throw an IllegalArgumentException.

      Specified by:
      -
      setPlaybackParameters in interface Player
      +
      setAudioAttributes in interface ExoPlayer
      Parameters:
      -
      playbackParameters - The playback parameters.
      +
      audioAttributes - The attributes to use for audio playback.
      +
      handleAudioFocus - True if the player should handle audio focus, false otherwise.
    - + + + + + + + + +
      +
    • +

      setAuxEffectInfo

      +
      public void setAuxEffectInfo​(AuxEffectInfo auxEffectInfo)
      +
      Description copied from interface: ExoPlayer
      +
      Sets information on an auxiliary audio effect to attach to the underlying audio track.
      +
      +
      Specified by:
      +
      setAuxEffectInfo in interface ExoPlayer
      +
      +
    • +
    + + + +
      +
    • +

      clearAuxEffectInfo

      +
      public void clearAuxEffectInfo()
      +
      Description copied from interface: ExoPlayer
      +
      Detaches any previously attached auxiliary audio effect from the underlying audio track.
      +
      +
      Specified by:
      +
      clearAuxEffectInfo in interface ExoPlayer
      +
      +
    • +
    + + + +
      +
    • +

      setSkipSilenceEnabled

      +
      public void setSkipSilenceEnabled​(boolean skipSilenceEnabled)
      +
      Description copied from interface: ExoPlayer
      +
      Sets whether skipping silences in the audio stream is enabled.
      +
      +
      Specified by:
      +
      setSkipSilenceEnabled in interface ExoPlayer
      +
      Parameters:
      +
      skipSilenceEnabled - Whether skipping silences in the audio stream is enabled.
      +
      +
    • +
    + + + +
      +
    • +

      getSkipSilenceEnabled

      +
      public boolean getSkipSilenceEnabled()
      +
      Description copied from interface: ExoPlayer
      +
      Returns whether skipping silences in the audio stream is enabled.
      +
      +
      Specified by:
      +
      getSkipSilenceEnabled in interface ExoPlayer
      +
      +
    • +
    + + + + + + + + + + + + + + + + + + + +
      +
    • +

      setVideoFrameMetadataListener

      +
      public void setVideoFrameMetadataListener​(VideoFrameMetadataListener listener)
      +
      Description copied from interface: ExoPlayer
      +
      Sets a listener to receive video frame metadata events. + +

      This method is intended to be called by the same component that sets the Surface + onto which video will be rendered. If using ExoPlayer's standard UI components, this method + should not be called directly from application code.

      +
      +
      Specified by:
      +
      setVideoFrameMetadataListener in interface ExoPlayer
      +
      Parameters:
      +
      listener - The listener.
      +
      +
    • +
    + + + +
      +
    • +

      clearVideoFrameMetadataListener

      +
      public void clearVideoFrameMetadataListener​(VideoFrameMetadataListener listener)
      +
      Description copied from interface: ExoPlayer
      +
      Clears the listener which receives video frame metadata events if it matches the one passed. + Else does nothing.
      +
      +
      Specified by:
      +
      clearVideoFrameMetadataListener in interface ExoPlayer
      +
      Parameters:
      +
      listener - The listener to clear.
      +
      +
    • +
    + + + + + + + +
      +
    • +

      clearCameraMotionListener

      +
      public void clearCameraMotionListener​(CameraMotionListener listener)
      +
      Description copied from interface: ExoPlayer
      +
      Clears the listener which receives camera motion events if it matches the one passed. Else does + nothing.
      +
      +
      Specified by:
      +
      clearCameraMotionListener in interface ExoPlayer
      +
      Parameters:
      +
      listener - The listener to clear.
    @@ -2051,35 +1569,6 @@ public void prepare​( - - - -
      -
    • -

      stop

      -
      public void stop​(boolean reset)
      -
      -
      Specified by:
      -
      stop in interface Player
      -
      -
    • -
    - - - -
      -
    • -

      release

      -
      public void release()
      -
      Description copied from interface: Player
      -
      Releases the player. This method must be called when the player is no longer required. The - player must not be used after calling this method.
      -
      -
      Specified by:
      -
      release in interface Player
      -
      -
    • -
    @@ -2091,8 +1580,8 @@ public void prepare​(Creates a message that can be sent to a PlayerMessage.Target. By default, the message will be delivered immediately without blocking on the playback thread. The default PlayerMessage.getType() is 0 and the default PlayerMessage.getPayload() is null. If a position is specified with PlayerMessage.setPosition(long), the message will be - delivered at this position in the current window defined by Player.getCurrentWindowIndex(). - Alternatively, the message can be sent at a specific window using PlayerMessage.setPosition(int, long). + delivered at this position in the current media item defined by Player.getCurrentMediaItemIndex(). Alternatively, the message can be sent at a specific mediaItem + using PlayerMessage.setPosition(int, long).
    Specified by:
    createMessage in interface ExoPlayer
    @@ -2132,7 +1621,7 @@ public void prepare​(Parameters:
    index - The index of the renderer.
    Returns:
    -
    One of the TRACK_TYPE_* constants defined in C.
    +
    The track type that the renderer handles.
    @@ -2152,682 +1641,6 @@ public  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      -
    • -

      getCurrentPeriodIndex

      -
      public int getCurrentPeriodIndex()
      -
      Description copied from interface: Player
      -
      Returns the index of the period currently being played.
      -
      -
      Specified by:
      -
      getCurrentPeriodIndex in interface Player
      -
      -
    • -
    - - - - - - - -
      -
    • -

      getDuration

      -
      public long getDuration()
      -
      Description copied from interface: Player
      -
      Returns the duration of the current content window or ad in milliseconds, or C.TIME_UNSET if the duration is not known.
      -
      -
      Specified by:
      -
      getDuration in interface Player
      -
      -
    • -
    - - - -
      -
    • -

      getCurrentPosition

      -
      public long getCurrentPosition()
      -
      Description copied from interface: Player
      -
      Returns the playback position in the current content window or ad, in milliseconds, or the - prospective position in milliseconds if the current timeline is - empty.
      -
      -
      Specified by:
      -
      getCurrentPosition in interface Player
      -
      -
    • -
    - - - -
      -
    • -

      getBufferedPosition

      -
      public long getBufferedPosition()
      -
      Description copied from interface: Player
      -
      Returns an estimate of the position in the current content window or ad up to which data is - buffered, in milliseconds.
      -
      -
      Specified by:
      -
      getBufferedPosition in interface Player
      -
      -
    • -
    - - - -
      -
    • -

      getTotalBufferedDuration

      -
      public long getTotalBufferedDuration()
      -
      Description copied from interface: Player
      -
      Returns an estimate of the total buffered duration from the current position, in milliseconds. - This includes pre-buffered data for subsequent ads and windows.
      -
      -
      Specified by:
      -
      getTotalBufferedDuration in interface Player
      -
      -
    • -
    - - - -
      -
    • -

      isPlayingAd

      -
      public boolean isPlayingAd()
      -
      Description copied from interface: Player
      -
      Returns whether the player is currently playing an ad.
      -
      -
      Specified by:
      -
      isPlayingAd in interface Player
      -
      -
    • -
    - - - - - - - - - - - -
      -
    • -

      getContentPosition

      -
      public long getContentPosition()
      -
      Description copied from interface: Player
      -
      If Player.isPlayingAd() returns true, returns the content position that will be - played once all ads in the ad group have finished playing, in milliseconds. If there is no ad - playing, the returned position is the same as that returned by Player.getCurrentPosition().
      -
      -
      Specified by:
      -
      getContentPosition in interface Player
      -
      -
    • -
    - - - -
      -
    • -

      getContentBufferedPosition

      -
      public long getContentBufferedPosition()
      -
      Description copied from interface: Player
      -
      If Player.isPlayingAd() returns true, returns an estimate of the content position in - the current content window up to which data is buffered, in milliseconds. If there is no ad - playing, the returned position is the same as that returned by Player.getBufferedPosition().
      -
      -
      Specified by:
      -
      getContentBufferedPosition in interface Player
      -
      -
    • -
    - - - - - - - -
      -
    • -

      setVolume

      -
      public void setVolume​(float audioVolume)
      -
      Description copied from interface: Player
      -
      Sets the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
      -
      -
      Specified by:
      -
      setVolume in interface Player
      -
      Parameters:
      -
      audioVolume - Linear output gain to apply to all audio channels.
      -
      -
    • -
    - - - -
      -
    • -

      getVolume

      -
      public float getVolume()
      -
      Description copied from interface: Player
      -
      Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
      -
      -
      Specified by:
      -
      getVolume in interface Player
      -
      Returns:
      -
      The linear gain applied to all audio channels.
      -
      -
    • -
    - - - - - - - -
      -
    • -

      clearVideoSurface

      -
      public void clearVideoSurface​(@Nullable
      -                              Surface surface)
      -
      Description copied from interface: Player
      -
      Clears the Surface onto which video is being rendered if it matches the one passed. - Else does nothing.
      -
      -
      Specified by:
      -
      clearVideoSurface in interface Player
      -
      Parameters:
      -
      surface - The surface to clear.
      -
      -
    • -
    - - - - - - - - - - - -
      -
    • -

      clearVideoSurfaceHolder

      -
      public void clearVideoSurfaceHolder​(@Nullable
      -                                    SurfaceHolder surfaceHolder)
      -
      Description copied from interface: Player
      -
      Clears the SurfaceHolder that holds the Surface onto which video is being - rendered if it matches the one passed. Else does nothing.
      -
      -
      Specified by:
      -
      clearVideoSurfaceHolder in interface Player
      -
      Parameters:
      -
      surfaceHolder - The surface holder to clear.
      -
      -
    • -
    - - - - - - - -
      -
    • -

      clearVideoSurfaceView

      -
      public void clearVideoSurfaceView​(@Nullable
      -                                  SurfaceView surfaceView)
      -
      Description copied from interface: Player
      -
      Clears the SurfaceView onto which video is being rendered if it matches the one passed. - Else does nothing.
      -
      -
      Specified by:
      -
      clearVideoSurfaceView in interface Player
      -
      Parameters:
      -
      surfaceView - The texture view to clear.
      -
      -
    • -
    - - - - - - - -
      -
    • -

      clearVideoTextureView

      -
      public void clearVideoTextureView​(@Nullable
      -                                  TextureView textureView)
      -
      Description copied from interface: Player
      -
      Clears the TextureView onto which video is being rendered if it matches the one passed. - Else does nothing.
      -
      -
      Specified by:
      -
      clearVideoTextureView in interface Player
      -
      Parameters:
      -
      textureView - The texture view to clear.
      -
      -
    • -
    - - - - - - - -
      -
    • -

      getCurrentCues

      -
      public List<Cue> getCurrentCues()
      -
      Description copied from interface: Player
      -
      Returns the current Cues. This list may be empty.
      -
      -
      Specified by:
      -
      getCurrentCues in interface Player
      -
      -
    • -
    - - - -
      -
    • -

      getDeviceInfo

      -
      public DeviceInfo getDeviceInfo()
      -
      Description copied from interface: Player
      -
      Gets the device information.
      -
      -
      Specified by:
      -
      getDeviceInfo in interface Player
      -
      -
    • -
    - - - - - - - -
      -
    • -

      isDeviceMuted

      -
      public boolean isDeviceMuted()
      -
      Description copied from interface: Player
      -
      Gets whether the device is muted or not.
      -
      -
      Specified by:
      -
      isDeviceMuted in interface Player
      -
      -
    • -
    - - - -
      -
    • -

      setDeviceVolume

      -
      public void setDeviceVolume​(int volume)
      -
      Description copied from interface: Player
      -
      Sets the volume of the device.
      -
      -
      Specified by:
      -
      setDeviceVolume in interface Player
      -
      Parameters:
      -
      volume - The volume to set.
      -
      -
    • -
    - - - -
      -
    • -

      increaseDeviceVolume

      -
      public void increaseDeviceVolume()
      -
      Description copied from interface: Player
      -
      Increases the volume of the device.
      -
      -
      Specified by:
      -
      increaseDeviceVolume in interface Player
      -
      -
    • -
    - - - -
      -
    • -

      decreaseDeviceVolume

      -
      public void decreaseDeviceVolume()
      -
      Description copied from interface: Player
      -
      Decreases the volume of the device.
      -
      -
      Specified by:
      -
      decreaseDeviceVolume in interface Player
      -
      -
    • -
    - - - -
      -
    • -

      setDeviceMuted

      -
      public void setDeviceMuted​(boolean muted)
      -
      Description copied from interface: Player
      -
      Sets the mute state of the device.
      -
      -
      Specified by:
      -
      setDeviceMuted in interface Player
      -
      -
    • -
    @@ -2878,7 +1691,7 @@ public Description copied from interface: ExoPlayer
    Sets whether to pause playback at the end of each media item. -

    This means the player will pause at the end of each window in the current timeline. Listeners will be informed by a call to Player.Listener.onPlayWhenReadyChanged(boolean, int) with the reason Player.PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM when this happens.

    +

    This means the player will pause at the end of each window in the current timeline. Listeners will be informed by a call to Player.Listener.onPlayWhenReadyChanged(boolean, int) with the reason Player.PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM when this happens.

    Specified by:
    setPauseAtEndOfMediaItems in interface ExoPlayer
    @@ -2904,6 +1717,173 @@ public  + + +
      +
    • +

      getAudioFormat

      +
      @Nullable
      +public Format getAudioFormat()
      +
      Description copied from interface: ExoPlayer
      +
      Returns the audio format currently being played, or null if no audio is being played.
      +
      +
      Specified by:
      +
      getAudioFormat in interface ExoPlayer
      +
      +
    • +
    + + + +
      +
    • +

      getVideoFormat

      +
      @Nullable
      +public Format getVideoFormat()
      +
      Description copied from interface: ExoPlayer
      +
      Returns the video format currently being played, or null if no video is being played.
      +
      +
      Specified by:
      +
      getVideoFormat in interface ExoPlayer
      +
      +
    • +
    + + + + + + + + + + + +
      +
    • +

      setHandleAudioBecomingNoisy

      +
      public void setHandleAudioBecomingNoisy​(boolean handleAudioBecomingNoisy)
      +
      Description copied from interface: ExoPlayer
      +
      Sets whether the player should pause automatically when audio is rerouted from a headset to + device speakers. See the audio + becoming noisy documentation for more information.
      +
      +
      Specified by:
      +
      setHandleAudioBecomingNoisy in interface ExoPlayer
      +
      Parameters:
      +
      handleAudioBecomingNoisy - Whether the player should pause automatically when audio is + rerouted from a headset to device speakers.
      +
      +
    • +
    + + + + + + + +
      +
    • +

      setWakeMode

      +
      public void setWakeMode​(int wakeMode)
      +
      Description copied from interface: ExoPlayer
      +
      Sets how the player should keep the device awake for playback when the screen is off. + +

      Enabling this feature requires the Manifest.permission.WAKE_LOCK permission. + It should be used together with a foreground Service for use cases where + playback occurs and the screen is off (e.g. background audio playback). It is not useful when + the screen will be kept on during playback (e.g. foreground video playback). + +

      When enabled, the locks (PowerManager.WakeLock / WifiManager.WifiLock) will be held whenever the player is in the Player.STATE_READY or Player.STATE_BUFFERING states with playWhenReady = true. The locks + held depends on the specified C.WakeMode.

      +
      +
      Specified by:
      +
      setWakeMode in interface ExoPlayer
      +
      Parameters:
      +
      wakeMode - The C.WakeMode option to keep the device awake during playback.
      +
      +
    • +
    + + + + + + + +
      +
    • +

      setThrowsWhenUsingWrongThread

      +
      @Deprecated
      +public void setThrowsWhenUsingWrongThread​(boolean throwsWhenUsingWrongThread)
      +
      Deprecated.
      +
      Description copied from interface: ExoPlayer
      +
      Sets whether the player should throw an IllegalStateException when methods are called + from a thread other than the one associated with Player.getApplicationLooper(). + +

      The default is true and this method will be removed in the future.

      +
      +
      Specified by:
      +
      setThrowsWhenUsingWrongThread in interface ExoPlayer
      +
      Parameters:
      +
      throwsWhenUsingWrongThread - Whether to throw when methods are called from a wrong thread.
      +
      +
    • +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/StubPlayer.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/StubPlayer.html new file mode 100644 index 0000000000..b1e6c14dcb --- /dev/null +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/StubPlayer.html @@ -0,0 +1,1958 @@ + + + + +StubPlayer (ExoPlayer library) + + + + + + + + + + + + + +
    + +
    + +
    +
    + +

    Class StubPlayer

    +
    +
    + +
    + +
    +
    + +
    +
    +
      +
    • + +
      +
        +
      • + + +

        Constructor Detail

        + + + +
          +
        • +

          StubPlayer

          +
          public StubPlayer()
          +
        • +
        +
      • +
      +
      + +
      +
        +
      • + + +

        Method Detail

        + + + +
          +
        • +

          getApplicationLooper

          +
          public Looper getApplicationLooper()
          +
          Description copied from interface: Player
          +
          Returns the Looper associated with the application thread that's used to access the + player and on which player events are received.
          +
        • +
        + + + +
          +
        • +

          addListener

          +
          public void addListener​(Player.Listener listener)
          +
          Description copied from interface: Player
          +
          Registers a listener to receive all events from the player. + +

          The listener's methods will be called on the thread associated with Player.getApplicationLooper().

          +
          +
          Parameters:
          +
          listener - The listener to register.
          +
          +
        • +
        + + + +
          +
        • +

          removeListener

          +
          public void removeListener​(Player.Listener listener)
          +
          Description copied from interface: Player
          +
          Unregister a listener registered through Player.addListener(Listener). The listener will no + longer receive events.
          +
          +
          Parameters:
          +
          listener - The listener to unregister.
          +
          +
        • +
        + + + + + + + + + + + + + + + +
          +
        • +

          prepare

          +
          public void prepare()
          +
          Description copied from interface: Player
          +
          Prepares the player.
          +
        • +
        + + + + + + + +
          +
        • +

          setMediaItems

          +
          public void setMediaItems​(List<MediaItem> mediaItems,
          +                          int startIndex,
          +                          long startPositionMs)
          +
          Description copied from interface: Player
          +
          Clears the playlist and adds the specified MediaItems.
          +
          +
          Parameters:
          +
          mediaItems - The new MediaItems.
          +
          startIndex - The MediaItem index to start playback from. If C.INDEX_UNSET + is passed, the current position is not reset.
          +
          startPositionMs - The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given MediaItem is used. In + any case, if startIndex is set to C.INDEX_UNSET, this parameter is ignored + and the position is not reset at all.
          +
          +
        • +
        + + + +
          +
        • +

          addMediaItems

          +
          public void addMediaItems​(int index,
          +                          List<MediaItem> mediaItems)
          +
          Description copied from interface: Player
          +
          Adds a list of media items at the given index of the playlist.
          +
          +
          Parameters:
          +
          index - The index at which to add the media items. If the index is larger than the size of + the playlist, the media items are added to the end of the playlist.
          +
          mediaItems - The MediaItems to add.
          +
          +
        • +
        + + + +
          +
        • +

          moveMediaItems

          +
          public void moveMediaItems​(int fromIndex,
          +                           int toIndex,
          +                           int newIndex)
          +
          Description copied from interface: Player
          +
          Moves the media item range to the new index.
          +
          +
          Parameters:
          +
          fromIndex - The start of the range to move.
          +
          toIndex - The first item not to be included in the range (exclusive).
          +
          newIndex - The new index of the first media item of the range. If the new index is larger + than the size of the remaining playlist after removing the range, the range is moved to the + end of the playlist.
          +
          +
        • +
        + + + +
          +
        • +

          removeMediaItems

          +
          public void removeMediaItems​(int fromIndex,
          +                             int toIndex)
          +
          Description copied from interface: Player
          +
          Removes a range of media items from the playlist.
          +
          +
          Parameters:
          +
          fromIndex - The index at which to start removing media items.
          +
          toIndex - The index of the first item to be kept (exclusive). If the index is larger than + the size of the playlist, media items to the end of the playlist are removed.
          +
          +
        • +
        + + + + + + + +
          +
        • +

          setPlayWhenReady

          +
          public void setPlayWhenReady​(boolean playWhenReady)
          +
          Description copied from interface: Player
          +
          Sets whether playback should proceed when Player.getPlaybackState() == Player.STATE_READY. + +

          If the player is already in the ready state then this method pauses and resumes playback.

          +
          +
          Parameters:
          +
          playWhenReady - Whether playback should proceed when ready.
          +
          +
        • +
        + + + + + + + +
          +
        • +

          setRepeatMode

          +
          public void setRepeatMode​(@RepeatMode
          +                          @com.google.android.exoplayer2.Player.RepeatMode int repeatMode)
          +
          Description copied from interface: Player
          +
          Sets the Player.RepeatMode to be used for playback.
          +
          +
          Parameters:
          +
          repeatMode - The repeat mode.
          +
          +
        • +
        + + + + + + + +
          +
        • +

          setShuffleModeEnabled

          +
          public void setShuffleModeEnabled​(boolean shuffleModeEnabled)
          +
          Description copied from interface: Player
          +
          Sets whether shuffling of media items is enabled.
          +
          +
          Parameters:
          +
          shuffleModeEnabled - Whether shuffling is enabled.
          +
          +
        • +
        + + + + + + + +
          +
        • +

          isLoading

          +
          public boolean isLoading()
          +
          Description copied from interface: Player
          +
          Whether the player is currently loading the source.
          +
          +
          Returns:
          +
          Whether the player is currently loading the source.
          +
          See Also:
          +
          Player.Listener.onIsLoadingChanged(boolean)
          +
          +
        • +
        + + + +
          +
        • +

          seekTo

          +
          public void seekTo​(int mediaItemIndex,
          +                   long positionMs)
          +
          Description copied from interface: Player
          +
          Seeks to a position specified in milliseconds in the specified MediaItem.
          +
          +
          Parameters:
          +
          mediaItemIndex - The index of the MediaItem.
          +
          positionMs - The seek position in the specified MediaItem, or C.TIME_UNSET + to seek to the media item's default position.
          +
          +
        • +
        + + + + + + + + + + + + + + + +
          +
        • +

          setPlaybackParameters

          +
          public void setPlaybackParameters​(PlaybackParameters playbackParameters)
          +
          Description copied from interface: Player
          +
          Attempts to set the playback parameters. Passing PlaybackParameters.DEFAULT resets the + player to the default, which means there is no speed or pitch adjustment. + +

          Playback parameters changes may cause the player to buffer. Player.Listener.onPlaybackParametersChanged(PlaybackParameters) will be called whenever the currently + active playback parameters change.

          +
          +
          Parameters:
          +
          playbackParameters - The playback parameters.
          +
          +
        • +
        + + + + + + + +
          +
        • +

          stop

          +
          public void stop()
          +
          Description copied from interface: Player
          +
          Stops playback without resetting the player. Use Player.pause() rather than this method if + the intention is to pause playback. + +

          Calling this method will cause the playback state to transition to Player.STATE_IDLE. The + player instance can still be used, and Player.release() must still be called on the player if + it's no longer required. + +

          Calling this method does not clear the playlist, reset the playback position or the playback + error.

          +
        • +
        + + + +
          +
        • +

          stop

          +
          @Deprecated
          +public void stop​(boolean reset)
          +
          Deprecated.
          +
        • +
        + + + +
          +
        • +

          release

          +
          public void release()
          +
          Description copied from interface: Player
          +
          Releases the player. This method must be called when the player is no longer required. The + player must not be used after calling this method.
          +
        • +
        + + + + + + + +
          +
        • +

          getCurrentTrackSelections

          +
          public TrackSelectionArray getCurrentTrackSelections()
          +
          Description copied from interface: Player
          +
          Returns the current track selections. + +

          A concrete implementation may include null elements if it has a fixed number of renderer + components, wishes to report a TrackSelection for each of them, and has one or more renderer + components that is not assigned any selected tracks.

          +
          +
          See Also:
          +
          Player.EventListener.onTracksChanged(TrackGroupArray, TrackSelectionArray)
          +
          +
        • +
        + + + + + + + +
          +
        • +

          getTrackSelectionParameters

          +
          public TrackSelectionParameters getTrackSelectionParameters()
          +
          Description copied from interface: Player
          +
          Returns the parameters constraining the track selection.
          +
          +
          See Also:
          +
          }
          +
          +
        • +
        + + + +
          +
        • +

          setTrackSelectionParameters

          +
          public void setTrackSelectionParameters​(TrackSelectionParameters parameters)
          +
          Description copied from interface: Player
          +
          Sets the parameters constraining the track selection. + +

          Unsupported parameters will be silently ignored. + +

          Use Player.getTrackSelectionParameters() to retrieve the current parameters. For example, + the following snippet restricts video to SD whilst keep other track selection parameters + unchanged: + +

          
          + player.setTrackSelectionParameters(
          +   player.getTrackSelectionParameters()
          +         .buildUpon()
          +         .setMaxVideoSizeSd()
          +         .build())
          + 
          +
        • +
        + + + + + + + + + + + +
          +
        • +

          setPlaylistMetadata

          +
          public void setPlaylistMetadata​(MediaMetadata mediaMetadata)
          +
          Description copied from interface: Player
          +
          Sets the playlist MediaMetadata.
          +
        • +
        + + + + + + + +
          +
        • +

          getCurrentPeriodIndex

          +
          public int getCurrentPeriodIndex()
          +
          Description copied from interface: Player
          +
          Returns the index of the period currently being played.
          +
        • +
        + + + +
          +
        • +

          getCurrentMediaItemIndex

          +
          public int getCurrentMediaItemIndex()
          +
          Description copied from interface: Player
          +
          Returns the index of the current MediaItem in the timeline, or the prospective index if the current timeline is + empty.
          +
        • +
        + + + +
          +
        • +

          getDuration

          +
          public long getDuration()
          +
          Description copied from interface: Player
          +
          Returns the duration of the current content or ad in milliseconds, or C.TIME_UNSET if + the duration is not known.
          +
        • +
        + + + +
          +
        • +

          getCurrentPosition

          +
          public long getCurrentPosition()
          +
          Description copied from interface: Player
          +
          Returns the playback position in the current content or ad, in milliseconds, or the prospective + position in milliseconds if the current timeline is empty.
          +
        • +
        + + + +
          +
        • +

          getBufferedPosition

          +
          public long getBufferedPosition()
          +
          Description copied from interface: Player
          +
          Returns an estimate of the position in the current content or ad up to which data is buffered, + in milliseconds.
          +
        • +
        + + + +
          +
        • +

          getTotalBufferedDuration

          +
          public long getTotalBufferedDuration()
          +
          Description copied from interface: Player
          +
          Returns an estimate of the total buffered duration from the current position, in milliseconds. + This includes pre-buffered data for subsequent ads and media items.
          +
        • +
        + + + +
          +
        • +

          isPlayingAd

          +
          public boolean isPlayingAd()
          +
          Description copied from interface: Player
          +
          Returns whether the player is currently playing an ad.
          +
        • +
        + + + +
          +
        • +

          getCurrentAdGroupIndex

          +
          public int getCurrentAdGroupIndex()
          +
          Description copied from interface: Player
          +
          If Player.isPlayingAd() returns true, returns the index of the ad group in the period + currently being played. Returns C.INDEX_UNSET otherwise.
          +
        • +
        + + + +
          +
        • +

          getCurrentAdIndexInAdGroup

          +
          public int getCurrentAdIndexInAdGroup()
          +
          Description copied from interface: Player
          +
          If Player.isPlayingAd() returns true, returns the index of the ad in its ad group. Returns + C.INDEX_UNSET otherwise.
          +
        • +
        + + + +
          +
        • +

          getContentPosition

          +
          public long getContentPosition()
          +
          Description copied from interface: Player
          +
          If Player.isPlayingAd() returns true, returns the content position that will be + played once all ads in the ad group have finished playing, in milliseconds. If there is no ad + playing, the returned position is the same as that returned by Player.getCurrentPosition().
          +
        • +
        + + + +
          +
        • +

          getContentBufferedPosition

          +
          public long getContentBufferedPosition()
          +
          Description copied from interface: Player
          +
          If Player.isPlayingAd() returns true, returns an estimate of the content position in + the current content up to which data is buffered, in milliseconds. If there is no ad playing, + the returned position is the same as that returned by Player.getBufferedPosition().
          +
        • +
        + + + +
          +
        • +

          getAudioAttributes

          +
          public AudioAttributes getAudioAttributes()
          +
          Description copied from interface: Player
          +
          Returns the attributes for audio playback.
          +
        • +
        + + + +
          +
        • +

          setVolume

          +
          public void setVolume​(float volume)
          +
          Description copied from interface: Player
          +
          Sets the audio volume, valid values are between 0 (silence) and 1 (unity gain, signal + unchanged), inclusive.
          +
          +
          Parameters:
          +
          volume - Linear output gain to apply to all audio channels.
          +
          +
        • +
        + + + +
          +
        • +

          getVolume

          +
          public float getVolume()
          +
          Description copied from interface: Player
          +
          Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
          +
          +
          Returns:
          +
          The linear gain applied to all audio channels.
          +
          +
        • +
        + + + + + + + +
          +
        • +

          clearVideoSurface

          +
          public void clearVideoSurface​(@Nullable
          +                              Surface surface)
          +
          Description copied from interface: Player
          +
          Clears the Surface onto which video is being rendered if it matches the one passed. + Else does nothing.
          +
          +
          Parameters:
          +
          surface - The surface to clear.
          +
          +
        • +
        + + + + + + + +
          +
        • +

          setVideoSurfaceHolder

          +
          public void setVideoSurfaceHolder​(@Nullable
          +                                  SurfaceHolder surfaceHolder)
          +
          Description copied from interface: Player
          +
          Sets the SurfaceHolder that holds the Surface onto which video will be + rendered. The player will track the lifecycle of the surface automatically. + +

          The thread that calls the SurfaceHolder.Callback methods must be the thread + associated with Player.getApplicationLooper().

          +
          +
          Parameters:
          +
          surfaceHolder - The surface holder.
          +
          +
        • +
        + + + +
          +
        • +

          clearVideoSurfaceHolder

          +
          public void clearVideoSurfaceHolder​(@Nullable
          +                                    SurfaceHolder surfaceHolder)
          +
          Description copied from interface: Player
          +
          Clears the SurfaceHolder that holds the Surface onto which video is being + rendered if it matches the one passed. Else does nothing.
          +
          +
          Parameters:
          +
          surfaceHolder - The surface holder to clear.
          +
          +
        • +
        + + + +
          +
        • +

          setVideoSurfaceView

          +
          public void setVideoSurfaceView​(@Nullable
          +                                SurfaceView surfaceView)
          +
          Description copied from interface: Player
          +
          Sets the SurfaceView onto which video will be rendered. The player will track the + lifecycle of the surface automatically. + +

          The thread that calls the SurfaceHolder.Callback methods must be the thread + associated with Player.getApplicationLooper().

          +
          +
          Parameters:
          +
          surfaceView - The surface view.
          +
          +
        • +
        + + + +
          +
        • +

          clearVideoSurfaceView

          +
          public void clearVideoSurfaceView​(@Nullable
          +                                  SurfaceView surfaceView)
          +
          Description copied from interface: Player
          +
          Clears the SurfaceView onto which video is being rendered if it matches the one passed. + Else does nothing.
          +
          +
          Parameters:
          +
          surfaceView - The texture view to clear.
          +
          +
        • +
        + + + +
          +
        • +

          setVideoTextureView

          +
          public void setVideoTextureView​(@Nullable
          +                                TextureView textureView)
          +
          Description copied from interface: Player
          +
          Sets the TextureView onto which video will be rendered. The player will track the + lifecycle of the surface automatically. + +

          The thread that calls the TextureView.SurfaceTextureListener methods must be the + thread associated with Player.getApplicationLooper().

          +
          +
          Parameters:
          +
          textureView - The texture view.
          +
          +
        • +
        + + + +
          +
        • +

          clearVideoTextureView

          +
          public void clearVideoTextureView​(@Nullable
          +                                  TextureView textureView)
          +
          Description copied from interface: Player
          +
          Clears the TextureView onto which video is being rendered if it matches the one passed. + Else does nothing.
          +
          +
          Parameters:
          +
          textureView - The texture view to clear.
          +
          +
        • +
        + + + + + + + +
          +
        • +

          getCurrentCues

          +
          public List<Cue> getCurrentCues()
          +
          Description copied from interface: Player
          +
          Returns the current Cues. This list may be empty.
          +
        • +
        + + + +
          +
        • +

          getDeviceInfo

          +
          public DeviceInfo getDeviceInfo()
          +
          Description copied from interface: Player
          +
          Gets the device information.
          +
        • +
        + + + + + + + +
          +
        • +

          isDeviceMuted

          +
          public boolean isDeviceMuted()
          +
          Description copied from interface: Player
          +
          Gets whether the device is muted or not.
          +
        • +
        + + + +
          +
        • +

          setDeviceVolume

          +
          public void setDeviceVolume​(int volume)
          +
          Description copied from interface: Player
          +
          Sets the volume of the device.
          +
          +
          Parameters:
          +
          volume - The volume to set.
          +
          +
        • +
        + + + +
          +
        • +

          increaseDeviceVolume

          +
          public void increaseDeviceVolume()
          +
          Description copied from interface: Player
          +
          Increases the volume of the device.
          +
        • +
        + + + +
          +
        • +

          decreaseDeviceVolume

          +
          public void decreaseDeviceVolume()
          +
          Description copied from interface: Player
          +
          Decreases the volume of the device.
          +
        • +
        + + + +
          +
        • +

          setDeviceMuted

          +
          public void setDeviceMuted​(boolean muted)
          +
          Description copied from interface: Player
          +
          Sets the mute state of the device.
          +
        • +
        +
      • +
      +
      +
    • +
    +
    +
    +
    + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/TestExoPlayerBuilder.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/TestExoPlayerBuilder.html index 44255b405d..35579becf9 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/TestExoPlayerBuilder.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/TestExoPlayerBuilder.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -210,6 +210,13 @@ extends +MediaSourceFactory +getMediaSourceFactory() + +
    Returns the MediaSourceFactory that will be used by the player, or null if no MediaSourceFactory has been set yet and no default is available.
    + + + Renderer[] getRenderers() @@ -217,7 +224,7 @@ extends Renderers have been explicitly set. - + RenderersFactory getRenderersFactory() @@ -225,98 +232,105 @@ extends - + long getSeekBackIncrementMs()
    Returns the seek back increment used by the player.
    - + long getSeekForwardIncrementMs()
    Returns the seek forward increment used by the player.
    - + DefaultTrackSelector getTrackSelector()
    Returns the track selector used by the player.
    - + boolean getUseLazyPreparation()
    Returns whether the player will use lazy preparation.
    - + TestExoPlayerBuilder setBandwidthMeter​(BandwidthMeter bandwidthMeter)
    Sets the BandwidthMeter.
    - + TestExoPlayerBuilder setClock​(Clock clock)
    Sets the Clock to be used by the player.
    - + TestExoPlayerBuilder setLoadControl​(LoadControl loadControl)
    Sets a LoadControl to be used by the player.
    - + TestExoPlayerBuilder setLooper​(Looper looper)
    Sets the Looper to be used by the player.
    - + +TestExoPlayerBuilder +setMediaSourceFactory​(MediaSourceFactory mediaSourceFactory) + +
    Sets the MediaSourceFactory to be used by the player.
    + + + TestExoPlayerBuilder setRenderers​(Renderer... renderers)
    Sets the Renderers.
    - + TestExoPlayerBuilder setRenderersFactory​(RenderersFactory renderersFactory) - + TestExoPlayerBuilder setSeekBackIncrementMs​(long seekBackIncrementMs)
    Sets the seek back increment to be used by the player.
    - + TestExoPlayerBuilder setSeekForwardIncrementMs​(long seekForwardIncrementMs)
    Sets the seek forward increment to be used by the player.
    - + TestExoPlayerBuilder setTrackSelector​(DefaultTrackSelector trackSelector) - + TestExoPlayerBuilder setUseLazyPreparation​(boolean useLazyPreparation) @@ -585,6 +599,33 @@ public  + + + + + + + @@ -645,10 +686,6 @@ public public SimpleExoPlayer build()
    Builds an SimpleExoPlayer using the provided values or their defaults.
    -
    -
    Returns:
    -
    The built ExoPlayerTestRunner.
    -
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/TestUtil.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/TestUtil.html index 0eb30f2d9b..67441c8699 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/TestUtil.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/TestUtil.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":9,"i1":9,"i2":9,"i3":9,"i4":9,"i5":9,"i6":9,"i7":9,"i8":9,"i9":9,"i10":9,"i11":9,"i12":9,"i13":9,"i14":9,"i15":9,"i16":9,"i17":9,"i18":9,"i19":9,"i20":9,"i21":9,"i22":9}; +var data = {"i0":9,"i1":9,"i2":9,"i3":9,"i4":9,"i5":9,"i6":9,"i7":9,"i8":9,"i9":9,"i10":9,"i11":9,"i12":9,"i13":9,"i14":9,"i15":9,"i16":9,"i17":9,"i18":9,"i19":9,"i20":9,"i21":9,"i22":9,"i23":9}; var tabs = {65535:["t0","All Methods"],1:["t1","Static Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -180,20 +180,28 @@ extends +static void +assertTimelinesSame​(List<Timeline> actualTimelines, + List<Timeline> expectedTimelines) + +
    Asserts that the actual timelines are the same to the expected timelines.
    + + + static Uri buildAssetUri​(String assetPath)
    Returns the Uri for the given asset path.
    - + static byte[] buildTestData​(int length)
    Equivalent to buildTestData(length, length).
    - + static byte[] buildTestData​(int length, int seed) @@ -201,7 +209,7 @@ extends Generates an array of random bytes with the specified length. - + static byte[] buildTestData​(int length, Random random) @@ -209,7 +217,7 @@ extends Generates an array of random bytes with the specified length. - + static String buildTestString​(int length, Random random) @@ -217,28 +225,28 @@ extends Generates a random string with the specified length. - + static byte[] createByteArray​(int... bytes)
    Converts an array of integers in the range [0, 255] into an equivalent byte array.
    - + static ImmutableList<Byte> createByteList​(int... bytes)
    Converts an array of integers in the range [0, 255] into an equivalent byte list.
    - + static MetadataInputBuffer createMetadataInputBuffer​(byte[] data)
    Create a new MetadataInputBuffer and copy data into the backing ByteBuffer.
    - + static File createTestFile​(File file, long length) @@ -246,7 +254,7 @@ extends Writes test data with the specified length to the file and returns it. - + static File createTestFile​(File directory, String name) @@ -254,7 +262,7 @@ extends Writes one byte long test data to the file and returns it. - + static File createTestFile​(File directory, String name, @@ -263,7 +271,7 @@ extends Writes test data with the specified length to the file and returns it. - + static FakeExtractorOutput extractAllSamplesFromFile​(Extractor extractor, Context context, @@ -272,7 +280,7 @@ extends Extracts all samples from the given file into a FakeTrackOutput. - + static SeekMap extractSeekMap​(Extractor extractor, FakeExtractorOutput output, @@ -283,7 +291,7 @@ extends - + static Bitmap getBitmap​(Context context, String fileName) @@ -291,7 +299,7 @@ extends Returns a Bitmap read from an asset file. - + static byte[] getByteArray​(Context context, String fileName) @@ -299,7 +307,7 @@ extends Returns the bytes of an asset file. - + static ExtractorInput getExtractorInputFromPosition​(DataSource dataSource, long position, @@ -308,14 +316,14 @@ extends Returns an ExtractorInput to read from the given input at given position. - + static DatabaseProvider getInMemoryDatabaseProvider()
    Returns a DatabaseProvider that provides an in-memory database.
    - + static InputStream getInputStream​(Context context, String fileName) @@ -323,7 +331,7 @@ extends Returns an InputStream for reading from an asset file. - + static String getString​(Context context, String fileName) @@ -331,7 +339,7 @@ extends Returns a String read from an asset file. - + static int seekToTimeUs​(Extractor extractor, SeekMap seekMap, @@ -594,6 +602,24 @@ extends Returns a DatabaseProvider that provides an in-memory database. + + + +
      +
    • +

      assertTimelinesSame

      +
      public static void assertTimelinesSame​(List<Timeline> actualTimelines,
      +                                       List<Timeline> expectedTimelines)
      +
      Asserts that the actual timelines are the same to the expected timelines. This assert differs + from testing equality by not comparing period ids which may be different due to id mapping of + child source period ids.
      +
      +
      Parameters:
      +
      actualTimelines - A list of actual timelines.
      +
      expectedTimelines - A list of expected timelines.
      +
      +
    • +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/TimelineAsserts.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/TimelineAsserts.html index f54b01ef26..58767ef775 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/TimelineAsserts.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/TimelineAsserts.html @@ -169,9 +169,9 @@ extends static void -assertEqualNextWindowIndices​(Timeline expectedTimeline, +assertEqualNextWindowIndices​(Timeline expectedTimeline, Timeline actualTimeline, - int repeatMode, + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode, boolean shuffleModeEnabled)
    Asserts that next window indices for each window of the actual timeline are equal to the @@ -180,9 +180,9 @@ extends static void -assertEqualPreviousWindowIndices​(Timeline expectedTimeline, +assertEqualPreviousWindowIndices​(Timeline expectedTimeline, Timeline actualTimeline, - int repeatMode, + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode, boolean shuffleModeEnabled)
    Asserts that previous window indices for each window of the actual timeline are equal to the @@ -199,8 +199,8 @@ extends static void -assertNextWindowIndices​(Timeline timeline, - int repeatMode, +assertNextWindowIndices​(Timeline timeline, + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode, boolean shuffleModeEnabled, int... expectedNextWindowIndices) @@ -235,8 +235,8 @@ extends static void -assertPreviousWindowIndices​(Timeline timeline, - int repeatMode, +assertPreviousWindowIndices​(Timeline timeline, + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode, boolean shuffleModeEnabled, int... expectedPreviousWindowIndices) @@ -329,7 +329,7 @@ extends Asserts that window properties Timeline.Window.isDynamic are set correctly.
    - + - + - +
      @@ -368,13 +368,13 @@ extends public static void assertEqualPreviousWindowIndices​(Timeline expectedTimeline, Timeline actualTimeline, @RepeatMode - int repeatMode, + @com.google.android.exoplayer2.Player.RepeatMode int repeatMode, boolean shuffleModeEnabled)
      Asserts that previous window indices for each window of the actual timeline are equal to the indices of the expected timeline depending on the repeat mode and the shuffle mode.
    - +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/package-summary.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/package-summary.html index 9f805fe524..f5167b8b35 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/package-summary.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/package-summary.html @@ -177,19 +177,19 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.AddMediaItems - + Action.ClearMediaItems - + Action.ClearVideoSurface - + @@ -201,7 +201,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.MoveMediaItem - + @@ -220,13 +220,13 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.RemoveMediaItem - + Action.RemoveMediaItems - + @@ -244,19 +244,19 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.SetAudioAttributes - + Action.SetMediaItems - + Action.SetMediaItemsResetPosition - + @@ -281,7 +281,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.SetRepeatMode - + @@ -299,7 +299,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.SetVideoSurface - + @@ -335,27 +335,27 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); Action.WaitForPlaybackState -
    Waits for a specified playback state, returning either immediately or after a call to Player.Listener.onPlaybackStateChanged(int).
    +
    Waits for a specified playback state, returning either immediately or after a call to Player.Listener.onPlaybackStateChanged(int).
    Action.WaitForPlayWhenReady
    Waits for a specified playWhenReady value, returning either immediately or after a call to - Player.Listener.onPlayWhenReadyChanged(boolean, int).
    + Player.Listener.onPlayWhenReadyChanged(boolean, int). Action.WaitForPositionDiscontinuity -
    Waits for Player.Listener.onPositionDiscontinuity(Player.PositionInfo, + Action.WaitForTimelineChanged - + @@ -389,205 +389,217 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); +AssetContentProvider + +
    A ContentProvider for reading asset data.
    + + + CacheAsserts
    Assertion methods for Cache.
    - + CacheAsserts.RequestSet
    Defines a set of data requests.
    - + CapturingAudioSink
    A ForwardingAudioSink that captures configuration, discontinuity and buffer events.
    - + CapturingRenderersFactory
    A RenderersFactory that captures interactions with the audio and video MediaCodecAdapter instances.
    - + DataSourceContractTest
    A collection of contract tests for DataSource implementations.
    - + DataSourceContractTest.FakeTransferListener
    A TransferListener that only keeps track of the transferred bytes.
    - + DataSourceContractTest.TestResource
    Information about a resource that can be used to test the DataSource instance.
    - + DataSourceContractTest.TestResource.Builder - + DecoderCountersUtil
    Assertions for DecoderCounters.
    - + DefaultRenderersFactoryAsserts
    Assertions for DefaultRenderersFactory.
    - + DownloadBuilder
    Builder for Download.
    - + DummyMainThread
    Helper class to simulate main/UI thread in tests.
    - + DumpableFormat
    Wraps a Format to allow dumping it.
    - + Dumper
    Helper utility to dump field values.
    - + DumpFileAsserts
    Helper class to enable assertions based on golden-data dump files.
    - + ExoHostedTest
    A HostActivity.HostedTest for ExoPlayer playback tests.
    - + ExoPlayerTestRunner
    Helper class to run an ExoPlayer test.
    - + ExoPlayerTestRunner.Builder -
    Builder to set-up a ExoPlayerTestRunner.
    +
    Builder to set-up an ExoPlayerTestRunner.
    - + ExtractorAsserts
    Assertion methods for Extractor.
    - + ExtractorAsserts.AssertionConfig
    A config for the assertions made (e.g.
    - + ExtractorAsserts.AssertionConfig.Builder
    Builder for ExtractorAsserts.AssertionConfig instances.
    - + ExtractorAsserts.SimulationConfig
    A config of different environments to simulate and extractor behaviours to test.
    - + FailOnCloseDataSink
    A DataSink that can simulate caching the bytes being written to it, and then failing to persist them when FailOnCloseDataSink.close() is called.
    - + FailOnCloseDataSink.Factory
    Factory to create a FailOnCloseDataSink.
    - + FakeAdaptiveDataSet
    Fake data set emulating the data of an adaptive media source.
    - + FakeAdaptiveDataSet.Factory
    Factory for FakeAdaptiveDataSets.
    - + FakeAdaptiveDataSet.Iterator
    MediaChunkIterator for the chunks defined by a fake adaptive data set.
    - + FakeAdaptiveMediaPeriod
    Fake MediaPeriod that provides tracks from the given TrackGroupArray.
    - + FakeAdaptiveMediaSource
    Fake MediaSource that provides a given timeline.
    - + FakeAudioRenderer - + FakeChunkSource
    Fake ChunkSource with adaptive media chunks of a given duration.
    - + FakeChunkSource.Factory
    Factory for a FakeChunkSource.
    - + FakeClock
    Fake Clock implementation that allows to advance the time manually to trigger pending timed messages.
    + +FakeCryptoConfig + + + + FakeDataSet @@ -691,6 +703,18 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); +FakeMediaSourceFactory + +
    Fake MediaSourceFactory that creates a FakeMediaSource.
    + + + +FakeMetadataEntry + + + + + FakeRenderer
    Fake Renderer that supports any format with the matching track type.
    @@ -789,37 +813,44 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height")); +StubPlayer + +
    An abstract Player implementation that throws UnsupportedOperationException from + every method.
    + + + TestExoPlayerBuilder
    A builder of SimpleExoPlayer instances for testing.
    - + TestUtil
    Utility methods for tests.
    - + TimelineAsserts
    Assertion methods for Timeline.
    - + WebServerDispatcher
    A Dispatcher for MockWebServer that allows per-path customisation of the static data served.
    - + WebServerDispatcher.Resource
    A resource served by WebServerDispatcher.
    - + WebServerDispatcher.Resource.Builder diff --git a/docs/doc/reference/com/google/android/exoplayer2/testutil/package-tree.html b/docs/doc/reference/com/google/android/exoplayer2/testutil/package-tree.html index 1962b15df7..55bc854cd1 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/testutil/package-tree.html +++ b/docs/doc/reference/com/google/android/exoplayer2/testutil/package-tree.html @@ -164,9 +164,13 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • com.google.android.exoplayer2.BasePlayer (implements com.google.android.exoplayer2.Player)
      +
    • com.google.android.exoplayer2.testutil.StubPlayer +
    • +
    +
  • com.google.android.exoplayer2.BaseRenderer (implements com.google.android.exoplayer2.Renderer, com.google.android.exoplayer2.RendererCapabilities)
    • com.google.android.exoplayer2.testutil.FakeRenderer @@ -190,6 +194,11 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • +
  • android.content.ContentProvider (implements android.content.ComponentCallbacks2) + +
  • android.content.Context
    • android.content.ContextWrapper @@ -243,6 +252,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    • com.google.android.exoplayer2.testutil.FakeChunkSource.Factory
    • com.google.android.exoplayer2.testutil.FakeClock (implements com.google.android.exoplayer2.util.Clock)
    • com.google.android.exoplayer2.testutil.FakeClock.HandlerMessage (implements java.lang.Comparable<T>, com.google.android.exoplayer2.util.HandlerWrapper.Message)
    • +
    • com.google.android.exoplayer2.testutil.FakeCryptoConfig (implements com.google.android.exoplayer2.decoder.CryptoConfig)
    • com.google.android.exoplayer2.testutil.FakeDataSet
      • com.google.android.exoplayer2.testutil.FakeAdaptiveDataSet
      • @@ -258,6 +268,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
      • com.google.android.exoplayer2.testutil.FakeExtractorInput.Builder
      • com.google.android.exoplayer2.testutil.FakeExtractorOutput (implements com.google.android.exoplayer2.testutil.Dumper.Dumpable, com.google.android.exoplayer2.extractor.ExtractorOutput)
      • com.google.android.exoplayer2.testutil.FakeMediaPeriod (implements com.google.android.exoplayer2.source.MediaPeriod)
      • +
      • com.google.android.exoplayer2.testutil.FakeMediaSourceFactory (implements com.google.android.exoplayer2.source.MediaSourceFactory)
      • +
      • com.google.android.exoplayer2.testutil.FakeMetadataEntry (implements com.google.android.exoplayer2.metadata.Metadata.Entry)
      • com.google.android.exoplayer2.testutil.FakeSampleStream (implements com.google.android.exoplayer2.source.SampleStream)
      • com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem
      • com.google.android.exoplayer2.testutil.FakeShuffleOrder (implements com.google.android.exoplayer2.source.ShuffleOrder)
      • diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.AnchorType.html b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.AnchorType.html index 6eb23858c9..273b95a2dd 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.AnchorType.html +++ b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.AnchorType.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
        @Documented
         @Retention(SOURCE)
        +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
         public static @interface Cue.AnchorType
        The type of anchor, which may be unset. One of Cue.TYPE_UNSET, Cue.ANCHOR_TYPE_START, Cue.ANCHOR_TYPE_MIDDLE or Cue.ANCHOR_TYPE_END.
        diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.Builder.html b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.Builder.html index 9cd6a35fdb..3e903c8d40 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.Builder.html +++ b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.Builder.html @@ -214,14 +214,14 @@ extends -int +@com.google.android.exoplayer2.text.Cue.AnchorType int getLineAnchor() -
        Gets the cue box anchor positioned by line.
        +
        Gets the cue box anchor positioned by line.
        -int +@com.google.android.exoplayer2.text.Cue.LineType int getLineType()
        Gets the type of the value of getLine().
        @@ -231,12 +231,12 @@ extends float getPosition() -
        Gets the fractional position of the positionAnchor of the cue - box within the viewport in the direction orthogonal to line.
        +
        Gets the fractional position of the positionAnchor of the cue + box within the viewport in the direction orthogonal to line.
        -int +@com.google.android.exoplayer2.text.Cue.AnchorType int getPositionAnchor()
        Gets the cue box anchor positioned by position.
        @@ -272,14 +272,14 @@ extends -int +@com.google.android.exoplayer2.text.Cue.TextSizeType int getTextSizeType()
        Gets the default text size type for this cue's text.
        -int +@com.google.android.exoplayer2.text.Cue.VerticalType int getVerticalType()
        Gets the vertical formatting for this Cue.
        @@ -315,8 +315,8 @@ extends Cue.Builder -setLine​(float line, - int lineType) +setLine​(float line, + @com.google.android.exoplayer2.text.Cue.LineType int lineType)
        Sets the position of the cue box within the viewport in the direction orthogonal to the writing direction.
        @@ -324,9 +324,9 @@ extends Cue.Builder -setLineAnchor​(int lineAnchor) +setLineAnchor​(@com.google.android.exoplayer2.text.Cue.AnchorType int lineAnchor) -
        Sets the cue box anchor positioned by line.
        +
        Sets the cue box anchor positioned by line.
        @@ -340,13 +340,13 @@ extends Cue.Builder setPosition​(float position) -
        Sets the fractional position of the positionAnchor of the cue - box within the viewport in the direction orthogonal to line.
        +
        Sets the fractional position of the positionAnchor of the cue + box within the viewport in the direction orthogonal to line.
        Cue.Builder -setPositionAnchor​(int positionAnchor) +setPositionAnchor​(@com.google.android.exoplayer2.text.Cue.AnchorType int positionAnchor)
        Sets the cue box anchor positioned by position.
        @@ -382,15 +382,15 @@ extends Cue.Builder -setTextSize​(float textSize, - int textSizeType) +setTextSize​(float textSize, + @com.google.android.exoplayer2.text.Cue.TextSizeType int textSizeType)
        Sets the default text size and type for this cue's text.
        Cue.Builder -setVerticalType​(int verticalType) +setVerticalType​(@com.google.android.exoplayer2.text.Cue.VerticalType int verticalType)
        Sets the vertical formatting for this Cue.
        @@ -557,7 +557,7 @@ public  +
          @@ -565,7 +565,7 @@ public public Cue.Builder setLine​(float line, @LineType - int lineType) + @com.google.android.exoplayer2.text.Cue.LineType int lineType)
          Sets the position of the cue box within the viewport in the direction orthogonal to the writing direction.
          @@ -599,7 +599,7 @@ public float getLine()

          getLineType

          @Pure
           @LineType
          -public int getLineType()
          +public @com.google.android.exoplayer2.text.Cue.LineType int getLineType()
          Gets the type of the value of getLine().
          See Also:
          @@ -607,15 +607,15 @@ public int getLineType()
        - +
        • setLineAnchor

          public Cue.Builder setLineAnchor​(@AnchorType
          -                                 int lineAnchor)
          -
          Sets the cue box anchor positioned by line.
          + @com.google.android.exoplayer2.text.Cue.AnchorType int lineAnchor) +
          Sets the cue box anchor positioned by line.
          See Also:
          Cue.lineAnchor
          @@ -630,8 +630,8 @@ public int getLineType()

          getLineAnchor

          @Pure
           @AnchorType
          -public int getLineAnchor()
          -
          Gets the cue box anchor positioned by line.
          +public @com.google.android.exoplayer2.text.Cue.AnchorType int getLineAnchor() +
          Gets the cue box anchor positioned by line.
          See Also:
          Cue.lineAnchor
          @@ -645,8 +645,8 @@ public int getLineAnchor()
        • setPosition

          public Cue.Builder setPosition​(float position)
          -
          Sets the fractional position of the positionAnchor of the cue - box within the viewport in the direction orthogonal to line.
          +
          Sets the fractional position of the positionAnchor of the cue + box within the viewport in the direction orthogonal to line.
          See Also:
          Cue.position
          @@ -661,22 +661,22 @@ public int getLineAnchor()

          getPosition

          @Pure
           public float getPosition()
          -
          Gets the fractional position of the positionAnchor of the cue - box within the viewport in the direction orthogonal to line.
          +
          Gets the fractional position of the positionAnchor of the cue + box within the viewport in the direction orthogonal to line.
          See Also:
          Cue.position
        - +
        • setPositionAnchor

          public Cue.Builder setPositionAnchor​(@AnchorType
          -                                     int positionAnchor)
          + @com.google.android.exoplayer2.text.Cue.AnchorType int positionAnchor)
          Sets the cue box anchor positioned by position.
          See Also:
          @@ -692,7 +692,7 @@ public float getPosition()

          getPositionAnchor

          @Pure
           @AnchorType
          -public int getPositionAnchor()
          +public @com.google.android.exoplayer2.text.Cue.AnchorType int getPositionAnchor()
          Gets the cue box anchor positioned by position.
          See Also:
          @@ -700,7 +700,7 @@ public int getPositionAnchor()
        - +
          @@ -708,7 +708,7 @@ public int getPositionAnchor()

          setTextSize

          public Cue.Builder setTextSize​(float textSize,
                                          @TextSizeType
          -                               int textSizeType)
          + @com.google.android.exoplayer2.text.Cue.TextSizeType int textSizeType)
          Sets the default text size and type for this cue's text.
          See Also:
          @@ -725,7 +725,7 @@ public int getPositionAnchor()

          getTextSizeType

          @Pure
           @TextSizeType
          -public int getTextSizeType()
          +public @com.google.android.exoplayer2.text.Cue.TextSizeType int getTextSizeType()
          Gets the default text size type for this cue's text.
          See Also:
          @@ -866,14 +866,14 @@ public int getWindowColor()
        - +
        • setVerticalType

          public Cue.Builder setVerticalType​(@VerticalType
          -                                   int verticalType)
          + @com.google.android.exoplayer2.text.Cue.VerticalType int verticalType)
          Sets the vertical formatting for this Cue.
          See Also:
          @@ -899,7 +899,7 @@ public int getWindowColor()

          getVerticalType

          @Pure
           @VerticalType
          -public int getVerticalType()
          +public @com.google.android.exoplayer2.text.Cue.VerticalType int getVerticalType()
          Gets the vertical formatting for this Cue.
          See Also:
          diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.LineType.html b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.LineType.html index 632df7691c..ab5f914c7b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.LineType.html +++ b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.LineType.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
          @Documented
           @Retention(SOURCE)
          +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
           public static @interface Cue.LineType
          The type of line, which may be unset. One of Cue.TYPE_UNSET, Cue.LINE_TYPE_FRACTION or Cue.LINE_TYPE_NUMBER.
          diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.TextSizeType.html b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.TextSizeType.html index 9cd2ad0ae6..b7ea166bb5 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.TextSizeType.html +++ b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.TextSizeType.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
          @Documented
           @Retention(SOURCE)
          +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
           public static @interface Cue.TextSizeType
          The type of default text size for this cue, which may be unset. One of Cue.TYPE_UNSET, Cue.TEXT_SIZE_TYPE_FRACTIONAL, Cue.TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING or Cue.TEXT_SIZE_TYPE_ABSOLUTE.
          diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.VerticalType.html b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.VerticalType.html index 8ffed3f999..d10ea25ec3 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.VerticalType.html +++ b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.VerticalType.html @@ -115,6 +115,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
          @Documented
           @Retention(SOURCE)
          +@Target({FIELD,METHOD,PARAMETER,LOCAL_VARIABLE,TYPE_USE})
           public static @interface Cue.VerticalType
          The type of vertical layout for this cue, which may be unset (i.e. horizontal). One of Cue.TYPE_UNSET, Cue.VERTICAL_TYPE_RL or Cue.VERTICAL_TYPE_LR.
        • diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.html b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.html index 71fde14006..4f2f64667c 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/text/Cue.html +++ b/docs/doc/reference/com/google/android/exoplayer2/text/Cue.html @@ -298,14 +298,14 @@ implements -int +@com.google.android.exoplayer2.text.Cue.AnchorType int lineAnchor
          The cue box anchor positioned by line when lineType is LINE_TYPE_FRACTION.
          -int +@com.google.android.exoplayer2.text.Cue.LineType int lineType
          The type of the line value.
          @@ -328,7 +328,7 @@ implements -int +@com.google.android.exoplayer2.text.Cue.AnchorType int positionAnchor
          The cue box anchor positioned by position.
          @@ -393,7 +393,7 @@ implements -int +@com.google.android.exoplayer2.text.Cue.TextSizeType int textSizeType
          The default text size type for this cue's text, or TYPE_UNSET if this cue has no @@ -422,7 +422,7 @@ implements -int +@com.google.android.exoplayer2.text.Cue.VerticalType int verticalType
          The vertical formatting of this Cue, or TYPE_UNSET if the cue has no vertical setting @@ -469,13 +469,13 @@ implements -Cue​(CharSequence text, +Cue​(CharSequence text, Layout.Alignment textAlignment, float line, - int lineType, - int lineAnchor, + @com.google.android.exoplayer2.text.Cue.LineType int lineType, + @com.google.android.exoplayer2.text.Cue.AnchorType int lineAnchor, float position, - int positionAnchor, + @com.google.android.exoplayer2.text.Cue.AnchorType int positionAnchor, float size)
          Deprecated. @@ -484,16 +484,16 @@ implements -Cue​(CharSequence text, +Cue​(CharSequence text, Layout.Alignment textAlignment, float line, - int lineType, - int lineAnchor, + @com.google.android.exoplayer2.text.Cue.LineType int lineType, + @com.google.android.exoplayer2.text.Cue.AnchorType int lineAnchor, float position, - int positionAnchor, + @com.google.android.exoplayer2.text.Cue.AnchorType int positionAnchor, float size, - boolean windowColorSet, - int windowColor) + @com.google.android.exoplayer2.text.Cue.TextSizeType int textSizeType, + float textSize)
          Deprecated. @@ -501,16 +501,16 @@ implements -Cue​(CharSequence text, +Cue​(CharSequence text, Layout.Alignment textAlignment, float line, - int lineType, - int lineAnchor, + @com.google.android.exoplayer2.text.Cue.LineType int lineType, + @com.google.android.exoplayer2.text.Cue.AnchorType int lineAnchor, float position, - int positionAnchor, + @com.google.android.exoplayer2.text.Cue.AnchorType int positionAnchor, float size, - int textSizeType, - float textSize) + boolean windowColorSet, + int windowColor)
          Deprecated. @@ -839,7 +839,7 @@ public final 

          lineType

          @LineType
          -public final int lineType
          +public final @com.google.android.exoplayer2.text.Cue.LineType int lineType
          The type of the line value.
            @@ -867,7 +867,7 @@ public final int lineType
          • lineAnchor

            @AnchorType
            -public final int lineAnchor
            +public final @com.google.android.exoplayer2.text.Cue.AnchorType int lineAnchor
            The cue box anchor positioned by line when lineType is LINE_TYPE_FRACTION.

            One of: @@ -911,7 +911,7 @@ public final int lineAnchor

          • positionAnchor

            @AnchorType
            -public final int positionAnchor
            +public final @com.google.android.exoplayer2.text.Cue.AnchorType int positionAnchor
            The cue box anchor positioned by position. One of ANCHOR_TYPE_START, ANCHOR_TYPE_MIDDLE, ANCHOR_TYPE_END and TYPE_UNSET.

            For the normal case of horizontal text, ANCHOR_TYPE_START, ANCHOR_TYPE_MIDDLE and ANCHOR_TYPE_END correspond to the left, middle and right of @@ -968,7 +968,7 @@ public final int positionAnchor

          • textSizeType

            @TextSizeType
            -public final int textSizeType
            +public final @com.google.android.exoplayer2.text.Cue.TextSizeType int textSizeType
            The default text size type for this cue's text, or TYPE_UNSET if this cue has no default text size.
          • @@ -991,7 +991,7 @@ public final int textSizeType
          • verticalType

            @VerticalType
            -public final int verticalType
            +public final @com.google.android.exoplayer2.text.Cue.VerticalType int verticalType
            The vertical formatting of this Cue, or TYPE_UNSET if the cue has no vertical setting (and so should be horizontal).
          • @@ -1045,7 +1045,7 @@ public Cue​( +
              @@ -1057,12 +1057,12 @@ public Cue​(Layout.Alignment textAlignment, float line, @LineType - int lineType, + @com.google.android.exoplayer2.text.Cue.LineType int lineType, @AnchorType - int lineAnchor, + @com.google.android.exoplayer2.text.Cue.AnchorType int lineAnchor, float position, @AnchorType - int positionAnchor, + @com.google.android.exoplayer2.text.Cue.AnchorType int positionAnchor, float size)
              Deprecated. @@ -1081,7 +1081,7 @@ public Cue​( +
                @@ -1093,15 +1093,15 @@ public Cue​(Layout.Alignment textAlignment, float line, @LineType - int lineType, + @com.google.android.exoplayer2.text.Cue.LineType int lineType, @AnchorType - int lineAnchor, + @com.google.android.exoplayer2.text.Cue.AnchorType int lineAnchor, float position, @AnchorType - int positionAnchor, + @com.google.android.exoplayer2.text.Cue.AnchorType int positionAnchor, float size, @TextSizeType - int textSizeType, + @com.google.android.exoplayer2.text.Cue.TextSizeType int textSizeType, float textSize)
                Deprecated. @@ -1122,7 +1122,7 @@ public Cue​( +
                  @@ -1134,12 +1134,12 @@ public Cue​(Layout.Alignment textAlignment, float line, @LineType - int lineType, + @com.google.android.exoplayer2.text.Cue.LineType int lineType, @AnchorType - int lineAnchor, + @com.google.android.exoplayer2.text.Cue.AnchorType int lineAnchor, float position, @AnchorType - int positionAnchor, + @com.google.android.exoplayer2.text.Cue.AnchorType int positionAnchor, float size, boolean windowColorSet, int windowColor) diff --git a/docs/doc/reference/com/google/android/exoplayer2/util/IntArrayQueue.html b/docs/doc/reference/com/google/android/exoplayer2/text/CueDecoder.html similarity index 72% rename from docs/doc/reference/com/google/android/exoplayer2/util/IntArrayQueue.html rename to docs/doc/reference/com/google/android/exoplayer2/text/CueDecoder.html index adf9c49028..7a845cd713 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/util/IntArrayQueue.html +++ b/docs/doc/reference/com/google/android/exoplayer2/text/CueDecoder.html @@ -2,7 +2,7 @@ -IntArrayQueue (ExoPlayer library) +CueDecoder (ExoPlayer library) @@ -19,13 +19,13 @@ + + + + + + + + + +
                  + +
                  + +
                  +
                  + +

                  Class CueEncoder

                  +
                  +
                  + +
                  +
                    +
                  • +
                    +
                    public final class CueEncoder
                    +extends Object
                    +
                    Encodes data that can be decoded by CueDecoder.
                    +
                  • +
                  +
                  +
                  + +
                  +
                  +
                    +
                  • + +
                    +
                      +
                    • + + +

                      Constructor Detail

                      + + + +
                        +
                      • +

                        CueEncoder

                        +
                        public CueEncoder()
                        +
                      • +
                      +
                    • +
                    +
                    + +
                    +
                      +
                    • + + +

                      Method Detail

                      + + + +
                        +
                      • +

                        encode

                        +
                        public byte[] encode​(List<Cue> cues)
                        +
                        Encodes an List of Cue to a byte array that can be decoded by CueDecoder.
                        +
                        +
                        Parameters:
                        +
                        cues - Cues to be encoded.
                        +
                        Returns:
                        +
                        The serialized byte array.
                        +
                        +
                      • +
                      +
                    • +
                    +
                    +
                  • +
                  +
                  +
                  +
                  + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/ExoplayerCuesDecoder.html b/docs/doc/reference/com/google/android/exoplayer2/text/ExoplayerCuesDecoder.html new file mode 100644 index 0000000000..ca24d1adde --- /dev/null +++ b/docs/doc/reference/com/google/android/exoplayer2/text/ExoplayerCuesDecoder.html @@ -0,0 +1,472 @@ + + + + +ExoplayerCuesDecoder (ExoPlayer library) + + + + + + + + + + + + + +
                  + +
                  + +
                  +
                  + +

                  Class ExoplayerCuesDecoder

                  +
                  +
                  +
                    +
                  • java.lang.Object
                  • +
                  • +
                      +
                    • com.google.android.exoplayer2.text.ExoplayerCuesDecoder
                    • +
                    +
                  • +
                  +
                  + +
                  +
                  + +
                  +
                  + +
                  +
                  +
                  + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleDecoder.html b/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleDecoder.html index 9adf827c7c..92be05fc3c 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleDecoder.html +++ b/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleDecoder.html @@ -126,7 +126,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • All Known Implementing Classes:
    -
    Cea608Decoder, Cea708Decoder, DvbDecoder, Mp4WebvttDecoder, PgsDecoder, SimpleSubtitleDecoder, SsaDecoder, SubripDecoder, TtmlDecoder, Tx3gDecoder, WebvttDecoder
    +
    Cea608Decoder, Cea708Decoder, DvbDecoder, ExoplayerCuesDecoder, Mp4WebvttDecoder, PgsDecoder, SimpleSubtitleDecoder, SsaDecoder, SubripDecoder, TtmlDecoder, Tx3gDecoder, WebvttDecoder

    public interface SubtitleDecoder
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleDecoderFactory.html b/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleDecoderFactory.html
    index 86680e3a65..0fb0e3b828 100644
    --- a/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleDecoderFactory.html
    +++ b/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleDecoderFactory.html
    @@ -222,6 +222,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
        
  • Cea708 (Cea708Decoder)
  • DVB (DvbDecoder)
  • PGS (PgsDecoder) +
  • Exoplayer Cues (ExoplayerCuesDecoder)
  • diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleExtractor.html b/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleExtractor.html new file mode 100644 index 0000000000..a565d2e869 --- /dev/null +++ b/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleExtractor.html @@ -0,0 +1,493 @@ + + + + +SubtitleExtractor (ExoPlayer library) + + + + + + + + + + + + + +
    + +
    + +
    +
    + +

    Class SubtitleExtractor

    +
    +
    +
      +
    • java.lang.Object
    • +
    • +
        +
      • com.google.android.exoplayer2.text.SubtitleExtractor
      • +
      +
    • +
    +
    +
      +
    • +
      +
      All Implemented Interfaces:
      +
      Extractor
      +
      +
      +
      public class SubtitleExtractor
      +extends Object
      +implements Extractor
      +
      Generic extractor for extracting subtitles from various subtitle formats.
      +
    • +
    +
    +
    + +
    +
    +
      +
    • + +
      +
        +
      • + + +

        Constructor Detail

        + + + +
          +
        • +

          SubtitleExtractor

          +
          public SubtitleExtractor​(SubtitleDecoder subtitleDecoder,
          +                         Format format)
          +
          +
          Parameters:
          +
          subtitleDecoder - The decoder used for decoding the subtitle data. The extractor will + release the decoder in release().
          +
          format - Format that describes subtitle data.
          +
          +
        • +
        +
      • +
      +
      + +
      +
        +
      • + + +

        Method Detail

        + + + +
          +
        • +

          sniff

          +
          public boolean sniff​(ExtractorInput input)
          +              throws IOException
          +
          Description copied from interface: Extractor
          +
          Returns whether this extractor can extract samples from the ExtractorInput, which must + provide data from the start of the stream. + +

          If true is returned, the input's reading position may have been modified. + Otherwise, only its peek position may have been modified.

          +
          +
          Specified by:
          +
          sniff in interface Extractor
          +
          Parameters:
          +
          input - The ExtractorInput from which data should be peeked/read.
          +
          Returns:
          +
          Whether this extractor can read the provided input.
          +
          Throws:
          +
          IOException - If an error occurred reading from the input.
          +
          +
        • +
        + + + + + + + +
          +
        • +

          read

          +
          public int read​(ExtractorInput input,
          +                PositionHolder seekPosition)
          +         throws IOException
          +
          Description copied from interface: Extractor
          +
          Extracts data read from a provided ExtractorInput. Must not be called before Extractor.init(ExtractorOutput). + +

          A single call to this method will block until some progress has been made, but will not + block for longer than this. Hence each call will consume only a small amount of input data. + +

          In the common case, Extractor.RESULT_CONTINUE is returned to indicate that the ExtractorInput passed to the next read is required to provide data continuing from the + position in the stream reached by the returning call. If the extractor requires data to be + provided from a different position, then that position is set in seekPosition and + Extractor.RESULT_SEEK is returned. If the extractor reached the end of the data provided by the + ExtractorInput, then Extractor.RESULT_END_OF_INPUT is returned. + +

          When this method throws an IOException, extraction may continue by providing an + ExtractorInput with an unchanged read position to + a subsequent call to this method.

          +
          +
          Specified by:
          +
          read in interface Extractor
          +
          Parameters:
          +
          input - The ExtractorInput from which data should be read.
          +
          seekPosition - If Extractor.RESULT_SEEK is returned, this holder is updated to hold the + position of the required data.
          +
          Returns:
          +
          One of the RESULT_ values defined in this interface.
          +
          Throws:
          +
          IOException - If an error occurred reading from or parsing the input.
          +
          +
        • +
        + + + +
          +
        • +

          seek

          +
          public void seek​(long position,
          +                 long timeUs)
          +
          Description copied from interface: Extractor
          +
          Notifies the extractor that a seek has occurred. + +

          Following a call to this method, the ExtractorInput passed to the next invocation of + Extractor.read(ExtractorInput, PositionHolder) is required to provide data starting from + position in the stream. Valid random access positions are the start of the stream and + positions that can be obtained from any SeekMap passed to the ExtractorOutput.

          +
          +
          Specified by:
          +
          seek in interface Extractor
          +
          Parameters:
          +
          position - The byte offset in the stream from which data will be provided.
          +
          timeUs - The seek time in microseconds.
          +
          +
        • +
        + + + +
          +
        • +

          release

          +
          public void release()
          +
          Releases the extractor's resources, including the SubtitleDecoder.
          +
          +
          Specified by:
          +
          release in interface Extractor
          +
          +
        • +
        +
      • +
      +
      +
    • +
    +
    +
    +
    + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleInputBuffer.html b/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleInputBuffer.html index c1fc18ff01..86f34c676f 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleInputBuffer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleInputBuffer.html @@ -186,7 +186,7 @@ extends DecoderInputBuffer -BUFFER_REPLACEMENT_MODE_DIRECT, BUFFER_REPLACEMENT_MODE_DISABLED, BUFFER_REPLACEMENT_MODE_NORMAL, cryptoInfo, data, supplementalData, timeUs, waitingForKeys +BUFFER_REPLACEMENT_MODE_DIRECT, BUFFER_REPLACEMENT_MODE_DISABLED, BUFFER_REPLACEMENT_MODE_NORMAL, cryptoInfo, data, format, supplementalData, timeUs, waitingForKeys diff --git a/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleOutputBuffer.html b/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleOutputBuffer.html index 41665a12c8..410332b356 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleOutputBuffer.html +++ b/docs/doc/reference/com/google/android/exoplayer2/text/SubtitleOutputBuffer.html @@ -124,7 +124,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • com.google.android.exoplayer2.decoder.Buffer
  • @@ -178,11 +178,11 @@ implements -
  • +
  • -

    Fields inherited from class com.google.android.exoplayer2.decoder.OutputBuffer

    -skippedOutputBufferCount, timeUs
  • +

    Fields inherited from class com.google.android.exoplayer2.decoder.DecoderOutputBuffer

    +skippedOutputBufferCount, timeUs @@ -270,11 +270,11 @@ implements -
  • +
  • -

    Methods inherited from class com.google.android.exoplayer2.decoder.OutputBuffer

    -release
  • +

    Methods inherited from class com.google.android.exoplayer2.decoder.DecoderOutputBuffer

    +release @@ -218,6 +225,16 @@ extends static int +DEFAULT_MAX_HEIGHT_TO_DISCARD +  + + +static int +DEFAULT_MAX_WIDTH_TO_DISCARD +  + + +static int DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS   @@ -260,13 +277,15 @@ extends protected -AdaptiveTrackSelection​(TrackGroup group, +AdaptiveTrackSelection​(TrackGroup group, int[] tracks, - int type, + @com.google.android.exoplayer2.trackselection.TrackSelection.Type int type, BandwidthMeter bandwidthMeter, long minDurationForQualityIncreaseMs, long maxDurationForQualityDecreaseMs, long minDurationToRetainAfterDiscardMs, + int maxWidthToDiscard, + int maxHeightToDiscard, float bandwidthFraction, float bufferedFractionToLiveEdgeForQualityIncrease, List<AdaptiveTrackSelection.AdaptationCheckpoint> adaptationCheckpoints, @@ -462,6 +481,32 @@ extends + + +
      +
    • +

      DEFAULT_MAX_WIDTH_TO_DISCARD

      +
      public static final int DEFAULT_MAX_WIDTH_TO_DISCARD
      +
      +
      See Also:
      +
      Constant Field Values
      +
      +
    • +
    + + + +
      +
    • +

      DEFAULT_MAX_HEIGHT_TO_DISCARD

      +
      public static final int DEFAULT_MAX_HEIGHT_TO_DISCARD
      +
      +
      See Also:
      +
      Constant Field Values
      +
      +
    • +
    @@ -516,7 +561,7 @@ extends + + @@ -229,9 +236,9 @@ implements   -BaseTrackSelection​(TrackGroup group, +BaseTrackSelection​(TrackGroup group, int[] tracks, - int type) + @com.google.android.exoplayer2.trackselection.TrackSelection.Type int type)   @@ -460,7 +467,7 @@ implements +
      @@ -468,7 +475,7 @@ implements TrackGroup group, int[] tracks, - int type)
    + @com.google.android.exoplayer2.trackselection.TrackSelection.Type int type)
    Parameters:
    group - The TrackGroup. Must not be null.
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.Parameters.html b/docs/doc/reference/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.Parameters.html index d02f0486da..d855721581 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.Parameters.html +++ b/docs/doc/reference/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.Parameters.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":9,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10}; +var data = {"i0":10,"i1":10,"i2":9,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10}; var tabs = {65535:["t0","All Methods"],1:["t1","Static Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -135,7 +135,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • All Implemented Interfaces:
    -
    Parcelable
    +
    Bundleable
    Enclosing class:
    @@ -144,7 +144,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    public static final class DefaultTrackSelector.Parameters
     extends TrackSelectionParameters
    -implements Parcelable
    +implements Bundleable
    Extends DefaultTrackSelector.Parameters by adding fields that are specific to DefaultTrackSelector.
  • @@ -167,11 +167,11 @@ implements TrackSelectionParameters.Builder
    @@ -233,9 +233,11 @@ implements -static Parcelable.Creator<DefaultTrackSelector.Parameters> +static Bundleable.Creator<DefaultTrackSelector.Parameters> CREATOR -  + +
    Object that can restore Parameters from a Bundle.
    + static DefaultTrackSelector.Parameters @@ -254,7 +256,7 @@ implements -int +@com.google.android.exoplayer2.C.SelectionFlags int disabledTextTrackSelectionFlags
    Bitmask of selection flags that are disabled for text track selections.
    @@ -295,14 +297,7 @@ implements TrackSelectionParameters -forceHighestSupportedBitrate, forceLowestBitrate, maxAudioBitrate, maxAudioChannelCount, maxVideoBitrate, maxVideoFrameRate, maxVideoHeight, maxVideoWidth, minVideoBitrate, minVideoFrameRate, minVideoHeight, minVideoWidth, preferredAudioLanguages, preferredAudioMimeTypes, preferredAudioRoleFlags, preferredTextLanguages, preferredTextRoleFlags, preferredVideoMimeTypes, selectUndeterminedTextLanguage, viewportHeight, viewportOrientationMayChange, viewportWidth - - @@ -329,30 +324,25 @@ implements -int -describeContents() -  - - boolean equals​(Object obj)   - + static DefaultTrackSelector.Parameters getDefaults​(Context context)
    Returns an instance configured with default values.
    - + boolean getRendererDisabled​(int rendererIndex)
    Returns whether the renderer is disabled.
    - + DefaultTrackSelector.SelectionOverride getSelectionOverride​(int rendererIndex, TrackGroupArray groups) @@ -360,12 +350,12 @@ implements Returns the override for the specified renderer and TrackGroupArray. - + int hashCode()   - + boolean hasSelectionOverride​(int rendererIndex, TrackGroupArray groups) @@ -373,11 +363,12 @@ implements Returns whether there is an override for the specified renderer and TrackGroupArray. - -void -writeToParcel​(Parcel dest, - int flags) -  + +Bundle +toBundle() + +
    Returns a Bundle representing the information stored in this object.
    + @@ -564,7 +546,7 @@ public final int disabledTextTrackSelectionFlags -
      +
      • allowMultipleAdaptiveSelections

        public final boolean allowMultipleAdaptiveSelections
        @@ -576,6 +558,16 @@ public final int disabledTextTrackSelectionFlags other track selection parameters.
      + + + +
    @@ -690,34 +682,20 @@ public final  - - - - + diff --git a/docs/doc/reference/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.ParametersBuilder.html b/docs/doc/reference/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.ParametersBuilder.html index 168ceb60a4..dda76457ee 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.ParametersBuilder.html +++ b/docs/doc/reference/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.ParametersBuilder.html @@ -25,8 +25,8 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10,"i36":10,"i37":10,"i38":10,"i39":10,"i40":10,"i41":10,"i42":10,"i43":10}; -var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; +var data = {"i0":10,"i1":42,"i2":42,"i3":42,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":10,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10,"i36":10,"i37":10,"i38":10,"i39":10,"i40":10,"i41":42,"i42":10,"i43":10,"i44":10,"i45":10,"i46":10}; +var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; var tableTab = "tableTab"; @@ -187,7 +187,7 @@ extends -All Methods Instance Methods Concrete Methods  +All Methods Instance Methods Concrete Methods Deprecated Methods  Modifier and Type Method @@ -205,21 +205,27 @@ extends clearSelectionOverride​(int rendererIndex, TrackGroupArray groups) -
    Clears a track selection override for the specified renderer and TrackGroupArray.
    + DefaultTrackSelector.ParametersBuilder clearSelectionOverrides() -
    Clears all track selection overrides for all renderers.
    + DefaultTrackSelector.ParametersBuilder clearSelectionOverrides​(int rendererIndex) -
    Clears all track selection overrides for the specified renderer.
    + @@ -238,41 +244,48 @@ extends +protected DefaultTrackSelector.ParametersBuilder +set​(TrackSelectionParameters parameters) + +
    Overrides the value of the builder with the value of TrackSelectionParameters.
    + + + DefaultTrackSelector.ParametersBuilder setAllowAudioMixedChannelCountAdaptiveness​(boolean allowAudioMixedChannelCountAdaptiveness)
    Sets whether to allow adaptive audio selections containing mixed channel counts.
    - + DefaultTrackSelector.ParametersBuilder setAllowAudioMixedMimeTypeAdaptiveness​(boolean allowAudioMixedMimeTypeAdaptiveness)
    Sets whether to allow adaptive audio selections containing mixed MIME types.
    - + DefaultTrackSelector.ParametersBuilder setAllowAudioMixedSampleRateAdaptiveness​(boolean allowAudioMixedSampleRateAdaptiveness)
    Sets whether to allow adaptive audio selections containing mixed sample rates.
    - + DefaultTrackSelector.ParametersBuilder setAllowMultipleAdaptiveSelections​(boolean allowMultipleAdaptiveSelections)
    Sets whether multiple adaptive selections with more than one track are allowed.
    - + DefaultTrackSelector.ParametersBuilder setAllowVideoMixedMimeTypeAdaptiveness​(boolean allowVideoMixedMimeTypeAdaptiveness)
    Sets whether to allow adaptive video selections containing mixed MIME types.
    - + DefaultTrackSelector.ParametersBuilder setAllowVideoNonSeamlessAdaptiveness​(boolean allowVideoNonSeamlessAdaptiveness) @@ -280,28 +293,36 @@ extends + DefaultTrackSelector.ParametersBuilder -setDisabledTextTrackSelectionFlags​(int disabledTextTrackSelectionFlags) +setDisabledTextTrackSelectionFlags​(@com.google.android.exoplayer2.C.SelectionFlags int disabledTextTrackSelectionFlags)
    Sets a bitmask of selection flags that are disabled for text track selections.
    - + +DefaultTrackSelector.ParametersBuilder +setDisabledTrackTypes​(Set<@TrackType Integer> disabledTrackTypes) + +
    Sets the disabled track types, preventing all tracks of those types from being selected for + playback.
    + + + DefaultTrackSelector.ParametersBuilder setExceedAudioConstraintsIfNecessary​(boolean exceedAudioConstraintsIfNecessary)
    Sets whether to exceed the setMaxAudioChannelCount(int) and setMaxAudioBitrate(int) constraints when no selection can be made otherwise.
    - + DefaultTrackSelector.ParametersBuilder setExceedRendererCapabilitiesIfNecessary​(boolean exceedRendererCapabilitiesIfNecessary)
    Sets whether to exceed renderer capabilities when no selection can be made otherwise.
    - + DefaultTrackSelector.ParametersBuilder setExceedVideoConstraintsIfNecessary​(boolean exceedVideoConstraintsIfNecessary) @@ -309,7 +330,7 @@ extends setMaxVideoFrameRate(int) constraints when no selection can be made otherwise. - + DefaultTrackSelector.ParametersBuilder setForceHighestSupportedBitrate​(boolean forceHighestSupportedBitrate) @@ -317,7 +338,7 @@ extends + DefaultTrackSelector.ParametersBuilder setForceLowestBitrate​(boolean forceLowestBitrate) @@ -325,35 +346,35 @@ extends + DefaultTrackSelector.ParametersBuilder setMaxAudioBitrate​(int maxAudioBitrate)
    Sets the maximum allowed audio bitrate.
    - + DefaultTrackSelector.ParametersBuilder setMaxAudioChannelCount​(int maxAudioChannelCount)
    Sets the maximum allowed audio channel count.
    - + DefaultTrackSelector.ParametersBuilder setMaxVideoBitrate​(int maxVideoBitrate)
    Sets the maximum allowed video bitrate.
    - + DefaultTrackSelector.ParametersBuilder setMaxVideoFrameRate​(int maxVideoFrameRate)
    Sets the maximum allowed video frame rate.
    - + DefaultTrackSelector.ParametersBuilder setMaxVideoSize​(int maxVideoWidth, int maxVideoHeight) @@ -361,28 +382,28 @@ extends Sets the maximum allowed video width and height. - + DefaultTrackSelector.ParametersBuilder setMaxVideoSizeSd() - + DefaultTrackSelector.ParametersBuilder setMinVideoBitrate​(int minVideoBitrate)
    Sets the minimum allowed video bitrate.
    - + DefaultTrackSelector.ParametersBuilder setMinVideoFrameRate​(int minVideoFrameRate)
    Sets the minimum allowed video frame rate.
    - + DefaultTrackSelector.ParametersBuilder setMinVideoSize​(int minVideoWidth, int minVideoHeight) @@ -390,49 +411,49 @@ extends Sets the minimum allowed video width and height. - + DefaultTrackSelector.ParametersBuilder setPreferredAudioLanguage​(String preferredAudioLanguage)
    Sets the preferred language for audio and forced text tracks.
    - + DefaultTrackSelector.ParametersBuilder setPreferredAudioLanguages​(String... preferredAudioLanguages)
    Sets the preferred languages for audio and forced text tracks.
    - + DefaultTrackSelector.ParametersBuilder setPreferredAudioMimeType​(String mimeType)
    Sets the preferred sample MIME type for audio tracks.
    - + DefaultTrackSelector.ParametersBuilder setPreferredAudioMimeTypes​(String... mimeTypes)
    Sets the preferred sample MIME types for audio tracks.
    - + DefaultTrackSelector.ParametersBuilder -setPreferredAudioRoleFlags​(int preferredAudioRoleFlags) +setPreferredAudioRoleFlags​(@com.google.android.exoplayer2.C.RoleFlags int preferredAudioRoleFlags)
    Sets the preferred C.RoleFlags for audio tracks.
    - + DefaultTrackSelector.ParametersBuilder setPreferredTextLanguage​(String preferredTextLanguage)
    Sets the preferred language for text tracks.
    - + DefaultTrackSelector.ParametersBuilder setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings​(Context context) @@ -440,35 +461,35 @@ extends CaptioningManager. - + DefaultTrackSelector.ParametersBuilder setPreferredTextLanguages​(String... preferredTextLanguages)
    Sets the preferred languages for text tracks.
    - + DefaultTrackSelector.ParametersBuilder -setPreferredTextRoleFlags​(int preferredTextRoleFlags) +setPreferredTextRoleFlags​(@com.google.android.exoplayer2.C.RoleFlags int preferredTextRoleFlags)
    Sets the preferred C.RoleFlags for text tracks.
    - + DefaultTrackSelector.ParametersBuilder setPreferredVideoMimeType​(String mimeType)
    Sets the preferred sample MIME type for video tracks.
    - + DefaultTrackSelector.ParametersBuilder setPreferredVideoMimeTypes​(String... mimeTypes)
    Sets the preferred sample MIME types for video tracks.
    - + DefaultTrackSelector.ParametersBuilder setRendererDisabled​(int rendererIndex, boolean disabled) @@ -476,16 +497,18 @@ extends Sets whether the renderer at the specified index is disabled. - + DefaultTrackSelector.ParametersBuilder setSelectionOverride​(int rendererIndex, TrackGroupArray groups, DefaultTrackSelector.SelectionOverride override) -
    Overrides the track selection for the renderer at the specified index.
    + - + DefaultTrackSelector.ParametersBuilder setSelectUndeterminedTextLanguage​(boolean selectUndeterminedTextLanguage) @@ -494,14 +517,21 @@ extends + +DefaultTrackSelector.ParametersBuilder +setTrackSelectionOverrides​(TrackSelectionOverrides trackSelectionOverrides) + +
    Sets the selection overrides.
    + + + DefaultTrackSelector.ParametersBuilder setTunnelingEnabled​(boolean tunnelingEnabled)
    Sets whether to enable tunneling if possible.
    - + DefaultTrackSelector.ParametersBuilder setViewportSize​(int viewportWidth, int viewportHeight, @@ -511,7 +541,7 @@ extends + DefaultTrackSelector.ParametersBuilder setViewportSizeToPhysicalDisplaySize​(Context context, boolean viewportOrientationMayChange) @@ -581,6 +611,21 @@ public ParametersBuilder()

    Method Detail

    + + + + @@ -939,19 +984,19 @@ public ParametersBuilder()
    - + - + - +
    • setDisabledTextTrackSelectionFlags

      public DefaultTrackSelector.ParametersBuilder setDisabledTextTrackSelectionFlags​(@SelectionFlags
      -                                                                                 int disabledTextTrackSelectionFlags)
      + @com.google.android.exoplayer2.C.SelectionFlags int disabledTextTrackSelectionFlags)
      Sets a bitmask of selection flags that are disabled for text track selections.
      Parameters:
      @@ -1278,6 +1323,45 @@ public ParametersBuilder()
    + + + + + + + + @@ -1358,10 +1442,14 @@ public ParametersBuilder() @@ -230,13 +225,17 @@ implements SelectionOverride​(int groupIndex, int... tracks) -  + +
    Constructs a SelectionOverride to override tracks of a group.
    + -SelectionOverride​(int groupIndex, +SelectionOverride​(int groupIndex, int[] tracks, - int type) -  + @com.google.android.exoplayer2.trackselection.TrackSelection.Type int type) + +
    Constructs a SelectionOverride of the given type to override tracks of a group.
    + @@ -264,25 +263,21 @@ implements -int -describeContents() -  - - boolean equals​(Object obj)   - + int hashCode()   - -void -writeToParcel​(Parcel dest, - int flags) -  + +Bundle +toBundle() + +
    Returns a Bundle representing the information stored in this object.
    + @@ -350,7 +345,8 @@ implements
  • CREATOR

    -
    public static final Parcelable.Creator<DefaultTrackSelector.SelectionOverride> CREATOR
    +
    public static final Bundleable.Creator<DefaultTrackSelector.SelectionOverride> CREATOR
    +
    Object that can restore SelectionOverride from a Bundle.
  • @@ -371,6 +367,7 @@ implements Constructs a SelectionOverride to override tracks of a group.
    Parameters:
    groupIndex - The overriding track group index.
    @@ -378,7 +375,7 @@ implements
    + @@ -289,7 +289,7 @@ extends - +
      @@ -297,7 +297,7 @@ extends Definition
      public Definition​(TrackGroup group,
                         int[] tracks,
      -                  int type)
      + @com.google.android.exoplayer2.trackselection.TrackSelection.Type int type)
      Parameters:
      group - The TrackGroup. Must not be null.
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/trackselection/ExoTrackSelection.html b/docs/doc/reference/com/google/android/exoplayer2/trackselection/ExoTrackSelection.html index 3d1c5ea47c..10e07433b1 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/trackselection/ExoTrackSelection.html +++ b/docs/doc/reference/com/google/android/exoplayer2/trackselection/ExoTrackSelection.html @@ -168,6 +168,13 @@ extends +
    • + + +

      Nested classes/interfaces inherited from interface com.google.android.exoplayer2.trackselection.TrackSelection

      +TrackSelection.Type
    • +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/trackselection/FixedTrackSelection.html b/docs/doc/reference/com/google/android/exoplayer2/trackselection/FixedTrackSelection.html index da40da4b81..cd0d6e34ac 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/trackselection/FixedTrackSelection.html +++ b/docs/doc/reference/com/google/android/exoplayer2/trackselection/FixedTrackSelection.html @@ -161,6 +161,13 @@ extends ExoTrackSelection ExoTrackSelection.Definition, ExoTrackSelection.Factory + @@ -207,15 +214,15 @@ extends   -FixedTrackSelection​(TrackGroup group, +FixedTrackSelection​(TrackGroup group, int track, - int type) + @com.google.android.exoplayer2.trackselection.TrackSelection.Type int type)   -FixedTrackSelection​(TrackGroup group, +FixedTrackSelection​(TrackGroup group, int track, - int type, + @com.google.android.exoplayer2.trackselection.TrackSelection.Type int type, int reason, Object data)   @@ -323,7 +330,7 @@ extends + - +
    • getTypeSupport

      @RendererSupport
      -public int getTypeSupport​(int trackType)
      +public int getTypeSupport​(@com.google.android.exoplayer2.C.TrackType int trackType)
      Returns the extent to which tracks of a specified type are supported. This is the best level of support obtained from getRendererSupport(int) for all renderers that handle the specified type. If no such renderers exist then RENDERER_SUPPORT_NO_TRACKS is returned.
      Parameters:
      -
      trackType - The track type. One of the C TRACK_TYPE_* constants.
      +
      trackType - The track type.
      Returns:
      The MappingTrackSelector.MappedTrackInfo.RendererSupport.
      diff --git a/docs/doc/reference/com/google/android/exoplayer2/trackselection/MappingTrackSelector.html b/docs/doc/reference/com/google/android/exoplayer2/trackselection/MappingTrackSelector.html index cb94cbd21e..0ed5d7f45c 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/trackselection/MappingTrackSelector.html +++ b/docs/doc/reference/com/google/android/exoplayer2/trackselection/MappingTrackSelector.html @@ -258,7 +258,7 @@ extends TrackSelector -getBandwidthMeter, init, invalidate
    • +getBandwidthMeter, getParameters, init, invalidate, isSetParametersSupported, setParameters
    + diff --git a/docs/doc/reference/com/google/android/exoplayer2/device/package-summary.html b/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelection.Type.html similarity index 66% rename from docs/doc/reference/com/google/android/exoplayer2/device/package-summary.html rename to docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelection.Type.html index 4b3d17cefc..f6817691e2 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/device/package-summary.html +++ b/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelection.Type.html @@ -2,7 +2,7 @@ -com.google.android.exoplayer2.device (ExoPlayer library) +TrackSelection.Type (ExoPlayer library) @@ -19,7 +19,7 @@
    - +
    • setPreferredAudioRoleFlags

      public TrackSelectionParameters.Builder setPreferredAudioRoleFlags​(@RoleFlags
      -                                                                   int preferredAudioRoleFlags)
      + @com.google.android.exoplayer2.C.RoleFlags int preferredAudioRoleFlags)
      Sets the preferred C.RoleFlags for audio tracks.
      Parameters:
      @@ -879,14 +926,14 @@ public Builder()
    - +
    • setPreferredTextRoleFlags

      public TrackSelectionParameters.Builder setPreferredTextRoleFlags​(@RoleFlags
      -                                                                  int preferredTextRoleFlags)
      + @com.google.android.exoplayer2.C.RoleFlags int preferredTextRoleFlags)
      Sets the preferred C.RoleFlags for text tracks.
      Parameters:
      @@ -951,6 +998,39 @@ public Builder()
    + + + +
      +
    • +

      setTrackSelectionOverrides

      +
      public TrackSelectionParameters.Builder setTrackSelectionOverrides​(TrackSelectionOverrides trackSelectionOverrides)
      +
      Sets the selection overrides.
      +
      +
      Parameters:
      +
      trackSelectionOverrides - The track selection overrides.
      +
      Returns:
      +
      This builder.
      +
      +
    • +
    + + + +
      +
    • +

      setDisabledTrackTypes

      +
      public TrackSelectionParameters.Builder setDisabledTrackTypes​(Set<@TrackType Integer> disabledTrackTypes)
      +
      Sets the disabled track types, preventing all tracks of those types from being selected for + playback.
      +
      +
      Parameters:
      +
      disabledTrackTypes - The track types to disable.
      +
      Returns:
      +
      This builder.
      +
      +
    • +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.html b/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.html index fcfdea1465..390d48545b 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.html +++ b/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":9,"i4":10,"i5":10}; +var data = {"i0":10,"i1":10,"i2":9,"i3":10,"i4":10}; var tabs = {65535:["t0","All Methods"],1:["t1","Static Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -130,7 +130,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • All Implemented Interfaces:
    -
    Parcelable
    +
    Bundleable
    Direct Known Subclasses:
    @@ -139,8 +139,24 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
    public class TrackSelectionParameters
     extends Object
    -implements Parcelable
    -
    Constraint parameters for track selection.
    +implements Bundleable +
    Constraint parameters for track selection. + +

    For example the following code modifies the parameters to restrict video track selections to + SD, and to select a German audio track if there is one: + +

    
    + // Build on the current parameters.
    + TrackSelectionParameters currentParameters = player.getTrackSelectionParameters()
    + // Build the resulting parameters.
    + TrackSelectionParameters newParameters = currentParameters
    +     .buildUpon()
    +     .setMaxVideoSizeSd()
    +     .setPreferredAudioLanguage("deu")
    +     .build();
    + // Set the new parameters.
    + player.setTrackSelectionParameters(newParameters);
    + 
  • @@ -170,11 +186,11 @@ implements -
  • +
  • -

    Nested classes/interfaces inherited from interface android.os.Parcelable

    -Parcelable.ClassLoaderCreator<T extends Object>, Parcelable.Creator<T extends Object>
  • +

    Nested classes/interfaces inherited from interface com.google.android.exoplayer2.Bundleable

    +Bundleable.Creator<T extends Bundleable> @@ -194,9 +210,11 @@ implements Description -static Parcelable.Creator<TrackSelectionParameters> +static Bundleable.Creator<TrackSelectionParameters> CREATOR -  + +
    Object that can restore TrackSelectionParameters from a Bundle.
    + static TrackSelectionParameters @@ -215,6 +233,13 @@ implements +ImmutableSet<@TrackType Integer> +disabledTrackTypes + +
    The track types that are disabled.
    + + + boolean forceHighestSupportedBitrate @@ -222,7 +247,7 @@ implements + boolean forceLowestBitrate @@ -230,77 +255,77 @@ implements + int maxAudioBitrate
    Maximum allowed audio bitrate in bits per second.
    - + int maxAudioChannelCount
    Maximum allowed audio channel count.
    - + int maxVideoBitrate
    Maximum allowed video bitrate in bits per second.
    - + int maxVideoFrameRate
    Maximum allowed video frame rate in hertz.
    - + int maxVideoHeight
    Maximum allowed video height in pixels.
    - + int maxVideoWidth
    Maximum allowed video width in pixels.
    - + int minVideoBitrate
    Minimum allowed video bitrate in bits per second.
    - + int minVideoFrameRate
    Minimum allowed video frame rate in hertz.
    - + int minVideoHeight
    Minimum allowed video height in pixels.
    - + int minVideoWidth
    Minimum allowed video width in pixels.
    - + ImmutableList<String> preferredAudioLanguages @@ -308,7 +333,7 @@ implements + ImmutableList<String> preferredAudioMimeTypes @@ -316,28 +341,28 @@ implements -int + +@com.google.android.exoplayer2.C.RoleFlags int preferredAudioRoleFlags
    The preferred C.RoleFlags for audio tracks.
    - + ImmutableList<String> preferredTextLanguages
    The preferred languages for text tracks as IETF BCP 47 conformant tags in order of preference.
    - -int + +@com.google.android.exoplayer2.C.RoleFlags int preferredTextRoleFlags
    The preferred C.RoleFlags for text tracks.
    - + ImmutableList<String> preferredVideoMimeTypes @@ -345,13 +370,20 @@ implements + boolean selectUndeterminedTextLanguage
    Whether a text track with undetermined language should be selected if no track with preferredTextLanguages is available, or if preferredTextLanguages is unset.
    + +TrackSelectionOverrides +trackSelectionOverrides + +
    Overrides to force tracks to be selected.
    + + int viewportHeight @@ -374,13 +406,6 @@ implements -
  • - - -

    Fields inherited from interface android.os.Parcelable

    -CONTENTS_FILE_DESCRIPTOR, PARCELABLE_WRITE_RETURN_VALUE
  • - @@ -429,32 +454,28 @@ implements -int -describeContents() -  - - boolean equals​(Object obj)   - + static TrackSelectionParameters getDefaults​(Context context)
    Returns an instance configured with default values.
    - + int hashCode()   - -void -writeToParcel​(Parcel dest, - int flags) -  + +Bundle +toBundle() + +
    Returns a Bundle representing the information stored in this object.
    +
      @@ -514,15 +535,6 @@ public static final  - - - @@ -678,7 +690,7 @@ public static final 

      preferredAudioRoleFlags

      @RoleFlags
      -public final int preferredAudioRoleFlags
      +public final @com.google.android.exoplayer2.C.RoleFlags int preferredAudioRoleFlags
      The preferred C.RoleFlags for audio tracks. 0 selects the default track if there is one, or the first track if there's no default. The default value is 0.
      @@ -735,7 +747,7 @@ public final int preferredAudioRoleFlags
    • preferredTextRoleFlags

      @RoleFlags
      -public final int preferredTextRoleFlags
      +public final @com.google.android.exoplayer2.C.RoleFlags int preferredTextRoleFlags
      The preferred C.RoleFlags for text tracks. 0 selects the default track if there is one, or no track otherwise. The default value is 0, or C.ROLE_FLAG_SUBTITLE | C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND if the accessibility CaptioningManager @@ -767,7 +779,7 @@ public final int preferredTextRoleFlags -
        +
        • forceHighestSupportedBitrate

          public final boolean forceHighestSupportedBitrate
          @@ -775,6 +787,38 @@ public final int preferredTextRoleFlags other constraints. The default value is false.
    + + + +
      +
    • +

      trackSelectionOverrides

      +
      public final TrackSelectionOverrides trackSelectionOverrides
      +
      Overrides to force tracks to be selected.
      +
    • +
    + + + +
      +
    • +

      disabledTrackTypes

      +
      public final ImmutableSet<@TrackType Integer> disabledTrackTypes
      +
      The track types that are disabled. No track of a disabled type will be selected, thus no track + type contained in the set will be played. The default value is that no track type is disabled + (empty set).
      +
    • +
    + + + + @@ -851,30 +895,18 @@ public final int preferredTextRoleFlags - - - - - + diff --git a/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.html b/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.html index aa3d848324..e6cfb850dd 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.html +++ b/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":9,"i1":9,"i2":9,"i3":9}; +var data = {"i0":9,"i1":9,"i2":9}; var tabs = {65535:["t0","All Methods"],1:["t1","Static Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -195,14 +195,6 @@ extends -static boolean -hasTrackOfType​(TrackSelectionArray trackSelections, - int trackType) - -
    Returns if a TrackSelectionArray has at least one track of the given type.
    - - - static DefaultTrackSelector.Parameters updateParametersWithOverride​(DefaultTrackSelector.Parameters parameters, int rendererIndex, @@ -284,17 +276,6 @@ extends - - - -
      -
    • -

      hasTrackOfType

      -
      public static boolean hasTrackOfType​(TrackSelectionArray trackSelections,
      -                                     int trackType)
      -
      Returns if a TrackSelectionArray has at least one track of the given type.
      -
    • -
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelector.html b/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelector.html index 78f23a7318..2e8741f757 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelector.html +++ b/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelector.html @@ -25,7 +25,7 @@ catch(err) { } //--> -var data = {"i0":10,"i1":10,"i2":10,"i3":6,"i4":6}; +var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":6,"i6":6,"i7":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -259,6 +259,13 @@ extends +TrackSelectionParameters +getParameters() + +
    Returns the current parameters for track selection.
    + + + void init​(TrackSelector.InvalidationListener listener, BandwidthMeter bandwidthMeter) @@ -266,7 +273,7 @@ extends Called by the player to initialize the selector. - + protected void invalidate() @@ -274,14 +281,21 @@ extends - + +boolean +isSetParametersSupported() + +
    Returns if this TrackSelector supports setParameters(TrackSelectionParameters).
    + + + abstract void onSelectionActivated​(Object info)
    Called by the player when a TrackSelectorResult previously generated by selectTracks(RendererCapabilities[], TrackGroupArray, MediaPeriodId, Timeline) is activated.
    - + abstract TrackSelectorResult selectTracks​(RendererCapabilities[] rendererCapabilities, TrackGroupArray trackGroups, @@ -291,6 +305,13 @@ extends Called by the player to perform a track selection. + +void +setParameters​(TrackSelectionParameters parameters) + +
    Called by the player to provide parameters for track selection.
    + + + + + +
      +
    • +

      getParameters

      +
      public TrackSelectionParameters getParameters()
      +
      Returns the current parameters for track selection.
      +
    • +
    + + + +
      +
    • +

      setParameters

      +
      public void setParameters​(TrackSelectionParameters parameters)
      +
      Called by the player to provide parameters for track selection. + +

      Only supported if isSetParametersSupported() returns true.

      +
      +
      Parameters:
      +
      parameters - The parameters for track selection.
      +
      +
    • +
    + + + +
      +
    • +

      isSetParametersSupported

      +
      public boolean isSetParametersSupported()
      +
      Returns if this TrackSelector supports setParameters(TrackSelectionParameters). + +

      The same value is always returned for a given TrackSelector instance.

      +
    • +
    diff --git a/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectorResult.html b/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectorResult.html index 8746eb6f88..4273f16111 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectorResult.html +++ b/docs/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelectorResult.html @@ -181,6 +181,13 @@ extends A ExoTrackSelection array containing the track selection for each renderer. + +TracksInfo +tracksInfo + +
    Describe the tracks and which one were selected.
    + + @@ -199,10 +206,22 @@ extends Description +TrackSelectorResult​(@NullableType RendererConfiguration[] rendererConfigurations, + @NullableType ExoTrackSelection[] selections, + TracksInfo tracksInfo, + Object info) +  + + TrackSelectorResult​(@NullableType RendererConfiguration[] rendererConfigurations, @NullableType ExoTrackSelection[] selections, Object info) -  + + + @@ -299,6 +318,16 @@ extends A ExoTrackSelection array containing the track selection for each renderer. + + + +
      +
    • +

      tracksInfo

      +
      public final TracksInfo tracksInfo
      +
      Describe the tracks and which one were selected.
      +
    • +
    @@ -324,11 +353,37 @@ public final  + + + + diff --git a/docs/doc/reference/com/google/android/exoplayer2/trackselection/package-tree.html b/docs/doc/reference/com/google/android/exoplayer2/trackselection/package-tree.html index 7464e1a1b0..d513b87acc 100644 --- a/docs/doc/reference/com/google/android/exoplayer2/trackselection/package-tree.html +++ b/docs/doc/reference/com/google/android/exoplayer2/trackselection/package-tree.html @@ -114,16 +114,19 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • com.google.android.exoplayer2.trackselection.DefaultTrackSelector.AudioTrackScore (implements java.lang.Comparable<T>)
  • com.google.android.exoplayer2.trackselection.DefaultTrackSelector.OtherTrackScore (implements java.lang.Comparable<T>)
  • -
  • com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride (implements android.os.Parcelable)
  • +
  • com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride (implements com.google.android.exoplayer2.Bundleable)
  • com.google.android.exoplayer2.trackselection.DefaultTrackSelector.TextTrackScore (implements java.lang.Comparable<T>)
  • com.google.android.exoplayer2.trackselection.DefaultTrackSelector.VideoTrackScore (implements java.lang.Comparable<T>)
  • com.google.android.exoplayer2.trackselection.ExoTrackSelection.Definition
  • com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo
  • com.google.android.exoplayer2.trackselection.RandomTrackSelection.Factory (implements com.google.android.exoplayer2.trackselection.ExoTrackSelection.Factory)
  • com.google.android.exoplayer2.trackselection.TrackSelectionArray
  • -
  • com.google.android.exoplayer2.trackselection.TrackSelectionParameters (implements android.os.Parcelable) +
  • com.google.android.exoplayer2.trackselection.TrackSelectionOverrides (implements com.google.android.exoplayer2.Bundleable)
  • +
  • com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.Builder
  • +
  • com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride (implements com.google.android.exoplayer2.Bundleable)
  • +
  • com.google.android.exoplayer2.trackselection.TrackSelectionParameters (implements com.google.android.exoplayer2.Bundleable)
  • com.google.android.exoplayer2.trackselection.TrackSelectionParameters.Builder @@ -159,6 +162,12 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
  • com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationListener
  • +
    +

    Annotation Type Hierarchy

    + +