mirror of
https://github.com/DrKLO/Telegram.git
synced 2024-12-22 14:35:03 +01:00
Update to 4.9.1
This commit is contained in:
parent
d073b80063
commit
fe599cd519
663 changed files with 40241 additions and 34380 deletions
|
@ -11,26 +11,29 @@ configurations {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.google.firebase:firebase-messaging:17.1.0'
|
||||
compile 'com.google.firebase:firebase-config:16.0.0'
|
||||
compile 'com.google.android.gms:play-services-maps:15.0.1'
|
||||
compile 'com.google.android.gms:play-services-vision:15.0.2'
|
||||
compile 'com.google.android.gms:play-services-wallet:15.0.1'
|
||||
compile 'com.google.android.gms:play-services-wearable:15.0.1'
|
||||
implementation 'com.android.support:support-core-ui:27.1.1'
|
||||
implementation 'com.android.support:support-compat:27.1.1'
|
||||
implementation 'com.android.support:support-core-utils:27.1.1'
|
||||
implementation 'com.android.support:support-v13:27.1.1'
|
||||
implementation 'com.android.support:palette-v7:27.1.1'
|
||||
implementation 'com.android.support:exifinterface:27.1.1'
|
||||
compile 'net.hockeyapp.android:HockeySDK:5.1.0'
|
||||
compile 'com.googlecode.mp4parser:isoparser:1.0.6'
|
||||
compile 'com.stripe:stripe-android:2.0.2'
|
||||
compileOnly 'org.checkerframework:checker-qual:2.5.0'
|
||||
compileOnly 'org.checkerframework:checker-compat-qual:2.5.0'
|
||||
implementation 'com.google.firebase:firebase-core:16.0.3'
|
||||
implementation 'com.google.firebase:firebase-messaging:17.3.0'
|
||||
implementation 'com.google.firebase:firebase-config:16.0.0'
|
||||
implementation 'com.google.android.gms:play-services-maps:15.0.1'
|
||||
implementation 'com.google.android.gms:play-services-vision:15.0.2'
|
||||
implementation 'com.google.android.gms:play-services-wallet:16.0.0'
|
||||
implementation 'com.google.android.gms:play-services-wearable:15.0.1'
|
||||
implementation 'com.android.support:support-core-ui:28.0.0-rc01'
|
||||
implementation 'com.android.support:support-compat:28.0.0-rc01'
|
||||
implementation 'com.android.support:support-core-utils:28.0.0-rc01'
|
||||
implementation 'com.android.support:support-v13:28.0.0-rc01'
|
||||
implementation 'com.android.support:palette-v7:28.0.0-rc01'
|
||||
implementation 'com.android.support:exifinterface:28.0.0-rc01'
|
||||
implementation 'net.hockeyapp.android:HockeySDK:5.1.0'
|
||||
implementation 'com.googlecode.mp4parser:isoparser:1.0.6'
|
||||
implementation 'com.stripe:stripe-android:2.0.2'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
buildToolsVersion '27.0.3'
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion '28.0.2'
|
||||
|
||||
defaultConfig.applicationId = "org.telegram.messenger"
|
||||
|
||||
|
@ -52,8 +55,8 @@ android {
|
|||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
|
@ -98,7 +101,7 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
defaultConfig.versionCode = 1340
|
||||
defaultConfig.versionCode = 1358
|
||||
|
||||
sourceSets.debug {
|
||||
manifest.srcFile 'config/debug/AndroidManifest.xml'
|
||||
|
@ -235,7 +238,7 @@ android {
|
|||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 27
|
||||
versionName "4.9.0"
|
||||
versionName "4.9.1"
|
||||
|
||||
vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi']
|
||||
|
||||
|
|
|
@ -387,7 +387,7 @@ include $(BUILD_STATIC_LIBRARY)
|
|||
include $(CLEAR_VARS)
|
||||
LOCAL_PRELINK_MODULE := false
|
||||
|
||||
LOCAL_MODULE := tmessages.28
|
||||
LOCAL_MODULE := tmessages.29
|
||||
LOCAL_CFLAGS := -w -std=c11 -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1
|
||||
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
|
||||
LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -ffast-math -D__STDC_CONSTANT_MACROS
|
||||
|
|
|
@ -142,10 +142,12 @@ jlong Java_org_telegram_SQLite_SQLiteDatabase_opendb(JNIEnv *env, jobject object
|
|||
char const *fileNameStr = env->GetStringUTFChars(fileName, 0);
|
||||
char const *tempDirStr = env->GetStringUTFChars(tempDir, 0);
|
||||
|
||||
if (sqlite3_temp_directory != 0) {
|
||||
if (sqlite3_temp_directory != 0 && strcmp(sqlite3_temp_directory, tempDirStr)) {
|
||||
sqlite3_free(sqlite3_temp_directory);
|
||||
}
|
||||
if (sqlite3_temp_directory == 0) {
|
||||
sqlite3_temp_directory = sqlite3_mprintf("%s", tempDirStr);
|
||||
}
|
||||
|
||||
sqlite3 *handle = 0;
|
||||
int err = sqlite3_open(fileNameStr, &handle);
|
||||
|
|
|
@ -39,6 +39,8 @@ jmethodID jclass_ConnectionsManager_onProxyError;
|
|||
jmethodID jclass_ConnectionsManager_getHostByName;
|
||||
jmethodID jclass_ConnectionsManager_getInitFlags;
|
||||
|
||||
bool check_utf8(const char *data, size_t len);
|
||||
|
||||
/*jint createLoadOpetation(JNIEnv *env, jclass c, jint dc_id, jlong id, jlong volume_id, jlong access_hash, jint local_id, jbyteArray encKey, jbyteArray encIv, jstring extension, jint version, jint size, jstring dest, jstring temp, jobject delegate) {
|
||||
if (encKey != nullptr && encIv == nullptr || encKey == nullptr && encIv != nullptr || extension == nullptr || dest == nullptr || temp == nullptr) {
|
||||
return 0;
|
||||
|
@ -196,7 +198,13 @@ void sendRequest(JNIEnv *env, jclass c, jint instanceNum, jlong object, jobject
|
|||
ptr = (jlong) resp->response.get();
|
||||
} else if (error != nullptr) {
|
||||
errorCode = error->code;
|
||||
errorText = jniEnv[instanceNum]->NewStringUTF(error->text.c_str());
|
||||
const char *text = error->text.c_str();
|
||||
size_t size = error->text.size();
|
||||
if (check_utf8(text, size)) {
|
||||
errorText = jniEnv[instanceNum]->NewStringUTF(text);
|
||||
} else {
|
||||
errorText = jniEnv[instanceNum]->NewStringUTF("UTF-8 ERROR");
|
||||
}
|
||||
}
|
||||
if (onComplete != nullptr) {
|
||||
jniEnv[instanceNum]->CallVoidMethod(onComplete, jclass_RequestDelegateInternal_run, ptr, errorCode, errorText, networkType);
|
||||
|
@ -632,3 +640,56 @@ extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) {
|
|||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
bool check_utf8(const char *data, size_t len) {
|
||||
const char *data_end = data + len;
|
||||
do {
|
||||
unsigned int a = (unsigned char) (*data++);
|
||||
if ((a & 0x80) == 0) {
|
||||
if (data == data_end + 1) {
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
#define ENSURE(condition) \
|
||||
if (!(condition)) { \
|
||||
return false; \
|
||||
}
|
||||
|
||||
ENSURE((a & 0x40) != 0);
|
||||
|
||||
unsigned int b = (unsigned char) (*data++);
|
||||
ENSURE((b & 0xc0) == 0x80);
|
||||
if ((a & 0x20) == 0) {
|
||||
ENSURE((a & 0x1e) > 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int c = (unsigned char) (*data++);
|
||||
ENSURE((c & 0xc0) == 0x80);
|
||||
if ((a & 0x10) == 0) {
|
||||
int x = (((a & 0x0f) << 6) | (b & 0x20));
|
||||
ENSURE(x != 0 && x != 0x360);
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int d = (unsigned char) (*data++);
|
||||
ENSURE((d & 0xc0) == 0x80);
|
||||
if ((a & 0x08) == 0) {
|
||||
int t = (((a & 0x07) << 6) | (b & 0x30));
|
||||
ENSURE(0 < t && t < 0x110);
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
#undef ENSURE
|
||||
} while (1);
|
||||
}
|
||||
|
|
|
@ -36,10 +36,10 @@ extern "C" {
|
|||
__VA_ARGS__))
|
||||
|
||||
#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
|
||||
JNIEXPORT RETURN_TYPE Java_org_telegram_messenger_exoplayer2_ext_ffmpeg_FfmpegDecoder_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__)
|
||||
JNIEXPORT RETURN_TYPE Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegDecoder_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__)
|
||||
|
||||
#define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \
|
||||
JNIEXPORT RETURN_TYPE Java_org_telegram_messenger_exoplayer2_ext_ffmpeg_FfmpegLibrary_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__)
|
||||
JNIEXPORT RETURN_TYPE Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegLibrary_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__)
|
||||
|
||||
#define ERROR_STRING_BUFFER_LENGTH 256
|
||||
|
||||
|
@ -60,8 +60,9 @@ AVCodec *getCodecByName(JNIEnv* env, jstring codecName);
|
|||
* provided extraData as initialization data for the decoder if it is non-NULL.
|
||||
* Returns the created context.
|
||||
*/
|
||||
AVCodecContext *createContext(JNIEnv *env, AVCodec *codec,
|
||||
jbyteArray extraData, jboolean outputFloat);
|
||||
AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
|
||||
jboolean outputFloat, jint rawSampleRate,
|
||||
jint rawChannelCount);
|
||||
|
||||
/**
|
||||
* Decodes the packet into the output buffer, returning the number of bytes
|
||||
|
@ -89,13 +90,14 @@ LIBRARY_FUNC(jboolean, ffmpegHasDecoder, jstring codecName) {
|
|||
}
|
||||
|
||||
DECODER_FUNC(jlong, ffmpegInitialize, jstring codecName, jbyteArray extraData,
|
||||
jboolean outputFloat) {
|
||||
jboolean outputFloat, jint rawSampleRate, jint rawChannelCount) {
|
||||
AVCodec *codec = getCodecByName(env, codecName);
|
||||
if (!codec) {
|
||||
LOGE("Codec not found.");
|
||||
return 0L;
|
||||
}
|
||||
return (jlong) createContext(env, codec, extraData, outputFloat);
|
||||
return (jlong)createContext(env, codec, extraData, outputFloat, rawSampleRate,
|
||||
rawChannelCount);
|
||||
}
|
||||
|
||||
DECODER_FUNC(jint, ffmpegDecode, jlong context, jobject inputData,
|
||||
|
@ -159,8 +161,11 @@ DECODER_FUNC(jlong, ffmpegReset, jlong jContext, jbyteArray extraData) {
|
|||
LOGE("Unexpected error finding codec %d.", codecId);
|
||||
return 0L;
|
||||
}
|
||||
return (jlong) createContext(env, codec, extraData,
|
||||
context->request_sample_fmt == OUTPUT_FORMAT_PCM_FLOAT);
|
||||
jboolean outputFloat =
|
||||
(jboolean)(context->request_sample_fmt == OUTPUT_FORMAT_PCM_FLOAT);
|
||||
return (jlong)createContext(env, codec, extraData, outputFloat,
|
||||
/* rawSampleRate= */ -1,
|
||||
/* rawChannelCount= */ -1);
|
||||
}
|
||||
|
||||
avcodec_flush_buffers(context);
|
||||
|
@ -183,8 +188,9 @@ AVCodec *getCodecByName(JNIEnv *env, jstring codecName) {
|
|||
return codec;
|
||||
}
|
||||
|
||||
AVCodecContext *createContext(JNIEnv *env, AVCodec *codec,
|
||||
jbyteArray extraData, jboolean outputFloat) {
|
||||
AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
|
||||
jboolean outputFloat, jint rawSampleRate,
|
||||
jint rawChannelCount) {
|
||||
AVCodecContext *context = avcodec_alloc_context3(codec);
|
||||
if (!context) {
|
||||
LOGE("Failed to allocate context.");
|
||||
|
@ -204,6 +210,12 @@ AVCodecContext *createContext(JNIEnv *env, AVCodec *codec,
|
|||
}
|
||||
env->GetByteArrayRegion(extraData, 0, size, (jbyte *) context->extradata);
|
||||
}
|
||||
if (context->codec_id == AV_CODEC_ID_PCM_MULAW ||
|
||||
context->codec_id == AV_CODEC_ID_PCM_ALAW) {
|
||||
context->sample_rate = rawSampleRate;
|
||||
context->channels = rawChannelCount;
|
||||
context->channel_layout = av_get_default_channel_layout(rawChannelCount);
|
||||
}
|
||||
int result = avcodec_open2(context, codec, NULL);
|
||||
if (result < 0) {
|
||||
logError("avcodec_open2", result);
|
||||
|
@ -244,7 +256,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
|
|||
// Resample output.
|
||||
AVSampleFormat sampleFormat = context->sample_fmt;
|
||||
int channelCount = context->channels;
|
||||
uint64_t channelLayout = context->channel_layout;
|
||||
int channelLayout = context->channel_layout;
|
||||
int sampleRate = context->sample_rate;
|
||||
int sampleCount = frame->nb_samples;
|
||||
int dataSize = av_samples_get_buffer_size(NULL, channelCount, sampleCount,
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "include/flac_parser.h"
|
||||
|
||||
#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
|
||||
RETURN_TYPE Java_org_telegram_messenger_exoplayer2_ext_flac_FlacDecoderJni_##NAME(JNIEnv *env, jobject thiz, ##__VA_ARGS__)
|
||||
RETURN_TYPE Java_com_google_android_exoplayer2_ext_flac_FlacDecoderJni_##NAME(JNIEnv *env, jobject thiz, ##__VA_ARGS__)
|
||||
|
||||
class JavaDataSource : public DataSource {
|
||||
public:
|
||||
|
@ -27,7 +27,7 @@ class JavaDataSource : public DataSource {
|
|||
this->env = env;
|
||||
this->flacDecoderJni = flacDecoderJni;
|
||||
if (mid == NULL) {
|
||||
jclass cls = env->GetObjectClass(flacDecoderJni);
|
||||
jclass cls = env->GetObjectClass(this->flacDecoderJni);
|
||||
mid = env->GetMethodID(cls, "read", "(Ljava/nio/ByteBuffer;)I");
|
||||
env->DeleteLocalRef(cls);
|
||||
}
|
||||
|
@ -86,7 +86,9 @@ DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) {
|
|||
const FLAC__StreamMetadata_StreamInfo &streamInfo =
|
||||
context->parser->getStreamInfo();
|
||||
|
||||
jclass cls = env->FindClass("org/telegram/messenger/exoplayer2/util/FlacStreamInfo");
|
||||
jclass cls = env->FindClass(
|
||||
"com/google/android/exoplayer2/util/"
|
||||
"FlacStreamInfo");
|
||||
jmethodID constructor = env->GetMethodID(cls, "<init>", "(IIIIIIIJ)V");
|
||||
|
||||
return env->NewObject(cls, constructor, streamInfo.min_blocksize,
|
||||
|
|
|
@ -28,10 +28,10 @@
|
|||
__VA_ARGS__))
|
||||
|
||||
#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
|
||||
JNIEXPORT RETURN_TYPE Java_org_telegram_messenger_exoplayer2_ext_opus_OpusDecoder_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__)
|
||||
JNIEXPORT RETURN_TYPE Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__)
|
||||
|
||||
#define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \
|
||||
JNIEXPORT RETURN_TYPE Java_org_telegram_messenger_exoplayer2_ext_opus_OpusLibrary_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__)
|
||||
JNIEXPORT RETURN_TYPE Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_##NAME(JNIEnv* env, jobject thiz, ##__VA_ARGS__)
|
||||
|
||||
// JNI references for SimpleOutputBuffer class.
|
||||
static jmethodID outputBufferInit;
|
||||
|
@ -65,7 +65,7 @@ DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount,
|
|||
|
||||
// Populate JNI References.
|
||||
const jclass outputBufferClass = env->FindClass(
|
||||
"org/telegram/messenger/exoplayer2/decoder/SimpleOutputBuffer");
|
||||
"com/google/android/exoplayer2/decoder/SimpleOutputBuffer");
|
||||
outputBufferInit = env->GetMethodID(outputBufferClass, "init",
|
||||
"(JI)Ljava/nio/ByteBuffer;");
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -52,6 +53,23 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIEnv *en
|
|||
(*env)->ReleaseByteArrayElements(env, iv, ivBuff, 0);
|
||||
}
|
||||
|
||||
JNIEXPORT jint Java_org_telegram_messenger_Utilities_pbkdf2(JNIEnv *env, jclass class, jbyteArray password, jbyteArray salt, jbyteArray dst, jint iterations) {
|
||||
jbyte *passwordBuff = (*env)->GetByteArrayElements(env, password, NULL);
|
||||
size_t passwordLength = (size_t) (*env)->GetArrayLength(env, password);
|
||||
jbyte *saltBuff = (*env)->GetByteArrayElements(env, salt, NULL);
|
||||
size_t saltLength = (size_t) (*env)->GetArrayLength(env, salt);
|
||||
jbyte *dstBuff = (*env)->GetByteArrayElements(env, dst, NULL);
|
||||
size_t dstLength = (size_t) (*env)->GetArrayLength(env, dst);
|
||||
|
||||
int result = PKCS5_PBKDF2_HMAC((char *) passwordBuff, passwordLength, (uint8_t *) saltBuff, saltLength, (unsigned int) iterations, EVP_sha512(), dstLength, (uint8_t *) dstBuff);
|
||||
|
||||
(*env)->ReleaseByteArrayElements(env, password, passwordBuff, JNI_ABORT);
|
||||
(*env)->ReleaseByteArrayElements(env, salt, saltBuff, JNI_ABORT);
|
||||
(*env)->ReleaseByteArrayElements(env, dst, dstBuff, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_Utilities_aesCtrDecryption(JNIEnv *env, jclass class, jobject buffer, jbyteArray key, jbyteArray iv, jint offset, jint length) {
|
||||
jbyte *what = (*env)->GetDirectBufferAddress(env, buffer) + offset;
|
||||
unsigned char *keyBuff = (unsigned char *)(*env)->GetByteArrayElements(env, key, NULL);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 8faf6f670037a8049ede4b85a004c40bdd359c6a
|
||||
Subproject commit 23ae67306d7fa1c4d5a8a9c8653f63ab93100f88
|
3
TMessagesProj/proguard-rules.pro
vendored
3
TMessagesProj/proguard-rules.pro
vendored
|
@ -4,9 +4,12 @@
|
|||
@com.google.android.gms.common.annotation.KeepName *;
|
||||
}
|
||||
-keep class org.telegram.** { *; }
|
||||
-keep class com.google.android.exoplayer2.** { *; }
|
||||
-keep class com.coremedia.** { *; }
|
||||
-keep class com.googlecode.mp4parser.** { *; }
|
||||
-dontwarn com.coremedia.**
|
||||
-dontwarn org.telegram.**
|
||||
-dontwarn com.google.android.exoplayer2.**
|
||||
-dontwarn com.google.android.gms.**
|
||||
-dontwarn com.google.common.cache.**
|
||||
-dontwarn com.google.common.primitives.**
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<uses-feature android:name="android.hardware.camera2" android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
|
|
@ -13,15 +13,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmInitData;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager;
|
||||
import org.telegram.messenger.exoplayer2.source.SampleStream;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.MediaClock;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MediaClock;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
|
@ -23,8 +23,8 @@ import android.media.MediaCodec;
|
|||
import android.media.MediaFormat;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.view.Surface;
|
||||
import org.telegram.messenger.exoplayer2.PlayerMessage.Target;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.PlayerMessage.Target;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.UUID;
|
||||
|
@ -77,6 +77,12 @@ public final class C {
|
|||
*/
|
||||
public static final long NANOS_PER_SECOND = 1000000000L;
|
||||
|
||||
/** The number of bits per byte. */
|
||||
public static final int BITS_PER_BYTE = 8;
|
||||
|
||||
/** The number of bytes per float. */
|
||||
public static final int BYTES_PER_FLOAT = 4;
|
||||
|
||||
/**
|
||||
* The name of the ASCII charset.
|
||||
*/
|
||||
|
@ -136,6 +142,8 @@ public final class C {
|
|||
ENCODING_PCM_24BIT,
|
||||
ENCODING_PCM_32BIT,
|
||||
ENCODING_PCM_FLOAT,
|
||||
ENCODING_PCM_MU_LAW,
|
||||
ENCODING_PCM_A_LAW,
|
||||
ENCODING_AC3,
|
||||
ENCODING_E_AC3,
|
||||
ENCODING_DTS,
|
||||
|
@ -144,12 +152,19 @@ public final class C {
|
|||
})
|
||||
public @interface Encoding {}
|
||||
|
||||
/**
|
||||
* Represents a PCM audio encoding, or an invalid or unset value.
|
||||
*/
|
||||
/** Represents a PCM audio encoding, or an invalid or unset value. */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT,
|
||||
ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_PCM_FLOAT})
|
||||
@IntDef({
|
||||
Format.NO_VALUE,
|
||||
ENCODING_INVALID,
|
||||
ENCODING_PCM_8BIT,
|
||||
ENCODING_PCM_16BIT,
|
||||
ENCODING_PCM_24BIT,
|
||||
ENCODING_PCM_32BIT,
|
||||
ENCODING_PCM_FLOAT,
|
||||
ENCODING_PCM_MU_LAW,
|
||||
ENCODING_PCM_A_LAW
|
||||
})
|
||||
public @interface PcmEncoding {}
|
||||
/** @see AudioFormat#ENCODING_INVALID */
|
||||
public static final int ENCODING_INVALID = AudioFormat.ENCODING_INVALID;
|
||||
|
@ -163,6 +178,10 @@ public final class C {
|
|||
public static final int ENCODING_PCM_32BIT = 0x40000000;
|
||||
/** @see AudioFormat#ENCODING_PCM_FLOAT */
|
||||
public static final int ENCODING_PCM_FLOAT = AudioFormat.ENCODING_PCM_FLOAT;
|
||||
/** Audio encoding for mu-law. */
|
||||
public static final int ENCODING_PCM_MU_LAW = 0x10000000;
|
||||
/** Audio encoding for A-law. */
|
||||
public static final int ENCODING_PCM_A_LAW = 0x20000000;
|
||||
/** @see AudioFormat#ENCODING_AC3 */
|
||||
public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3;
|
||||
/** @see AudioFormat#ENCODING_E_AC3 */
|
||||
|
@ -226,7 +245,7 @@ public final class C {
|
|||
public static final int STREAM_TYPE_DEFAULT = STREAM_TYPE_MUSIC;
|
||||
|
||||
/**
|
||||
* Content types for {@link org.telegram.messenger.exoplayer2.audio.AudioAttributes}.
|
||||
* Content types for {@link com.google.android.exoplayer2.audio.AudioAttributes}.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({CONTENT_TYPE_MOVIE, CONTENT_TYPE_MUSIC, CONTENT_TYPE_SONIFICATION, CONTENT_TYPE_SPEECH,
|
||||
|
@ -257,7 +276,7 @@ public final class C {
|
|||
android.media.AudioAttributes.CONTENT_TYPE_UNKNOWN;
|
||||
|
||||
/**
|
||||
* Flags for {@link org.telegram.messenger.exoplayer2.audio.AudioAttributes}.
|
||||
* Flags for {@link com.google.android.exoplayer2.audio.AudioAttributes}.
|
||||
* <p>
|
||||
* Note that {@code FLAG_HW_AV_SYNC} is not available because the player takes care of setting the
|
||||
* flag when tunneling is enabled via a track selector.
|
||||
|
@ -272,7 +291,7 @@ public final class C {
|
|||
android.media.AudioAttributes.FLAG_AUDIBILITY_ENFORCED;
|
||||
|
||||
/**
|
||||
* Usage types for {@link org.telegram.messenger.exoplayer2.audio.AudioAttributes}.
|
||||
* Usage types for {@link com.google.android.exoplayer2.audio.AudioAttributes}.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({USAGE_ALARM, USAGE_ASSISTANCE_ACCESSIBILITY, USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
|
||||
|
@ -664,7 +683,7 @@ public final class C {
|
|||
/**
|
||||
* A type of a message that can be passed to an audio {@link Renderer} via {@link
|
||||
* ExoPlayer#createMessage(Target)}. The message payload should be an {@link
|
||||
* org.telegram.messenger.exoplayer2.audio.AudioAttributes} instance that will configure the
|
||||
* com.google.android.exoplayer2.audio.AudioAttributes} instance that will configure the
|
||||
* underlying audio track. If not set, the default audio attributes will be used. They are
|
||||
* suitable for general media playback.
|
||||
*
|
||||
|
@ -797,6 +816,45 @@ public final class C {
|
|||
*/
|
||||
public static final int PRIORITY_DOWNLOAD = PRIORITY_PLAYBACK - 1000;
|
||||
|
||||
/** Network connection type. */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
NETWORK_TYPE_UNKNOWN,
|
||||
NETWORK_TYPE_OFFLINE,
|
||||
NETWORK_TYPE_WIFI,
|
||||
NETWORK_TYPE_2G,
|
||||
NETWORK_TYPE_3G,
|
||||
NETWORK_TYPE_4G,
|
||||
NETWORK_TYPE_CELLULAR_UNKNOWN,
|
||||
NETWORK_TYPE_ETHERNET,
|
||||
NETWORK_TYPE_OTHER
|
||||
})
|
||||
public @interface NetworkType {}
|
||||
/** Unknown network type. */
|
||||
public static final int NETWORK_TYPE_UNKNOWN = 0;
|
||||
/** No network connection. */
|
||||
public static final int NETWORK_TYPE_OFFLINE = 1;
|
||||
/** Network type for a Wifi connection. */
|
||||
public static final int NETWORK_TYPE_WIFI = 2;
|
||||
/** Network type for a 2G cellular connection. */
|
||||
public static final int NETWORK_TYPE_2G = 3;
|
||||
/** Network type for a 3G cellular connection. */
|
||||
public static final int NETWORK_TYPE_3G = 4;
|
||||
/** Network type for a 4G cellular connection. */
|
||||
public static final int NETWORK_TYPE_4G = 5;
|
||||
/**
|
||||
* Network type for cellular connections which cannot be mapped to one of {@link
|
||||
* #NETWORK_TYPE_2G}, {@link #NETWORK_TYPE_3G}, or {@link #NETWORK_TYPE_4G}.
|
||||
*/
|
||||
public static final int NETWORK_TYPE_CELLULAR_UNKNOWN = 6;
|
||||
/** Network type for an Ethernet connection. */
|
||||
public static final int NETWORK_TYPE_ETHERNET = 7;
|
||||
/**
|
||||
* Network type for other connections which are not Wifi or cellular (e.g. Ethernet, VPN,
|
||||
* Bluetooth).
|
||||
*/
|
||||
public static final int NETWORK_TYPE_OTHER = 8;
|
||||
|
||||
/**
|
||||
* Converts a time in microseconds to the corresponding time in milliseconds, preserving
|
||||
* {@link #TIME_UNSET} and {@link #TIME_END_OF_SOURCE} values.
|
|
@ -13,9 +13,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.Player.RepeatMode;
|
||||
import com.google.android.exoplayer2.Player.RepeatMode;
|
||||
|
||||
/**
|
||||
* Dispatches operations to the {@link Player}.
|
|
@ -13,9 +13,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.Player.RepeatMode;
|
||||
import com.google.android.exoplayer2.Player.RepeatMode;
|
||||
|
||||
/**
|
||||
* Default {@link ControlDispatcher} that dispatches all operations to the player without
|
|
@ -13,15 +13,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.source.TrackGroupArray;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import org.telegram.messenger.exoplayer2.upstream.Allocator;
|
||||
import org.telegram.messenger.exoplayer2.upstream.DefaultAllocator;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.PriorityTaskManager;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.PriorityTaskManager;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
/**
|
||||
* The default {@link LoadControl} implementation.
|
|
@ -13,12 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.util.Clock;
|
||||
import org.telegram.messenger.exoplayer2.util.MediaClock;
|
||||
import org.telegram.messenger.exoplayer2.util.StandaloneMediaClock;
|
||||
import com.google.android.exoplayer2.util.Clock;
|
||||
import com.google.android.exoplayer2.util.MediaClock;
|
||||
import com.google.android.exoplayer2.util.StandaloneMediaClock;
|
||||
|
||||
/**
|
||||
* Default {@link MediaClock} which uses a renderer media clock and falls back to a
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
|
@ -21,20 +21,20 @@ import android.os.Looper;
|
|||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioCapabilities;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioProcessor;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener;
|
||||
import org.telegram.messenger.exoplayer2.audio.MediaCodecAudioRenderer;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager;
|
||||
import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecSelector;
|
||||
import org.telegram.messenger.exoplayer2.metadata.MetadataOutput;
|
||||
import org.telegram.messenger.exoplayer2.metadata.MetadataRenderer;
|
||||
import org.telegram.messenger.exoplayer2.text.TextOutput;
|
||||
import org.telegram.messenger.exoplayer2.text.TextRenderer;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector;
|
||||
import org.telegram.messenger.exoplayer2.video.MediaCodecVideoRenderer;
|
||||
import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener;
|
||||
import com.google.android.exoplayer2.audio.AudioCapabilities;
|
||||
import com.google.android.exoplayer2.audio.AudioProcessor;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
|
||||
import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
|
||||
import com.google.android.exoplayer2.metadata.MetadataOutput;
|
||||
import com.google.android.exoplayer2.metadata.MetadataRenderer;
|
||||
import com.google.android.exoplayer2.text.TextOutput;
|
||||
import com.google.android.exoplayer2.text.TextRenderer;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
|
||||
import com.google.android.exoplayer2.video.VideoRendererEventListener;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
@ -221,13 +221,13 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
|||
try {
|
||||
// Full class names used for constructor args so the LINT rule triggers if any of them move.
|
||||
// LINT.IfChange
|
||||
Class<?> clazz = Class.forName("org.telegram.messenger.exoplayer2.ext.vp9.LibvpxVideoRenderer");
|
||||
Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer");
|
||||
Constructor<?> constructor =
|
||||
clazz.getConstructor(
|
||||
boolean.class,
|
||||
long.class,
|
||||
android.os.Handler.class,
|
||||
org.telegram.messenger.exoplayer2.video.VideoRendererEventListener.class,
|
||||
com.google.android.exoplayer2.video.VideoRendererEventListener.class,
|
||||
int.class);
|
||||
// LINT.ThenChange(../../../../../../../proguard-rules.txt)
|
||||
Renderer renderer =
|
||||
|
@ -288,12 +288,12 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
|||
try {
|
||||
// Full class names used for constructor args so the LINT rule triggers if any of them move.
|
||||
// LINT.IfChange
|
||||
Class<?> clazz = Class.forName("org.telegram.messenger.exoplayer2.ext.opus.LibopusAudioRenderer");
|
||||
Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer");
|
||||
Constructor<?> constructor =
|
||||
clazz.getConstructor(
|
||||
android.os.Handler.class,
|
||||
org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.class,
|
||||
org.telegram.messenger.exoplayer2.audio.AudioProcessor[].class);
|
||||
com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
|
||||
com.google.android.exoplayer2.audio.AudioProcessor[].class);
|
||||
// LINT.ThenChange(../../../../../../../proguard-rules.txt)
|
||||
Renderer renderer =
|
||||
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors);
|
||||
|
@ -309,12 +309,12 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
|||
try {
|
||||
// Full class names used for constructor args so the LINT rule triggers if any of them move.
|
||||
// LINT.IfChange
|
||||
Class<?> clazz = Class.forName("org.telegram.messenger.exoplayer2.ext.flac.LibflacAudioRenderer");
|
||||
Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer");
|
||||
Constructor<?> constructor =
|
||||
clazz.getConstructor(
|
||||
android.os.Handler.class,
|
||||
org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.class,
|
||||
org.telegram.messenger.exoplayer2.audio.AudioProcessor[].class);
|
||||
com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
|
||||
com.google.android.exoplayer2.audio.AudioProcessor[].class);
|
||||
// LINT.ThenChange(../../../../../../../proguard-rules.txt)
|
||||
Renderer renderer =
|
||||
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors);
|
||||
|
@ -331,12 +331,12 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
|||
// Full class names used for constructor args so the LINT rule triggers if any of them move.
|
||||
// LINT.IfChange
|
||||
Class<?> clazz =
|
||||
Class.forName("org.telegram.messenger.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer");
|
||||
Class.forName("com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer");
|
||||
Constructor<?> constructor =
|
||||
clazz.getConstructor(
|
||||
android.os.Handler.class,
|
||||
org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.class,
|
||||
org.telegram.messenger.exoplayer2.audio.AudioProcessor[].class);
|
||||
com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
|
||||
com.google.android.exoplayer2.audio.AudioProcessor[].class);
|
||||
// LINT.ThenChange(../../../../../../../proguard-rules.txt)
|
||||
Renderer renderer =
|
||||
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors);
|
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.support.annotation.IntDef;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
|
@ -13,24 +13,24 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.audio.MediaCodecAudioRenderer;
|
||||
import org.telegram.messenger.exoplayer2.metadata.MetadataRenderer;
|
||||
import org.telegram.messenger.exoplayer2.source.ClippingMediaSource;
|
||||
import org.telegram.messenger.exoplayer2.source.ConcatenatingMediaSource;
|
||||
import org.telegram.messenger.exoplayer2.source.ExtractorMediaSource;
|
||||
import org.telegram.messenger.exoplayer2.source.LoopingMediaSource;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource;
|
||||
import org.telegram.messenger.exoplayer2.source.MergingMediaSource;
|
||||
import org.telegram.messenger.exoplayer2.source.SingleSampleMediaSource;
|
||||
import org.telegram.messenger.exoplayer2.text.TextRenderer;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector;
|
||||
import org.telegram.messenger.exoplayer2.upstream.DataSource;
|
||||
import org.telegram.messenger.exoplayer2.video.MediaCodecVideoRenderer;
|
||||
import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer;
|
||||
import com.google.android.exoplayer2.metadata.MetadataRenderer;
|
||||
import com.google.android.exoplayer2.source.ClippingMediaSource;
|
||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.LoopingMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MergingMediaSource;
|
||||
import com.google.android.exoplayer2.source.SingleSampleMediaSource;
|
||||
import com.google.android.exoplayer2.text.TextRenderer;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
|
||||
|
||||
/**
|
||||
* An extensible media player that plays {@link MediaSource}s. Instances can be obtained from {@link
|
||||
|
@ -89,12 +89,13 @@ import org.telegram.messenger.exoplayer2.video.MediaCodecVideoRenderer;
|
|||
* model">
|
||||
*
|
||||
* <ul>
|
||||
* <li>It is strongly recommended that ExoPlayer instances are created and accessed from a single
|
||||
* application thread. The application's main thread is ideal. Accessing an instance from
|
||||
* multiple threads is discouraged as it may cause synchronization problems.
|
||||
* <li>Registered listeners are called on the thread that created the ExoPlayer instance, unless
|
||||
* the thread that created the ExoPlayer instance does not have a {@link Looper}. In that
|
||||
* case, registered listeners will be called on the application's main thread.
|
||||
* <li>ExoPlayer instances must be accessed from the thread associated with {@link
|
||||
* #getApplicationLooper()}. This Looper can be specified when creating the player, or this is
|
||||
* the Looper of the thread the player is created on, or the Looper of the application's main
|
||||
* thread if the player is created on a thread without Looper.
|
||||
* <li>Registered listeners are called on the thread thread associated with {@link
|
||||
* #getApplicationLooper()}. Note that this means registered listeners are called on the same
|
||||
* thread which must be used to access the player.
|
||||
* <li>An internal playback thread is responsible for playback. Injected player components such as
|
||||
* Renderers, MediaSources, TrackSelectors and LoadControls are called by the player on this
|
||||
* thread.
|
||||
|
@ -178,13 +179,15 @@ public interface ExoPlayer extends Player {
|
|||
@Deprecated
|
||||
@RepeatMode int REPEAT_MODE_ALL = Player.REPEAT_MODE_ALL;
|
||||
|
||||
/**
|
||||
* Gets the {@link Looper} associated with the playback thread.
|
||||
*
|
||||
* @return The {@link Looper} associated with the playback thread.
|
||||
*/
|
||||
/** Returns the {@link Looper} associated with the playback thread. */
|
||||
Looper getPlaybackLooper();
|
||||
|
||||
/**
|
||||
* Returns the {@link Looper} associated with the application thread that's used to access the
|
||||
* player and on which player events are received.
|
||||
*/
|
||||
Looper getApplicationLooper();
|
||||
|
||||
/**
|
||||
* Prepares the player to play the provided {@link MediaSource}. Equivalent to
|
||||
* {@code prepare(mediaSource, true, true)}.
|
||||
|
@ -239,4 +242,7 @@ public interface ExoPlayer extends Player {
|
|||
* @param seekParameters The seek parameters, or {@code null} to use the defaults.
|
||||
*/
|
||||
void setSeekParameters(@Nullable SeekParameters seekParameters);
|
||||
|
||||
/** Returns the currently active {@link SeekParameters} of the player. */
|
||||
SeekParameters getSeekParameters();
|
||||
}
|
|
@ -13,21 +13,27 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.analytics.AnalyticsCollector;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager;
|
||||
import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector;
|
||||
import org.telegram.messenger.exoplayer2.util.Clock;
|
||||
import com.google.android.exoplayer2.analytics.AnalyticsCollector;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.util.Clock;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
/**
|
||||
* A factory for {@link ExoPlayer} instances.
|
||||
*/
|
||||
public final class ExoPlayerFactory {
|
||||
|
||||
private static @Nullable BandwidthMeter singletonBandwidthMeter;
|
||||
|
||||
private ExoPlayerFactory() {}
|
||||
|
||||
/**
|
||||
|
@ -155,8 +161,12 @@ public final class ExoPlayerFactory {
|
|||
*/
|
||||
public static SimpleExoPlayer newSimpleInstance(RenderersFactory renderersFactory,
|
||||
TrackSelector trackSelector, LoadControl loadControl) {
|
||||
return new SimpleExoPlayer(
|
||||
renderersFactory, trackSelector, loadControl, /* drmSessionManager= */ null);
|
||||
return newSimpleInstance(
|
||||
renderersFactory,
|
||||
trackSelector,
|
||||
loadControl,
|
||||
/* drmSessionManager= */ null,
|
||||
Util.getLooper());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -173,7 +183,34 @@ public final class ExoPlayerFactory {
|
|||
TrackSelector trackSelector,
|
||||
LoadControl loadControl,
|
||||
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
|
||||
return new SimpleExoPlayer(renderersFactory, trackSelector, loadControl, drmSessionManager);
|
||||
return newSimpleInstance(
|
||||
renderersFactory, trackSelector, loadControl, drmSessionManager, Util.getLooper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link SimpleExoPlayer} instance.
|
||||
*
|
||||
* @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance.
|
||||
* @param trackSelector The {@link TrackSelector} that will be used by the instance.
|
||||
* @param loadControl The {@link LoadControl} that will be used by the instance.
|
||||
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
|
||||
* will not be used for DRM protected playbacks.
|
||||
* @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance.
|
||||
*/
|
||||
public static SimpleExoPlayer newSimpleInstance(
|
||||
RenderersFactory renderersFactory,
|
||||
TrackSelector trackSelector,
|
||||
LoadControl loadControl,
|
||||
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
|
||||
BandwidthMeter bandwidthMeter) {
|
||||
return newSimpleInstance(
|
||||
renderersFactory,
|
||||
trackSelector,
|
||||
loadControl,
|
||||
drmSessionManager,
|
||||
bandwidthMeter,
|
||||
new AnalyticsCollector.Factory(),
|
||||
Util.getLooper());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -193,8 +230,100 @@ public final class ExoPlayerFactory {
|
|||
LoadControl loadControl,
|
||||
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
|
||||
AnalyticsCollector.Factory analyticsCollectorFactory) {
|
||||
return newSimpleInstance(
|
||||
renderersFactory,
|
||||
trackSelector,
|
||||
loadControl,
|
||||
drmSessionManager,
|
||||
analyticsCollectorFactory,
|
||||
Util.getLooper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link SimpleExoPlayer} instance.
|
||||
*
|
||||
* @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance.
|
||||
* @param trackSelector The {@link TrackSelector} that will be used by the instance.
|
||||
* @param loadControl The {@link LoadControl} that will be used by the instance.
|
||||
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
|
||||
* will not be used for DRM protected playbacks.
|
||||
* @param looper The {@link Looper} which must be used for all calls to the player and which is
|
||||
* used to call listeners on.
|
||||
*/
|
||||
public static SimpleExoPlayer newSimpleInstance(
|
||||
RenderersFactory renderersFactory,
|
||||
TrackSelector trackSelector,
|
||||
LoadControl loadControl,
|
||||
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
|
||||
Looper looper) {
|
||||
return newSimpleInstance(
|
||||
renderersFactory,
|
||||
trackSelector,
|
||||
loadControl,
|
||||
drmSessionManager,
|
||||
new AnalyticsCollector.Factory(),
|
||||
looper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link SimpleExoPlayer} instance.
|
||||
*
|
||||
* @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance.
|
||||
* @param trackSelector The {@link TrackSelector} that will be used by the instance.
|
||||
* @param loadControl The {@link LoadControl} that will be used by the instance.
|
||||
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
|
||||
* will not be used for DRM protected playbacks.
|
||||
* @param analyticsCollectorFactory A factory for creating the {@link AnalyticsCollector} that
|
||||
* will collect and forward all player events.
|
||||
* @param looper The {@link Looper} which must be used for all calls to the player and which is
|
||||
* used to call listeners on.
|
||||
*/
|
||||
public static SimpleExoPlayer newSimpleInstance(
|
||||
RenderersFactory renderersFactory,
|
||||
TrackSelector trackSelector,
|
||||
LoadControl loadControl,
|
||||
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
|
||||
AnalyticsCollector.Factory analyticsCollectorFactory,
|
||||
Looper looper) {
|
||||
return newSimpleInstance(
|
||||
renderersFactory,
|
||||
trackSelector,
|
||||
loadControl,
|
||||
drmSessionManager,
|
||||
getDefaultBandwidthMeter(),
|
||||
analyticsCollectorFactory,
|
||||
looper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link SimpleExoPlayer} instance.
|
||||
*
|
||||
* @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance.
|
||||
* @param trackSelector The {@link TrackSelector} that will be used by the instance.
|
||||
* @param loadControl The {@link LoadControl} that will be used by the instance.
|
||||
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
|
||||
* will not be used for DRM protected playbacks.
|
||||
* @param analyticsCollectorFactory A factory for creating the {@link AnalyticsCollector} that
|
||||
* will collect and forward all player events.
|
||||
* @param looper The {@link Looper} which must be used for all calls to the player and which is
|
||||
* used to call listeners on.
|
||||
*/
|
||||
public static SimpleExoPlayer newSimpleInstance(
|
||||
RenderersFactory renderersFactory,
|
||||
TrackSelector trackSelector,
|
||||
LoadControl loadControl,
|
||||
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
|
||||
BandwidthMeter bandwidthMeter,
|
||||
AnalyticsCollector.Factory analyticsCollectorFactory,
|
||||
Looper looper) {
|
||||
return new SimpleExoPlayer(
|
||||
renderersFactory, trackSelector, loadControl, drmSessionManager, analyticsCollectorFactory);
|
||||
renderersFactory,
|
||||
trackSelector,
|
||||
loadControl,
|
||||
drmSessionManager,
|
||||
bandwidthMeter,
|
||||
analyticsCollectorFactory,
|
||||
looper);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -216,7 +345,47 @@ public final class ExoPlayerFactory {
|
|||
*/
|
||||
public static ExoPlayer newInstance(Renderer[] renderers, TrackSelector trackSelector,
|
||||
LoadControl loadControl) {
|
||||
return new ExoPlayerImpl(renderers, trackSelector, loadControl, Clock.DEFAULT);
|
||||
return newInstance(renderers, trackSelector, loadControl, Util.getLooper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link ExoPlayer} instance.
|
||||
*
|
||||
* @param renderers The {@link Renderer}s that will be used by the instance.
|
||||
* @param trackSelector The {@link TrackSelector} that will be used by the instance.
|
||||
* @param loadControl The {@link LoadControl} that will be used by the instance.
|
||||
* @param looper The {@link Looper} which must be used for all calls to the player and which is
|
||||
* used to call listeners on.
|
||||
*/
|
||||
public static ExoPlayer newInstance(
|
||||
Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl, Looper looper) {
|
||||
return newInstance(renderers, trackSelector, loadControl, getDefaultBandwidthMeter(), looper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link ExoPlayer} instance.
|
||||
*
|
||||
* @param renderers The {@link Renderer}s that will be used by the instance.
|
||||
* @param trackSelector The {@link TrackSelector} that will be used by the instance.
|
||||
* @param loadControl The {@link LoadControl} that will be used by the instance.
|
||||
* @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance.
|
||||
* @param looper The {@link Looper} which must be used for all calls to the player and which is
|
||||
* used to call listeners on.
|
||||
*/
|
||||
public static ExoPlayer newInstance(
|
||||
Renderer[] renderers,
|
||||
TrackSelector trackSelector,
|
||||
LoadControl loadControl,
|
||||
BandwidthMeter bandwidthMeter,
|
||||
Looper looper) {
|
||||
return new ExoPlayerImpl(
|
||||
renderers, trackSelector, loadControl, bandwidthMeter, Clock.DEFAULT, looper);
|
||||
}
|
||||
|
||||
private static synchronized BandwidthMeter getDefaultBandwidthMeter() {
|
||||
if (singletonBandwidthMeter == null) {
|
||||
singletonBandwidthMeter = new DefaultBandwidthMeter.Builder().build();
|
||||
}
|
||||
return singletonBandwidthMeter;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Handler;
|
||||
|
@ -22,19 +22,22 @@ import android.os.Message;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import org.telegram.messenger.exoplayer2.PlayerMessage.Target;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import org.telegram.messenger.exoplayer2.source.TrackGroupArray;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelection;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectorResult;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.Clock;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.PlayerMessage.Target;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Clock;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
|
@ -53,6 +56,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
private final CopyOnWriteArraySet<Player.EventListener> listeners;
|
||||
private final Timeline.Window window;
|
||||
private final Timeline.Period period;
|
||||
private final ArrayDeque<PlaybackInfoUpdate> pendingPlaybackInfoUpdates;
|
||||
|
||||
private boolean playWhenReady;
|
||||
private @RepeatMode int repeatMode;
|
||||
|
@ -61,6 +65,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
private boolean hasPendingPrepare;
|
||||
private boolean hasPendingSeek;
|
||||
private PlaybackParameters playbackParameters;
|
||||
private SeekParameters seekParameters;
|
||||
private @Nullable ExoPlaybackException playbackError;
|
||||
|
||||
// Playback information when there is no pending seek/set source operation.
|
||||
|
@ -77,11 +82,19 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
* @param renderers The {@link Renderer}s that will be used by the instance.
|
||||
* @param trackSelector The {@link TrackSelector} that will be used by the instance.
|
||||
* @param loadControl The {@link LoadControl} that will be used by the instance.
|
||||
* @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance.
|
||||
* @param clock The {@link Clock} that will be used by the instance.
|
||||
* @param looper The {@link Looper} which must be used for all calls to the player and which is
|
||||
* used to call listeners on.
|
||||
*/
|
||||
@SuppressLint("HandlerLeak")
|
||||
public ExoPlayerImpl(
|
||||
Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl, Clock clock) {
|
||||
Renderer[] renderers,
|
||||
TrackSelector trackSelector,
|
||||
LoadControl loadControl,
|
||||
BandwidthMeter bandwidthMeter,
|
||||
Clock clock,
|
||||
Looper looper) {
|
||||
Log.i(TAG, "Init " + Integer.toHexString(System.identityHashCode(this)) + " ["
|
||||
+ ExoPlayerLibraryInfo.VERSION_SLASHY + "] [" + Util.DEVICE_DEBUG_INFO + "]");
|
||||
Assertions.checkState(renderers.length > 0);
|
||||
|
@ -99,25 +112,23 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
window = new Timeline.Window();
|
||||
period = new Timeline.Period();
|
||||
playbackParameters = PlaybackParameters.DEFAULT;
|
||||
Looper eventLooper = Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper();
|
||||
eventHandler = new Handler(eventLooper) {
|
||||
seekParameters = SeekParameters.DEFAULT;
|
||||
eventHandler =
|
||||
new Handler(looper) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
ExoPlayerImpl.this.handleEvent(msg);
|
||||
}
|
||||
};
|
||||
playbackInfo =
|
||||
new PlaybackInfo(
|
||||
Timeline.EMPTY,
|
||||
/* startPositionUs= */ 0,
|
||||
TrackGroupArray.EMPTY,
|
||||
emptyTrackSelectorResult);
|
||||
playbackInfo = PlaybackInfo.createDummy(/* startPositionUs= */ 0, emptyTrackSelectorResult);
|
||||
pendingPlaybackInfoUpdates = new ArrayDeque<>();
|
||||
internalPlayer =
|
||||
new ExoPlayerImplInternal(
|
||||
renderers,
|
||||
trackSelector,
|
||||
emptyTrackSelectorResult,
|
||||
loadControl,
|
||||
bandwidthMeter,
|
||||
playWhenReady,
|
||||
repeatMode,
|
||||
shuffleModeEnabled,
|
||||
|
@ -127,6 +138,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AudioComponent getAudioComponent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoComponent getVideoComponent() {
|
||||
return null;
|
||||
|
@ -142,6 +158,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
return internalPlayer.getPlaybackLooper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Looper getApplicationLooper() {
|
||||
return eventHandler.getLooper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(Player.EventListener listener) {
|
||||
listeners.add(listener);
|
||||
|
@ -185,7 +206,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
/* positionDiscontinuity= */ false,
|
||||
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
||||
TIMELINE_CHANGE_REASON_RESET,
|
||||
/* seekProcessed= */ false);
|
||||
/* seekProcessed= */ false,
|
||||
/* playWhenReadyChanged= */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -193,10 +215,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
if (this.playWhenReady != playWhenReady) {
|
||||
this.playWhenReady = playWhenReady;
|
||||
internalPlayer.setPlayWhenReady(playWhenReady);
|
||||
PlaybackInfo playbackInfo = this.playbackInfo;
|
||||
for (Player.EventListener listener : listeners) {
|
||||
listener.onPlayerStateChanged(playWhenReady, playbackInfo.playbackState);
|
||||
}
|
||||
updatePlaybackInfo(
|
||||
playbackInfo,
|
||||
/* positionDiscontinuity= */ false,
|
||||
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
||||
/* ignored */ TIMELINE_CHANGE_REASON_RESET,
|
||||
/* seekProcessed= */ false,
|
||||
/* playWhenReadyChanged= */ true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,10 +311,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
} else {
|
||||
long windowPositionUs = positionMs == C.TIME_UNSET
|
||||
? timeline.getWindow(windowIndex, window).getDefaultPositionUs() : C.msToUs(positionMs);
|
||||
Pair<Integer, Long> periodIndexAndPositon =
|
||||
Pair<Integer, Long> periodIndexAndPosition =
|
||||
timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs);
|
||||
maskingWindowPositionMs = C.usToMs(windowPositionUs);
|
||||
maskingPeriodIndex = periodIndexAndPositon.first;
|
||||
maskingPeriodIndex = periodIndexAndPosition.first;
|
||||
}
|
||||
internalPlayer.seekTo(timeline, windowIndex, C.msToUs(positionMs));
|
||||
for (Player.EventListener listener : listeners) {
|
||||
|
@ -315,8 +340,16 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
if (seekParameters == null) {
|
||||
seekParameters = SeekParameters.DEFAULT;
|
||||
}
|
||||
if (!this.seekParameters.equals(seekParameters)) {
|
||||
this.seekParameters = seekParameters;
|
||||
internalPlayer.setSeekParameters(seekParameters);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekParameters getSeekParameters() {
|
||||
return seekParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object getCurrentTag() {
|
||||
|
@ -352,7 +385,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
/* positionDiscontinuity= */ false,
|
||||
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
||||
TIMELINE_CHANGE_REASON_RESET,
|
||||
/* seekProcessed= */ false);
|
||||
/* seekProcessed= */ false,
|
||||
/* playWhenReadyChanged= */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -461,29 +495,37 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
public long getCurrentPosition() {
|
||||
if (shouldMaskPosition()) {
|
||||
return maskingWindowPositionMs;
|
||||
} else if (playbackInfo.periodId.isAd()) {
|
||||
return C.usToMs(playbackInfo.positionUs);
|
||||
} else {
|
||||
return playbackInfoPositionUsToWindowPositionMs(playbackInfo.positionUs);
|
||||
return periodPositionUsToWindowPositionMs(playbackInfo.periodId, playbackInfo.positionUs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBufferedPosition() {
|
||||
// TODO - Implement this properly.
|
||||
if (shouldMaskPosition()) {
|
||||
return maskingWindowPositionMs;
|
||||
} else {
|
||||
return playbackInfoPositionUsToWindowPositionMs(playbackInfo.bufferedPositionUs);
|
||||
if (isPlayingAd()) {
|
||||
return playbackInfo.loadingMediaPeriodId.equals(playbackInfo.periodId)
|
||||
? C.usToMs(playbackInfo.bufferedPositionUs)
|
||||
: getDuration();
|
||||
}
|
||||
return getContentBufferedPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBufferedPercentage() {
|
||||
long position = getBufferedPosition();
|
||||
long duration = getDuration();
|
||||
return position == C.TIME_UNSET || duration == C.TIME_UNSET ? 0
|
||||
return position == C.TIME_UNSET || duration == C.TIME_UNSET
|
||||
? 0
|
||||
: (duration == 0 ? 100 : Util.constrainValue((int) ((position * 100) / duration), 0, 100));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalBufferedDuration() {
|
||||
return Math.max(0, C.usToMs(playbackInfo.totalBufferedDurationUs));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrentWindowDynamic() {
|
||||
Timeline timeline = playbackInfo.timeline;
|
||||
|
@ -521,6 +563,29 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getContentBufferedPosition() {
|
||||
if (shouldMaskPosition()) {
|
||||
return maskingWindowPositionMs;
|
||||
}
|
||||
if (playbackInfo.loadingMediaPeriodId.windowSequenceNumber
|
||||
!= playbackInfo.periodId.windowSequenceNumber) {
|
||||
return playbackInfo.timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs();
|
||||
}
|
||||
long contentBufferedPositionUs = playbackInfo.bufferedPositionUs;
|
||||
if (playbackInfo.loadingMediaPeriodId.isAd()) {
|
||||
Timeline.Period loadingPeriod =
|
||||
playbackInfo.timeline.getPeriod(playbackInfo.loadingMediaPeriodId.periodIndex, period);
|
||||
contentBufferedPositionUs =
|
||||
loadingPeriod.getAdGroupTimeUs(playbackInfo.loadingMediaPeriodId.adGroupIndex);
|
||||
if (contentBufferedPositionUs == C.TIME_END_OF_SOURCE) {
|
||||
contentBufferedPositionUs = loadingPeriod.durationUs;
|
||||
}
|
||||
}
|
||||
return periodPositionUsToWindowPositionMs(
|
||||
playbackInfo.loadingMediaPeriodId, contentBufferedPositionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRendererCount() {
|
||||
return renderers.length;
|
||||
|
@ -615,7 +680,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
positionDiscontinuity,
|
||||
positionDiscontinuityReason,
|
||||
timelineChangeReason,
|
||||
seekProcessed);
|
||||
seekProcessed,
|
||||
/* playWhenReadyChanged= */ false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,23 +705,100 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
playbackState,
|
||||
/* isLoading= */ false,
|
||||
resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
|
||||
resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult);
|
||||
resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
|
||||
playbackInfo.periodId,
|
||||
playbackInfo.startPositionUs,
|
||||
/* totalBufferedDurationUs= */ 0,
|
||||
playbackInfo.startPositionUs);
|
||||
}
|
||||
|
||||
private void updatePlaybackInfo(
|
||||
PlaybackInfo newPlaybackInfo,
|
||||
PlaybackInfo playbackInfo,
|
||||
boolean positionDiscontinuity,
|
||||
@Player.DiscontinuityReason int positionDiscontinuityReason,
|
||||
@Player.TimelineChangeReason int timelineChangeReason,
|
||||
boolean seekProcessed) {
|
||||
boolean timelineOrManifestChanged =
|
||||
playbackInfo.timeline != newPlaybackInfo.timeline
|
||||
|| playbackInfo.manifest != newPlaybackInfo.manifest;
|
||||
boolean playbackStateChanged = playbackInfo.playbackState != newPlaybackInfo.playbackState;
|
||||
boolean isLoadingChanged = playbackInfo.isLoading != newPlaybackInfo.isLoading;
|
||||
boolean trackSelectorResultChanged =
|
||||
playbackInfo.trackSelectorResult != newPlaybackInfo.trackSelectorResult;
|
||||
playbackInfo = newPlaybackInfo;
|
||||
boolean seekProcessed,
|
||||
boolean playWhenReadyChanged) {
|
||||
boolean isRunningRecursiveListenerNotification = !pendingPlaybackInfoUpdates.isEmpty();
|
||||
pendingPlaybackInfoUpdates.addLast(
|
||||
new PlaybackInfoUpdate(
|
||||
playbackInfo,
|
||||
/* previousPlaybackInfo= */ this.playbackInfo,
|
||||
listeners,
|
||||
trackSelector,
|
||||
positionDiscontinuity,
|
||||
positionDiscontinuityReason,
|
||||
timelineChangeReason,
|
||||
seekProcessed,
|
||||
playWhenReady,
|
||||
playWhenReadyChanged));
|
||||
// Assign playback info immediately such that all getters return the right values.
|
||||
this.playbackInfo = playbackInfo;
|
||||
if (isRunningRecursiveListenerNotification) {
|
||||
return;
|
||||
}
|
||||
while (!pendingPlaybackInfoUpdates.isEmpty()) {
|
||||
pendingPlaybackInfoUpdates.peekFirst().notifyListeners();
|
||||
pendingPlaybackInfoUpdates.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
private long periodPositionUsToWindowPositionMs(MediaPeriodId periodId, long positionUs) {
|
||||
long positionMs = C.usToMs(positionUs);
|
||||
playbackInfo.timeline.getPeriod(periodId.periodIndex, period);
|
||||
positionMs += period.getPositionInWindowMs();
|
||||
return positionMs;
|
||||
}
|
||||
|
||||
private boolean shouldMaskPosition() {
|
||||
return playbackInfo.timeline.isEmpty() || pendingOperationAcks > 0;
|
||||
}
|
||||
|
||||
private static final class PlaybackInfoUpdate {
|
||||
|
||||
private final PlaybackInfo playbackInfo;
|
||||
private final Set<Player.EventListener> listeners;
|
||||
private final TrackSelector trackSelector;
|
||||
private final boolean positionDiscontinuity;
|
||||
private final @Player.DiscontinuityReason int positionDiscontinuityReason;
|
||||
private final @Player.TimelineChangeReason int timelineChangeReason;
|
||||
private final boolean seekProcessed;
|
||||
private final boolean playWhenReady;
|
||||
private final boolean playbackStateOrPlayWhenReadyChanged;
|
||||
private final boolean timelineOrManifestChanged;
|
||||
private final boolean isLoadingChanged;
|
||||
private final boolean trackSelectorResultChanged;
|
||||
|
||||
public PlaybackInfoUpdate(
|
||||
PlaybackInfo playbackInfo,
|
||||
PlaybackInfo previousPlaybackInfo,
|
||||
Set<Player.EventListener> listeners,
|
||||
TrackSelector trackSelector,
|
||||
boolean positionDiscontinuity,
|
||||
@Player.DiscontinuityReason int positionDiscontinuityReason,
|
||||
@Player.TimelineChangeReason int timelineChangeReason,
|
||||
boolean seekProcessed,
|
||||
boolean playWhenReady,
|
||||
boolean playWhenReadyChanged) {
|
||||
this.playbackInfo = playbackInfo;
|
||||
this.listeners = listeners;
|
||||
this.trackSelector = trackSelector;
|
||||
this.positionDiscontinuity = positionDiscontinuity;
|
||||
this.positionDiscontinuityReason = positionDiscontinuityReason;
|
||||
this.timelineChangeReason = timelineChangeReason;
|
||||
this.seekProcessed = seekProcessed;
|
||||
this.playWhenReady = playWhenReady;
|
||||
playbackStateOrPlayWhenReadyChanged =
|
||||
playWhenReadyChanged || previousPlaybackInfo.playbackState != playbackInfo.playbackState;
|
||||
timelineOrManifestChanged =
|
||||
previousPlaybackInfo.timeline != playbackInfo.timeline
|
||||
|| previousPlaybackInfo.manifest != playbackInfo.manifest;
|
||||
isLoadingChanged = previousPlaybackInfo.isLoading != playbackInfo.isLoading;
|
||||
trackSelectorResultChanged =
|
||||
previousPlaybackInfo.trackSelectorResult != playbackInfo.trackSelectorResult;
|
||||
}
|
||||
|
||||
public void notifyListeners() {
|
||||
if (timelineOrManifestChanged || timelineChangeReason == TIMELINE_CHANGE_REASON_PREPARED) {
|
||||
for (Player.EventListener listener : listeners) {
|
||||
listener.onTimelineChanged(
|
||||
|
@ -679,7 +822,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
listener.onLoadingChanged(playbackInfo.isLoading);
|
||||
}
|
||||
}
|
||||
if (playbackStateChanged) {
|
||||
if (playbackStateOrPlayWhenReadyChanged) {
|
||||
for (Player.EventListener listener : listeners) {
|
||||
listener.onPlayerStateChanged(playWhenReady, playbackInfo.playbackState);
|
||||
}
|
||||
|
@ -690,17 +833,5 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long playbackInfoPositionUsToWindowPositionMs(long positionUs) {
|
||||
long positionMs = C.usToMs(positionUs);
|
||||
if (!playbackInfo.periodId.isAd()) {
|
||||
playbackInfo.timeline.getPeriod(playbackInfo.periodId.periodIndex, period);
|
||||
positionMs += period.getPositionInWindowMs();
|
||||
}
|
||||
return positionMs;
|
||||
}
|
||||
|
||||
private boolean shouldMaskPosition() {
|
||||
return playbackInfo.timeline.isEmpty() || pendingOperationAcks > 0;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
|
@ -25,21 +25,22 @@ import android.support.annotation.NonNull;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import org.telegram.messenger.exoplayer2.DefaultMediaClock.PlaybackParameterListener;
|
||||
import org.telegram.messenger.exoplayer2.Player.DiscontinuityReason;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaPeriod;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import org.telegram.messenger.exoplayer2.source.SampleStream;
|
||||
import org.telegram.messenger.exoplayer2.source.TrackGroupArray;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelection;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectorResult;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.Clock;
|
||||
import org.telegram.messenger.exoplayer2.util.HandlerWrapper;
|
||||
import org.telegram.messenger.exoplayer2.util.TraceUtil;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.DefaultMediaClock.PlaybackParameterListener;
|
||||
import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Clock;
|
||||
import com.google.android.exoplayer2.util.HandlerWrapper;
|
||||
import com.google.android.exoplayer2.util.TraceUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -77,6 +78,7 @@ import java.util.Collections;
|
|||
private static final int MSG_SET_SHUFFLE_ENABLED = 13;
|
||||
private static final int MSG_SEND_MESSAGE = 14;
|
||||
private static final int MSG_SEND_MESSAGE_TO_TARGET_THREAD = 15;
|
||||
private static final int MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL = 16;
|
||||
|
||||
private static final int PREPARING_SOURCE_INTERVAL_MS = 10;
|
||||
private static final int RENDERING_INTERVAL_MS = 10;
|
||||
|
@ -87,6 +89,7 @@ import java.util.Collections;
|
|||
private final TrackSelector trackSelector;
|
||||
private final TrackSelectorResult emptyTrackSelectorResult;
|
||||
private final LoadControl loadControl;
|
||||
private final BandwidthMeter bandwidthMeter;
|
||||
private final HandlerWrapper handler;
|
||||
private final HandlerThread internalPlaybackThread;
|
||||
private final Handler eventHandler;
|
||||
|
@ -123,6 +126,7 @@ import java.util.Collections;
|
|||
TrackSelector trackSelector,
|
||||
TrackSelectorResult emptyTrackSelectorResult,
|
||||
LoadControl loadControl,
|
||||
BandwidthMeter bandwidthMeter,
|
||||
boolean playWhenReady,
|
||||
@Player.RepeatMode int repeatMode,
|
||||
boolean shuffleModeEnabled,
|
||||
|
@ -133,6 +137,7 @@ import java.util.Collections;
|
|||
this.trackSelector = trackSelector;
|
||||
this.emptyTrackSelectorResult = emptyTrackSelectorResult;
|
||||
this.loadControl = loadControl;
|
||||
this.bandwidthMeter = bandwidthMeter;
|
||||
this.playWhenReady = playWhenReady;
|
||||
this.repeatMode = repeatMode;
|
||||
this.shuffleModeEnabled = shuffleModeEnabled;
|
||||
|
@ -146,11 +151,7 @@ import java.util.Collections;
|
|||
|
||||
seekParameters = SeekParameters.DEFAULT;
|
||||
playbackInfo =
|
||||
new PlaybackInfo(
|
||||
Timeline.EMPTY,
|
||||
/* startPositionUs= */ C.TIME_UNSET,
|
||||
TrackGroupArray.EMPTY,
|
||||
emptyTrackSelectorResult);
|
||||
PlaybackInfo.createDummy(/* startPositionUs= */ C.TIME_UNSET, emptyTrackSelectorResult);
|
||||
playbackInfoUpdate = new PlaybackInfoUpdate();
|
||||
rendererCapabilities = new RendererCapabilities[renderers.length];
|
||||
for (int i = 0; i < renderers.length; i++) {
|
||||
|
@ -162,7 +163,7 @@ import java.util.Collections;
|
|||
enabledRenderers = new Renderer[0];
|
||||
window = new Timeline.Window();
|
||||
period = new Timeline.Period();
|
||||
trackSelector.init(this);
|
||||
trackSelector.init(/* listener= */ this, bandwidthMeter);
|
||||
|
||||
// Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can
|
||||
// not normally change to this priority" is incorrect.
|
||||
|
@ -271,8 +272,9 @@ import java.util.Collections;
|
|||
|
||||
@Override
|
||||
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
|
||||
eventHandler.obtainMessage(MSG_PLAYBACK_PARAMETERS_CHANGED, playbackParameters).sendToTarget();
|
||||
updateTrackSelectionPlaybackSpeed(playbackParameters.speed);
|
||||
handler
|
||||
.obtainMessage(MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL, playbackParameters)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
// Handler.Callback implementation.
|
||||
|
@ -324,6 +326,9 @@ import java.util.Collections;
|
|||
case MSG_TRACK_SELECTION_INVALIDATED:
|
||||
reselectTracksInternal();
|
||||
break;
|
||||
case MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL:
|
||||
handlePlaybackParameters((PlaybackParameters) msg.obj);
|
||||
break;
|
||||
case MSG_SEND_MESSAGE:
|
||||
sendMessageInternal((PlayerMessage) msg.obj);
|
||||
break;
|
||||
|
@ -393,7 +398,11 @@ import java.util.Collections;
|
|||
loadControl.onPrepared();
|
||||
this.mediaSource = mediaSource;
|
||||
setState(Player.STATE_BUFFERING);
|
||||
mediaSource.prepareSource(player, /* isTopLevelSource= */ true, /* listener= */ this);
|
||||
mediaSource.prepareSource(
|
||||
player,
|
||||
/* isTopLevelSource= */ true,
|
||||
/* listener= */ this,
|
||||
bandwidthMeter.getTransferListener());
|
||||
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
|
||||
}
|
||||
|
||||
|
@ -419,6 +428,7 @@ import java.util.Collections;
|
|||
if (!queue.updateRepeatMode(repeatMode)) {
|
||||
seekToCurrentPosition(/* sendDiscontinuity= */ true);
|
||||
}
|
||||
updateLoadingMediaPeriodId();
|
||||
}
|
||||
|
||||
private void setShuffleModeEnabledInternal(boolean shuffleModeEnabled)
|
||||
|
@ -427,6 +437,7 @@ import java.util.Collections;
|
|||
if (!queue.updateShuffleModeEnabled(shuffleModeEnabled)) {
|
||||
seekToCurrentPosition(/* sendDiscontinuity= */ true);
|
||||
}
|
||||
updateLoadingMediaPeriodId();
|
||||
}
|
||||
|
||||
private void seekToCurrentPosition(boolean sendDiscontinuity) throws ExoPlaybackException {
|
||||
|
@ -483,11 +494,12 @@ import java.util.Collections;
|
|||
playbackInfo.positionUs = periodPositionUs;
|
||||
}
|
||||
|
||||
// Update the buffered position.
|
||||
// Update the buffered position and total buffered duration.
|
||||
MediaPeriodHolder loadingPeriod = queue.getLoadingPeriod();
|
||||
playbackInfo.bufferedPositionUs =
|
||||
enabledRenderers.length == 0
|
||||
? playingPeriodHolder.info.durationUs
|
||||
: playingPeriodHolder.getBufferedPositionUs(/* convertEosToDuration= */ true);
|
||||
loadingPeriod.getBufferedPositionUs(/* convertEosToDuration= */ true);
|
||||
playbackInfo.totalBufferedDurationUs =
|
||||
playbackInfo.bufferedPositionUs - loadingPeriod.toPeriodTime(rendererPositionUs);
|
||||
}
|
||||
|
||||
private void doSomeWork() throws ExoPlaybackException, IOException {
|
||||
|
@ -587,7 +599,7 @@ import java.util.Collections;
|
|||
if (resolvedSeekPosition == null) {
|
||||
// The seek position was valid for the timeline that it was performed into, but the
|
||||
// timeline has changed or is not ready and a suitable seek position could not be resolved.
|
||||
periodId = new MediaPeriodId(getFirstPeriodIndex());
|
||||
periodId = getFirstMediaPeriodId();
|
||||
periodPositionUs = C.TIME_UNSET;
|
||||
contentPositionUs = C.TIME_UNSET;
|
||||
seekPositionAdjusted = true;
|
||||
|
@ -660,7 +672,7 @@ import java.util.Collections;
|
|||
MediaPeriodHolder oldPlayingPeriodHolder = queue.getPlayingPeriod();
|
||||
MediaPeriodHolder newPlayingPeriodHolder = oldPlayingPeriodHolder;
|
||||
while (newPlayingPeriodHolder != null) {
|
||||
if (shouldKeepPeriodHolder(periodId, periodPositionUs, newPlayingPeriodHolder)) {
|
||||
if (periodId.equals(newPlayingPeriodHolder.info.id) && newPlayingPeriodHolder.prepared) {
|
||||
queue.removeAfter(newPlayingPeriodHolder);
|
||||
break;
|
||||
}
|
||||
|
@ -691,23 +703,11 @@ import java.util.Collections;
|
|||
resetRendererPosition(periodPositionUs);
|
||||
}
|
||||
|
||||
updateLoadingMediaPeriodId();
|
||||
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
|
||||
return periodPositionUs;
|
||||
}
|
||||
|
||||
private boolean shouldKeepPeriodHolder(
|
||||
MediaPeriodId seekPeriodId, long positionUs, MediaPeriodHolder holder) {
|
||||
if (seekPeriodId.equals(holder.info.id) && holder.prepared) {
|
||||
playbackInfo.timeline.getPeriod(holder.info.id.periodIndex, period);
|
||||
int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs);
|
||||
if (nextAdGroupIndex == C.INDEX_UNSET
|
||||
|| period.getAdGroupTimeUs(nextAdGroupIndex) == holder.info.endPositionUs) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void resetRendererPosition(long periodPositionUs) throws ExoPlaybackException {
|
||||
rendererPositionUs =
|
||||
!queue.hasPlayingPeriod()
|
||||
|
@ -749,12 +749,15 @@ import java.util.Collections;
|
|||
}
|
||||
}
|
||||
|
||||
private int getFirstPeriodIndex() {
|
||||
private MediaPeriodId getFirstMediaPeriodId() {
|
||||
Timeline timeline = playbackInfo.timeline;
|
||||
return timeline.isEmpty()
|
||||
? 0
|
||||
: timeline.getWindow(timeline.getFirstWindowIndex(shuffleModeEnabled), window)
|
||||
if (timeline.isEmpty()) {
|
||||
return PlaybackInfo.DUMMY_MEDIA_PERIOD_ID;
|
||||
}
|
||||
int firstPeriodIndex =
|
||||
timeline.getWindow(timeline.getFirstWindowIndex(shuffleModeEnabled), window)
|
||||
.firstPeriodIndex;
|
||||
return new MediaPeriodId(firstPeriodIndex);
|
||||
}
|
||||
|
||||
private void resetInternal(
|
||||
|
@ -785,18 +788,25 @@ import java.util.Collections;
|
|||
pendingMessages.clear();
|
||||
nextPendingMessageIndex = 0;
|
||||
}
|
||||
// Set the start position to TIME_UNSET so that a subsequent seek to 0 isn't ignored.
|
||||
MediaPeriodId mediaPeriodId = resetPosition ? getFirstMediaPeriodId() : playbackInfo.periodId;
|
||||
long startPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.positionUs;
|
||||
long contentPositionUs = resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs;
|
||||
playbackInfo =
|
||||
new PlaybackInfo(
|
||||
resetState ? Timeline.EMPTY : playbackInfo.timeline,
|
||||
resetState ? null : playbackInfo.manifest,
|
||||
resetPosition ? new MediaPeriodId(getFirstPeriodIndex()) : playbackInfo.periodId,
|
||||
// Set the start position to TIME_UNSET so that a subsequent seek to 0 isn't ignored.
|
||||
resetPosition ? C.TIME_UNSET : playbackInfo.positionUs,
|
||||
resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs,
|
||||
mediaPeriodId,
|
||||
startPositionUs,
|
||||
contentPositionUs,
|
||||
playbackInfo.playbackState,
|
||||
/* isLoading= */ false,
|
||||
resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
|
||||
resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult);
|
||||
resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
|
||||
mediaPeriodId,
|
||||
startPositionUs,
|
||||
/* totalBufferedDurationUs= */ 0,
|
||||
startPositionUs);
|
||||
if (releaseMediaSource) {
|
||||
if (mediaSource != null) {
|
||||
mediaSource.releaseSource(/* listener= */ this);
|
||||
|
@ -892,7 +902,7 @@ import java.util.Collections;
|
|||
pendingMessageInfo.setResolvedPosition(
|
||||
periodPosition.first,
|
||||
periodPosition.second,
|
||||
playbackInfo.timeline.getPeriod(periodPosition.first, period, true).uid);
|
||||
playbackInfo.timeline.getUidOfPeriod(periodPosition.first));
|
||||
} else {
|
||||
// Position has been resolved for a previous timeline. Try to find the updated period index.
|
||||
int index = playbackInfo.timeline.getIndexOfPeriod(pendingMessageInfo.resolvedPeriodUid);
|
||||
|
@ -1051,6 +1061,7 @@ import java.util.Collections;
|
|||
updateLoadControlTrackSelection(periodHolder.trackGroups, periodHolder.trackSelectorResult);
|
||||
}
|
||||
}
|
||||
updateLoadingMediaPeriodId();
|
||||
if (playbackInfo.playbackState != Player.STATE_ENDED) {
|
||||
maybeContinueLoading();
|
||||
updatePlaybackPositions();
|
||||
|
@ -1142,8 +1153,15 @@ import java.util.Collections;
|
|||
playbackInfoUpdate.incrementPendingOperationAcks(pendingPrepareCount);
|
||||
pendingPrepareCount = 0;
|
||||
if (pendingInitialSeekPosition != null) {
|
||||
Pair<Integer, Long> periodPosition =
|
||||
Pair<Integer, Long> periodPosition;
|
||||
try {
|
||||
periodPosition =
|
||||
resolveSeekPosition(pendingInitialSeekPosition, /* trySubsequentPeriods= */ true);
|
||||
} catch (IllegalSeekPositionException e) {
|
||||
playbackInfo =
|
||||
playbackInfo.fromNewPosition(getFirstMediaPeriodId(), C.TIME_UNSET, C.TIME_UNSET);
|
||||
throw e;
|
||||
}
|
||||
pendingInitialSeekPosition = null;
|
||||
if (periodPosition == null) {
|
||||
// The seek position was valid for the timeline that it was performed into, but the
|
||||
|
@ -1176,22 +1194,28 @@ import java.util.Collections;
|
|||
return;
|
||||
}
|
||||
|
||||
int playingPeriodIndex = playbackInfo.periodId.periodIndex;
|
||||
long contentPositionUs = playbackInfo.contentPositionUs;
|
||||
if (oldTimeline.isEmpty()) {
|
||||
// If the old timeline is empty, the period queue is also empty.
|
||||
if (!timeline.isEmpty()) {
|
||||
MediaPeriodId periodId =
|
||||
queue.resolveMediaPeriodIdForAds(playingPeriodIndex, contentPositionUs);
|
||||
Pair<Integer, Long> defaultPosition =
|
||||
getPeriodPosition(
|
||||
timeline, timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET);
|
||||
int periodIndex = defaultPosition.first;
|
||||
long startPositionUs = defaultPosition.second;
|
||||
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodIndex, startPositionUs);
|
||||
playbackInfo =
|
||||
playbackInfo.fromNewPosition(
|
||||
periodId, periodId.isAd() ? 0 : contentPositionUs, contentPositionUs);
|
||||
periodId,
|
||||
/* startPositionUs= */ periodId.isAd() ? 0 : startPositionUs,
|
||||
/* contentPositionUs= */ startPositionUs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
MediaPeriodHolder periodHolder = queue.getFrontPeriod();
|
||||
Object playingPeriodUid = periodHolder == null
|
||||
? oldTimeline.getPeriod(playingPeriodIndex, period, true).uid : periodHolder.uid;
|
||||
int playingPeriodIndex = playbackInfo.periodId.periodIndex;
|
||||
long contentPositionUs = playbackInfo.contentPositionUs;
|
||||
Object playingPeriodUid =
|
||||
periodHolder == null ? oldTimeline.getUidOfPeriod(playingPeriodIndex) : periodHolder.uid;
|
||||
int periodIndex = timeline.getIndexOfPeriod(playingPeriodUid);
|
||||
if (periodIndex == C.INDEX_UNSET) {
|
||||
// We didn't find the current period in the new timeline. Attempt to resolve a subsequent
|
||||
|
@ -1208,11 +1232,10 @@ import java.util.Collections;
|
|||
newPeriodIndex = defaultPosition.first;
|
||||
contentPositionUs = defaultPosition.second;
|
||||
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(newPeriodIndex, contentPositionUs);
|
||||
timeline.getPeriod(newPeriodIndex, period, true);
|
||||
if (periodHolder != null) {
|
||||
// Clear the index of each holder that doesn't contain the default position. If a holder
|
||||
// contains the default position then update its index so it can be re-used when seeking.
|
||||
Object newPeriodUid = period.uid;
|
||||
Object newPeriodUid = timeline.getUidOfPeriod(newPeriodIndex);
|
||||
periodHolder.info = periodHolder.info.copyWithPeriodIndex(C.INDEX_UNSET);
|
||||
while (periodHolder.next != null) {
|
||||
periodHolder = periodHolder.next;
|
||||
|
@ -1249,6 +1272,7 @@ import java.util.Collections;
|
|||
if (!queue.updateQueuedPeriods(playingPeriodId, rendererPositionUs)) {
|
||||
seekToCurrentPosition(/* sendDiscontinuity= */ false);
|
||||
}
|
||||
updateLoadingMediaPeriodId();
|
||||
}
|
||||
|
||||
private void handleSourceInfoRefreshEndedPlayback() {
|
||||
|
@ -1279,8 +1303,7 @@ import java.util.Collections;
|
|||
// We've reached the end of the old timeline.
|
||||
break;
|
||||
}
|
||||
newPeriodIndex = newTimeline.getIndexOfPeriod(
|
||||
oldTimeline.getPeriod(oldPeriodIndex, period, true).uid);
|
||||
newPeriodIndex = newTimeline.getIndexOfPeriod(oldTimeline.getUidOfPeriod(oldPeriodIndex));
|
||||
}
|
||||
return newPeriodIndex;
|
||||
}
|
||||
|
@ -1324,8 +1347,7 @@ import java.util.Collections;
|
|||
return periodPosition;
|
||||
}
|
||||
// Attempt to find the mapped period in the internal timeline.
|
||||
int periodIndex = timeline.getIndexOfPeriod(
|
||||
seekTimeline.getPeriod(periodPosition.first, period, true).uid);
|
||||
int periodIndex = timeline.getIndexOfPeriod(seekTimeline.getUidOfPeriod(periodPosition.first));
|
||||
if (periodIndex != C.INDEX_UNSET) {
|
||||
// We successfully located the period in the internal timeline.
|
||||
return Pair.create(periodIndex, periodPosition.second);
|
||||
|
@ -1483,7 +1505,7 @@ import java.util.Collections;
|
|||
if (info == null) {
|
||||
mediaSource.maybeThrowSourceInfoRefreshError();
|
||||
} else {
|
||||
Object uid = playbackInfo.timeline.getPeriod(info.id.periodIndex, period, true).uid;
|
||||
Object uid = playbackInfo.timeline.getUidOfPeriod(info.id.periodIndex);
|
||||
MediaPeriod mediaPeriod =
|
||||
queue.enqueueNextMediaPeriod(
|
||||
rendererCapabilities,
|
||||
|
@ -1494,6 +1516,7 @@ import java.util.Collections;
|
|||
info);
|
||||
mediaPeriod.prepare(this, info.startPositionUs);
|
||||
setIsLoading(true);
|
||||
updateLoadingMediaPeriodId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1525,6 +1548,17 @@ import java.util.Collections;
|
|||
maybeContinueLoading();
|
||||
}
|
||||
|
||||
private void handlePlaybackParameters(PlaybackParameters playbackParameters)
|
||||
throws ExoPlaybackException {
|
||||
eventHandler.obtainMessage(MSG_PLAYBACK_PARAMETERS_CHANGED, playbackParameters).sendToTarget();
|
||||
updateTrackSelectionPlaybackSpeed(playbackParameters.speed);
|
||||
for (Renderer renderer : renderers) {
|
||||
if (renderer != null) {
|
||||
renderer.setOperatingRate(playbackParameters.speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeContinueLoading() {
|
||||
MediaPeriodHolder loadingPeriodHolder = queue.getLoadingPeriod();
|
||||
long nextLoadPositionUs = loadingPeriodHolder.getNextLoadPositionUs();
|
||||
|
@ -1543,6 +1577,7 @@ import java.util.Collections;
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ParameterNotNullable")
|
||||
private void updatePlayingPeriodRenderers(@Nullable MediaPeriodHolder oldPlayingPeriodHolder)
|
||||
throws ExoPlaybackException {
|
||||
MediaPeriodHolder newPlayingPeriodHolder = queue.getPlayingPeriod();
|
||||
|
@ -1619,6 +1654,13 @@ import java.util.Collections;
|
|||
&& renderer.hasReadStreamToEnd();
|
||||
}
|
||||
|
||||
private void updateLoadingMediaPeriodId() {
|
||||
MediaPeriodHolder loadingMediaPeriodHolder = queue.getLoadingPeriod();
|
||||
MediaPeriodId loadingMediaPeriodId =
|
||||
loadingMediaPeriodHolder == null ? playbackInfo.periodId : loadingMediaPeriodHolder.info.id;
|
||||
playbackInfo = playbackInfo.copyWithLoadingMediaPeriodId(loadingMediaPeriodId);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Format[] getFormats(TrackSelection newSelection) {
|
||||
// Build an array of formats contained by the selection.
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
|
@ -29,11 +29,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.8.1";
|
||||
public static final String VERSION = "2.8.3";
|
||||
|
||||
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
|
||||
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
|
||||
public static final String VERSION_SLASHY = "ExoPlayerLib/2.8.1";
|
||||
public static final String VERSION_SLASHY = "ExoPlayerLib/2.8.3";
|
||||
|
||||
/**
|
||||
* The version of the library expressed as an integer, for example 1002003.
|
||||
|
@ -43,16 +43,19 @@ 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 = 2008001;
|
||||
public static final int VERSION_INT = 2008003;
|
||||
|
||||
/**
|
||||
* Whether the library was compiled with {@link org.telegram.messenger.exoplayer2.util.Assertions}
|
||||
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}
|
||||
* checks enabled.
|
||||
*/
|
||||
public static final boolean ASSERTIONS_ENABLED = true;
|
||||
|
||||
/** Whether an exception should be thrown in case of an OpenGl error. */
|
||||
public static final boolean GL_ASSERTIONS_ENABLED = false;
|
||||
|
||||
/**
|
||||
* Whether the library was compiled with {@link org.telegram.messenger.exoplayer2.util.TraceUtil}
|
||||
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.TraceUtil}
|
||||
* trace enabled.
|
||||
*/
|
||||
public static final boolean TRACE_ENABLED = true;
|
File diff suppressed because it is too large
Load diff
|
@ -13,16 +13,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Holds a {@link Format}.
|
||||
*/
|
||||
public final class FormatHolder {
|
||||
|
||||
/**
|
||||
* The held {@link Format}.
|
||||
*/
|
||||
public Format format;
|
||||
|
||||
/** The held {@link Format}. */
|
||||
public @Nullable Format format;
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
/**
|
||||
* Thrown when an attempt is made to seek to a position that does not exist in the player's
|
|
@ -13,12 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.source.TrackGroup;
|
||||
import org.telegram.messenger.exoplayer2.source.TrackGroupArray;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import org.telegram.messenger.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
|
||||
/**
|
||||
* Controls buffering of media.
|
|
@ -13,21 +13,21 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.util.Log;
|
||||
import org.telegram.messenger.exoplayer2.source.ClippingMediaPeriod;
|
||||
import org.telegram.messenger.exoplayer2.source.EmptySampleStream;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaPeriod;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource;
|
||||
import org.telegram.messenger.exoplayer2.source.SampleStream;
|
||||
import org.telegram.messenger.exoplayer2.source.TrackGroupArray;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelection;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectorResult;
|
||||
import org.telegram.messenger.exoplayer2.upstream.Allocator;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.source.ClippingMediaPeriod;
|
||||
import com.google.android.exoplayer2.source.EmptySampleStream;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
||||
/** Holds a {@link MediaPeriod} with information required to play it as part of a timeline. */
|
||||
/* package */ final class MediaPeriodHolder {
|
||||
|
@ -82,13 +82,13 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
sampleStreams = new SampleStream[rendererCapabilities.length];
|
||||
mayRetainStreamFlags = new boolean[rendererCapabilities.length];
|
||||
MediaPeriod mediaPeriod = mediaSource.createPeriod(info.id, allocator);
|
||||
if (info.endPositionUs != C.TIME_END_OF_SOURCE) {
|
||||
if (info.id.endPositionUs != C.TIME_END_OF_SOURCE) {
|
||||
mediaPeriod =
|
||||
new ClippingMediaPeriod(
|
||||
mediaPeriod,
|
||||
/* enableInitialDiscontinuity= */ true,
|
||||
/* startUs= */ 0,
|
||||
info.endPositionUs);
|
||||
info.id.endPositionUs);
|
||||
}
|
||||
this.mediaPeriod = mediaPeriod;
|
||||
}
|
||||
|
@ -127,7 +127,8 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
if (!prepared) {
|
||||
return info.startPositionUs;
|
||||
}
|
||||
long bufferedPositionUs = mediaPeriod.getBufferedPositionUs();
|
||||
long bufferedPositionUs =
|
||||
hasEnabledTracks ? mediaPeriod.getBufferedPositionUs() : C.TIME_END_OF_SOURCE;
|
||||
return bufferedPositionUs == C.TIME_END_OF_SOURCE && convertEosToDuration
|
||||
? info.durationUs
|
||||
: bufferedPositionUs;
|
||||
|
@ -218,7 +219,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
public void release() {
|
||||
updatePeriodTrackSelectorResult(null);
|
||||
try {
|
||||
if (info.endPositionUs != C.TIME_END_OF_SOURCE) {
|
||||
if (info.id.endPositionUs != C.TIME_END_OF_SOURCE) {
|
||||
mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod);
|
||||
} else {
|
||||
mediaSource.releasePeriod(mediaPeriod);
|
|
@ -13,10 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.source.MediaPeriod;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
|
||||
/** Stores the information required to load and play a {@link MediaPeriod}. */
|
||||
/* package */ final class MediaPeriodInfo {
|
||||
|
@ -25,18 +25,13 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
|
|||
public final MediaPeriodId id;
|
||||
/** The start position of the media to play within the media period, in microseconds. */
|
||||
public final long startPositionUs;
|
||||
/**
|
||||
* The end position of the media to play within the media period, in microseconds, or {@link
|
||||
* C#TIME_END_OF_SOURCE} if the end position is the end of the media period.
|
||||
*/
|
||||
public final long endPositionUs;
|
||||
/**
|
||||
* If this is an ad, the position to play in the next content media period. {@link C#TIME_UNSET}
|
||||
* otherwise.
|
||||
*/
|
||||
public final long contentPositionUs;
|
||||
/**
|
||||
* The duration of the media period, like {@link #endPositionUs} but with {@link
|
||||
* The duration of the media period, like {@link MediaPeriodId#endPositionUs} but with {@link
|
||||
* C#TIME_END_OF_SOURCE} resolved to the timeline period duration. May be {@link C#TIME_UNSET} if
|
||||
* the end position is not known.
|
||||
*/
|
||||
|
@ -55,14 +50,12 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
|
|||
MediaPeriodInfo(
|
||||
MediaPeriodId id,
|
||||
long startPositionUs,
|
||||
long endPositionUs,
|
||||
long contentPositionUs,
|
||||
long durationUs,
|
||||
boolean isLastInTimelinePeriod,
|
||||
boolean isFinal) {
|
||||
this.id = id;
|
||||
this.startPositionUs = startPositionUs;
|
||||
this.endPositionUs = endPositionUs;
|
||||
this.contentPositionUs = contentPositionUs;
|
||||
this.durationUs = durationUs;
|
||||
this.isLastInTimelinePeriod = isLastInTimelinePeriod;
|
||||
|
@ -77,7 +70,6 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
|
|||
return new MediaPeriodInfo(
|
||||
id.copyWithPeriodIndex(periodIndex),
|
||||
startPositionUs,
|
||||
endPositionUs,
|
||||
contentPositionUs,
|
||||
durationUs,
|
||||
isLastInTimelinePeriod,
|
||||
|
@ -89,7 +81,6 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
|
|||
return new MediaPeriodInfo(
|
||||
id,
|
||||
startPositionUs,
|
||||
endPositionUs,
|
||||
contentPositionUs,
|
||||
durationUs,
|
||||
isLastInTimelinePeriod,
|
|
@ -13,17 +13,17 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Pair;
|
||||
import org.telegram.messenger.exoplayer2.Player.RepeatMode;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaPeriod;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector;
|
||||
import org.telegram.messenger.exoplayer2.upstream.Allocator;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.Player.RepeatMode;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
||||
/**
|
||||
* Holds a queue of media periods, from the currently playing media period at the front to the
|
||||
|
@ -47,17 +47,18 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
private Timeline timeline;
|
||||
private @RepeatMode int repeatMode;
|
||||
private boolean shuffleModeEnabled;
|
||||
private MediaPeriodHolder playing;
|
||||
private MediaPeriodHolder reading;
|
||||
private MediaPeriodHolder loading;
|
||||
private @Nullable MediaPeriodHolder playing;
|
||||
private @Nullable MediaPeriodHolder reading;
|
||||
private @Nullable MediaPeriodHolder loading;
|
||||
private int length;
|
||||
private Object oldFrontPeriodUid;
|
||||
private @Nullable Object oldFrontPeriodUid;
|
||||
private long oldFrontPeriodWindowSequenceNumber;
|
||||
|
||||
/** Creates a new media period queue. */
|
||||
public MediaPeriodQueue() {
|
||||
period = new Timeline.Period();
|
||||
window = new Timeline.Window();
|
||||
timeline = Timeline.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,11 +229,13 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
reading = playing.next;
|
||||
}
|
||||
playing.release();
|
||||
playing = playing.next;
|
||||
length--;
|
||||
if (length == 0) {
|
||||
loading = null;
|
||||
oldFrontPeriodUid = playing.uid;
|
||||
oldFrontPeriodWindowSequenceNumber = playing.info.id.windowSequenceNumber;
|
||||
}
|
||||
playing = playing.next;
|
||||
} else {
|
||||
playing = loading;
|
||||
reading = loading;
|
||||
|
@ -312,7 +315,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
} else {
|
||||
// Check this period holder still follows the previous one, based on the new timeline.
|
||||
if (periodIndex == C.INDEX_UNSET
|
||||
|| !periodHolder.uid.equals(timeline.getPeriod(periodIndex, period, true).uid)) {
|
||||
|| !periodHolder.uid.equals(timeline.getUidOfPeriod(periodIndex))) {
|
||||
// The holder uid is inconsistent with the new timeline.
|
||||
return !removeAfter(previousPeriodHolder);
|
||||
}
|
||||
|
@ -389,7 +392,12 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
timeline.getPeriod(periodIndex, period);
|
||||
int adGroupIndex = period.getAdGroupIndexForPositionUs(positionUs);
|
||||
if (adGroupIndex == C.INDEX_UNSET) {
|
||||
return new MediaPeriodId(periodIndex, windowSequenceNumber);
|
||||
int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs);
|
||||
long endPositionUs =
|
||||
nextAdGroupIndex == C.INDEX_UNSET
|
||||
? C.TIME_END_OF_SOURCE
|
||||
: period.getAdGroupTimeUs(nextAdGroupIndex);
|
||||
return new MediaPeriodId(periodIndex, windowSequenceNumber, endPositionUs);
|
||||
} else {
|
||||
int adIndexInAdGroup = period.getFirstAdIndexToPlay(adGroupIndex);
|
||||
return new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber);
|
||||
|
@ -448,7 +456,6 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
private boolean canKeepMediaPeriodHolder(MediaPeriodHolder periodHolder, MediaPeriodInfo info) {
|
||||
MediaPeriodInfo periodHolderInfo = periodHolder.info;
|
||||
return periodHolderInfo.startPositionUs == info.startPositionUs
|
||||
&& periodHolderInfo.endPositionUs == info.endPositionUs
|
||||
&& periodHolderInfo.id.equals(info.id);
|
||||
}
|
||||
|
||||
|
@ -591,14 +598,14 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
mediaPeriodInfo.contentPositionUs,
|
||||
currentPeriodId.windowSequenceNumber);
|
||||
}
|
||||
} else if (mediaPeriodInfo.endPositionUs != C.TIME_END_OF_SOURCE) {
|
||||
} else if (mediaPeriodInfo.id.endPositionUs != C.TIME_END_OF_SOURCE) {
|
||||
// Play the next ad group if it's available.
|
||||
int nextAdGroupIndex = period.getAdGroupIndexForPositionUs(mediaPeriodInfo.endPositionUs);
|
||||
int nextAdGroupIndex = period.getAdGroupIndexForPositionUs(mediaPeriodInfo.id.endPositionUs);
|
||||
if (nextAdGroupIndex == C.INDEX_UNSET) {
|
||||
// The next ad group can't be played. Play content from the ad group position instead.
|
||||
return getMediaPeriodInfoForContent(
|
||||
currentPeriodId.periodIndex,
|
||||
mediaPeriodInfo.endPositionUs,
|
||||
mediaPeriodInfo.id.endPositionUs,
|
||||
currentPeriodId.windowSequenceNumber);
|
||||
}
|
||||
int adIndexInAdGroup = period.getFirstAdIndexToPlay(nextAdGroupIndex);
|
||||
|
@ -608,7 +615,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
currentPeriodId.periodIndex,
|
||||
nextAdGroupIndex,
|
||||
adIndexInAdGroup,
|
||||
mediaPeriodInfo.endPositionUs,
|
||||
mediaPeriodInfo.id.endPositionUs,
|
||||
currentPeriodId.windowSequenceNumber);
|
||||
} else {
|
||||
// Check if the postroll ad should be played.
|
||||
|
@ -637,18 +644,18 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
|
||||
private MediaPeriodInfo getUpdatedMediaPeriodInfo(MediaPeriodInfo info, MediaPeriodId newId) {
|
||||
long startPositionUs = info.startPositionUs;
|
||||
long endPositionUs = info.endPositionUs;
|
||||
boolean isLastInPeriod = isLastInPeriod(newId, endPositionUs);
|
||||
boolean isLastInPeriod = isLastInPeriod(newId);
|
||||
boolean isLastInTimeline = isLastInTimeline(newId, isLastInPeriod);
|
||||
timeline.getPeriod(newId.periodIndex, period);
|
||||
long durationUs =
|
||||
newId.isAd()
|
||||
? period.getAdDurationUs(newId.adGroupIndex, newId.adIndexInAdGroup)
|
||||
: (endPositionUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endPositionUs);
|
||||
: (newId.endPositionUs == C.TIME_END_OF_SOURCE
|
||||
? period.getDurationUs()
|
||||
: newId.endPositionUs);
|
||||
return new MediaPeriodInfo(
|
||||
newId,
|
||||
startPositionUs,
|
||||
endPositionUs,
|
||||
info.contentPositionUs,
|
||||
durationUs,
|
||||
isLastInPeriod,
|
||||
|
@ -681,7 +688,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
long windowSequenceNumber) {
|
||||
MediaPeriodId id =
|
||||
new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber);
|
||||
boolean isLastInPeriod = isLastInPeriod(id, C.TIME_END_OF_SOURCE);
|
||||
boolean isLastInPeriod = isLastInPeriod(id);
|
||||
boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod);
|
||||
long durationUs =
|
||||
timeline
|
||||
|
@ -694,7 +701,6 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
return new MediaPeriodInfo(
|
||||
id,
|
||||
startPositionUs,
|
||||
C.TIME_END_OF_SOURCE,
|
||||
contentPositionUs,
|
||||
durationUs,
|
||||
isLastInPeriod,
|
||||
|
@ -703,21 +709,22 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
|
||||
private MediaPeriodInfo getMediaPeriodInfoForContent(
|
||||
int periodIndex, long startPositionUs, long windowSequenceNumber) {
|
||||
MediaPeriodId id = new MediaPeriodId(periodIndex, windowSequenceNumber);
|
||||
timeline.getPeriod(id.periodIndex, period);
|
||||
int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(startPositionUs);
|
||||
long endUs =
|
||||
long endPositionUs =
|
||||
nextAdGroupIndex == C.INDEX_UNSET
|
||||
? C.TIME_END_OF_SOURCE
|
||||
: period.getAdGroupTimeUs(nextAdGroupIndex);
|
||||
boolean isLastInPeriod = isLastInPeriod(id, endUs);
|
||||
MediaPeriodId id = new MediaPeriodId(periodIndex, windowSequenceNumber, endPositionUs);
|
||||
timeline.getPeriod(id.periodIndex, period);
|
||||
boolean isLastInPeriod = isLastInPeriod(id);
|
||||
boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod);
|
||||
long durationUs = endUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endUs;
|
||||
long durationUs =
|
||||
endPositionUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endPositionUs;
|
||||
return new MediaPeriodInfo(
|
||||
id, startPositionUs, endUs, C.TIME_UNSET, durationUs, isLastInPeriod, isLastInTimeline);
|
||||
id, startPositionUs, C.TIME_UNSET, durationUs, isLastInPeriod, isLastInTimeline);
|
||||
}
|
||||
|
||||
private boolean isLastInPeriod(MediaPeriodId id, long endPositionUs) {
|
||||
private boolean isLastInPeriod(MediaPeriodId id) {
|
||||
int adGroupCount = timeline.getPeriod(id.periodIndex, period).getAdGroupCount();
|
||||
if (adGroupCount == 0) {
|
||||
return true;
|
||||
|
@ -727,7 +734,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
|
|||
boolean isAd = id.isAd();
|
||||
if (period.getAdGroupTimeUs(lastAdGroupIndex) != C.TIME_END_OF_SOURCE) {
|
||||
// There's no postroll ad.
|
||||
return !isAd && endPositionUs == C.TIME_END_OF_SOURCE;
|
||||
return !isAd && id.endPositionUs == C.TIME_END_OF_SOURCE;
|
||||
}
|
||||
|
||||
int postrollAdCount = period.getAdCountInAdGroup(lastAdGroupIndex);
|
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.source.SampleStream;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.MediaClock;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MediaClock;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import java.io.IOException;
|
||||
|
254
TMessagesProj/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java
Executable file
254
TMessagesProj/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java
Executable file
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
|
||||
|
||||
/**
|
||||
* Information about an ongoing playback.
|
||||
*/
|
||||
/* package */ final class PlaybackInfo {
|
||||
|
||||
/**
|
||||
* Dummy media period id used while the timeline is empty and no period id is specified. This id
|
||||
* is used when playback infos are created with {@link #createDummy(long, TrackSelectorResult)}.
|
||||
*/
|
||||
public static final MediaPeriodId DUMMY_MEDIA_PERIOD_ID = new MediaPeriodId(/* periodIndex= */ 0);
|
||||
|
||||
/** The current {@link Timeline}. */
|
||||
public final Timeline timeline;
|
||||
/** The current manifest. */
|
||||
public final @Nullable Object manifest;
|
||||
/** The {@link MediaPeriodId} of the currently playing media period in the {@link #timeline}. */
|
||||
public final MediaPeriodId periodId;
|
||||
/**
|
||||
* The start position at which playback started in {@link #periodId} relative to the start of the
|
||||
* associated period in the {@link #timeline}, in microseconds.
|
||||
*/
|
||||
public final long startPositionUs;
|
||||
/**
|
||||
* If {@link #periodId} refers to an ad, the position of the suspended content relative to the
|
||||
* start of the associated period in the {@link #timeline}, in microseconds. {@link C#TIME_UNSET}
|
||||
* if {@link #periodId} does not refer to an ad.
|
||||
*/
|
||||
public final long contentPositionUs;
|
||||
/** The current playback state. One of the {@link Player}.STATE_ constants. */
|
||||
public final int playbackState;
|
||||
/** Whether the player is currently loading. */
|
||||
public final boolean isLoading;
|
||||
/** The currently available track groups. */
|
||||
public final TrackGroupArray trackGroups;
|
||||
/** The result of the current track selection. */
|
||||
public final TrackSelectorResult trackSelectorResult;
|
||||
/** The {@link MediaPeriodId} of the currently loading media period in the {@link #timeline}. */
|
||||
public final MediaPeriodId loadingMediaPeriodId;
|
||||
|
||||
/**
|
||||
* Position up to which media is buffered in {@link #loadingMediaPeriodId) relative to the start
|
||||
* of the associated period in the {@link #timeline}, in microseconds.
|
||||
*/
|
||||
public volatile long bufferedPositionUs;
|
||||
/**
|
||||
* Total duration of buffered media from {@link #positionUs} to {@link #bufferedPositionUs}
|
||||
* including all ads.
|
||||
*/
|
||||
public volatile long totalBufferedDurationUs;
|
||||
/**
|
||||
* Current playback position in {@link #periodId} relative to the start of the associated period
|
||||
* in the {@link #timeline}, in microseconds.
|
||||
*/
|
||||
public volatile long positionUs;
|
||||
|
||||
/**
|
||||
* Creates empty dummy playback info which can be used for masking as long as no real playback
|
||||
* info is available.
|
||||
*
|
||||
* @param startPositionUs The start position at which playback should start, in microseconds.
|
||||
* @param emptyTrackSelectorResult An empty track selector result with null entries for each
|
||||
* renderer.
|
||||
* @return A dummy playback info.
|
||||
*/
|
||||
public static PlaybackInfo createDummy(
|
||||
long startPositionUs, TrackSelectorResult emptyTrackSelectorResult) {
|
||||
return new PlaybackInfo(
|
||||
Timeline.EMPTY,
|
||||
/* manifest= */ null,
|
||||
DUMMY_MEDIA_PERIOD_ID,
|
||||
startPositionUs,
|
||||
/* contentPositionUs =*/ C.TIME_UNSET,
|
||||
Player.STATE_IDLE,
|
||||
/* isLoading= */ false,
|
||||
TrackGroupArray.EMPTY,
|
||||
emptyTrackSelectorResult,
|
||||
DUMMY_MEDIA_PERIOD_ID,
|
||||
startPositionUs,
|
||||
/* totalBufferedDurationUs= */ 0,
|
||||
startPositionUs);
|
||||
}
|
||||
|
||||
public PlaybackInfo(
|
||||
Timeline timeline,
|
||||
@Nullable Object manifest,
|
||||
MediaPeriodId periodId,
|
||||
long startPositionUs,
|
||||
long contentPositionUs,
|
||||
int playbackState,
|
||||
boolean isLoading,
|
||||
TrackGroupArray trackGroups,
|
||||
TrackSelectorResult trackSelectorResult,
|
||||
MediaPeriodId loadingMediaPeriodId,
|
||||
long bufferedPositionUs,
|
||||
long totalBufferedDurationUs,
|
||||
long positionUs) {
|
||||
this.timeline = timeline;
|
||||
this.manifest = manifest;
|
||||
this.periodId = periodId;
|
||||
this.startPositionUs = startPositionUs;
|
||||
this.contentPositionUs = contentPositionUs;
|
||||
this.playbackState = playbackState;
|
||||
this.isLoading = isLoading;
|
||||
this.trackGroups = trackGroups;
|
||||
this.trackSelectorResult = trackSelectorResult;
|
||||
this.loadingMediaPeriodId = loadingMediaPeriodId;
|
||||
this.bufferedPositionUs = bufferedPositionUs;
|
||||
this.totalBufferedDurationUs = totalBufferedDurationUs;
|
||||
this.positionUs = positionUs;
|
||||
}
|
||||
|
||||
public PlaybackInfo fromNewPosition(
|
||||
MediaPeriodId periodId, long startPositionUs, long contentPositionUs) {
|
||||
return new PlaybackInfo(
|
||||
timeline,
|
||||
manifest,
|
||||
periodId,
|
||||
startPositionUs,
|
||||
periodId.isAd() ? contentPositionUs : C.TIME_UNSET,
|
||||
playbackState,
|
||||
isLoading,
|
||||
trackGroups,
|
||||
trackSelectorResult,
|
||||
periodId,
|
||||
startPositionUs,
|
||||
/* totalBufferedDurationUs= */ 0,
|
||||
startPositionUs);
|
||||
}
|
||||
|
||||
public PlaybackInfo copyWithPeriodIndex(int periodIndex) {
|
||||
return new PlaybackInfo(
|
||||
timeline,
|
||||
manifest,
|
||||
periodId.copyWithPeriodIndex(periodIndex),
|
||||
startPositionUs,
|
||||
contentPositionUs,
|
||||
playbackState,
|
||||
isLoading,
|
||||
trackGroups,
|
||||
trackSelectorResult,
|
||||
loadingMediaPeriodId,
|
||||
bufferedPositionUs,
|
||||
totalBufferedDurationUs,
|
||||
positionUs);
|
||||
}
|
||||
|
||||
public PlaybackInfo copyWithTimeline(Timeline timeline, Object manifest) {
|
||||
return new PlaybackInfo(
|
||||
timeline,
|
||||
manifest,
|
||||
periodId,
|
||||
startPositionUs,
|
||||
contentPositionUs,
|
||||
playbackState,
|
||||
isLoading,
|
||||
trackGroups,
|
||||
trackSelectorResult,
|
||||
loadingMediaPeriodId,
|
||||
bufferedPositionUs,
|
||||
totalBufferedDurationUs,
|
||||
positionUs);
|
||||
}
|
||||
|
||||
public PlaybackInfo copyWithPlaybackState(int playbackState) {
|
||||
return new PlaybackInfo(
|
||||
timeline,
|
||||
manifest,
|
||||
periodId,
|
||||
startPositionUs,
|
||||
contentPositionUs,
|
||||
playbackState,
|
||||
isLoading,
|
||||
trackGroups,
|
||||
trackSelectorResult,
|
||||
loadingMediaPeriodId,
|
||||
bufferedPositionUs,
|
||||
totalBufferedDurationUs,
|
||||
positionUs);
|
||||
}
|
||||
|
||||
public PlaybackInfo copyWithIsLoading(boolean isLoading) {
|
||||
return new PlaybackInfo(
|
||||
timeline,
|
||||
manifest,
|
||||
periodId,
|
||||
startPositionUs,
|
||||
contentPositionUs,
|
||||
playbackState,
|
||||
isLoading,
|
||||
trackGroups,
|
||||
trackSelectorResult,
|
||||
loadingMediaPeriodId,
|
||||
bufferedPositionUs,
|
||||
totalBufferedDurationUs,
|
||||
positionUs);
|
||||
}
|
||||
|
||||
public PlaybackInfo copyWithTrackInfo(
|
||||
TrackGroupArray trackGroups, TrackSelectorResult trackSelectorResult) {
|
||||
return new PlaybackInfo(
|
||||
timeline,
|
||||
manifest,
|
||||
periodId,
|
||||
startPositionUs,
|
||||
contentPositionUs,
|
||||
playbackState,
|
||||
isLoading,
|
||||
trackGroups,
|
||||
trackSelectorResult,
|
||||
loadingMediaPeriodId,
|
||||
bufferedPositionUs,
|
||||
totalBufferedDurationUs,
|
||||
positionUs);
|
||||
}
|
||||
|
||||
public PlaybackInfo copyWithLoadingMediaPeriodId(MediaPeriodId loadingMediaPeriodId) {
|
||||
return new PlaybackInfo(
|
||||
timeline,
|
||||
manifest,
|
||||
periodId,
|
||||
startPositionUs,
|
||||
contentPositionUs,
|
||||
playbackState,
|
||||
isLoading,
|
||||
trackGroups,
|
||||
trackSelectorResult,
|
||||
loadingMediaPeriodId,
|
||||
bufferedPositionUs,
|
||||
totalBufferedDurationUs,
|
||||
positionUs);
|
||||
}
|
||||
}
|
|
@ -13,10 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
||||
/**
|
||||
* The parameters that apply to playback.
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
/** Called to prepare a playback. */
|
||||
public interface PlaybackPreparer {
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.IntDef;
|
||||
|
@ -22,10 +22,13 @@ import android.view.Surface;
|
|||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.TextureView;
|
||||
import org.telegram.messenger.exoplayer2.source.TrackGroupArray;
|
||||
import org.telegram.messenger.exoplayer2.text.TextOutput;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import org.telegram.messenger.exoplayer2.video.VideoListener;
|
||||
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||
import com.google.android.exoplayer2.audio.AudioListener;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.text.TextOutput;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.video.VideoListener;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
|
@ -50,6 +53,58 @@ import java.lang.annotation.RetentionPolicy;
|
|||
*/
|
||||
public interface Player {
|
||||
|
||||
/** The audio component of a {@link Player}. */
|
||||
interface AudioComponent {
|
||||
|
||||
/**
|
||||
* Adds a listener to receive audio events.
|
||||
*
|
||||
* @param listener The listener to register.
|
||||
*/
|
||||
void addAudioListener(AudioListener listener);
|
||||
|
||||
/**
|
||||
* Removes a listener of audio events.
|
||||
*
|
||||
* @param listener The listener to unregister.
|
||||
*/
|
||||
void removeAudioListener(AudioListener listener);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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 {@link Util#getStreamTypeForAudioUsage(int)}.
|
||||
*
|
||||
* @param audioAttributes The attributes to use for audio playback.
|
||||
*/
|
||||
void setAudioAttributes(AudioAttributes audioAttributes);
|
||||
|
||||
/** Returns the attributes for audio playback. */
|
||||
AudioAttributes getAudioAttributes();
|
||||
|
||||
/** Returns the audio session identifier, or {@link C#AUDIO_SESSION_ID_UNSET} if not set. */
|
||||
int getAudioSessionId();
|
||||
|
||||
/**
|
||||
* Sets the audio volume, with 0 being silence and 1 being unity gain.
|
||||
*
|
||||
* @param audioVolume The audio volume.
|
||||
*/
|
||||
void setVolume(float audioVolume);
|
||||
|
||||
/** Returns the audio volume, with 0 being silence and 1 being unity gain. */
|
||||
float getVolume();
|
||||
}
|
||||
|
||||
/** The video component of a {@link Player}. */
|
||||
interface VideoComponent {
|
||||
|
||||
|
@ -97,7 +152,7 @@ public interface Player {
|
|||
*
|
||||
* @param surface The {@link Surface}.
|
||||
*/
|
||||
void setVideoSurface(Surface surface);
|
||||
void setVideoSurface(@Nullable Surface surface);
|
||||
|
||||
/**
|
||||
* Clears the {@link Surface} onto which video is being rendered if it matches the one passed.
|
||||
|
@ -175,23 +230,25 @@ public interface Player {
|
|||
}
|
||||
|
||||
/**
|
||||
* Listener of changes in player state.
|
||||
* Listener of changes in player state. All methods have no-op default implementations to allow
|
||||
* selective overrides.
|
||||
*/
|
||||
interface EventListener {
|
||||
|
||||
/**
|
||||
* Called when the timeline and/or manifest has been refreshed.
|
||||
* <p>
|
||||
* Note that if the timeline has changed then a position discontinuity may also have occurred.
|
||||
* For example, the current period index may have changed as a result of periods being added or
|
||||
* removed from the timeline. This will <em>not</em> be reported via a separate call to
|
||||
*
|
||||
* <p>Note that if the timeline has changed then a position discontinuity may also have
|
||||
* occurred. For example, the current period index may have changed as a result of periods being
|
||||
* added or removed from the timeline. This will <em>not</em> be reported via a separate call to
|
||||
* {@link #onPositionDiscontinuity(int)}.
|
||||
*
|
||||
* @param timeline The latest timeline. Never null, but may be empty.
|
||||
* @param manifest The latest manifest. May be null.
|
||||
* @param reason The {@link TimelineChangeReason} responsible for this timeline change.
|
||||
*/
|
||||
void onTimelineChanged(Timeline timeline, Object manifest, @TimelineChangeReason int reason);
|
||||
default void onTimelineChanged(
|
||||
Timeline timeline, Object manifest, @TimelineChangeReason int reason) {}
|
||||
|
||||
/**
|
||||
* Called when the available or selected tracks change.
|
||||
|
@ -200,46 +257,47 @@ public interface Player {
|
|||
* @param trackSelections The track selections for each renderer. Never null and always of
|
||||
* length {@link #getRendererCount()}, but may contain null elements.
|
||||
*/
|
||||
void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections);
|
||||
default void onTracksChanged(
|
||||
TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {}
|
||||
|
||||
/**
|
||||
* Called when the player starts or stops loading the source.
|
||||
*
|
||||
* @param isLoading Whether the source is currently being loaded.
|
||||
*/
|
||||
void onLoadingChanged(boolean isLoading);
|
||||
default void onLoadingChanged(boolean isLoading) {}
|
||||
|
||||
/**
|
||||
* Called when the value returned from either {@link #getPlayWhenReady()} or
|
||||
* {@link #getPlaybackState()} changes.
|
||||
* Called when the value returned from either {@link #getPlayWhenReady()} or {@link
|
||||
* #getPlaybackState()} changes.
|
||||
*
|
||||
* @param playWhenReady Whether playback will proceed when ready.
|
||||
* @param playbackState One of the {@code STATE} constants.
|
||||
*/
|
||||
void onPlayerStateChanged(boolean playWhenReady, int playbackState);
|
||||
default void onPlayerStateChanged(boolean playWhenReady, int playbackState) {}
|
||||
|
||||
/**
|
||||
* Called when the value of {@link #getRepeatMode()} changes.
|
||||
*
|
||||
* @param repeatMode The {@link RepeatMode} used for playback.
|
||||
*/
|
||||
void onRepeatModeChanged(@RepeatMode int repeatMode);
|
||||
default void onRepeatModeChanged(@RepeatMode int repeatMode) {}
|
||||
|
||||
/**
|
||||
* Called when the value of {@link #getShuffleModeEnabled()} changes.
|
||||
*
|
||||
* @param shuffleModeEnabled Whether shuffling of windows is enabled.
|
||||
*/
|
||||
void onShuffleModeEnabledChanged(boolean shuffleModeEnabled);
|
||||
default void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {}
|
||||
|
||||
/**
|
||||
* Called when an error occurs. The playback state will transition to {@link #STATE_IDLE}
|
||||
* immediately after this method is called. The player instance can still be used, and
|
||||
* {@link #release()} must still be called on the player should it no longer be required.
|
||||
* immediately after this method is called. The player instance can still be used, and {@link
|
||||
* #release()} must still be called on the player should it no longer be required.
|
||||
*
|
||||
* @param error The error.
|
||||
*/
|
||||
void onPlayerError(ExoPlaybackException error);
|
||||
default void onPlayerError(ExoPlaybackException error) {}
|
||||
|
||||
/**
|
||||
* Called when a position discontinuity occurs without a change to the timeline. A position
|
||||
|
@ -247,14 +305,14 @@ public interface Player {
|
|||
* transitioning from one period in the timeline to the next), or when the playback position
|
||||
* jumps within the period currently being played (as a result of a seek being performed, or
|
||||
* when the source introduces a discontinuity internally).
|
||||
* <p>
|
||||
* When a position discontinuity occurs as a result of a change to the timeline this method is
|
||||
* <em>not</em> called. {@link #onTimelineChanged(Timeline, Object, int)} is called in this
|
||||
*
|
||||
* <p>When a position discontinuity occurs as a result of a change to the timeline this method
|
||||
* is <em>not</em> called. {@link #onTimelineChanged(Timeline, Object, int)} is called in this
|
||||
* case.
|
||||
*
|
||||
* @param reason The {@link DiscontinuityReason} responsible for the discontinuity.
|
||||
*/
|
||||
void onPositionDiscontinuity(@DiscontinuityReason int reason);
|
||||
default void onPositionDiscontinuity(@DiscontinuityReason int reason) {}
|
||||
|
||||
/**
|
||||
* Called when the current playback parameters change. The playback parameters may change due to
|
||||
|
@ -264,20 +322,21 @@ public interface Player {
|
|||
*
|
||||
* @param playbackParameters The playback parameters.
|
||||
*/
|
||||
void onPlaybackParametersChanged(PlaybackParameters playbackParameters);
|
||||
default void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {}
|
||||
|
||||
/**
|
||||
* Called when all pending seek requests have been processed by the player. This is guaranteed
|
||||
* to happen after any necessary changes to the player state were reported to
|
||||
* {@link #onPlayerStateChanged(boolean, int)}.
|
||||
* to happen after any necessary changes to the player state were reported to {@link
|
||||
* #onPlayerStateChanged(boolean, int)}.
|
||||
*/
|
||||
void onSeekProcessed();
|
||||
|
||||
default void onSeekProcessed() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link EventListener} allowing selective overrides. All methods are implemented as no-ops.
|
||||
* @deprecated Use {@link EventListener} interface directly for selective overrides as all methods
|
||||
* are implemented as no-op default methods.
|
||||
*/
|
||||
@Deprecated
|
||||
abstract class DefaultEventListener implements EventListener {
|
||||
|
||||
@Override
|
||||
|
@ -287,60 +346,11 @@ public interface Player {
|
|||
onTimelineChanged(timeline, manifest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadingChanged(boolean isLoading) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeatModeChanged(@RepeatMode int repeatMode) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerError(ExoPlaybackException error) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionDiscontinuity(@DiscontinuityReason int reason) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSeekProcessed() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link DefaultEventListener#onTimelineChanged(Timeline, Object, int)}
|
||||
* instead.
|
||||
*/
|
||||
/** @deprecated Use {@link EventListener#onTimelineChanged(Timeline, Object, int)} instead. */
|
||||
@Deprecated
|
||||
public void onTimelineChanged(Timeline timeline, Object manifest) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -428,6 +438,10 @@ public interface Player {
|
|||
*/
|
||||
int TIMELINE_CHANGE_REASON_DYNAMIC = 2;
|
||||
|
||||
/** Returns the component of this player for audio output, or null if audio is not supported. */
|
||||
@Nullable
|
||||
AudioComponent getAudioComponent();
|
||||
|
||||
/** Returns the component of this player for video output, or null if video is not supported. */
|
||||
@Nullable
|
||||
VideoComponent getVideoComponent();
|
||||
|
@ -678,23 +692,27 @@ public interface Player {
|
|||
*/
|
||||
long getDuration();
|
||||
|
||||
/**
|
||||
* Returns the playback position in the current window, in milliseconds.
|
||||
*/
|
||||
/** Returns the playback position in the current content window or ad, in milliseconds. */
|
||||
long getCurrentPosition();
|
||||
|
||||
/**
|
||||
* Returns an estimate of the position in the current window up to which data is buffered, in
|
||||
* milliseconds.
|
||||
* Returns an estimate of the position in the current content window or ad up to which data is
|
||||
* buffered, in milliseconds.
|
||||
*/
|
||||
long getBufferedPosition();
|
||||
|
||||
/**
|
||||
* Returns an estimate of the percentage in the current window up to which data is buffered, or 0
|
||||
* if no estimate is available.
|
||||
* Returns an estimate of the percentage in the current content window or ad up to which data is
|
||||
* buffered, or 0 if no estimate is available.
|
||||
*/
|
||||
int getBufferedPercentage();
|
||||
|
||||
/**
|
||||
* Returns an estimate of the total buffered duration from the current position, in milliseconds.
|
||||
* This includes pre-buffered data for subsequent ads and windows.
|
||||
*/
|
||||
long getTotalBufferedDuration();
|
||||
|
||||
/**
|
||||
* Returns whether the current window is dynamic, or {@code false} if the {@link Timeline} is
|
||||
* empty.
|
||||
|
@ -735,4 +753,10 @@ public interface Player {
|
|||
*/
|
||||
long getContentPosition();
|
||||
|
||||
/**
|
||||
* If {@link #isPlayingAd()} returns {@code 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 {@link #getBufferedPosition()}.
|
||||
*/
|
||||
long getContentBufferedPosition();
|
||||
}
|
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
||||
/**
|
||||
* Defines a player message which can be sent with a {@link Sender} and received by a {@link
|
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.support.annotation.IntDef;
|
||||
import org.telegram.messenger.exoplayer2.source.SampleStream;
|
||||
import org.telegram.messenger.exoplayer2.util.MediaClock;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.util.MediaClock;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -192,6 +192,18 @@ public interface Renderer extends PlayerMessage.Target {
|
|||
*/
|
||||
void resetPosition(long positionUs) throws ExoPlaybackException;
|
||||
|
||||
/**
|
||||
* Sets the operating rate of this renderer, where 1 is the default rate, 2 is twice the default
|
||||
* rate, 0.5 is half the default rate and so on. The operating rate is a hint to the renderer of
|
||||
* the speed at which playback will proceed, and may be used for resource planning.
|
||||
*
|
||||
* <p>The default implementation is a no-op.
|
||||
*
|
||||
* @param operatingRate The operating rate.
|
||||
* @throws ExoPlaybackException If an error occurs handling the operating rate.
|
||||
*/
|
||||
default void setOperatingRate(float operatingRate) throws ExoPlaybackException {};
|
||||
|
||||
/**
|
||||
* Incrementally renders the {@link SampleStream}.
|
||||
* <p>
|
|
@ -13,9 +13,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
|
||||
/**
|
||||
* Defines the capabilities of a {@link Renderer}.
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
|
@ -13,16 +13,16 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager;
|
||||
import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import org.telegram.messenger.exoplayer2.metadata.MetadataOutput;
|
||||
import org.telegram.messenger.exoplayer2.text.TextOutput;
|
||||
import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import com.google.android.exoplayer2.metadata.MetadataOutput;
|
||||
import com.google.android.exoplayer2.text.TextOutput;
|
||||
import com.google.android.exoplayer2.video.VideoRendererEventListener;
|
||||
|
||||
/**
|
||||
* Builds {@link Renderer} instances for use by a {@link SimpleExoPlayer}.
|
|
@ -13,10 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
||||
/**
|
||||
* Parameters that apply to seeking.
|
|
@ -13,9 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.PlaybackParams;
|
||||
|
@ -27,25 +28,27 @@ import android.view.Surface;
|
|||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.TextureView;
|
||||
import org.telegram.messenger.exoplayer2.analytics.AnalyticsCollector;
|
||||
import org.telegram.messenger.exoplayer2.analytics.AnalyticsListener;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioAttributes;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener;
|
||||
import org.telegram.messenger.exoplayer2.decoder.DecoderCounters;
|
||||
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionManager;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager;
|
||||
import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import org.telegram.messenger.exoplayer2.metadata.Metadata;
|
||||
import org.telegram.messenger.exoplayer2.metadata.MetadataOutput;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource;
|
||||
import org.telegram.messenger.exoplayer2.source.TrackGroupArray;
|
||||
import org.telegram.messenger.exoplayer2.text.Cue;
|
||||
import org.telegram.messenger.exoplayer2.text.TextOutput;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector;
|
||||
import org.telegram.messenger.exoplayer2.util.Clock;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener;
|
||||
import com.google.android.exoplayer2.analytics.AnalyticsCollector;
|
||||
import com.google.android.exoplayer2.analytics.AnalyticsListener;
|
||||
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||
import com.google.android.exoplayer2.audio.AudioListener;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
|
||||
import com.google.android.exoplayer2.decoder.DecoderCounters;
|
||||
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.MetadataOutput;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
import com.google.android.exoplayer2.text.TextOutput;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.util.Clock;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.video.VideoRendererEventListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -56,11 +59,12 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
* be obtained from {@link ExoPlayerFactory}.
|
||||
*/
|
||||
@TargetApi(16)
|
||||
public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player.TextComponent {
|
||||
public class SimpleExoPlayer
|
||||
implements ExoPlayer, Player.AudioComponent, Player.VideoComponent, Player.TextComponent {
|
||||
|
||||
/** @deprecated Use {@link org.telegram.messenger.exoplayer2.video.VideoListener}. */
|
||||
/** @deprecated Use {@link com.google.android.exoplayer2.video.VideoListener}. */
|
||||
@Deprecated
|
||||
public interface VideoListener extends org.telegram.messenger.exoplayer2.video.VideoListener {}
|
||||
public interface VideoListener extends com.google.android.exoplayer2.video.VideoListener {}
|
||||
|
||||
private static final String TAG = "SimpleExoPlayer";
|
||||
|
||||
|
@ -69,12 +73,14 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
private final ExoPlayer player;
|
||||
private final Handler eventHandler;
|
||||
private final ComponentListener componentListener;
|
||||
private final CopyOnWriteArraySet<org.telegram.messenger.exoplayer2.video.VideoListener>
|
||||
private final CopyOnWriteArraySet<com.google.android.exoplayer2.video.VideoListener>
|
||||
videoListeners;
|
||||
private final CopyOnWriteArraySet<AudioListener> audioListeners;
|
||||
private final CopyOnWriteArraySet<TextOutput> textOutputs;
|
||||
private final CopyOnWriteArraySet<MetadataOutput> metadataOutputs;
|
||||
private final CopyOnWriteArraySet<VideoRendererEventListener> videoDebugListeners;
|
||||
private final CopyOnWriteArraySet<AudioRendererEventListener> audioDebugListeners;
|
||||
private final BandwidthMeter bandwidthMeter;
|
||||
private final AnalyticsCollector analyticsCollector;
|
||||
|
||||
private Format videoFormat;
|
||||
|
@ -84,10 +90,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
|
||||
private Surface surface;
|
||||
private boolean ownsSurface;
|
||||
@C.VideoScalingMode
|
||||
private int videoScalingMode;
|
||||
private @C.VideoScalingMode int videoScalingMode;
|
||||
private SurfaceHolder surfaceHolder;
|
||||
private TextureView textureView;
|
||||
private int surfaceWidth;
|
||||
private int surfaceHeight;
|
||||
private DecoderCounters videoDecoderCounters;
|
||||
private DecoderCounters audioDecoderCounters;
|
||||
private int audioSessionId;
|
||||
|
@ -100,20 +107,27 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
* @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance.
|
||||
* @param trackSelector The {@link TrackSelector} that will be used by the instance.
|
||||
* @param loadControl The {@link LoadControl} that will be used by the instance.
|
||||
* @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance.
|
||||
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
|
||||
* will not be used for DRM protected playbacks.
|
||||
* @param looper The {@link Looper} which must be used for all calls to the player and which is
|
||||
* used to call listeners on.
|
||||
*/
|
||||
protected SimpleExoPlayer(
|
||||
RenderersFactory renderersFactory,
|
||||
TrackSelector trackSelector,
|
||||
LoadControl loadControl,
|
||||
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
|
||||
BandwidthMeter bandwidthMeter,
|
||||
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
|
||||
Looper looper) {
|
||||
this(
|
||||
renderersFactory,
|
||||
trackSelector,
|
||||
loadControl,
|
||||
drmSessionManager,
|
||||
new AnalyticsCollector.Factory());
|
||||
bandwidthMeter,
|
||||
new AnalyticsCollector.Factory(),
|
||||
looper);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,22 +136,29 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
* @param loadControl The {@link LoadControl} that will be used by the instance.
|
||||
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
|
||||
* will not be used for DRM protected playbacks.
|
||||
* @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance.
|
||||
* @param analyticsCollectorFactory A factory for creating the {@link AnalyticsCollector} that
|
||||
* will collect and forward all player events.
|
||||
* @param looper The {@link Looper} which must be used for all calls to the player and which is
|
||||
* used to call listeners on.
|
||||
*/
|
||||
protected SimpleExoPlayer(
|
||||
RenderersFactory renderersFactory,
|
||||
TrackSelector trackSelector,
|
||||
LoadControl loadControl,
|
||||
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
|
||||
AnalyticsCollector.Factory analyticsCollectorFactory) {
|
||||
BandwidthMeter bandwidthMeter,
|
||||
AnalyticsCollector.Factory analyticsCollectorFactory,
|
||||
Looper looper) {
|
||||
this(
|
||||
renderersFactory,
|
||||
trackSelector,
|
||||
loadControl,
|
||||
drmSessionManager,
|
||||
bandwidthMeter,
|
||||
analyticsCollectorFactory,
|
||||
Clock.DEFAULT);
|
||||
Clock.DEFAULT,
|
||||
looper);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,26 +167,32 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
* @param loadControl The {@link LoadControl} that will be used by the instance.
|
||||
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
|
||||
* will not be used for DRM protected playbacks.
|
||||
* @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance.
|
||||
* @param analyticsCollectorFactory A factory for creating the {@link AnalyticsCollector} that
|
||||
* will collect and forward all player events.
|
||||
* @param clock The {@link Clock} that will be used by the instance. Should always be {@link
|
||||
* Clock#DEFAULT}, unless the player is being used from a test.
|
||||
* @param looper The {@link Looper} which must be used for all calls to the player and which is
|
||||
* used to call listeners on.
|
||||
*/
|
||||
protected SimpleExoPlayer(
|
||||
RenderersFactory renderersFactory,
|
||||
TrackSelector trackSelector,
|
||||
LoadControl loadControl,
|
||||
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
|
||||
BandwidthMeter bandwidthMeter,
|
||||
AnalyticsCollector.Factory analyticsCollectorFactory,
|
||||
Clock clock) {
|
||||
Clock clock,
|
||||
Looper looper) {
|
||||
this.bandwidthMeter = bandwidthMeter;
|
||||
componentListener = new ComponentListener();
|
||||
videoListeners = new CopyOnWriteArraySet<>();
|
||||
audioListeners = new CopyOnWriteArraySet<>();
|
||||
textOutputs = new CopyOnWriteArraySet<>();
|
||||
metadataOutputs = new CopyOnWriteArraySet<>();
|
||||
videoDebugListeners = new CopyOnWriteArraySet<>();
|
||||
audioDebugListeners = new CopyOnWriteArraySet<>();
|
||||
Looper eventLooper = Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper();
|
||||
eventHandler = new Handler(eventLooper);
|
||||
eventHandler = new Handler(looper);
|
||||
renderers =
|
||||
renderersFactory.createRenderers(
|
||||
eventHandler,
|
||||
|
@ -183,17 +210,26 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
currentCues = Collections.emptyList();
|
||||
|
||||
// Build the player and associated objects.
|
||||
player = createExoPlayerImpl(renderers, trackSelector, loadControl, clock);
|
||||
player =
|
||||
createExoPlayerImpl(renderers, trackSelector, loadControl, bandwidthMeter, clock, looper);
|
||||
analyticsCollector = analyticsCollectorFactory.createAnalyticsCollector(player, clock);
|
||||
addListener(analyticsCollector);
|
||||
videoDebugListeners.add(analyticsCollector);
|
||||
videoListeners.add(analyticsCollector);
|
||||
audioDebugListeners.add(analyticsCollector);
|
||||
audioListeners.add(analyticsCollector);
|
||||
addMetadataOutput(analyticsCollector);
|
||||
bandwidthMeter.addEventListener(eventHandler, analyticsCollector);
|
||||
if (drmSessionManager instanceof DefaultDrmSessionManager) {
|
||||
((DefaultDrmSessionManager) drmSessionManager).addListener(eventHandler, analyticsCollector);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AudioComponent getAudioComponent() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoComponent getVideoComponent() {
|
||||
return this;
|
||||
|
@ -240,6 +276,8 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
public void setVideoSurface(Surface surface) {
|
||||
removeSurfaceCallbacks();
|
||||
setVideoSurfaceInternal(surface, false);
|
||||
int newSurfaceSize = surface == null ? 0 : C.LENGTH_UNSET;
|
||||
maybeNotifySurfaceSizeChanged(/* width= */ newSurfaceSize, /* height= */ newSurfaceSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -255,10 +293,18 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
this.surfaceHolder = surfaceHolder;
|
||||
if (surfaceHolder == null) {
|
||||
setVideoSurfaceInternal(null, false);
|
||||
maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
|
||||
} else {
|
||||
surfaceHolder.addCallback(componentListener);
|
||||
Surface surface = surfaceHolder.getSurface();
|
||||
setVideoSurfaceInternal(surface != null && surface.isValid() ? surface : null, false);
|
||||
if (surface != null && surface.isValid()) {
|
||||
setVideoSurfaceInternal(surface, /* ownsSurface= */ false);
|
||||
Rect surfaceSize = surfaceHolder.getSurfaceFrame();
|
||||
maybeNotifySurfaceSizeChanged(surfaceSize.width(), surfaceSize.height());
|
||||
} else {
|
||||
setVideoSurfaceInternal(/* surface= */ null, /* ownsSurface= */ false);
|
||||
maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,6 +335,7 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
needSetSurface = true;
|
||||
if (textureView == null) {
|
||||
setVideoSurfaceInternal(null, true);
|
||||
maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
|
||||
} else {
|
||||
if (textureView.getSurfaceTextureListener() != null) {
|
||||
Log.w(TAG, "Replacing existing SurfaceTextureListener.");
|
||||
|
@ -296,7 +343,13 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
textureView.setSurfaceTextureListener(componentListener);
|
||||
SurfaceTexture surfaceTexture = textureView.isAvailable() ? textureView.getSurfaceTexture()
|
||||
: null;
|
||||
setVideoSurfaceInternal(surfaceTexture == null ? null : new Surface(surfaceTexture), true);
|
||||
if (surfaceTexture == null) {
|
||||
setVideoSurfaceInternal(/* surface= */ null, /* ownsSurface= */ true);
|
||||
maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
|
||||
} else {
|
||||
setVideoSurfaceInternal(new Surface(surfaceTexture), /* ownsSurface= */ true);
|
||||
maybeNotifySurfaceSizeChanged(textureView.getWidth(), textureView.getHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -307,6 +360,68 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAudioListener(AudioListener listener) {
|
||||
audioListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAudioListener(AudioListener listener) {
|
||||
audioListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAudioAttributes(AudioAttributes audioAttributes) {
|
||||
if (Util.areEqual(this.audioAttributes, audioAttributes)) {
|
||||
return;
|
||||
}
|
||||
this.audioAttributes = audioAttributes;
|
||||
for (Renderer renderer : renderers) {
|
||||
if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) {
|
||||
player
|
||||
.createMessage(renderer)
|
||||
.setType(C.MSG_SET_AUDIO_ATTRIBUTES)
|
||||
.setPayload(audioAttributes)
|
||||
.send();
|
||||
}
|
||||
}
|
||||
for (AudioListener audioListener : audioListeners) {
|
||||
audioListener.onAudioAttributesChanged(audioAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AudioAttributes getAudioAttributes() {
|
||||
return audioAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAudioSessionId() {
|
||||
return audioSessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolume(float audioVolume) {
|
||||
audioVolume = Util.constrainValue(audioVolume, /* min= */ 0, /* max= */ 1);
|
||||
if (this.audioVolume == audioVolume) {
|
||||
return;
|
||||
}
|
||||
this.audioVolume = audioVolume;
|
||||
for (Renderer renderer : renderers) {
|
||||
if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) {
|
||||
player.createMessage(renderer).setType(C.MSG_SET_VOLUME).setPayload(audioVolume).send();
|
||||
}
|
||||
}
|
||||
for (AudioListener audioListener : audioListeners) {
|
||||
audioListener.onVolumeChanged(audioVolume);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVolume() {
|
||||
return audioVolume;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stream type for audio playback, used by the underlying audio track.
|
||||
* <p>
|
||||
|
@ -361,63 +476,6 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
analyticsCollector.removeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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 {@link Util#getStreamTypeForAudioUsage(int)}.
|
||||
*
|
||||
* @param audioAttributes The attributes to use for audio playback.
|
||||
*/
|
||||
public void setAudioAttributes(AudioAttributes audioAttributes) {
|
||||
this.audioAttributes = audioAttributes;
|
||||
for (Renderer renderer : renderers) {
|
||||
if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) {
|
||||
player
|
||||
.createMessage(renderer)
|
||||
.setType(C.MSG_SET_AUDIO_ATTRIBUTES)
|
||||
.setPayload(audioAttributes)
|
||||
.send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attributes for audio playback.
|
||||
*/
|
||||
public AudioAttributes getAudioAttributes() {
|
||||
return audioAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the audio volume, with 0 being silence and 1 being unity gain.
|
||||
*
|
||||
* @param audioVolume The audio volume.
|
||||
*/
|
||||
public void setVolume(float audioVolume) {
|
||||
this.audioVolume = audioVolume;
|
||||
for (Renderer renderer : renderers) {
|
||||
if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) {
|
||||
player.createMessage(renderer).setType(C.MSG_SET_VOLUME).setPayload(audioVolume).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the audio volume, with 0 being silence and 1 being unity gain.
|
||||
*/
|
||||
public float getVolume() {
|
||||
return audioVolume;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link PlaybackParams} governing audio playback.
|
||||
*
|
||||
|
@ -451,13 +509,6 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
return audioFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the audio session identifier, or {@link C#AUDIO_SESSION_ID_UNSET} if not set.
|
||||
*/
|
||||
public int getAudioSessionId() {
|
||||
return audioSessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link DecoderCounters} for video, or null if no video is being played.
|
||||
*/
|
||||
|
@ -473,12 +524,12 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener listener) {
|
||||
public void addVideoListener(com.google.android.exoplayer2.video.VideoListener listener) {
|
||||
videoListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener listener) {
|
||||
public void removeVideoListener(com.google.android.exoplayer2.video.VideoListener listener) {
|
||||
videoListeners.remove(listener);
|
||||
}
|
||||
|
||||
|
@ -486,7 +537,7 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
* Sets a listener to receive video events, removing all existing listeners.
|
||||
*
|
||||
* @param listener The listener.
|
||||
* @deprecated Use {@link #addVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener)}.
|
||||
* @deprecated Use {@link #addVideoListener(com.google.android.exoplayer2.video.VideoListener)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setVideoListener(VideoListener listener) {
|
||||
|
@ -497,11 +548,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
}
|
||||
|
||||
/**
|
||||
* Equivalent to {@link #removeVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener)}.
|
||||
* Equivalent to {@link #removeVideoListener(com.google.android.exoplayer2.video.VideoListener)}.
|
||||
*
|
||||
* @param listener The listener to clear.
|
||||
* @deprecated Use {@link
|
||||
* #removeVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener)}.
|
||||
* #removeVideoListener(com.google.android.exoplayer2.video.VideoListener)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public void clearVideoListener(VideoListener listener) {
|
||||
|
@ -656,6 +707,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
return player.getPlaybackLooper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Looper getApplicationLooper() {
|
||||
return player.getApplicationLooper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(Player.EventListener listener) {
|
||||
player.addListener(listener);
|
||||
|
@ -768,6 +824,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
player.setSeekParameters(seekParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekParameters getSeekParameters() {
|
||||
return player.getSeekParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object getCurrentTag() {
|
||||
return player.getCurrentTag();
|
||||
|
@ -802,6 +863,7 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
if (mediaSource != null) {
|
||||
mediaSource.removeEventListener(analyticsCollector);
|
||||
}
|
||||
bandwidthMeter.removeEventListener(analyticsCollector);
|
||||
currentCues = Collections.emptyList();
|
||||
}
|
||||
|
||||
|
@ -890,6 +952,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
return player.getBufferedPercentage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalBufferedDuration() {
|
||||
return player.getTotalBufferedDuration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrentWindowDynamic() {
|
||||
return player.isCurrentWindowDynamic();
|
||||
|
@ -920,6 +987,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
return player.getContentPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getContentBufferedPosition() {
|
||||
return player.getContentBufferedPosition();
|
||||
}
|
||||
|
||||
// Internal methods.
|
||||
|
||||
/**
|
||||
|
@ -928,12 +1000,20 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
* @param renderers The {@link Renderer}s that will be used by the instance.
|
||||
* @param trackSelector The {@link TrackSelector} that will be used by the instance.
|
||||
* @param loadControl The {@link LoadControl} that will be used by the instance.
|
||||
* @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance.
|
||||
* @param clock The {@link Clock} that will be used by this instance.
|
||||
* @param looper The {@link Looper} which must be used for all calls to the player and which is
|
||||
* used to call listeners on.
|
||||
* @return A new {@link ExoPlayer} instance.
|
||||
*/
|
||||
protected ExoPlayer createExoPlayerImpl(
|
||||
Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl, Clock clock) {
|
||||
return new ExoPlayerImpl(renderers, trackSelector, loadControl, clock);
|
||||
Renderer[] renderers,
|
||||
TrackSelector trackSelector,
|
||||
LoadControl loadControl,
|
||||
BandwidthMeter bandwidthMeter,
|
||||
Clock clock,
|
||||
Looper looper) {
|
||||
return new ExoPlayerImpl(renderers, trackSelector, loadControl, bandwidthMeter, clock, looper);
|
||||
}
|
||||
|
||||
private void removeSurfaceCallbacks() {
|
||||
|
@ -979,6 +1059,16 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
this.ownsSurface = ownsSurface;
|
||||
}
|
||||
|
||||
private void maybeNotifySurfaceSizeChanged(int width, int height) {
|
||||
if (width != surfaceWidth || height != surfaceHeight) {
|
||||
surfaceWidth = width;
|
||||
surfaceHeight = height;
|
||||
for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) {
|
||||
videoListener.onSurfaceSizeChanged(width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class ComponentListener implements VideoRendererEventListener,
|
||||
AudioRendererEventListener, TextOutput, MetadataOutput, SurfaceHolder.Callback,
|
||||
TextureView.SurfaceTextureListener {
|
||||
|
@ -1020,9 +1110,13 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
@Override
|
||||
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
|
||||
float pixelWidthHeightRatio) {
|
||||
for (org.telegram.messenger.exoplayer2.video.VideoListener videoListener : videoListeners) {
|
||||
videoListener.onVideoSizeChanged(width, height, unappliedRotationDegrees,
|
||||
pixelWidthHeightRatio);
|
||||
for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) {
|
||||
// Prevent duplicate notification if a listener is both a VideoRendererEventListener and
|
||||
// a VideoListener, as they have the same method signature.
|
||||
if (!videoDebugListeners.contains(videoListener)) {
|
||||
videoListener.onVideoSizeChanged(
|
||||
width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
|
||||
}
|
||||
}
|
||||
for (VideoRendererEventListener videoDebugListener : videoDebugListeners) {
|
||||
videoDebugListener.onVideoSizeChanged(width, height, unappliedRotationDegrees,
|
||||
|
@ -1033,7 +1127,7 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
@Override
|
||||
public void onRenderedFirstFrame(Surface surface) {
|
||||
if (SimpleExoPlayer.this.surface == surface) {
|
||||
for (org.telegram.messenger.exoplayer2.video.VideoListener videoListener : videoListeners) {
|
||||
for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) {
|
||||
videoListener.onRenderedFirstFrame();
|
||||
}
|
||||
}
|
||||
|
@ -1063,7 +1157,17 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
|
||||
@Override
|
||||
public void onAudioSessionId(int sessionId) {
|
||||
if (audioSessionId == sessionId) {
|
||||
return;
|
||||
}
|
||||
audioSessionId = sessionId;
|
||||
for (AudioListener audioListener : audioListeners) {
|
||||
// Prevent duplicate notification if a listener is both a AudioRendererEventListener and
|
||||
// a AudioListener, as they have the same method signature.
|
||||
if (!audioDebugListeners.contains(audioListener)) {
|
||||
audioListener.onAudioSessionId(sessionId);
|
||||
}
|
||||
}
|
||||
for (AudioRendererEventListener audioDebugListener : audioDebugListeners) {
|
||||
audioDebugListener.onAudioSessionId(sessionId);
|
||||
}
|
||||
|
@ -1132,12 +1236,13 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
// Do nothing.
|
||||
maybeNotifySurfaceSizeChanged(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
setVideoSurfaceInternal(null, false);
|
||||
maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
|
||||
}
|
||||
|
||||
// TextureView.SurfaceTextureListener implementation
|
||||
|
@ -1148,33 +1253,34 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
|
|||
setVideoSurfaceInternal(new Surface(surfaceTexture), true);
|
||||
needSetSurface = false;
|
||||
}
|
||||
maybeNotifySurfaceSizeChanged(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
|
||||
// Do nothing.
|
||||
maybeNotifySurfaceSizeChanged(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
|
||||
for (org.telegram.messenger.exoplayer2.video.VideoListener videoListener : videoListeners) {
|
||||
for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) {
|
||||
if (videoListener.onSurfaceDestroyed(surfaceTexture)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
setVideoSurfaceInternal(null, true);
|
||||
maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
|
||||
needSetSurface = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
|
||||
for (org.telegram.messenger.exoplayer2.video.VideoListener videoListener : videoListeners) {
|
||||
for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) {
|
||||
videoListener.onSurfaceTextureUpdated(surfaceTexture);
|
||||
}
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -13,12 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2;
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Pair;
|
||||
import org.telegram.messenger.exoplayer2.source.ads.AdPlaybackState;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
||||
/**
|
||||
* A flexible representation of the structure of media. A timeline is able to represent the
|
||||
|
@ -520,6 +520,11 @@ public abstract class Timeline {
|
|||
public int getIndexOfPeriod(Object uid) {
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getUidOfPeriod(int periodIndex) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -737,6 +742,17 @@ public abstract class Timeline {
|
|||
return Pair.create(periodIndex, periodPositionUs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates a {@link Period} with data for the period with the specified unique identifier.
|
||||
*
|
||||
* @param periodUid The unique identifier of the period.
|
||||
* @param period The {@link Period} to populate. Must not be null.
|
||||
* @return The populated {@link Period}, for convenience.
|
||||
*/
|
||||
public Period getPeriodByUid(Object periodUid, Period period) {
|
||||
return getPeriod(getIndexOfPeriod(periodUid), period, /* setIds= */ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates a {@link Period} with data for the period at the specified index. Does not populate
|
||||
* {@link Period#id} and {@link Period#uid}.
|
||||
|
@ -770,4 +786,11 @@ public abstract class Timeline {
|
|||
*/
|
||||
public abstract int getIndexOfPeriod(Object uid);
|
||||
|
||||
/**
|
||||
* Returns the unique id of the period identified by its index in the timeline.
|
||||
*
|
||||
* @param periodIndex The index of the period.
|
||||
* @return The unique id of the period.
|
||||
*/
|
||||
public abstract Object getUidOfPeriod(int periodIndex);
|
||||
}
|
|
@ -13,39 +13,43 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.analytics;
|
||||
package com.google.android.exoplayer2.analytics;
|
||||
|
||||
import android.net.NetworkInfo;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.Surface;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.ExoPlaybackException;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.PlaybackParameters;
|
||||
import org.telegram.messenger.exoplayer2.Player;
|
||||
import org.telegram.messenger.exoplayer2.Timeline;
|
||||
import org.telegram.messenger.exoplayer2.Timeline.Period;
|
||||
import org.telegram.messenger.exoplayer2.Timeline.Window;
|
||||
import org.telegram.messenger.exoplayer2.analytics.AnalyticsListener.EventTime;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener;
|
||||
import org.telegram.messenger.exoplayer2.decoder.DecoderCounters;
|
||||
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionEventListener;
|
||||
import org.telegram.messenger.exoplayer2.metadata.Metadata;
|
||||
import org.telegram.messenger.exoplayer2.metadata.MetadataOutput;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener;
|
||||
import org.telegram.messenger.exoplayer2.source.TrackGroupArray;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import org.telegram.messenger.exoplayer2.upstream.BandwidthMeter;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.Clock;
|
||||
import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.Timeline.Period;
|
||||
import com.google.android.exoplayer2.Timeline.Window;
|
||||
import com.google.android.exoplayer2.analytics.AnalyticsListener.EventTime;
|
||||
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||
import com.google.android.exoplayer2.audio.AudioListener;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
|
||||
import com.google.android.exoplayer2.decoder.DecoderCounters;
|
||||
import com.google.android.exoplayer2.drm.DefaultDrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.MetadataOutput;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Clock;
|
||||
import com.google.android.exoplayer2.video.VideoListener;
|
||||
import com.google.android.exoplayer2.video.VideoRendererEventListener;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/**
|
||||
* Data collector which is able to forward analytics events to {@link AnalyticsListener}s by
|
||||
|
@ -58,7 +62,9 @@ public class AnalyticsCollector
|
|||
VideoRendererEventListener,
|
||||
MediaSourceEventListener,
|
||||
BandwidthMeter.EventListener,
|
||||
DefaultDrmSessionEventListener {
|
||||
DefaultDrmSessionEventListener,
|
||||
VideoListener,
|
||||
AudioListener {
|
||||
|
||||
/** Factory for an analytics collector. */
|
||||
public static class Factory {
|
||||
|
@ -66,29 +72,34 @@ public class AnalyticsCollector
|
|||
/**
|
||||
* Creates an analytics collector for the specified player.
|
||||
*
|
||||
* @param player The {@link Player} for which data will be collected.
|
||||
* @param player The {@link Player} for which data will be collected. Can be null, if the player
|
||||
* is set by calling {@link AnalyticsCollector#setPlayer(Player)} before using the analytics
|
||||
* collector.
|
||||
* @param clock A {@link Clock} used to generate timestamps.
|
||||
* @return An analytics collector.
|
||||
*/
|
||||
public AnalyticsCollector createAnalyticsCollector(Player player, Clock clock) {
|
||||
public AnalyticsCollector createAnalyticsCollector(@Nullable Player player, Clock clock) {
|
||||
return new AnalyticsCollector(player, clock);
|
||||
}
|
||||
}
|
||||
|
||||
private final CopyOnWriteArraySet<AnalyticsListener> listeners;
|
||||
private final Player player;
|
||||
private final Clock clock;
|
||||
private final Window window;
|
||||
private final MediaPeriodQueueTracker mediaPeriodQueueTracker;
|
||||
|
||||
private @MonotonicNonNull Player player;
|
||||
|
||||
/**
|
||||
* Creates an analytics collector for the specified player.
|
||||
*
|
||||
* @param player The {@link Player} for which data will be collected.
|
||||
* @param player The {@link Player} for which data will be collected. Can be null, if the player
|
||||
* is set by calling {@link AnalyticsCollector#setPlayer(Player)} before using the analytics
|
||||
* collector.
|
||||
* @param clock A {@link Clock} used to generate timestamps.
|
||||
*/
|
||||
protected AnalyticsCollector(Player player, Clock clock) {
|
||||
this.player = Assertions.checkNotNull(player);
|
||||
protected AnalyticsCollector(@Nullable Player player, Clock clock) {
|
||||
this.player = player;
|
||||
this.clock = Assertions.checkNotNull(clock);
|
||||
listeners = new CopyOnWriteArraySet<>();
|
||||
mediaPeriodQueueTracker = new MediaPeriodQueueTracker();
|
||||
|
@ -113,6 +124,17 @@ public class AnalyticsCollector
|
|||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player for which data will be collected. Must only be called if no player has been set
|
||||
* yet.
|
||||
*
|
||||
* @param player The {@link Player} for which data will be collected.
|
||||
*/
|
||||
public void setPlayer(Player player) {
|
||||
Assertions.checkState(this.player == null);
|
||||
this.player = Assertions.checkNotNull(player);
|
||||
}
|
||||
|
||||
// External events.
|
||||
|
||||
/**
|
||||
|
@ -129,31 +151,6 @@ public class AnalyticsCollector
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify analytics collector that the viewport size changed.
|
||||
*
|
||||
* @param width The new width of the viewport in device-independent pixels (dp).
|
||||
* @param height The new height of the viewport in device-independent pixels (dp).
|
||||
*/
|
||||
public final void notifyViewportSizeChanged(int width, int height) {
|
||||
EventTime eventTime = generatePlayingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onViewportSizeChange(eventTime, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify analytics collector that the network type or connectivity changed.
|
||||
*
|
||||
* @param networkInfo The new network info, or null if no network connection exists.
|
||||
*/
|
||||
public final void notifyNetworkTypeChanged(@Nullable NetworkInfo networkInfo) {
|
||||
EventTime eventTime = generatePlayingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onNetworkTypeChanged(eventTime, networkInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the analytics collector for a new media source. Should be called before the player is
|
||||
* prepared with a new media source.
|
||||
|
@ -188,14 +185,6 @@ public class AnalyticsCollector
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onAudioSessionId(int audioSessionId) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioSessionId(eventTime, audioSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onAudioDecoderInitialized(
|
||||
String decoderName, long initializedTimestampMs, long initializationDurationMs) {
|
||||
|
@ -233,6 +222,32 @@ public class AnalyticsCollector
|
|||
}
|
||||
}
|
||||
|
||||
// AudioListener implementation.
|
||||
|
||||
@Override
|
||||
public final void onAudioSessionId(int audioSessionId) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioSessionId(eventTime, audioSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioAttributesChanged(AudioAttributes audioAttributes) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioAttributesChanged(eventTime, audioAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVolumeChanged(float audioVolume) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onVolumeChanged(eventTime, audioVolume);
|
||||
}
|
||||
}
|
||||
|
||||
// VideoRendererEventListener implementation.
|
||||
|
||||
@Override
|
||||
|
@ -271,12 +286,12 @@ public class AnalyticsCollector
|
|||
}
|
||||
|
||||
@Override
|
||||
public final void onVideoSizeChanged(
|
||||
int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
public final void onVideoDisabled(DecoderCounters counters) {
|
||||
// The renderers are disabled after we changed the playing media period on the playback thread
|
||||
// but before this change is reported to the app thread.
|
||||
EventTime eventTime = generateLastReportedPlayingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onVideoSizeChanged(
|
||||
eventTime, width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
|
||||
listener.onDecoderDisabled(eventTime, C.TRACK_TYPE_VIDEO, counters);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,16 +303,31 @@ public class AnalyticsCollector
|
|||
}
|
||||
}
|
||||
|
||||
// VideoListener implementation.
|
||||
|
||||
@Override
|
||||
public final void onVideoDisabled(DecoderCounters counters) {
|
||||
// The renderers are disabled after we changed the playing media period on the playback thread
|
||||
// but before this change is reported to the app thread.
|
||||
EventTime eventTime = generateLastReportedPlayingMediaPeriodEventTime();
|
||||
public final void onVideoSizeChanged(
|
||||
int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onDecoderDisabled(eventTime, C.TRACK_TYPE_VIDEO, counters);
|
||||
listener.onVideoSizeChanged(
|
||||
eventTime, width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceSizeChanged(int width, int height) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onSurfaceSizeChanged(eventTime, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onRenderedFirstFrame() {
|
||||
// Do nothing. Already reported in VideoRendererEventListener.onRenderedFirstFrame.
|
||||
}
|
||||
|
||||
// MediaSourceEventListener implementation.
|
||||
|
||||
@Override
|
||||
|
@ -420,6 +450,16 @@ public class AnalyticsCollector
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onLoadingChanged(boolean isLoading) {
|
||||
EventTime eventTime = generatePlayingMediaPeriodEventTime();
|
||||
|
@ -541,6 +581,7 @@ public class AnalyticsCollector
|
|||
|
||||
/** Returns a new {@link EventTime} for the specified window index and media period id. */
|
||||
protected EventTime generateEventTime(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
Assertions.checkNotNull(player);
|
||||
long realtimeMs = clock.elapsedRealtime();
|
||||
Timeline timeline = player.getCurrentTimeline();
|
||||
long eventPositionMs;
|
||||
|
@ -565,8 +606,6 @@ public class AnalyticsCollector
|
|||
// This event is for content in a future window. Assume default start position.
|
||||
eventPositionMs = timeline.getWindow(windowIndex, window).getDefaultPositionMs();
|
||||
}
|
||||
// TODO(b/30792113): implement this properly (player.getTotalBufferedDuration()).
|
||||
long bufferedDurationMs = player.getBufferedPosition() - player.getContentPosition();
|
||||
return new EventTime(
|
||||
realtimeMs,
|
||||
timeline,
|
||||
|
@ -574,12 +613,12 @@ public class AnalyticsCollector
|
|||
mediaPeriodId,
|
||||
eventPositionMs,
|
||||
player.getCurrentPosition(),
|
||||
bufferedDurationMs);
|
||||
player.getTotalBufferedDuration());
|
||||
}
|
||||
|
||||
private EventTime generateEventTime(@Nullable WindowAndMediaPeriodId mediaPeriod) {
|
||||
if (mediaPeriod == null) {
|
||||
int windowIndex = player.getCurrentWindowIndex();
|
||||
int windowIndex = Assertions.checkNotNull(player).getCurrentWindowIndex();
|
||||
MediaPeriodId mediaPeriodId = mediaPeriodQueueTracker.tryResolveWindowIndex(windowIndex);
|
||||
return generateEventTime(windowIndex, mediaPeriodId);
|
||||
}
|
||||
|
@ -756,8 +795,7 @@ public class AnalyticsCollector
|
|||
if (newTimeline.isEmpty() || timeline.isEmpty()) {
|
||||
return mediaPeriod;
|
||||
}
|
||||
Object uid =
|
||||
timeline.getPeriod(mediaPeriod.mediaPeriodId.periodIndex, period, /* setIds= */ true).uid;
|
||||
Object uid = timeline.getUidOfPeriod(mediaPeriod.mediaPeriodId.periodIndex);
|
||||
int newPeriodIndex = newTimeline.getIndexOfPeriod(uid);
|
||||
if (newPeriodIndex == C.INDEX_UNSET) {
|
||||
return mediaPeriod;
|
|
@ -13,27 +13,27 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.analytics;
|
||||
package com.google.android.exoplayer2.analytics;
|
||||
|
||||
import android.net.NetworkInfo;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.Surface;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.ExoPlaybackException;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.PlaybackParameters;
|
||||
import org.telegram.messenger.exoplayer2.Player;
|
||||
import org.telegram.messenger.exoplayer2.Player.DiscontinuityReason;
|
||||
import org.telegram.messenger.exoplayer2.Player.TimelineChangeReason;
|
||||
import org.telegram.messenger.exoplayer2.Timeline;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioSink;
|
||||
import org.telegram.messenger.exoplayer2.decoder.DecoderCounters;
|
||||
import org.telegram.messenger.exoplayer2.metadata.Metadata;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.LoadEventInfo;
|
||||
import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.MediaLoadData;
|
||||
import org.telegram.messenger.exoplayer2.source.TrackGroupArray;
|
||||
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
||||
import com.google.android.exoplayer2.Player.TimelineChangeReason;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||
import com.google.android.exoplayer2.audio.AudioSink;
|
||||
import com.google.android.exoplayer2.decoder.DecoderCounters;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.LoadEventInfo;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.MediaLoadData;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
@ -41,6 +41,8 @@ import java.io.IOException;
|
|||
*
|
||||
* <p>All events are recorded with an {@link EventTime} specifying the elapsed real time and media
|
||||
* time at the time of the event.
|
||||
*
|
||||
* <p>All methods have no-op default implementations to allow selective overrides.
|
||||
*/
|
||||
public interface AnalyticsListener {
|
||||
|
||||
|
@ -127,7 +129,8 @@ public interface AnalyticsListener {
|
|||
* @param playWhenReady Whether the playback will proceed when ready.
|
||||
* @param playbackState One of the {@link Player}.STATE constants.
|
||||
*/
|
||||
void onPlayerStateChanged(EventTime eventTime, boolean playWhenReady, int playbackState);
|
||||
default void onPlayerStateChanged(
|
||||
EventTime eventTime, boolean playWhenReady, int playbackState) {}
|
||||
|
||||
/**
|
||||
* Called when the timeline changed.
|
||||
|
@ -135,7 +138,7 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param reason The reason for the timeline change.
|
||||
*/
|
||||
void onTimelineChanged(EventTime eventTime, @TimelineChangeReason int reason);
|
||||
default void onTimelineChanged(EventTime eventTime, @TimelineChangeReason int reason) {}
|
||||
|
||||
/**
|
||||
* Called when a position discontinuity occurred.
|
||||
|
@ -143,21 +146,21 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param reason The reason for the position discontinuity.
|
||||
*/
|
||||
void onPositionDiscontinuity(EventTime eventTime, @DiscontinuityReason int reason);
|
||||
default void onPositionDiscontinuity(EventTime eventTime, @DiscontinuityReason int reason) {}
|
||||
|
||||
/**
|
||||
* Called when a seek operation started.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
*/
|
||||
void onSeekStarted(EventTime eventTime);
|
||||
default void onSeekStarted(EventTime eventTime) {}
|
||||
|
||||
/**
|
||||
* Called when a seek operation was processed.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
*/
|
||||
void onSeekProcessed(EventTime eventTime);
|
||||
default void onSeekProcessed(EventTime eventTime) {}
|
||||
|
||||
/**
|
||||
* Called when the playback parameters changed.
|
||||
|
@ -165,7 +168,8 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param playbackParameters The new playback parameters.
|
||||
*/
|
||||
void onPlaybackParametersChanged(EventTime eventTime, PlaybackParameters playbackParameters);
|
||||
default void onPlaybackParametersChanged(
|
||||
EventTime eventTime, PlaybackParameters playbackParameters) {}
|
||||
|
||||
/**
|
||||
* Called when the repeat mode changed.
|
||||
|
@ -173,7 +177,7 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param repeatMode The new repeat mode.
|
||||
*/
|
||||
void onRepeatModeChanged(EventTime eventTime, @Player.RepeatMode int repeatMode);
|
||||
default void onRepeatModeChanged(EventTime eventTime, @Player.RepeatMode int repeatMode) {}
|
||||
|
||||
/**
|
||||
* Called when the shuffle mode changed.
|
||||
|
@ -181,7 +185,7 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param shuffleModeEnabled Whether the shuffle mode is enabled.
|
||||
*/
|
||||
void onShuffleModeChanged(EventTime eventTime, boolean shuffleModeEnabled);
|
||||
default void onShuffleModeChanged(EventTime eventTime, boolean shuffleModeEnabled) {}
|
||||
|
||||
/**
|
||||
* Called when the player starts or stops loading data from a source.
|
||||
|
@ -189,7 +193,7 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param isLoading Whether the player is loading.
|
||||
*/
|
||||
void onLoadingChanged(EventTime eventTime, boolean isLoading);
|
||||
default void onLoadingChanged(EventTime eventTime, boolean isLoading) {}
|
||||
|
||||
/**
|
||||
* Called when a fatal player error occurred.
|
||||
|
@ -197,7 +201,7 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param error The error.
|
||||
*/
|
||||
void onPlayerError(EventTime eventTime, ExoPlaybackException error);
|
||||
default void onPlayerError(EventTime eventTime, ExoPlaybackException error) {}
|
||||
|
||||
/**
|
||||
* Called when the available or selected tracks for the renderers changed.
|
||||
|
@ -206,8 +210,8 @@ public interface AnalyticsListener {
|
|||
* @param trackGroups The available tracks. May be empty.
|
||||
* @param trackSelections The track selections for each renderer. May contain null elements.
|
||||
*/
|
||||
void onTracksChanged(
|
||||
EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections);
|
||||
default void onTracksChanged(
|
||||
EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {}
|
||||
|
||||
/**
|
||||
* Called when a media source started loading data.
|
||||
|
@ -216,7 +220,8 @@ public interface AnalyticsListener {
|
|||
* @param loadEventInfo The {@link LoadEventInfo} defining the load event.
|
||||
* @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
|
||||
*/
|
||||
void onLoadStarted(EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData);
|
||||
default void onLoadStarted(
|
||||
EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {}
|
||||
|
||||
/**
|
||||
* Called when a media source completed loading data.
|
||||
|
@ -225,8 +230,8 @@ public interface AnalyticsListener {
|
|||
* @param loadEventInfo The {@link LoadEventInfo} defining the load event.
|
||||
* @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
|
||||
*/
|
||||
void onLoadCompleted(
|
||||
EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData);
|
||||
default void onLoadCompleted(
|
||||
EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {}
|
||||
|
||||
/**
|
||||
* Called when a media source canceled loading data.
|
||||
|
@ -235,8 +240,8 @@ public interface AnalyticsListener {
|
|||
* @param loadEventInfo The {@link LoadEventInfo} defining the load event.
|
||||
* @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
|
||||
*/
|
||||
void onLoadCanceled(
|
||||
EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData);
|
||||
default void onLoadCanceled(
|
||||
EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {}
|
||||
|
||||
/**
|
||||
* Called when a media source loading error occurred. These errors are just for informational
|
||||
|
@ -248,12 +253,12 @@ public interface AnalyticsListener {
|
|||
* @param error The load error.
|
||||
* @param wasCanceled Whether the load was canceled as a result of the error.
|
||||
*/
|
||||
void onLoadError(
|
||||
default void onLoadError(
|
||||
EventTime eventTime,
|
||||
LoadEventInfo loadEventInfo,
|
||||
MediaLoadData mediaLoadData,
|
||||
IOException error,
|
||||
boolean wasCanceled);
|
||||
boolean wasCanceled) {}
|
||||
|
||||
/**
|
||||
* Called when the downstream format sent to the renderers changed.
|
||||
|
@ -261,7 +266,7 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param mediaLoadData The {@link MediaLoadData} defining the newly selected media data.
|
||||
*/
|
||||
void onDownstreamFormatChanged(EventTime eventTime, MediaLoadData mediaLoadData);
|
||||
default void onDownstreamFormatChanged(EventTime eventTime, MediaLoadData mediaLoadData) {}
|
||||
|
||||
/**
|
||||
* Called when data is removed from the back of a media buffer, typically so that it can be
|
||||
|
@ -270,28 +275,28 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param mediaLoadData The {@link MediaLoadData} defining the media being discarded.
|
||||
*/
|
||||
void onUpstreamDiscarded(EventTime eventTime, MediaLoadData mediaLoadData);
|
||||
default void onUpstreamDiscarded(EventTime eventTime, MediaLoadData mediaLoadData) {}
|
||||
|
||||
/**
|
||||
* Called when a media source created a media period.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
*/
|
||||
void onMediaPeriodCreated(EventTime eventTime);
|
||||
default void onMediaPeriodCreated(EventTime eventTime) {}
|
||||
|
||||
/**
|
||||
* Called when a media source released a media period.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
*/
|
||||
void onMediaPeriodReleased(EventTime eventTime);
|
||||
default void onMediaPeriodReleased(EventTime eventTime) {}
|
||||
|
||||
/**
|
||||
* Called when the player started reading a media period.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
*/
|
||||
void onReadingStarted(EventTime eventTime);
|
||||
default void onReadingStarted(EventTime eventTime) {}
|
||||
|
||||
/**
|
||||
* Called when the bandwidth estimate for the current data source has been updated.
|
||||
|
@ -301,25 +306,19 @@ public interface AnalyticsListener {
|
|||
* @param totalBytesLoaded The total bytes loaded this update is based on.
|
||||
* @param bitrateEstimate The bandwidth estimate, in bits per second.
|
||||
*/
|
||||
void onBandwidthEstimate(
|
||||
EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate);
|
||||
default void onBandwidthEstimate(
|
||||
EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) {}
|
||||
|
||||
/**
|
||||
* Called when the viewport size of the output surface changed.
|
||||
* Called when the output surface size changed.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
* @param width The width of the viewport in device-independent pixels (dp).
|
||||
* @param height The height of the viewport in device-independent pixels (dp).
|
||||
* @param width The surface width in pixels. May be {@link C#LENGTH_UNSET} if unknown, or 0 if the
|
||||
* video is not rendered onto a surface.
|
||||
* @param height The surface height in pixels. May be {@link C#LENGTH_UNSET} if unknown, or 0 if
|
||||
* the video is not rendered onto a surface.
|
||||
*/
|
||||
void onViewportSizeChange(EventTime eventTime, int width, int height);
|
||||
|
||||
/**
|
||||
* Called when the type of the network connection changed.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
* @param networkInfo The network info for the current connection, or null if disconnected.
|
||||
*/
|
||||
void onNetworkTypeChanged(EventTime eventTime, @Nullable NetworkInfo networkInfo);
|
||||
default void onSurfaceSizeChanged(EventTime eventTime, int width, int height) {}
|
||||
|
||||
/**
|
||||
* Called when there is {@link Metadata} associated with the current playback time.
|
||||
|
@ -327,7 +326,7 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param metadata The metadata.
|
||||
*/
|
||||
void onMetadata(EventTime eventTime, Metadata metadata);
|
||||
default void onMetadata(EventTime eventTime, Metadata metadata) {}
|
||||
|
||||
/**
|
||||
* Called when an audio or video decoder has been enabled.
|
||||
|
@ -337,7 +336,8 @@ public interface AnalyticsListener {
|
|||
* {@link C#TRACK_TYPE_VIDEO}.
|
||||
* @param decoderCounters The accumulated event counters associated with this decoder.
|
||||
*/
|
||||
void onDecoderEnabled(EventTime eventTime, int trackType, DecoderCounters decoderCounters);
|
||||
default void onDecoderEnabled(
|
||||
EventTime eventTime, int trackType, DecoderCounters decoderCounters) {}
|
||||
|
||||
/**
|
||||
* Called when an audio or video decoder has been initialized.
|
||||
|
@ -348,8 +348,8 @@ public interface AnalyticsListener {
|
|||
* @param decoderName The decoder that was created.
|
||||
* @param initializationDurationMs Time taken to initialize the decoder, in milliseconds.
|
||||
*/
|
||||
void onDecoderInitialized(
|
||||
EventTime eventTime, int trackType, String decoderName, long initializationDurationMs);
|
||||
default void onDecoderInitialized(
|
||||
EventTime eventTime, int trackType, String decoderName, long initializationDurationMs) {}
|
||||
|
||||
/**
|
||||
* Called when an audio or video decoder input format changed.
|
||||
|
@ -359,7 +359,7 @@ public interface AnalyticsListener {
|
|||
* C#TRACK_TYPE_AUDIO} or {@link C#TRACK_TYPE_VIDEO}.
|
||||
* @param format The new input format for the decoder.
|
||||
*/
|
||||
void onDecoderInputFormatChanged(EventTime eventTime, int trackType, Format format);
|
||||
default void onDecoderInputFormatChanged(EventTime eventTime, int trackType, Format format) {}
|
||||
|
||||
/**
|
||||
* Called when an audio or video decoder has been disabled.
|
||||
|
@ -369,7 +369,8 @@ public interface AnalyticsListener {
|
|||
* {@link C#TRACK_TYPE_VIDEO}.
|
||||
* @param decoderCounters The accumulated event counters associated with this decoder.
|
||||
*/
|
||||
void onDecoderDisabled(EventTime eventTime, int trackType, DecoderCounters decoderCounters);
|
||||
default void onDecoderDisabled(
|
||||
EventTime eventTime, int trackType, DecoderCounters decoderCounters) {}
|
||||
|
||||
/**
|
||||
* Called when the audio session id is set.
|
||||
|
@ -377,7 +378,23 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param audioSessionId The audio session id.
|
||||
*/
|
||||
void onAudioSessionId(EventTime eventTime, int audioSessionId);
|
||||
default void onAudioSessionId(EventTime eventTime, int audioSessionId) {}
|
||||
|
||||
/**
|
||||
* Called when the audio attributes change.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
* @param audioAttributes The audio attributes.
|
||||
*/
|
||||
default void onAudioAttributesChanged(EventTime eventTime, AudioAttributes audioAttributes) {}
|
||||
|
||||
/**
|
||||
* Called when the volume changes.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
* @param volume The new volume, with 0 being silence and 1 being unity gain.
|
||||
*/
|
||||
default void onVolumeChanged(EventTime eventTime, float volume) {}
|
||||
|
||||
/**
|
||||
* Called when an audio underrun occurred.
|
||||
|
@ -389,8 +406,8 @@ public interface AnalyticsListener {
|
|||
* as the buffered media can have a variable bitrate so the duration may be unknown.
|
||||
* @param elapsedSinceLastFeedMs The time since the {@link AudioSink} was last fed data.
|
||||
*/
|
||||
void onAudioUnderrun(
|
||||
EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs);
|
||||
default void onAudioUnderrun(
|
||||
EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {}
|
||||
|
||||
/**
|
||||
* Called after video frames have been dropped.
|
||||
|
@ -401,7 +418,7 @@ public interface AnalyticsListener {
|
|||
* is timed from when the renderer was started or from when dropped frames were last reported
|
||||
* (whichever was more recent), and not from when the first of the reported drops occurred.
|
||||
*/
|
||||
void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedMs);
|
||||
default void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedMs) {}
|
||||
|
||||
/**
|
||||
* Called before a frame is rendered for the first time since setting the surface, and each time
|
||||
|
@ -416,12 +433,12 @@ public interface AnalyticsListener {
|
|||
* since the renderer will apply all necessary rotations internally.
|
||||
* @param pixelWidthHeightRatio The width to height ratio of each pixel.
|
||||
*/
|
||||
void onVideoSizeChanged(
|
||||
default void onVideoSizeChanged(
|
||||
EventTime eventTime,
|
||||
int width,
|
||||
int height,
|
||||
int unappliedRotationDegrees,
|
||||
float pixelWidthHeightRatio);
|
||||
float pixelWidthHeightRatio) {}
|
||||
|
||||
/**
|
||||
* Called when a frame is rendered for the first time since setting the surface, and when a frame
|
||||
|
@ -431,14 +448,14 @@ public interface AnalyticsListener {
|
|||
* @param surface The {@link Surface} to which a first frame has been rendered, or {@code null} if
|
||||
* the renderer renders to something that isn't a {@link Surface}.
|
||||
*/
|
||||
void onRenderedFirstFrame(EventTime eventTime, Surface surface);
|
||||
default void onRenderedFirstFrame(EventTime eventTime, Surface surface) {}
|
||||
|
||||
/**
|
||||
* Called each time drm keys are loaded.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
*/
|
||||
void onDrmKeysLoaded(EventTime eventTime);
|
||||
default void onDrmKeysLoaded(EventTime eventTime) {}
|
||||
|
||||
/**
|
||||
* Called when a drm error occurs. These errors are just for informational purposes and the player
|
||||
|
@ -447,19 +464,19 @@ public interface AnalyticsListener {
|
|||
* @param eventTime The event time.
|
||||
* @param error The error.
|
||||
*/
|
||||
void onDrmSessionManagerError(EventTime eventTime, Exception error);
|
||||
default void onDrmSessionManagerError(EventTime eventTime, Exception error) {}
|
||||
|
||||
/**
|
||||
* Called each time offline drm keys are restored.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
*/
|
||||
void onDrmKeysRestored(EventTime eventTime);
|
||||
default void onDrmKeysRestored(EventTime eventTime) {}
|
||||
|
||||
/**
|
||||
* Called each time offline drm keys are removed.
|
||||
*
|
||||
* @param eventTime The event time.
|
||||
*/
|
||||
void onDrmKeysRemoved(EventTime eventTime);
|
||||
default void onDrmKeysRemoved(EventTime eventTime) {}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.analytics;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link AnalyticsListener} directly for selective overrides as all methods are
|
||||
* implemented as no-op default methods.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class DefaultAnalyticsListener implements AnalyticsListener {}
|
|
@ -13,16 +13,16 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.support.annotation.IntDef;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.audio.Ac3Util.SyncFrameInfo.StreamType;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmInitData;
|
||||
import org.telegram.messenger.exoplayer2.util.MimeTypes;
|
||||
import org.telegram.messenger.exoplayer2.util.ParsableBitArray;
|
||||
import org.telegram.messenger.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.audio.Ac3Util.SyncFrameInfo.StreamType;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -137,17 +137,17 @@ public final class Ac3Util {
|
|||
121, 139, 174, 208, 243, 278, 348, 417, 487, 557, 696, 835, 975, 1114, 1253, 1393};
|
||||
|
||||
/**
|
||||
* Returns the AC-3 format given {@code data} containing the AC3SpecificBox according to
|
||||
* ETSI TS 102 366 Annex F. The reading position of {@code data} will be modified.
|
||||
* Returns the AC-3 format given {@code data} containing the AC3SpecificBox according to ETSI TS
|
||||
* 102 366 Annex F. The reading position of {@code data} will be modified.
|
||||
*
|
||||
* @param data The AC3SpecificBox to parse.
|
||||
* @param trackId The track identifier to set on the format, or null.
|
||||
* @param trackId The track identifier to set on the format.
|
||||
* @param language The language to set on the format.
|
||||
* @param drmInitData {@link DrmInitData} to be included in the format.
|
||||
* @return The AC-3 format parsed from data in the header.
|
||||
*/
|
||||
public static Format parseAc3AnnexFFormat(ParsableByteArray data, String trackId,
|
||||
String language, DrmInitData drmInitData) {
|
||||
public static Format parseAc3AnnexFFormat(
|
||||
ParsableByteArray data, String trackId, String language, DrmInitData drmInitData) {
|
||||
int fscod = (data.readUnsignedByte() & 0xC0) >> 6;
|
||||
int sampleRate = SAMPLE_RATE_BY_FSCOD[fscod];
|
||||
int nextByte = data.readUnsignedByte();
|
||||
|
@ -155,22 +155,32 @@ public final class Ac3Util {
|
|||
if ((nextByte & 0x04) != 0) { // lfeon
|
||||
channelCount++;
|
||||
}
|
||||
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_AC3, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0, language);
|
||||
return Format.createAudioSampleFormat(
|
||||
trackId,
|
||||
MimeTypes.AUDIO_AC3,
|
||||
/* codecs= */ null,
|
||||
Format.NO_VALUE,
|
||||
Format.NO_VALUE,
|
||||
channelCount,
|
||||
sampleRate,
|
||||
/* initializationData= */ null,
|
||||
drmInitData,
|
||||
/* selectionFlags= */ 0,
|
||||
language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the E-AC-3 format given {@code data} containing the EC3SpecificBox according to
|
||||
* ETSI TS 102 366 Annex F. The reading position of {@code data} will be modified.
|
||||
* Returns the E-AC-3 format given {@code data} containing the EC3SpecificBox according to ETSI TS
|
||||
* 102 366 Annex F. The reading position of {@code data} will be modified.
|
||||
*
|
||||
* @param data The EC3SpecificBox to parse.
|
||||
* @param trackId The track identifier to set on the format, or null.
|
||||
* @param trackId The track identifier to set on the format.
|
||||
* @param language The language to set on the format.
|
||||
* @param drmInitData {@link DrmInitData} to be included in the format.
|
||||
* @return The E-AC-3 format parsed from data in the header.
|
||||
*/
|
||||
public static Format parseEAc3AnnexFFormat(ParsableByteArray data, String trackId,
|
||||
String language, DrmInitData drmInitData) {
|
||||
public static Format parseEAc3AnnexFFormat(
|
||||
ParsableByteArray data, String trackId, String language, DrmInitData drmInitData) {
|
||||
data.skipBytes(2); // data_rate, num_ind_sub
|
||||
|
||||
// Read the first independent substream.
|
||||
|
@ -200,8 +210,18 @@ public final class Ac3Util {
|
|||
mimeType = MimeTypes.AUDIO_E_AC3_JOC;
|
||||
}
|
||||
}
|
||||
return Format.createAudioSampleFormat(trackId, mimeType, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0, language);
|
||||
return Format.createAudioSampleFormat(
|
||||
trackId,
|
||||
mimeType,
|
||||
/* codecs= */ null,
|
||||
Format.NO_VALUE,
|
||||
Format.NO_VALUE,
|
||||
channelCount,
|
||||
sampleRate,
|
||||
/* initializationData= */ null,
|
||||
drmInitData,
|
||||
/* selectionFlags= */ 0,
|
||||
language);
|
||||
}
|
||||
|
||||
/**
|
|
@ -13,18 +13,18 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.C;
|
||||
|
||||
/**
|
||||
* Attributes for audio playback, which configure the underlying platform
|
||||
* {@link android.media.AudioTrack}.
|
||||
* <p>
|
||||
* To set the audio attributes, create an instance using the {@link Builder} and either pass it to
|
||||
* {@link org.telegram.messenger.exoplayer2.SimpleExoPlayer#setAudioAttributes(AudioAttributes)} or
|
||||
* {@link com.google.android.exoplayer2.SimpleExoPlayer#setAudioAttributes(AudioAttributes)} or
|
||||
* send a message of type {@link C#MSG_SET_AUDIO_ATTRIBUTES} to the audio renderers.
|
||||
* <p>
|
||||
* This class is based on {@link android.media.AudioAttributes}, but can be used on all supported
|
||||
|
@ -39,12 +39,9 @@ public final class AudioAttributes {
|
|||
*/
|
||||
public static final class Builder {
|
||||
|
||||
@C.AudioContentType
|
||||
private int contentType;
|
||||
@C.AudioFlags
|
||||
private int flags;
|
||||
@C.AudioUsage
|
||||
private int usage;
|
||||
private @C.AudioContentType int contentType;
|
||||
private @C.AudioFlags int flags;
|
||||
private @C.AudioUsage int usage;
|
||||
|
||||
/**
|
||||
* Creates a new builder for {@link AudioAttributes}.
|
||||
|
@ -91,14 +88,11 @@ public final class AudioAttributes {
|
|||
|
||||
}
|
||||
|
||||
@C.AudioContentType
|
||||
public final int contentType;
|
||||
@C.AudioFlags
|
||||
public final int flags;
|
||||
@C.AudioUsage
|
||||
public final int usage;
|
||||
public final @C.AudioContentType int contentType;
|
||||
public final @C.AudioFlags int flags;
|
||||
public final @C.AudioUsage int usage;
|
||||
|
||||
private android.media.AudioAttributes audioAttributesV21;
|
||||
private @Nullable android.media.AudioAttributes audioAttributesV21;
|
||||
|
||||
private AudioAttributes(@C.AudioContentType int contentType, @C.AudioFlags int flags,
|
||||
@C.AudioUsage int usage) {
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
|
@ -50,7 +50,7 @@ public final class AudioCapabilities {
|
|||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
/* package */ static AudioCapabilities getCapabilities(Intent intent) {
|
||||
/* package */ static AudioCapabilities getCapabilities(@Nullable Intent intent) {
|
||||
if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) {
|
||||
return DEFAULT_AUDIO_CAPABILITIES;
|
||||
}
|
|
@ -13,15 +13,16 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.media.AudioManager;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
/**
|
||||
* Receives broadcast events indicating changes to the device's audio capabilities, notifying a
|
||||
|
@ -45,9 +46,9 @@ public final class AudioCapabilitiesReceiver {
|
|||
|
||||
private final Context context;
|
||||
private final Listener listener;
|
||||
private final BroadcastReceiver receiver;
|
||||
private final @Nullable BroadcastReceiver receiver;
|
||||
|
||||
/* package */ AudioCapabilities audioCapabilities;
|
||||
/* package */ @Nullable AudioCapabilities audioCapabilities;
|
||||
|
||||
/**
|
||||
* @param context A context for registering the receiver.
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
/** Thrown when an audio decoder error occurs. */
|
||||
public class AudioDecoderException extends Exception {
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
/** A listener for changes in audio configuration. */
|
||||
public interface AudioListener {
|
||||
|
||||
/**
|
||||
* Called when the audio session is set.
|
||||
*
|
||||
* @param audioSessionId The audio session id.
|
||||
*/
|
||||
default void onAudioSessionId(int audioSessionId) {}
|
||||
|
||||
/**
|
||||
* Called when the audio attributes change.
|
||||
*
|
||||
* @param audioAttributes The audio attributes.
|
||||
*/
|
||||
default void onAudioAttributesChanged(AudioAttributes audioAttributes) {}
|
||||
|
||||
/**
|
||||
* Called when the volume changes.
|
||||
*
|
||||
* @param volume The new volume, with 0 being silence and 1 being unity gain.
|
||||
*/
|
||||
default void onVolumeChanged(float volume) {}
|
||||
}
|
|
@ -13,9 +13,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
|
@ -13,16 +13,16 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.Renderer;
|
||||
import org.telegram.messenger.exoplayer2.decoder.DecoderCounters;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.Renderer;
|
||||
import com.google.android.exoplayer2.decoder.DecoderCounters;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
||||
/**
|
||||
* Listener of audio {@link Renderer} events.
|
|
@ -13,12 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.media.AudioTrack;
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
|
@ -13,15 +13,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.media.AudioTimestamp;
|
||||
import android.media.AudioTrack;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
|
@ -13,15 +13,18 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import static com.google.android.exoplayer2.util.Util.castNonNull;
|
||||
|
||||
import android.media.AudioTimestamp;
|
||||
import android.media.AudioTrack;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.IntDef;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -128,10 +131,10 @@ import java.lang.reflect.Method;
|
|||
private final Listener listener;
|
||||
private final long[] playheadOffsets;
|
||||
|
||||
private AudioTrack audioTrack;
|
||||
private @Nullable AudioTrack audioTrack;
|
||||
private int outputPcmFrameSize;
|
||||
private int bufferSize;
|
||||
private AudioTimestampPoller audioTimestampPoller;
|
||||
private @Nullable AudioTimestampPoller audioTimestampPoller;
|
||||
private int outputSampleRate;
|
||||
private boolean needsPassthroughWorkarounds;
|
||||
private long bufferSizeUs;
|
||||
|
@ -139,7 +142,7 @@ import java.lang.reflect.Method;
|
|||
private long smoothedPlayheadOffsetUs;
|
||||
private long lastPlayheadSampleTimeUs;
|
||||
|
||||
private Method getLatencyMethod;
|
||||
private @Nullable Method getLatencyMethod;
|
||||
private long latencyUs;
|
||||
private boolean hasData;
|
||||
|
||||
|
@ -193,7 +196,7 @@ import java.lang.reflect.Method;
|
|||
audioTimestampPoller = new AudioTimestampPoller(audioTrack);
|
||||
outputSampleRate = audioTrack.getSampleRate();
|
||||
needsPassthroughWorkarounds = needsPassthroughWorkarounds(outputEncoding);
|
||||
isOutputPcm = Util.isEncodingPcm(outputEncoding);
|
||||
isOutputPcm = Util.isEncodingLinearPcm(outputEncoding);
|
||||
bufferSizeUs = isOutputPcm ? framesToDurationUs(bufferSize / outputPcmFrameSize) : C.TIME_UNSET;
|
||||
lastRawPlaybackHeadPosition = 0;
|
||||
rawPlaybackHeadWrapCount = 0;
|
||||
|
@ -205,13 +208,14 @@ import java.lang.reflect.Method;
|
|||
}
|
||||
|
||||
public long getCurrentPositionUs(boolean sourceEnded) {
|
||||
if (audioTrack.getPlayState() == PLAYSTATE_PLAYING) {
|
||||
if (Assertions.checkNotNull(this.audioTrack).getPlayState() == PLAYSTATE_PLAYING) {
|
||||
maybeSampleSyncParams();
|
||||
}
|
||||
|
||||
// If the device supports it, use the playback timestamp from AudioTrack.getTimestamp.
|
||||
// Otherwise, derive a smoothed position by sampling the track's frame position.
|
||||
long systemTimeUs = System.nanoTime() / 1000;
|
||||
AudioTimestampPoller audioTimestampPoller = Assertions.checkNotNull(this.audioTimestampPoller);
|
||||
if (audioTimestampPoller.hasTimestamp()) {
|
||||
// Calculate the speed-adjusted position using the timestamp (which may be in the future).
|
||||
long timestampPositionFrames = audioTimestampPoller.getTimestampPositionFrames();
|
||||
|
@ -241,12 +245,12 @@ import java.lang.reflect.Method;
|
|||
|
||||
/** Starts position tracking. Must be called immediately before {@link AudioTrack#play()}. */
|
||||
public void start() {
|
||||
audioTimestampPoller.reset();
|
||||
Assertions.checkNotNull(audioTimestampPoller).reset();
|
||||
}
|
||||
|
||||
/** Returns whether the audio track is in the playing state. */
|
||||
public boolean isPlaying() {
|
||||
return audioTrack.getPlayState() == PLAYSTATE_PLAYING;
|
||||
return Assertions.checkNotNull(audioTrack).getPlayState() == PLAYSTATE_PLAYING;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -257,7 +261,7 @@ import java.lang.reflect.Method;
|
|||
* @return Whether the caller can write data to the track.
|
||||
*/
|
||||
public boolean mayHandleBuffer(long writtenFrames) {
|
||||
@PlayState int playState = audioTrack.getPlayState();
|
||||
@PlayState int playState = Assertions.checkNotNull(audioTrack).getPlayState();
|
||||
if (needsPassthroughWorkarounds) {
|
||||
// An AC-3 audio track continues to play data written while it is paused. Stop writing so its
|
||||
// buffer empties. See [Internal: b/18899620].
|
||||
|
@ -339,7 +343,7 @@ import java.lang.reflect.Method;
|
|||
if (stopTimestampUs == C.TIME_UNSET) {
|
||||
// The audio track is going to be paused, so reset the timestamp poller to ensure it doesn't
|
||||
// supply an advancing position.
|
||||
audioTimestampPoller.reset();
|
||||
Assertions.checkNotNull(audioTimestampPoller).reset();
|
||||
return true;
|
||||
}
|
||||
// We've handled the end of the stream already, so there's no need to pause the track.
|
||||
|
@ -388,6 +392,7 @@ import java.lang.reflect.Method;
|
|||
}
|
||||
|
||||
private void maybePollAndCheckTimestamp(long systemTimeUs, long playbackPositionUs) {
|
||||
AudioTimestampPoller audioTimestampPoller = Assertions.checkNotNull(this.audioTimestampPoller);
|
||||
if (!audioTimestampPoller.maybePollTimestamp(systemTimeUs)) {
|
||||
return;
|
||||
}
|
||||
|
@ -423,7 +428,9 @@ import java.lang.reflect.Method;
|
|||
// Compute the audio track latency, excluding the latency due to the buffer (leaving
|
||||
// latency due to the mixer and audio hardware driver).
|
||||
latencyUs =
|
||||
(Integer) getLatencyMethod.invoke(audioTrack, (Object[]) null) * 1000L - bufferSizeUs;
|
||||
castNonNull((Integer) getLatencyMethod.invoke(Assertions.checkNotNull(audioTrack)))
|
||||
* 1000L
|
||||
- bufferSizeUs;
|
||||
// Sanity check that the latency is non-negative.
|
||||
latencyUs = Math.max(latencyUs, 0);
|
||||
// Sanity check that the latency isn't too large.
|
||||
|
@ -457,7 +464,7 @@ import java.lang.reflect.Method;
|
|||
*/
|
||||
private boolean forceHasPendingData() {
|
||||
return needsPassthroughWorkarounds
|
||||
&& audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED
|
||||
&& Assertions.checkNotNull(audioTrack).getPlayState() == AudioTrack.PLAYSTATE_PAUSED
|
||||
&& getPlaybackHeadPosition() == 0;
|
||||
}
|
||||
|
||||
|
@ -483,6 +490,7 @@ import java.lang.reflect.Method;
|
|||
* @return The playback head position, in frames.
|
||||
*/
|
||||
private long getPlaybackHeadPosition() {
|
||||
AudioTrack audioTrack = Assertions.checkNotNull(this.audioTrack);
|
||||
if (stopTimestampUs != C.TIME_UNSET) {
|
||||
// Simulate the playback head position up to the total number of frames submitted.
|
||||
long elapsedTimeSinceStopUs = (SystemClock.elapsedRealtime() * 1000) - stopTimestampUs;
|
|
@ -13,13 +13,13 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.C.Encoding;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.C.Encoding;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
|
@ -25,10 +25,10 @@ import android.os.SystemClock;
|
|||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.PlaybackParameters;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -371,7 +371,7 @@ public final class DefaultAudioSink implements AudioSink {
|
|||
|
||||
@Override
|
||||
public boolean isEncodingSupported(@C.Encoding int encoding) {
|
||||
if (Util.isEncodingPcm(encoding)) {
|
||||
if (Util.isEncodingLinearPcm(encoding)) {
|
||||
// AudioTrack supports 16-bit integer PCM output in all platform API versions, and float
|
||||
// output from platform API version 21 only. Other integer PCM encodings are resampled by this
|
||||
// sink to 16-bit PCM.
|
||||
|
@ -405,7 +405,7 @@ public final class DefaultAudioSink implements AudioSink {
|
|||
this.inputSampleRate = inputSampleRate;
|
||||
int channelCount = inputChannelCount;
|
||||
int sampleRate = inputSampleRate;
|
||||
isInputPcm = Util.isEncodingPcm(inputEncoding);
|
||||
isInputPcm = Util.isEncodingLinearPcm(inputEncoding);
|
||||
shouldConvertHighResIntPcmToFloat =
|
||||
enableConvertHighResIntPcmToFloat
|
||||
&& isEncodingSupported(C.ENCODING_PCM_32BIT)
|
|
@ -13,12 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmInitData;
|
||||
import org.telegram.messenger.exoplayer2.util.MimeTypes;
|
||||
import org.telegram.messenger.exoplayer2.util.ParsableBitArray;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -74,13 +74,13 @@ public final class DtsUtil {
|
|||
* subsections 5.3/5.4.
|
||||
*
|
||||
* @param frame The DTS frame to parse.
|
||||
* @param trackId The track identifier to set on the format, or null.
|
||||
* @param trackId The track identifier to set on the format.
|
||||
* @param language The language to set on the format.
|
||||
* @param drmInitData {@link DrmInitData} to be included in the format.
|
||||
* @return The DTS format parsed from data in the header.
|
||||
*/
|
||||
public static Format parseDtsFormat(byte[] frame, String trackId, String language,
|
||||
DrmInitData drmInitData) {
|
||||
public static Format parseDtsFormat(
|
||||
byte[] frame, String trackId, String language, DrmInitData drmInitData) {
|
||||
ParsableBitArray frameBits = getNormalizedFrameHeader(frame);
|
||||
frameBits.skipBits(32 + 1 + 5 + 1 + 7 + 14); // SYNC, FTYPE, SHORT, CPF, NBLKS, FSIZE
|
||||
int amode = frameBits.readBits(6);
|
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
|
@ -25,26 +25,28 @@ import android.media.MediaFormat;
|
|||
import android.media.audiofx.Virtualizer;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.ExoPlaybackException;
|
||||
import org.telegram.messenger.exoplayer2.ExoPlayer;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.PlaybackParameters;
|
||||
import org.telegram.messenger.exoplayer2.PlayerMessage.Target;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
|
||||
import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmInitData;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager;
|
||||
import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecInfo;
|
||||
import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecRenderer;
|
||||
import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecSelector;
|
||||
import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
|
||||
import org.telegram.messenger.exoplayer2.mediacodec.MediaFormatUtil;
|
||||
import org.telegram.messenger.exoplayer2.util.MediaClock;
|
||||
import org.telegram.messenger.exoplayer2.util.MimeTypes;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.PlayerMessage.Target;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaFormatUtil;
|
||||
import com.google.android.exoplayer2.util.MediaClock;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Decodes and renders audio using {@link MediaCodec} and an {@link AudioSink}.
|
||||
|
@ -56,7 +58,7 @@ import java.nio.ByteBuffer;
|
|||
* <li>Message with type {@link C#MSG_SET_VOLUME} to set the volume. The message payload should be
|
||||
* a {@link Float} with 0 being silence and 1 being unity gain.
|
||||
* <li>Message with type {@link C#MSG_SET_AUDIO_ATTRIBUTES} to set the audio attributes. The
|
||||
* message payload should be an {@link org.telegram.messenger.exoplayer2.audio.AudioAttributes}
|
||||
* message payload should be an {@link com.google.android.exoplayer2.audio.AudioAttributes}
|
||||
* instance that will configure the underlying audio track.
|
||||
* </ul>
|
||||
*/
|
||||
|
@ -229,7 +231,12 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||
@Nullable Handler eventHandler,
|
||||
@Nullable AudioRendererEventListener eventListener,
|
||||
AudioSink audioSink) {
|
||||
super(C.TRACK_TYPE_AUDIO, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys);
|
||||
super(
|
||||
C.TRACK_TYPE_AUDIO,
|
||||
mediaCodecSelector,
|
||||
drmSessionManager,
|
||||
playClearSamplesWithoutKeys,
|
||||
/* assumedMinimumCodecOperatingRate= */ 44100);
|
||||
this.context = context.getApplicationContext();
|
||||
this.audioSink = audioSink;
|
||||
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
|
||||
|
@ -262,15 +269,21 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||
requiresSecureDecryption |= drmInitData.get(i).requiresSecureDecryption;
|
||||
}
|
||||
}
|
||||
MediaCodecInfo decoderInfo = mediaCodecSelector.getDecoderInfo(mimeType,
|
||||
requiresSecureDecryption);
|
||||
if (decoderInfo == null) {
|
||||
return requiresSecureDecryption && mediaCodecSelector.getDecoderInfo(mimeType, false) != null
|
||||
? FORMAT_UNSUPPORTED_DRM : FORMAT_UNSUPPORTED_SUBTYPE;
|
||||
List<MediaCodecInfo> decoderInfos =
|
||||
mediaCodecSelector.getDecoderInfos(format, requiresSecureDecryption);
|
||||
if (decoderInfos.isEmpty()) {
|
||||
return requiresSecureDecryption
|
||||
&& !mediaCodecSelector
|
||||
.getDecoderInfos(format, /* requiresSecureDecoder= */ false)
|
||||
.isEmpty()
|
||||
? FORMAT_UNSUPPORTED_DRM
|
||||
: FORMAT_UNSUPPORTED_SUBTYPE;
|
||||
}
|
||||
if (!supportsFormatDrm) {
|
||||
return FORMAT_UNSUPPORTED_DRM;
|
||||
}
|
||||
// Check capabilities for the first decoder in the list, which takes priority.
|
||||
MediaCodecInfo decoderInfo = decoderInfos.get(0);
|
||||
// Note: We assume support for unknown sampleRate and channelCount.
|
||||
boolean decoderCapable = Util.SDK_INT < 21
|
||||
|| ((format.sampleRate == Format.NO_VALUE
|
||||
|
@ -282,15 +295,16 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||
}
|
||||
|
||||
@Override
|
||||
protected MediaCodecInfo getDecoderInfo(MediaCodecSelector mediaCodecSelector,
|
||||
Format format, boolean requiresSecureDecoder) throws DecoderQueryException {
|
||||
protected List<MediaCodecInfo> getDecoderInfos(
|
||||
MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder)
|
||||
throws DecoderQueryException {
|
||||
if (allowPassthrough(format.sampleMimeType)) {
|
||||
MediaCodecInfo passthroughDecoderInfo = mediaCodecSelector.getPassthroughDecoderInfo();
|
||||
if (passthroughDecoderInfo != null) {
|
||||
return passthroughDecoderInfo;
|
||||
return Collections.singletonList(passthroughDecoderInfo);
|
||||
}
|
||||
}
|
||||
return super.getDecoderInfo(mediaCodecSelector, format, requiresSecureDecoder);
|
||||
return super.getDecoderInfos(mediaCodecSelector, format, requiresSecureDecoder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -307,13 +321,18 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format,
|
||||
MediaCrypto crypto) {
|
||||
protected void configureCodec(
|
||||
MediaCodecInfo codecInfo,
|
||||
MediaCodec codec,
|
||||
Format format,
|
||||
MediaCrypto crypto,
|
||||
float codecOperatingRate) {
|
||||
codecMaxInputSize = getCodecMaxInputSize(codecInfo, format, getStreamFormats());
|
||||
codecNeedsDiscardChannelsWorkaround = codecNeedsDiscardChannelsWorkaround(codecInfo.name);
|
||||
passthroughEnabled = codecInfo.passthrough;
|
||||
String codecMimeType = codecInfo.mimeType == null ? MimeTypes.AUDIO_RAW : codecInfo.mimeType;
|
||||
MediaFormat mediaFormat = getMediaFormat(format, codecMimeType, codecMaxInputSize);
|
||||
MediaFormat mediaFormat =
|
||||
getMediaFormat(format, codecMimeType, codecMaxInputSize, codecOperatingRate);
|
||||
codec.configure(mediaFormat, /* surface= */ null, crypto, /* flags= */ 0);
|
||||
if (passthroughEnabled) {
|
||||
// Store the input MIME type if we're using the passthrough codec.
|
||||
|
@ -341,6 +360,14 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getCodecOperatingRate(
|
||||
float operatingRate, Format format, Format[] streamFormats) {
|
||||
return format.sampleRate == Format.NO_VALUE
|
||||
? CODEC_OPERATING_RATE_UNSET
|
||||
: (format.sampleRate * operatingRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCodecInitialized(String name, long initializedTimestampMs,
|
||||
long initializationDurationMs) {
|
||||
|
@ -624,10 +651,13 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||
* @param format The format of the media.
|
||||
* @param codecMimeType The MIME type handled by the codec.
|
||||
* @param codecMaxInputSize The maximum input size supported by the codec.
|
||||
* @param codecOperatingRate The codec operating rate, or {@link #CODEC_OPERATING_RATE_UNSET} if
|
||||
* no codec operating rate should be set.
|
||||
* @return The framework media format.
|
||||
*/
|
||||
@SuppressLint("InlinedApi")
|
||||
protected MediaFormat getMediaFormat(Format format, String codecMimeType, int codecMaxInputSize) {
|
||||
protected MediaFormat getMediaFormat(
|
||||
Format format, String codecMimeType, int codecMaxInputSize, float codecOperatingRate) {
|
||||
MediaFormat mediaFormat = new MediaFormat();
|
||||
// Set format parameters that should always be set.
|
||||
mediaFormat.setString(MediaFormat.KEY_MIME, codecMimeType);
|
||||
|
@ -639,6 +669,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||
// Set codec configuration values.
|
||||
if (Util.SDK_INT >= 23) {
|
||||
mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */);
|
||||
if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET) {
|
||||
mediaFormat.setFloat(MediaFormat.KEY_OPERATING_RATE, codecOperatingRate);
|
||||
}
|
||||
}
|
||||
return mediaFormat;
|
||||
}
|
|
@ -13,10 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.support.annotation.IntDef;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.nio.ByteBuffer;
|
|
@ -13,35 +13,36 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.media.audiofx.Virtualizer;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.IntDef;
|
||||
import org.telegram.messenger.exoplayer2.BaseRenderer;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.ExoPlaybackException;
|
||||
import org.telegram.messenger.exoplayer2.ExoPlayer;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.FormatHolder;
|
||||
import org.telegram.messenger.exoplayer2.PlaybackParameters;
|
||||
import org.telegram.messenger.exoplayer2.PlayerMessage.Target;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
|
||||
import org.telegram.messenger.exoplayer2.decoder.DecoderCounters;
|
||||
import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import org.telegram.messenger.exoplayer2.decoder.SimpleDecoder;
|
||||
import org.telegram.messenger.exoplayer2.decoder.SimpleOutputBuffer;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSession;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager;
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaCrypto;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.MediaClock;
|
||||
import org.telegram.messenger.exoplayer2.util.MimeTypes;
|
||||
import org.telegram.messenger.exoplayer2.util.TraceUtil;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.BaseRenderer;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.FormatHolder;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.PlayerMessage.Target;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.decoder.DecoderCounters;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.decoder.SimpleDecoder;
|
||||
import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MediaClock;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.TraceUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
|
@ -55,7 +56,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||
* <li>Message with type {@link C#MSG_SET_VOLUME} to set the volume. The message payload should be
|
||||
* a {@link Float} with 0 being silence and 1 being unity gain.
|
||||
* <li>Message with type {@link C#MSG_SET_AUDIO_ATTRIBUTES} to set the audio attributes. The
|
||||
* message payload should be an {@link org.telegram.messenger.exoplayer2.audio.AudioAttributes}
|
||||
* message payload should be an {@link com.google.android.exoplayer2.audio.AudioAttributes}
|
||||
* instance that will configure the underlying audio track.
|
||||
* </ul>
|
||||
*/
|
||||
|
@ -121,7 +122,9 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||
* @param audioProcessors Optional {@link AudioProcessor}s that will process audio before output.
|
||||
*/
|
||||
public SimpleDecoderAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener,
|
||||
public SimpleDecoderAudioRenderer(
|
||||
@Nullable Handler eventHandler,
|
||||
@Nullable AudioRendererEventListener eventListener,
|
||||
AudioProcessor... audioProcessors) {
|
||||
this(
|
||||
eventHandler,
|
||||
|
@ -139,8 +142,10 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the
|
||||
* default capabilities (no encoded audio passthrough support) should be assumed.
|
||||
*/
|
||||
public SimpleDecoderAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener,
|
||||
AudioCapabilities audioCapabilities) {
|
||||
public SimpleDecoderAudioRenderer(
|
||||
@Nullable Handler eventHandler,
|
||||
@Nullable AudioRendererEventListener eventListener,
|
||||
@Nullable AudioCapabilities audioCapabilities) {
|
||||
this(
|
||||
eventHandler,
|
||||
eventListener,
|
||||
|
@ -164,9 +169,13 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||
* has obtained the keys necessary to decrypt encrypted regions of the media.
|
||||
* @param audioProcessors Optional {@link AudioProcessor}s that will process audio before output.
|
||||
*/
|
||||
public SimpleDecoderAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener,
|
||||
AudioCapabilities audioCapabilities, DrmSessionManager<ExoMediaCrypto> drmSessionManager,
|
||||
boolean playClearSamplesWithoutKeys, AudioProcessor... audioProcessors) {
|
||||
public SimpleDecoderAudioRenderer(
|
||||
@Nullable Handler eventHandler,
|
||||
@Nullable AudioRendererEventListener eventListener,
|
||||
@Nullable AudioCapabilities audioCapabilities,
|
||||
@Nullable DrmSessionManager<ExoMediaCrypto> drmSessionManager,
|
||||
boolean playClearSamplesWithoutKeys,
|
||||
AudioProcessor... audioProcessors) {
|
||||
this(eventHandler, eventListener, drmSessionManager,
|
||||
playClearSamplesWithoutKeys, new DefaultAudioSink(audioCapabilities, audioProcessors));
|
||||
}
|
||||
|
@ -184,8 +193,11 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||
* has obtained the keys necessary to decrypt encrypted regions of the media.
|
||||
* @param audioSink The sink to which audio will be output.
|
||||
*/
|
||||
public SimpleDecoderAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener,
|
||||
DrmSessionManager<ExoMediaCrypto> drmSessionManager, boolean playClearSamplesWithoutKeys,
|
||||
public SimpleDecoderAudioRenderer(
|
||||
@Nullable Handler eventHandler,
|
||||
@Nullable AudioRendererEventListener eventListener,
|
||||
@Nullable DrmSessionManager<ExoMediaCrypto> drmSessionManager,
|
||||
boolean playClearSamplesWithoutKeys,
|
||||
AudioSink audioSink) {
|
||||
super(C.TRACK_TYPE_AUDIO);
|
||||
this.drmSessionManager = drmSessionManager;
|
|
@ -14,9 +14,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -31,60 +31,6 @@ import java.util.Arrays;
|
|||
private static final int MAXIMUM_PITCH = 400;
|
||||
private static final int AMDF_FREQUENCY = 4000;
|
||||
|
||||
private static final int SINC_FILTER_POINTS = 12;
|
||||
private static final int SINC_TABLE_SIZE = 601;
|
||||
|
||||
private static final short sincTable[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, -1, -1, -2, -2, -3, -4, -6, -7, -9, -10, -12, -14,
|
||||
-17, -19, -21, -24, -26, -29, -32, -34, -37, -40, -42, -44, -47, -48, -50,
|
||||
-51, -52, -53, -53, -53, -52, -50, -48, -46, -43, -39, -34, -29, -22, -16,
|
||||
-8, 0, 9, 19, 29, 41, 53, 65, 79, 92, 107, 121, 137, 152, 168, 184, 200,
|
||||
215, 231, 247, 262, 276, 291, 304, 317, 328, 339, 348, 357, 363, 369, 372,
|
||||
374, 375, 373, 369, 363, 355, 345, 332, 318, 300, 281, 259, 234, 208, 178,
|
||||
147, 113, 77, 39, 0, -41, -85, -130, -177, -225, -274, -324, -375, -426,
|
||||
-478, -530, -581, -632, -682, -731, -779, -825, -870, -912, -951, -989,
|
||||
-1023, -1053, -1080, -1104, -1123, -1138, -1149, -1154, -1155, -1151,
|
||||
-1141, -1125, -1105, -1078, -1046, -1007, -963, -913, -857, -796, -728,
|
||||
-655, -576, -492, -403, -309, -210, -107, 0, 111, 225, 342, 462, 584, 708,
|
||||
833, 958, 1084, 1209, 1333, 1455, 1575, 1693, 1807, 1916, 2022, 2122, 2216,
|
||||
2304, 2384, 2457, 2522, 2579, 2625, 2663, 2689, 2706, 2711, 2705, 2687,
|
||||
2657, 2614, 2559, 2491, 2411, 2317, 2211, 2092, 1960, 1815, 1658, 1489,
|
||||
1308, 1115, 912, 698, 474, 241, 0, -249, -506, -769, -1037, -1310, -1586,
|
||||
-1864, -2144, -2424, -2703, -2980, -3254, -3523, -3787, -4043, -4291,
|
||||
-4529, -4757, -4972, -5174, -5360, -5531, -5685, -5819, -5935, -6029,
|
||||
-6101, -6150, -6175, -6175, -6149, -6096, -6015, -5905, -5767, -5599,
|
||||
-5401, -5172, -4912, -4621, -4298, -3944, -3558, -3141, -2693, -2214,
|
||||
-1705, -1166, -597, 0, 625, 1277, 1955, 2658, 3386, 4135, 4906, 5697, 6506,
|
||||
7332, 8173, 9027, 9893, 10769, 11654, 12544, 13439, 14335, 15232, 16128,
|
||||
17019, 17904, 18782, 19649, 20504, 21345, 22170, 22977, 23763, 24527,
|
||||
25268, 25982, 26669, 27327, 27953, 28547, 29107, 29632, 30119, 30569,
|
||||
30979, 31349, 31678, 31964, 32208, 32408, 32565, 32677, 32744, 32767,
|
||||
32744, 32677, 32565, 32408, 32208, 31964, 31678, 31349, 30979, 30569,
|
||||
30119, 29632, 29107, 28547, 27953, 27327, 26669, 25982, 25268, 24527,
|
||||
23763, 22977, 22170, 21345, 20504, 19649, 18782, 17904, 17019, 16128,
|
||||
15232, 14335, 13439, 12544, 11654, 10769, 9893, 9027, 8173, 7332, 6506,
|
||||
5697, 4906, 4135, 3386, 2658, 1955, 1277, 625, 0, -597, -1166, -1705,
|
||||
-2214, -2693, -3141, -3558, -3944, -4298, -4621, -4912, -5172, -5401,
|
||||
-5599, -5767, -5905, -6015, -6096, -6149, -6175, -6175, -6150, -6101,
|
||||
-6029, -5935, -5819, -5685, -5531, -5360, -5174, -4972, -4757, -4529,
|
||||
-4291, -4043, -3787, -3523, -3254, -2980, -2703, -2424, -2144, -1864,
|
||||
-1586, -1310, -1037, -769, -506, -249, 0, 241, 474, 698, 912, 1115, 1308,
|
||||
1489, 1658, 1815, 1960, 2092, 2211, 2317, 2411, 2491, 2559, 2614, 2657,
|
||||
2687, 2705, 2711, 2706, 2689, 2663, 2625, 2579, 2522, 2457, 2384, 2304,
|
||||
2216, 2122, 2022, 1916, 1807, 1693, 1575, 1455, 1333, 1209, 1084, 958, 833,
|
||||
708, 584, 462, 342, 225, 111, 0, -107, -210, -309, -403, -492, -576, -655,
|
||||
-728, -796, -857, -913, -963, -1007, -1046, -1078, -1105, -1125, -1141,
|
||||
-1151, -1155, -1154, -1149, -1138, -1123, -1104, -1080, -1053, -1023, -989,
|
||||
-951, -912, -870, -825, -779, -731, -682, -632, -581, -530, -478, -426,
|
||||
-375, -324, -274, -225, -177, -130, -85, -41, 0, 39, 77, 113, 147, 178,
|
||||
208, 234, 259, 281, 300, 318, 332, 345, 355, 363, 369, 373, 375, 374, 372,
|
||||
369, 363, 357, 348, 339, 328, 317, 304, 291, 276, 262, 247, 231, 215, 200,
|
||||
184, 168, 152, 137, 121, 107, 92, 79, 65, 53, 41, 29, 19, 9, 0, -8, -16,
|
||||
-22, -29, -34, -39, -43, -46, -48, -50, -52, -53, -53, -53, -52, -51, -50,
|
||||
-48, -47, -44, -42, -40, -37, -34, -32, -29, -26, -24, -21, -19, -17, -14,
|
||||
-12, -10, -9, -7, -6, -4, -3, -2, -2, -1, -1, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
private final int inputSampleRateHz;
|
||||
private final int channelCount;
|
||||
private final float speed;
|
||||
|
@ -264,14 +210,14 @@ import java.util.Arrays;
|
|||
return frameCount;
|
||||
}
|
||||
|
||||
private void downSampleInput(short samples[], int position, int skip) {
|
||||
int numSamples = maxRequiredFrameCount / skip;
|
||||
private void downSampleInput(short[] samples, int position, int skip) {
|
||||
// If skip is greater than one, average skip samples together and write them to the down-sample
|
||||
// buffer. If channelCount is greater than one, mix the channels together as we down sample.
|
||||
int frameCount = maxRequiredFrameCount / skip;
|
||||
int samplesPerValue = channelCount * skip;
|
||||
int value;
|
||||
|
||||
position *= channelCount;
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
value = 0;
|
||||
for (int i = 0; i < frameCount; i++) {
|
||||
int value = 0;
|
||||
for (int j = 0; j < samplesPerValue; j++) {
|
||||
value += samples[position + i * samplesPerValue + j];
|
||||
}
|
||||
|
@ -280,23 +226,24 @@ import java.util.Arrays;
|
|||
}
|
||||
}
|
||||
|
||||
private int findPitchPeriodInRange(
|
||||
short samples[],
|
||||
int position,
|
||||
int minPeriod,
|
||||
int maxPeriod)
|
||||
{
|
||||
int bestPeriod = 0, worstPeriod = 255;
|
||||
int minDiff = 1, maxDiff = 0;
|
||||
|
||||
private int findPitchPeriodInRange(short[] samples, int position, int minPeriod, int maxPeriod) {
|
||||
// Find the best frequency match in the range, and given a sample skip multiple. For now, just
|
||||
// find the pitch of the first channel.
|
||||
int bestPeriod = 0;
|
||||
int worstPeriod = 255;
|
||||
int minDiff = 1;
|
||||
int maxDiff = 0;
|
||||
position *= channelCount;
|
||||
for (int period = minPeriod; period <= maxPeriod; period++) {
|
||||
int diff = 0;
|
||||
for (int i = 0; i < period; i++) {
|
||||
short sVal = samples[position + i];
|
||||
short pVal = samples[position + period + i];
|
||||
diff += sVal >= pVal? sVal - pVal : pVal - sVal;
|
||||
diff += Math.abs(sVal - pVal);
|
||||
}
|
||||
// Note that the highest number of samples we add into diff will be less than 256, since we
|
||||
// skip samples. Thus, diff is a 24 bit number, and we can safely multiply by numSamples
|
||||
// without overflow.
|
||||
if (diff * bestPeriod < minDiff * period) {
|
||||
minDiff = diff;
|
||||
bestPeriod = period;
|
||||
|
@ -308,7 +255,6 @@ import java.util.Arrays;
|
|||
}
|
||||
this.minDiff = minDiff / bestPeriod;
|
||||
this.maxDiff = maxDiff / worstPeriod;
|
||||
|
||||
return bestPeriod;
|
||||
}
|
||||
|
||||
|
@ -316,28 +262,7 @@ import java.util.Arrays;
|
|||
* Returns whether the previous pitch period estimate is a better approximation, which can occur
|
||||
* at the abrupt end of voiced words.
|
||||
*/
|
||||
private boolean previousPeriodBetter(int minDiff, int maxDiff, boolean preferNewPeriod) {
|
||||
if (minDiff == 0 || prevPeriod == 0) {
|
||||
return false;
|
||||
}
|
||||
if (preferNewPeriod) {
|
||||
if (maxDiff > minDiff * 3) {
|
||||
// Got a reasonable match this period
|
||||
return false;
|
||||
}
|
||||
if (minDiff * 2 <= prevMinDiff * 3) {
|
||||
// Mismatch is not that much greater this period
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (minDiff <= prevMinDiff) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*private boolean previousPeriodBetter(int minDiff, int maxDiff) {
|
||||
private boolean previousPeriodBetter(int minDiff, int maxDiff) {
|
||||
if (minDiff == 0 || prevPeriod == 0) {
|
||||
return false;
|
||||
}
|
||||
|
@ -350,51 +275,9 @@ import java.util.Arrays;
|
|||
return false;
|
||||
}
|
||||
return true;
|
||||
}*/
|
||||
|
||||
private int findPitchPeriod(short samples[], int position, boolean preferNewPeriod) {
|
||||
int period, retPeriod;
|
||||
int skip = 1;
|
||||
|
||||
int quality = 1;
|
||||
if (inputSampleRateHz > AMDF_FREQUENCY && quality == 0) {
|
||||
skip = inputSampleRateHz / AMDF_FREQUENCY;
|
||||
}
|
||||
if (channelCount == 1 && skip == 1) {
|
||||
period = findPitchPeriodInRange(samples, position, minPeriod, maxPeriod);
|
||||
} else {
|
||||
downSampleInput(samples, position, skip);
|
||||
period = findPitchPeriodInRange(downSampleBuffer, 0, minPeriod / skip,
|
||||
maxPeriod / skip);
|
||||
if (skip != 1) {
|
||||
period *= skip;
|
||||
int minP = period - (skip << 2);
|
||||
int maxP = period + (skip << 2);
|
||||
if (minP < minPeriod) {
|
||||
minP = minPeriod;
|
||||
}
|
||||
if (maxP > maxPeriod) {
|
||||
maxP = maxPeriod;
|
||||
}
|
||||
if (channelCount == 1) {
|
||||
period = findPitchPeriodInRange(samples, position, minP, maxP);
|
||||
} else {
|
||||
downSampleInput(samples, position, 1);
|
||||
period = findPitchPeriodInRange(downSampleBuffer, 0, minP, maxP);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (previousPeriodBetter(minDiff, maxDiff, preferNewPeriod)) {
|
||||
retPeriod = prevPeriod;
|
||||
} else {
|
||||
retPeriod = period;
|
||||
}
|
||||
prevMinDiff = minDiff;
|
||||
prevPeriod = period;
|
||||
return retPeriod;
|
||||
}
|
||||
|
||||
/*private int findPitchPeriod(short[] samples, int position) {
|
||||
private int findPitchPeriod(short[] samples, int position) {
|
||||
// Find the pitch period. This is a critical step, and we may have to try multiple ways to get a
|
||||
// good answer. This version uses AMDF. To improve speed, we down sample by an integer factor
|
||||
// get in the 11 kHz range, and then do it again with a narrower frequency range without down
|
||||
|
@ -433,7 +316,7 @@ import java.util.Arrays;
|
|||
prevMinDiff = minDiff;
|
||||
prevPeriod = period;
|
||||
return retPeriod;
|
||||
}*/
|
||||
}
|
||||
|
||||
private void moveNewSamplesToPitchBuffer(int originalOutputFrameCount) {
|
||||
int frameCount = outputFrameCount - originalOutputFrameCount;
|
||||
|
@ -461,78 +344,6 @@ import java.util.Arrays;
|
|||
pitchFrameCount -= frameCount;
|
||||
}
|
||||
|
||||
private void adjustPitch(int originalNumOutputSamples) {
|
||||
int period, newPeriod, separation;
|
||||
int position = 0;
|
||||
|
||||
if (outputFrameCount == originalNumOutputSamples) {
|
||||
return;
|
||||
}
|
||||
moveNewSamplesToPitchBuffer(originalNumOutputSamples);
|
||||
while (pitchFrameCount - position >= maxRequiredFrameCount) {
|
||||
period = findPitchPeriod(pitchBuffer, position, false);
|
||||
newPeriod = (int) (period / pitch);
|
||||
outputBuffer = ensureSpaceForAdditionalFrames(outputBuffer, outputFrameCount, newPeriod);
|
||||
if (pitch >= 1.0f) {
|
||||
overlapAdd(newPeriod, channelCount, outputBuffer, outputFrameCount, pitchBuffer,
|
||||
position, pitchBuffer, position + period - newPeriod);
|
||||
} else {
|
||||
separation = newPeriod - period;
|
||||
overlapAddWithSeparation(period, channelCount, separation, outputBuffer, outputFrameCount,
|
||||
pitchBuffer, position, pitchBuffer, position);
|
||||
}
|
||||
outputFrameCount += newPeriod;
|
||||
position += period;
|
||||
}
|
||||
removePitchFrames(position);
|
||||
}
|
||||
|
||||
// Aproximate the sinc function times a Hann window from the sinc table.
|
||||
private int findSincCoefficient(int i, int ratio, int width) {
|
||||
int lobePoints = (SINC_TABLE_SIZE - 1) / SINC_FILTER_POINTS;
|
||||
int left = i * lobePoints + (ratio * lobePoints) / width;
|
||||
int right = left + 1;
|
||||
int position = i * lobePoints * width + ratio * lobePoints - left * width;
|
||||
int leftVal = sincTable[left];
|
||||
int rightVal = sincTable[right];
|
||||
|
||||
return ((leftVal * (width - position) + rightVal * position) << 1) / width;
|
||||
}
|
||||
|
||||
// Return 1 if value >= 0, else -1. This represents the sign of value.
|
||||
private int getSign(int value) {
|
||||
return value >= 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
/*private short interpolate(short in[], int inPos, int oldSampleRate, int newSampleRate) {
|
||||
int i;
|
||||
int total = 0;
|
||||
int position = newRatePosition * oldSampleRate;
|
||||
int leftPosition = oldRatePosition * newSampleRate;
|
||||
int rightPosition = (oldRatePosition + 1) * newSampleRate;
|
||||
int ratio = rightPosition - position - 1;
|
||||
int width = rightPosition - leftPosition;
|
||||
int weight, value;
|
||||
int oldSign;
|
||||
int overflowCount = 0;
|
||||
|
||||
for (i = 0; i < SINC_FILTER_POINTS; i++) {
|
||||
weight = findSincCoefficient(i, ratio, width);
|
||||
value = in[inPos + i * channelCount] * weight;
|
||||
oldSign = getSign(total);
|
||||
total += value;
|
||||
if (oldSign != getSign(total) && getSign(value) == oldSign) {
|
||||
overflowCount += oldSign;
|
||||
}
|
||||
}
|
||||
if (overflowCount > 0) {
|
||||
return Short.MAX_VALUE;
|
||||
} else if (overflowCount < 0) {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
return (short) (total >> 16);
|
||||
}*/
|
||||
|
||||
private short interpolate(short[] in, int inPos, int oldSampleRate, int newSampleRate) {
|
||||
short left = in[inPos];
|
||||
short right = in[inPos + channelCount];
|
||||
|
@ -544,26 +355,27 @@ import java.util.Arrays;
|
|||
return (short) ((ratio * left + (width - ratio) * right) / width);
|
||||
}
|
||||
|
||||
private void adjustRate(float rate, int originalNumOutputSamples) {
|
||||
private void adjustRate(float rate, int originalOutputFrameCount) {
|
||||
if (outputFrameCount == originalOutputFrameCount) {
|
||||
return;
|
||||
}
|
||||
int newSampleRate = (int) (inputSampleRateHz / rate);
|
||||
int oldSampleRate = inputSampleRateHz;
|
||||
int position;
|
||||
|
||||
// Set these values to help with the integer math
|
||||
// Set these values to help with the integer math.
|
||||
while (newSampleRate > (1 << 14) || oldSampleRate > (1 << 14)) {
|
||||
newSampleRate >>= 1;
|
||||
oldSampleRate >>= 1;
|
||||
newSampleRate /= 2;
|
||||
oldSampleRate /= 2;
|
||||
}
|
||||
moveNewSamplesToPitchBuffer(originalNumOutputSamples);
|
||||
// Leave at least one pitch sample in the buffer
|
||||
for (position = 0; position < pitchFrameCount - 1; position++) {
|
||||
moveNewSamplesToPitchBuffer(originalOutputFrameCount);
|
||||
// Leave at least one pitch sample in the buffer.
|
||||
for (int position = 0; position < pitchFrameCount - 1; position++) {
|
||||
while ((oldRatePosition + 1) * newSampleRate > newRatePosition * oldSampleRate) {
|
||||
outputBuffer =
|
||||
ensureSpaceForAdditionalFrames(
|
||||
outputBuffer, outputFrameCount, /* additionalFrameCount= */ 1);
|
||||
for (int i = 0; i < channelCount; i++) {
|
||||
outputBuffer[outputFrameCount * channelCount + i] = interpolate(pitchBuffer,
|
||||
position * channelCount + i, oldSampleRate, newSampleRate);
|
||||
outputBuffer[outputFrameCount * channelCount + i] =
|
||||
interpolate(pitchBuffer, position * channelCount + i, oldSampleRate, newSampleRate);
|
||||
}
|
||||
newRatePosition++;
|
||||
outputFrameCount++;
|
||||
|
@ -575,7 +387,7 @@ import java.util.Arrays;
|
|||
newRatePosition = 0;
|
||||
}
|
||||
}
|
||||
removePitchFrames(position);
|
||||
removePitchFrames(pitchFrameCount - 1);
|
||||
}
|
||||
|
||||
private int skipPitchPeriod(short[] samples, int position, float speed, int period) {
|
||||
|
@ -635,49 +447,36 @@ import java.util.Arrays;
|
|||
if (inputFrameCount < maxRequiredFrameCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
int numSamples = inputFrameCount;
|
||||
int position = 0, period, newSamples;
|
||||
|
||||
int frameCount = inputFrameCount;
|
||||
int positionFrames = 0;
|
||||
do {
|
||||
if (remainingInputToCopyFrameCount > 0) {
|
||||
newSamples = copyInputToOutput(position);
|
||||
position += newSamples;
|
||||
positionFrames += copyInputToOutput(positionFrames);
|
||||
} else {
|
||||
period = findPitchPeriod(inputBuffer, position, true);
|
||||
int period = findPitchPeriod(inputBuffer, positionFrames);
|
||||
if (speed > 1.0) {
|
||||
newSamples = skipPitchPeriod(inputBuffer, position, speed, period);
|
||||
position += period + newSamples;
|
||||
positionFrames += period + skipPitchPeriod(inputBuffer, positionFrames, speed, period);
|
||||
} else {
|
||||
newSamples = insertPitchPeriod(inputBuffer, position, speed, period);
|
||||
position += newSamples;
|
||||
positionFrames += insertPitchPeriod(inputBuffer, positionFrames, speed, period);
|
||||
}
|
||||
}
|
||||
} while (position + maxRequiredFrameCount <= numSamples);
|
||||
removeProcessedInputFrames(position);
|
||||
} while (positionFrames + maxRequiredFrameCount <= frameCount);
|
||||
removeProcessedInputFrames(positionFrames);
|
||||
}
|
||||
|
||||
private void processStreamInput() {
|
||||
int originalNumOutputSamples = outputFrameCount;
|
||||
// Resample as many pitch periods as we have buffered on the input.
|
||||
int originalOutputFrameCount = outputFrameCount;
|
||||
float s = speed / pitch;
|
||||
float r = rate;
|
||||
|
||||
boolean useChordPitch = false;
|
||||
if (!useChordPitch) {
|
||||
r *= pitch;
|
||||
}
|
||||
float r = rate * pitch;
|
||||
if (s > 1.00001 || s < 0.99999) {
|
||||
changeSpeed(s);
|
||||
} else {
|
||||
copyToOutput(inputBuffer, 0, inputFrameCount);
|
||||
inputFrameCount = 0;
|
||||
}
|
||||
if (useChordPitch) {
|
||||
if (pitch != 1.0f) {
|
||||
adjustPitch(originalNumOutputSamples);
|
||||
}
|
||||
} else if (r != 1.0f) {
|
||||
adjustRate(r, originalNumOutputSamples);
|
||||
if (r != 1.0f) {
|
||||
adjustRate(r, originalOutputFrameCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -703,35 +502,4 @@ import java.util.Arrays;
|
|||
}
|
||||
}
|
||||
|
||||
private static void overlapAddWithSeparation(
|
||||
int numSamples,
|
||||
int numChannels,
|
||||
int separation,
|
||||
short out[],
|
||||
int outPos,
|
||||
short rampDown[],
|
||||
int rampDownPos,
|
||||
short rampUp[],
|
||||
int rampUpPos)
|
||||
{
|
||||
for(int i = 0; i < numChannels; i++) {
|
||||
int o = outPos*numChannels + i;
|
||||
int u = rampUpPos*numChannels + i;
|
||||
int d = rampDownPos*numChannels + i;
|
||||
for(int t = 0; t < numSamples + separation; t++) {
|
||||
if(t < separation) {
|
||||
out[o] = (short)(rampDown[d]*(numSamples - t)/numSamples);
|
||||
d += numChannels;
|
||||
} else if(t < numSamples) {
|
||||
out[o] = (short)((rampDown[d]*(numSamples - t) + rampUp[u]*(t - separation))/numSamples);
|
||||
d += numChannels;
|
||||
u += numChannels;
|
||||
} else {
|
||||
out[o] = (short)(rampUp[u]*(t - separation)/numSamples);
|
||||
u += numChannels;
|
||||
}
|
||||
o += numChannels;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,14 +13,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.C.Encoding;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.C.Encoding;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
|
@ -13,12 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.audio;
|
||||
package com.google.android.exoplayer2.audio;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.C.Encoding;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.C.Encoding;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
|
@ -13,9 +13,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.decoder;
|
||||
package com.google.android.exoplayer2.decoder;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.C;
|
||||
|
||||
/**
|
||||
* Base class for buffers with flags.
|
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.decoder;
|
||||
package com.google.android.exoplayer2.decoder;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
/**
|
||||
* Compatibility wrapper for {@link android.media.MediaCodec.CryptoInfo}.
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.decoder;
|
||||
package com.google.android.exoplayer2.decoder;
|
||||
|
||||
/**
|
||||
* A media decoder.
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.decoder;
|
||||
package com.google.android.exoplayer2.decoder;
|
||||
|
||||
/**
|
||||
* Maintains decoder event counts, for debugging purposes only.
|
|
@ -13,10 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.decoder;
|
||||
package com.google.android.exoplayer2.decoder;
|
||||
|
||||
import android.support.annotation.IntDef;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.nio.ByteBuffer;
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.decoder;
|
||||
package com.google.android.exoplayer2.decoder;
|
||||
|
||||
/**
|
||||
* Output buffer decoded by a {@link Decoder}.
|
|
@ -13,11 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.decoder;
|
||||
package com.google.android.exoplayer2.decoder;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import java.util.LinkedList;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
/**
|
||||
* Base class for {@link Decoder}s that use their own decode thread.
|
||||
|
@ -28,8 +29,8 @@ public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends Outp
|
|||
private final Thread decodeThread;
|
||||
|
||||
private final Object lock;
|
||||
private final LinkedList<I> queuedInputBuffers;
|
||||
private final LinkedList<O> queuedOutputBuffers;
|
||||
private final ArrayDeque<I> queuedInputBuffers;
|
||||
private final ArrayDeque<O> queuedOutputBuffers;
|
||||
private final I[] availableInputBuffers;
|
||||
private final O[] availableOutputBuffers;
|
||||
|
||||
|
@ -48,8 +49,8 @@ public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends Outp
|
|||
*/
|
||||
protected SimpleDecoder(I[] inputBuffers, O[] outputBuffers) {
|
||||
lock = new Object();
|
||||
queuedInputBuffers = new LinkedList<>();
|
||||
queuedOutputBuffers = new LinkedList<>();
|
||||
queuedInputBuffers = new ArrayDeque<>();
|
||||
queuedOutputBuffers = new ArrayDeque<>();
|
||||
availableInputBuffers = inputBuffers;
|
||||
availableInputBufferCount = inputBuffers.length;
|
||||
for (int i = 0; i < availableInputBufferCount; i++) {
|
||||
|
@ -142,7 +143,7 @@ public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends Outp
|
|||
releaseInputBufferInternal(queuedInputBuffers.removeFirst());
|
||||
}
|
||||
while (!queuedOutputBuffers.isEmpty()) {
|
||||
releaseOutputBufferInternal(queuedOutputBuffers.removeFirst());
|
||||
queuedOutputBuffers.removeFirst().release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,10 +241,10 @@ public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends Outp
|
|||
|
||||
synchronized (lock) {
|
||||
if (flushed) {
|
||||
releaseOutputBufferInternal(outputBuffer);
|
||||
outputBuffer.release();
|
||||
} else if (outputBuffer.isDecodeOnly()) {
|
||||
skippedOutputBufferCount++;
|
||||
releaseOutputBufferInternal(outputBuffer);
|
||||
outputBuffer.release();
|
||||
} else {
|
||||
outputBuffer.skippedOutputBufferCount = skippedOutputBufferCount;
|
||||
skippedOutputBufferCount = 0;
|
||||
|
@ -292,14 +293,13 @@ public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends Outp
|
|||
* Decodes the {@code inputBuffer} and stores any decoded output in {@code outputBuffer}.
|
||||
*
|
||||
* @param inputBuffer The buffer to decode.
|
||||
* @param outputBuffer The output buffer to store decoded data. The flag
|
||||
* {@link C#BUFFER_FLAG_DECODE_ONLY} will be set if the same flag is set on
|
||||
* {@code inputBuffer}, but may be set/unset as required. If the flag is set when the call
|
||||
* returns then the output buffer will not be made available to dequeue. The output buffer
|
||||
* may not have been populated in this case.
|
||||
* @param outputBuffer The output buffer to store decoded data. The flag {@link
|
||||
* C#BUFFER_FLAG_DECODE_ONLY} will be set if the same flag is set on {@code inputBuffer}, but
|
||||
* may be set/unset as required. If the flag is set when the call returns then the output
|
||||
* buffer will not be made available to dequeue. The output buffer may not have been populated
|
||||
* in this case.
|
||||
* @param reset Whether the decoder must be reset before decoding.
|
||||
* @return A decoder exception if an error occurred, or null if decoding was successful.
|
||||
*/
|
||||
protected abstract E decode(I inputBuffer, O outputBuffer, boolean reset);
|
||||
|
||||
protected abstract @Nullable E decode(I inputBuffer, O outputBuffer, boolean reset);
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.decoder;
|
||||
package com.google.android.exoplayer2.decoder;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
|
@ -13,10 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.util.Log;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
/**
|
||||
* Thrown when a non-platform component fails to decrypt data.
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
|
@ -22,13 +22,14 @@ import android.os.Handler;
|
|||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionEventListener.EventDispatcher;
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.DefaultKeyRequest;
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.KeyRequest;
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
|
||||
import com.google.android.exoplayer2.util.EventDispatcher;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -77,11 +78,10 @@ import java.util.UUID;
|
|||
|
||||
private final ExoMediaDrm<T> mediaDrm;
|
||||
private final ProvisioningManager<T> provisioningManager;
|
||||
private final byte[] initData;
|
||||
private final String mimeType;
|
||||
private final SchemeData schemeData;
|
||||
private final @DefaultDrmSessionManager.Mode int mode;
|
||||
private final HashMap<String, String> optionalKeyRequestParameters;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
|
||||
private final int initialDrmRequestRetryCount;
|
||||
|
||||
/* package */ final MediaDrmCallback callback;
|
||||
|
@ -97,15 +97,20 @@ import java.util.UUID;
|
|||
private byte[] sessionId;
|
||||
private byte[] offlineLicenseKeySetId;
|
||||
|
||||
private Object currentKeyRequest;
|
||||
private Object currentProvisionRequest;
|
||||
|
||||
/**
|
||||
* Instantiates a new DRM session.
|
||||
*
|
||||
* @param uuid The UUID of the drm scheme.
|
||||
* @param mediaDrm The media DRM.
|
||||
* @param provisioningManager The manager for provisioning.
|
||||
* @param initData The DRM init data.
|
||||
* @param schemeData The DRM data for this session, or null if a {@code offlineLicenseKeySetId} is
|
||||
* provided.
|
||||
* @param mode The DRM mode.
|
||||
* @param offlineLicenseKeySetId The offlineLicense KeySetId.
|
||||
* @param offlineLicenseKeySetId The offline license key set identifier, or null when not using
|
||||
* offline keys.
|
||||
* @param optionalKeyRequestParameters The optional key request parameters.
|
||||
* @param callback The media DRM callback.
|
||||
* @param playbackLooper The playback looper.
|
||||
|
@ -117,20 +122,20 @@ import java.util.UUID;
|
|||
UUID uuid,
|
||||
ExoMediaDrm<T> mediaDrm,
|
||||
ProvisioningManager<T> provisioningManager,
|
||||
byte[] initData,
|
||||
String mimeType,
|
||||
@Nullable SchemeData schemeData,
|
||||
@DefaultDrmSessionManager.Mode int mode,
|
||||
byte[] offlineLicenseKeySetId,
|
||||
@Nullable byte[] offlineLicenseKeySetId,
|
||||
HashMap<String, String> optionalKeyRequestParameters,
|
||||
MediaDrmCallback callback,
|
||||
Looper playbackLooper,
|
||||
EventDispatcher eventDispatcher,
|
||||
EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher,
|
||||
int initialDrmRequestRetryCount) {
|
||||
this.uuid = uuid;
|
||||
this.provisioningManager = provisioningManager;
|
||||
this.mediaDrm = mediaDrm;
|
||||
this.mode = mode;
|
||||
this.offlineLicenseKeySetId = offlineLicenseKeySetId;
|
||||
this.schemeData = offlineLicenseKeySetId == null ? schemeData : null;
|
||||
this.optionalKeyRequestParameters = optionalKeyRequestParameters;
|
||||
this.callback = callback;
|
||||
this.initialDrmRequestRetryCount = initialDrmRequestRetryCount;
|
||||
|
@ -141,14 +146,6 @@ import java.util.UUID;
|
|||
requestHandlerThread = new HandlerThread("DrmRequestHandler");
|
||||
requestHandlerThread.start();
|
||||
postRequestHandler = new PostRequestHandler(requestHandlerThread.getLooper());
|
||||
|
||||
if (offlineLicenseKeySetId == null) {
|
||||
this.initData = initData;
|
||||
this.mimeType = mimeType;
|
||||
} else {
|
||||
this.initData = null;
|
||||
this.mimeType = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Life cycle.
|
||||
|
@ -177,6 +174,8 @@ import java.util.UUID;
|
|||
requestHandlerThread = null;
|
||||
mediaCrypto = null;
|
||||
lastException = null;
|
||||
currentKeyRequest = null;
|
||||
currentProvisionRequest = null;
|
||||
if (sessionId != null) {
|
||||
mediaDrm.closeSession(sessionId);
|
||||
sessionId = null;
|
||||
|
@ -187,18 +186,42 @@ import java.util.UUID;
|
|||
}
|
||||
|
||||
public boolean hasInitData(byte[] initData) {
|
||||
return Arrays.equals(this.initData, initData);
|
||||
return Arrays.equals(schemeData != null ? schemeData.data : null, initData);
|
||||
}
|
||||
|
||||
public boolean hasSessionId(byte[] sessionId) {
|
||||
return Arrays.equals(this.sessionId, sessionId);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void onMediaDrmEvent(int what) {
|
||||
if (!isOpen()) {
|
||||
return;
|
||||
}
|
||||
switch (what) {
|
||||
case ExoMediaDrm.EVENT_KEY_REQUIRED:
|
||||
doLicense(false);
|
||||
break;
|
||||
case ExoMediaDrm.EVENT_KEY_EXPIRED:
|
||||
// When an already expired key is loaded MediaDrm sends this event immediately. Ignore
|
||||
// this event if the state isn't STATE_OPENED_WITH_KEYS yet which means we're still
|
||||
// waiting for key response.
|
||||
onKeysExpired();
|
||||
break;
|
||||
case ExoMediaDrm.EVENT_PROVISION_REQUIRED:
|
||||
state = STATE_OPENED;
|
||||
provisioningManager.provisionRequired(this);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Provisioning implementation.
|
||||
|
||||
public void provision() {
|
||||
ProvisionRequest request = mediaDrm.getProvisionRequest();
|
||||
postRequestHandler.obtainMessage(MSG_PROVISION, request, true).sendToTarget();
|
||||
currentProvisionRequest = mediaDrm.getProvisionRequest();
|
||||
postRequestHandler.post(MSG_PROVISION, currentProvisionRequest, /* allowRetry= */ true);
|
||||
}
|
||||
|
||||
public void onProvisionCompleted() {
|
||||
|
@ -271,11 +294,12 @@ import java.util.UUID;
|
|||
return false;
|
||||
}
|
||||
|
||||
private void onProvisionResponse(Object response) {
|
||||
if (state != STATE_OPENING && !isOpen()) {
|
||||
private void onProvisionResponse(Object request, Object response) {
|
||||
if (request != currentProvisionRequest || (state != STATE_OPENING && !isOpen())) {
|
||||
// This event is stale.
|
||||
return;
|
||||
}
|
||||
currentProvisionRequest = null;
|
||||
|
||||
if (response instanceof Exception) {
|
||||
provisioningManager.onProvisionError((Exception) response);
|
||||
|
@ -309,7 +333,7 @@ import java.util.UUID;
|
|||
onError(new KeysExpiredException());
|
||||
} else {
|
||||
state = STATE_OPENED_WITH_KEYS;
|
||||
eventDispatcher.drmKeysRestored();
|
||||
eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysRestored);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -356,24 +380,30 @@ import java.util.UUID;
|
|||
|
||||
private void postKeyRequest(int type, boolean allowRetry) {
|
||||
byte[] scope = type == ExoMediaDrm.KEY_TYPE_RELEASE ? offlineLicenseKeySetId : sessionId;
|
||||
try {
|
||||
KeyRequest request = mediaDrm.getKeyRequest(scope, initData, mimeType, type,
|
||||
optionalKeyRequestParameters);
|
||||
if (C.CLEARKEY_UUID.equals(uuid)) {
|
||||
request = new DefaultKeyRequest(ClearKeyUtil.adjustRequestData(request.getData()),
|
||||
request.getDefaultUrl());
|
||||
byte[] initData = null;
|
||||
String mimeType = null;
|
||||
String licenseServerUrl = null;
|
||||
if (schemeData != null) {
|
||||
initData = schemeData.data;
|
||||
mimeType = schemeData.mimeType;
|
||||
licenseServerUrl = schemeData.licenseServerUrl;
|
||||
}
|
||||
postRequestHandler.obtainMessage(MSG_KEYS, request, allowRetry).sendToTarget();
|
||||
try {
|
||||
KeyRequest mediaDrmKeyRequest =
|
||||
mediaDrm.getKeyRequest(scope, initData, mimeType, type, optionalKeyRequestParameters);
|
||||
currentKeyRequest = Pair.create(mediaDrmKeyRequest, licenseServerUrl);
|
||||
postRequestHandler.post(MSG_KEYS, currentKeyRequest, allowRetry);
|
||||
} catch (Exception e) {
|
||||
onKeysError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void onKeyResponse(Object response) {
|
||||
if (!isOpen()) {
|
||||
private void onKeyResponse(Object request, Object response) {
|
||||
if (request != currentKeyRequest || !isOpen()) {
|
||||
// This event is stale.
|
||||
return;
|
||||
}
|
||||
currentKeyRequest = null;
|
||||
|
||||
if (response instanceof Exception) {
|
||||
onKeysError((Exception) response);
|
||||
|
@ -382,12 +412,9 @@ import java.util.UUID;
|
|||
|
||||
try {
|
||||
byte[] responseData = (byte[]) response;
|
||||
if (C.CLEARKEY_UUID.equals(uuid)) {
|
||||
responseData = ClearKeyUtil.adjustResponseData(responseData);
|
||||
}
|
||||
if (mode == DefaultDrmSessionManager.MODE_RELEASE) {
|
||||
mediaDrm.provideKeyResponse(offlineLicenseKeySetId, responseData);
|
||||
eventDispatcher.drmKeysRemoved();
|
||||
eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysRestored);
|
||||
} else {
|
||||
byte[] keySetId = mediaDrm.provideKeyResponse(sessionId, responseData);
|
||||
if ((mode == DefaultDrmSessionManager.MODE_DOWNLOAD
|
||||
|
@ -396,7 +423,7 @@ import java.util.UUID;
|
|||
offlineLicenseKeySetId = keySetId;
|
||||
}
|
||||
state = STATE_OPENED_WITH_KEYS;
|
||||
eventDispatcher.drmKeysLoaded();
|
||||
eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysLoaded);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
onKeysError(e);
|
||||
|
@ -420,7 +447,7 @@ import java.util.UUID;
|
|||
|
||||
private void onError(final Exception e) {
|
||||
lastException = new DrmSessionException(e);
|
||||
eventDispatcher.drmSessionManagerError(e);
|
||||
eventDispatcher.dispatch(listener -> listener.onDrmSessionManagerError(e));
|
||||
if (state != STATE_OPENED_WITH_KEYS) {
|
||||
state = STATE_ERROR;
|
||||
}
|
||||
|
@ -430,30 +457,7 @@ import java.util.UUID;
|
|||
return state == STATE_OPENED || state == STATE_OPENED_WITH_KEYS;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void onMediaDrmEvent(int what) {
|
||||
if (!isOpen()) {
|
||||
return;
|
||||
}
|
||||
switch (what) {
|
||||
case ExoMediaDrm.EVENT_KEY_REQUIRED:
|
||||
doLicense(false);
|
||||
break;
|
||||
case ExoMediaDrm.EVENT_KEY_EXPIRED:
|
||||
// When an already expired key is loaded MediaDrm sends this event immediately. Ignore
|
||||
// this event if the state isn't STATE_OPENED_WITH_KEYS yet which means we're still
|
||||
// waiting for key response.
|
||||
onKeysExpired();
|
||||
break;
|
||||
case ExoMediaDrm.EVENT_PROVISION_REQUIRED:
|
||||
state = STATE_OPENED;
|
||||
provisioningManager.provisionRequired(this);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
// Internal classes.
|
||||
|
||||
@SuppressLint("HandlerLeak")
|
||||
private class PostResponseHandler extends Handler {
|
||||
|
@ -464,12 +468,15 @@ import java.util.UUID;
|
|||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
Pair<?, ?> requestAndResponse = (Pair<?, ?>) msg.obj;
|
||||
Object request = requestAndResponse.first;
|
||||
Object response = requestAndResponse.second;
|
||||
switch (msg.what) {
|
||||
case MSG_PROVISION:
|
||||
onProvisionResponse(msg.obj);
|
||||
onProvisionResponse(request, response);
|
||||
break;
|
||||
case MSG_KEYS:
|
||||
onKeyResponse(msg.obj);
|
||||
onKeyResponse(request, response);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -486,21 +493,27 @@ import java.util.UUID;
|
|||
super(backgroundLooper);
|
||||
}
|
||||
|
||||
Message obtainMessage(int what, Object object, boolean allowRetry) {
|
||||
return obtainMessage(what, allowRetry ? 1 : 0 /* allow retry*/, 0 /* error count */,
|
||||
object);
|
||||
void post(int what, Object request, boolean allowRetry) {
|
||||
int allowRetryInt = allowRetry ? 1 : 0;
|
||||
int errorCount = 0;
|
||||
obtainMessage(what, allowRetryInt, errorCount, request).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void handleMessage(Message msg) {
|
||||
Object request = msg.obj;
|
||||
Object response;
|
||||
try {
|
||||
switch (msg.what) {
|
||||
case MSG_PROVISION:
|
||||
response = callback.executeProvisionRequest(uuid, (ProvisionRequest) msg.obj);
|
||||
response = callback.executeProvisionRequest(uuid, (ProvisionRequest) request);
|
||||
break;
|
||||
case MSG_KEYS:
|
||||
response = callback.executeKeyRequest(uuid, (KeyRequest) msg.obj);
|
||||
Pair<KeyRequest, String> keyRequest = (Pair<KeyRequest, String>) request;
|
||||
KeyRequest mediaDrmKeyRequest = keyRequest.first;
|
||||
String licenseServerUrl = keyRequest.second;
|
||||
response = callback.executeKeyRequest(uuid, mediaDrmKeyRequest, licenseServerUrl);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
|
@ -511,7 +524,7 @@ import java.util.UUID;
|
|||
}
|
||||
response = e;
|
||||
}
|
||||
postResponseHandler.obtainMessage(msg.what, response).sendToTarget();
|
||||
postResponseHandler.obtainMessage(msg.what, Pair.create(request, response)).sendToTarget();
|
||||
}
|
||||
|
||||
private boolean maybeRetryRequest(Message originalMsg) {
|
||||
|
@ -534,5 +547,4 @@ import java.util.UUID;
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import com.google.android.exoplayer2.Player;
|
||||
|
||||
/** Listener of {@link DefaultDrmSessionManager} events. */
|
||||
public interface DefaultDrmSessionEventListener {
|
||||
|
||||
/** Called each time keys are loaded. */
|
||||
void onDrmKeysLoaded();
|
||||
|
||||
/**
|
||||
* Called when a drm error occurs.
|
||||
*
|
||||
* <p>This method being called does not indicate that playback has failed, or that it will fail.
|
||||
* The player may be able to recover from the error and continue. Hence applications should
|
||||
* <em>not</em> implement this method to display a user visible error or initiate an application
|
||||
* level retry ({@link Player.EventListener#onPlayerError} is the appropriate place to implement
|
||||
* such behavior). This method is called to provide the application with an opportunity to log the
|
||||
* error if it wishes to do so.
|
||||
*
|
||||
* @param error The corresponding exception.
|
||||
*/
|
||||
void onDrmSessionManagerError(Exception error);
|
||||
|
||||
/** Called each time offline keys are restored. */
|
||||
void onDrmKeysRestored();
|
||||
|
||||
/** Called each time offline keys are removed. */
|
||||
void onDrmKeysRemoved();
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
|
@ -24,16 +24,15 @@ import android.support.annotation.IntDef;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSession.ProvisioningManager;
|
||||
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionEventListener.EventDispatcher;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.OnEventListener;
|
||||
import org.telegram.messenger.exoplayer2.extractor.mp4.PsshAtomUtil;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.MimeTypes;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DefaultDrmSession.ProvisioningManager;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.OnEventListener;
|
||||
import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.EventDispatcher;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
|
@ -89,13 +88,12 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
|||
public static final int INITIAL_DRM_REQUEST_RETRY_COUNT = 3;
|
||||
|
||||
private static final String TAG = "DefaultDrmSessionMgr";
|
||||
private static final String CENC_SCHEME_MIME_TYPE = "cenc";
|
||||
|
||||
private final UUID uuid;
|
||||
private final ExoMediaDrm<T> mediaDrm;
|
||||
private final MediaDrmCallback callback;
|
||||
private final HashMap<String, String> optionalKeyRequestParameters;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
|
||||
private final boolean multiSession;
|
||||
private final int initialDrmRequestRetryCount;
|
||||
|
||||
|
@ -356,7 +354,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
|||
this.mediaDrm = mediaDrm;
|
||||
this.callback = callback;
|
||||
this.optionalKeyRequestParameters = optionalKeyRequestParameters;
|
||||
this.eventDispatcher = new EventDispatcher();
|
||||
this.eventDispatcher = new EventDispatcher<>();
|
||||
this.multiSession = multiSession;
|
||||
this.initialDrmRequestRetryCount = initialDrmRequestRetryCount;
|
||||
mode = MODE_PLAYBACK;
|
||||
|
@ -509,17 +507,14 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
|||
}
|
||||
}
|
||||
|
||||
byte[] initData = null;
|
||||
String mimeType = null;
|
||||
SchemeData schemeData = null;
|
||||
if (offlineLicenseKeySetId == null) {
|
||||
SchemeData data = getSchemeData(drmInitData, uuid, false);
|
||||
if (data == null) {
|
||||
schemeData = getSchemeData(drmInitData, uuid, false);
|
||||
if (schemeData == null) {
|
||||
final MissingSchemeDataException error = new MissingSchemeDataException(uuid);
|
||||
eventDispatcher.drmSessionManagerError(error);
|
||||
eventDispatcher.dispatch(listener -> listener.onDrmSessionManagerError(error));
|
||||
return new ErrorStateDrmSession<>(new DrmSessionException(error));
|
||||
}
|
||||
initData = getSchemeInitData(data, uuid);
|
||||
mimeType = getSchemeMimeType(data, uuid);
|
||||
}
|
||||
|
||||
DefaultDrmSession<T> session;
|
||||
|
@ -528,6 +523,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
|||
} else {
|
||||
// Only use an existing session if it has matching init data.
|
||||
session = null;
|
||||
byte[] initData = schemeData != null ? schemeData.data : null;
|
||||
for (DefaultDrmSession<T> existingSession : sessions) {
|
||||
if (existingSession.hasInitData(initData)) {
|
||||
session = existingSession;
|
||||
|
@ -543,8 +539,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
|||
uuid,
|
||||
mediaDrm,
|
||||
this,
|
||||
initData,
|
||||
mimeType,
|
||||
schemeData,
|
||||
mode,
|
||||
offlineLicenseKeySetId,
|
||||
optionalKeyRequestParameters,
|
||||
|
@ -650,31 +645,6 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
|||
return matchingSchemeDatas.get(0);
|
||||
}
|
||||
|
||||
private static byte[] getSchemeInitData(SchemeData data, UUID uuid) {
|
||||
byte[] schemeInitData = data.data;
|
||||
if (Util.SDK_INT < 21) {
|
||||
// Prior to L the Widevine CDM required data to be extracted from the PSSH atom.
|
||||
byte[] psshData = PsshAtomUtil.parseSchemeSpecificData(schemeInitData, uuid);
|
||||
if (psshData == null) {
|
||||
// Extraction failed. schemeData isn't a Widevine PSSH atom, so leave it unchanged.
|
||||
} else {
|
||||
schemeInitData = psshData;
|
||||
}
|
||||
}
|
||||
return schemeInitData;
|
||||
}
|
||||
|
||||
private static String getSchemeMimeType(SchemeData data, UUID uuid) {
|
||||
String schemeMimeType = data.mimeType;
|
||||
if (Util.SDK_INT < 26 && C.CLEARKEY_UUID.equals(uuid)
|
||||
&& (MimeTypes.VIDEO_MP4.equals(schemeMimeType)
|
||||
|| MimeTypes.AUDIO_MP4.equals(schemeMimeType))) {
|
||||
// Prior to API level 26 the ClearKey CDM only accepted "cenc" as the scheme for MP4.
|
||||
schemeMimeType = CENC_SCHEME_MIME_TYPE;
|
||||
}
|
||||
return schemeMimeType;
|
||||
}
|
||||
|
||||
@SuppressLint("HandlerLeak")
|
||||
private class MediaDrmHandler extends Handler {
|
||||
|
|
@ -13,15 +13,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
@ -266,9 +266,9 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
|||
* applies to all schemes).
|
||||
*/
|
||||
private final UUID uuid;
|
||||
/**
|
||||
* The mimeType of {@link #data}.
|
||||
*/
|
||||
/** The URL of the server to which license requests should be made. May be null if unknown. */
|
||||
public final @Nullable String licenseServerUrl;
|
||||
/** The mimeType of {@link #data}. */
|
||||
public final String mimeType;
|
||||
/**
|
||||
* The initialization data. May be null for scheme support checks only.
|
||||
|
@ -297,7 +297,25 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
|||
* @param requiresSecureDecryption See {@link #requiresSecureDecryption}.
|
||||
*/
|
||||
public SchemeData(UUID uuid, String mimeType, byte[] data, boolean requiresSecureDecryption) {
|
||||
this(uuid, /* licenseServerUrl= */ null, mimeType, data, requiresSecureDecryption);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uuid The {@link UUID} of the DRM scheme, or {@link C#UUID_NIL} if the data is
|
||||
* universal (i.e. applies to all schemes).
|
||||
* @param licenseServerUrl See {@link #licenseServerUrl}.
|
||||
* @param mimeType See {@link #mimeType}.
|
||||
* @param data See {@link #data}.
|
||||
* @param requiresSecureDecryption See {@link #requiresSecureDecryption}.
|
||||
*/
|
||||
public SchemeData(
|
||||
UUID uuid,
|
||||
@Nullable String licenseServerUrl,
|
||||
String mimeType,
|
||||
byte[] data,
|
||||
boolean requiresSecureDecryption) {
|
||||
this.uuid = Assertions.checkNotNull(uuid);
|
||||
this.licenseServerUrl = licenseServerUrl;
|
||||
this.mimeType = Assertions.checkNotNull(mimeType);
|
||||
this.data = data;
|
||||
this.requiresSecureDecryption = requiresSecureDecryption;
|
||||
|
@ -305,6 +323,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
|||
|
||||
/* package */ SchemeData(Parcel in) {
|
||||
uuid = new UUID(in.readLong(), in.readLong());
|
||||
licenseServerUrl = in.readString();
|
||||
mimeType = in.readString();
|
||||
data = in.createByteArray();
|
||||
requiresSecureDecryption = in.readByte() != 0;
|
||||
|
@ -346,7 +365,9 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
|||
return true;
|
||||
}
|
||||
SchemeData other = (SchemeData) obj;
|
||||
return mimeType.equals(other.mimeType) && Util.areEqual(uuid, other.uuid)
|
||||
return Util.areEqual(licenseServerUrl, other.licenseServerUrl)
|
||||
&& Util.areEqual(mimeType, other.mimeType)
|
||||
&& Util.areEqual(uuid, other.uuid)
|
||||
&& Arrays.equals(data, other.data);
|
||||
}
|
||||
|
||||
|
@ -354,6 +375,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
|||
public int hashCode() {
|
||||
if (hashCode == 0) {
|
||||
int result = uuid.hashCode();
|
||||
result = 31 * result + (licenseServerUrl == null ? 0 : licenseServerUrl.hashCode());
|
||||
result = 31 * result + mimeType.hashCode();
|
||||
result = 31 * result + Arrays.hashCode(data);
|
||||
hashCode = result;
|
||||
|
@ -372,6 +394,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
|||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(uuid.getMostSignificantBits());
|
||||
dest.writeLong(uuid.getLeastSignificantBits());
|
||||
dest.writeString(licenseServerUrl);
|
||||
dest.writeString(mimeType);
|
||||
dest.writeByteArray(data);
|
||||
dest.writeByte((byte) (requiresSecureDecryption ? 1 : 0));
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.media.MediaDrm;
|
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Looper;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
|
||||
/**
|
||||
* Manages a DRM session.
|
|
@ -13,9 +13,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.util.Map;
|
||||
|
||||
/** A {@link DrmSession} that's in a terminal error state. */
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
/**
|
||||
* An opaque {@link android.media.MediaCrypto} equivalent.
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.media.DeniedByServerException;
|
||||
import android.media.MediaCryptoException;
|
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.media.MediaCrypto;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
||||
/**
|
||||
* An {@link ExoMediaCrypto} implementation that wraps the framework {@link MediaCrypto}.
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.media.DeniedByServerException;
|
||||
|
@ -25,9 +25,11 @@ import android.media.NotProvisionedException;
|
|||
import android.media.UnsupportedSchemeException;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -40,6 +42,8 @@ import java.util.UUID;
|
|||
@TargetApi(23)
|
||||
public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto> {
|
||||
|
||||
private static final String CENC_SCHEME_MIME_TYPE = "cenc";
|
||||
|
||||
private final UUID uuid;
|
||||
private final MediaDrm mediaDrm;
|
||||
|
||||
|
@ -67,6 +71,9 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
|
|||
uuid = Util.SDK_INT < 27 && C.CLEARKEY_UUID.equals(uuid) ? C.COMMON_PSSH_UUID : uuid;
|
||||
this.uuid = uuid;
|
||||
this.mediaDrm = new MediaDrm(uuid);
|
||||
if (C.WIDEVINE_UUID.equals(uuid) && needsForceL3Workaround()) {
|
||||
mediaDrm.setPropertyString("securityLevel", "L3");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -116,14 +123,49 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
|
|||
@Override
|
||||
public KeyRequest getKeyRequest(byte[] scope, byte[] init, String mimeType, int keyType,
|
||||
HashMap<String, String> optionalParameters) throws NotProvisionedException {
|
||||
|
||||
// Prior to L the Widevine CDM required data to be extracted from the PSSH atom. Some Amazon
|
||||
// devices also required data to be extracted from the PSSH atom for PlayReady.
|
||||
if ((Util.SDK_INT < 21 && C.WIDEVINE_UUID.equals(uuid))
|
||||
|| (C.PLAYREADY_UUID.equals(uuid)
|
||||
&& "Amazon".equals(Util.MANUFACTURER)
|
||||
&& ("AFTB".equals(Util.MODEL) // Fire TV Gen 1
|
||||
|| "AFTS".equals(Util.MODEL) // Fire TV Gen 2
|
||||
|| "AFTM".equals(Util.MODEL)))) { // Fire TV Stick Gen 1
|
||||
byte[] psshData = PsshAtomUtil.parseSchemeSpecificData(init, uuid);
|
||||
if (psshData == null) {
|
||||
// Extraction failed. schemeData isn't a PSSH atom, so leave it unchanged.
|
||||
} else {
|
||||
init = psshData;
|
||||
}
|
||||
}
|
||||
|
||||
// Prior to API level 26 the ClearKey CDM only accepted "cenc" as the scheme for MP4.
|
||||
if (Util.SDK_INT < 26
|
||||
&& C.CLEARKEY_UUID.equals(uuid)
|
||||
&& (MimeTypes.VIDEO_MP4.equals(mimeType) || MimeTypes.AUDIO_MP4.equals(mimeType))) {
|
||||
mimeType = CENC_SCHEME_MIME_TYPE;
|
||||
}
|
||||
|
||||
final MediaDrm.KeyRequest request = mediaDrm.getKeyRequest(scope, init, mimeType, keyType,
|
||||
optionalParameters);
|
||||
return new DefaultKeyRequest(request.getData(), request.getDefaultUrl());
|
||||
|
||||
byte[] requestData = request.getData();
|
||||
if (C.CLEARKEY_UUID.equals(uuid)) {
|
||||
requestData = ClearKeyUtil.adjustRequestData(requestData);
|
||||
}
|
||||
|
||||
return new DefaultKeyRequest(requestData, request.getDefaultUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] provideKeyResponse(byte[] scope, byte[] response)
|
||||
throws NotProvisionedException, DeniedByServerException {
|
||||
|
||||
if (C.CLEARKEY_UUID.equals(uuid)) {
|
||||
response = ClearKeyUtil.adjustResponseData(response);
|
||||
}
|
||||
|
||||
return mediaDrm.provideKeyResponse(scope, response);
|
||||
}
|
||||
|
||||
|
@ -183,4 +225,12 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
|
|||
forceAllowInsecureDecoderComponents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the device codec is known to fail if security level L1 is used.
|
||||
*
|
||||
* <p>See <a href="https://github.com/google/ExoPlayer/issues/4413">GitHub issue #4413</a>.
|
||||
*/
|
||||
private static boolean needsForceL3Workaround() {
|
||||
return "ASUS_Z00AD".equals(Util.MODEL);
|
||||
}
|
||||
}
|
|
@ -13,20 +13,21 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.KeyRequest;
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
|
||||
import org.telegram.messenger.exoplayer2.upstream.DataSourceInputStream;
|
||||
import org.telegram.messenger.exoplayer2.upstream.DataSpec;
|
||||
import org.telegram.messenger.exoplayer2.upstream.HttpDataSource;
|
||||
import org.telegram.messenger.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import org.telegram.messenger.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
|
||||
import com.google.android.exoplayer2.upstream.DataSourceInputStream;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -108,13 +109,19 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback {
|
|||
|
||||
@Override
|
||||
public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws IOException {
|
||||
String url = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData());
|
||||
String url =
|
||||
request.getDefaultUrl() + "&signedRequest=" + Util.fromUtf8Bytes(request.getData());
|
||||
return executePost(dataSourceFactory, url, new byte[0], null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception {
|
||||
public byte[] executeKeyRequest(
|
||||
UUID uuid, KeyRequest request, @Nullable String mediaProvidedLicenseServerUrl)
|
||||
throws Exception {
|
||||
String url = request.getDefaultUrl();
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
url = mediaProvidedLicenseServerUrl;
|
||||
}
|
||||
if (forceDefaultLicenseUrl || TextUtils.isEmpty(url)) {
|
||||
url = defaultLicenseUrl;
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
/**
|
||||
* Thrown when the drm keys loaded into an open session expire.
|
|
@ -13,11 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.KeyRequest;
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -44,7 +45,9 @@ public final class LocalMediaDrmCallback implements MediaDrmCallback {
|
|||
}
|
||||
|
||||
@Override
|
||||
public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception {
|
||||
public byte[] executeKeyRequest(
|
||||
UUID uuid, KeyRequest request, @Nullable String mediaProvidedLicenseServerUrl)
|
||||
throws Exception {
|
||||
return keyResponse;
|
||||
}
|
||||
|
|
@ -13,10 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.KeyRequest;
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
|
@ -38,10 +39,13 @@ public interface MediaDrmCallback {
|
|||
* Executes a key request.
|
||||
*
|
||||
* @param uuid The UUID of the content protection scheme.
|
||||
* @param request The request.
|
||||
* @param request The request generated by the content decryption module.
|
||||
* @param mediaProvidedLicenseServerUrl A license server URL provided by the media, or null if the
|
||||
* media does not include any license server URL.
|
||||
* @return The response data.
|
||||
* @throws Exception If an error occurred executing the request.
|
||||
*/
|
||||
byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception;
|
||||
|
||||
byte[] executeKeyRequest(
|
||||
UUID uuid, KeyRequest request, @Nullable String mediaProvidedLicenseServerUrl)
|
||||
throws Exception;
|
||||
}
|
|
@ -13,19 +13,19 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.media.MediaDrm;
|
||||
import android.os.ConditionVariable;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.Pair;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionManager.Mode;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import org.telegram.messenger.exoplayer2.upstream.HttpDataSource;
|
||||
import org.telegram.messenger.exoplayer2.upstream.HttpDataSource.Factory;
|
||||
import org.telegram.messenger.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager.Mode;
|
||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource.Factory;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.support.annotation.IntDef;
|
||||
import java.lang.annotation.Retention;
|
|
@ -13,10 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.drm;
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.util.Pair;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
|
@ -13,42 +13,41 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.ext.ffmpeg;
|
||||
package com.google.android.exoplayer2.ext.ffmpeg;
|
||||
|
||||
import android.os.Handler;
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.ExoPlaybackException;
|
||||
import org.telegram.messenger.exoplayer2.Format;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioProcessor;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener;
|
||||
import org.telegram.messenger.exoplayer2.audio.AudioSink;
|
||||
import org.telegram.messenger.exoplayer2.audio.DefaultAudioSink;
|
||||
import org.telegram.messenger.exoplayer2.audio.SimpleDecoderAudioRenderer;
|
||||
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager;
|
||||
import org.telegram.messenger.exoplayer2.drm.ExoMediaCrypto;
|
||||
import org.telegram.messenger.exoplayer2.util.MimeTypes;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.audio.AudioProcessor;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
|
||||
import com.google.android.exoplayer2.audio.AudioSink;
|
||||
import com.google.android.exoplayer2.audio.DefaultAudioSink;
|
||||
import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import java.util.Collections;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/**
|
||||
* Decodes and renders audio using FFmpeg.
|
||||
*/
|
||||
public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
|
||||
|
||||
/**
|
||||
* The number of input and output buffers.
|
||||
*/
|
||||
/** The number of input and output buffers. */
|
||||
private static final int NUM_BUFFERS = 16;
|
||||
/**
|
||||
* The initial input buffer size. Input buffers are reallocated dynamically if this value is
|
||||
* insufficient.
|
||||
*/
|
||||
private static final int INITIAL_INPUT_BUFFER_SIZE = 960 * 6;
|
||||
/** The default input buffer size. */
|
||||
private static final int DEFAULT_INPUT_BUFFER_SIZE = 960 * 6;
|
||||
|
||||
private final boolean enableFloatOutput;
|
||||
|
||||
private FfmpegDecoder decoder;
|
||||
private @MonotonicNonNull FfmpegDecoder decoder;
|
||||
|
||||
public FfmpegAudioRenderer() {
|
||||
this(null, null);
|
||||
this(/* eventHandler= */ null, /* eventListener= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,9 +56,15 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
|
|||
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||
* @param audioProcessors Optional {@link AudioProcessor}s that will process audio before output.
|
||||
*/
|
||||
public FfmpegAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener,
|
||||
public FfmpegAudioRenderer(
|
||||
@Nullable Handler eventHandler,
|
||||
@Nullable AudioRendererEventListener eventListener,
|
||||
AudioProcessor... audioProcessors) {
|
||||
this(eventHandler, eventListener, new DefaultAudioSink(null, audioProcessors), false);
|
||||
this(
|
||||
eventHandler,
|
||||
eventListener,
|
||||
new DefaultAudioSink(/* audioCapabilities= */ null, audioProcessors),
|
||||
/* enableFloatOutput= */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,8 +77,11 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
|
|||
* 32-bit float output, any audio processing will be disabled, including playback speed/pitch
|
||||
* adjustment.
|
||||
*/
|
||||
public FfmpegAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener,
|
||||
AudioSink audioSink, boolean enableFloatOutput) {
|
||||
public FfmpegAudioRenderer(
|
||||
@Nullable Handler eventHandler,
|
||||
@Nullable AudioRendererEventListener eventListener,
|
||||
AudioSink audioSink,
|
||||
boolean enableFloatOutput) {
|
||||
super(
|
||||
eventHandler,
|
||||
eventListener,
|
||||
|
@ -86,10 +94,11 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
|
|||
@Override
|
||||
protected int supportsFormatInternal(DrmSessionManager<ExoMediaCrypto> drmSessionManager,
|
||||
Format format) {
|
||||
String sampleMimeType = format.sampleMimeType;
|
||||
if (!MimeTypes.isAudio(sampleMimeType)) {
|
||||
Assertions.checkNotNull(format.sampleMimeType);
|
||||
if (!MimeTypes.isAudio(format.sampleMimeType)) {
|
||||
return FORMAT_UNSUPPORTED_TYPE;
|
||||
} else if (!FfmpegLibrary.supportsFormat(sampleMimeType) || !isOutputSupported(format)) {
|
||||
} else if (!FfmpegLibrary.supportsFormat(format.sampleMimeType, format.pcmEncoding)
|
||||
|| !isOutputSupported(format)) {
|
||||
return FORMAT_UNSUPPORTED_SUBTYPE;
|
||||
} else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) {
|
||||
return FORMAT_UNSUPPORTED_DRM;
|
||||
|
@ -106,18 +115,33 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
|
|||
@Override
|
||||
protected FfmpegDecoder createDecoder(Format format, ExoMediaCrypto mediaCrypto)
|
||||
throws FfmpegDecoderException {
|
||||
decoder = new FfmpegDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE,
|
||||
format.sampleMimeType, format.initializationData, shouldUseFloatOutput(format));
|
||||
int initialInputBufferSize =
|
||||
format.maxInputSize != Format.NO_VALUE ? format.maxInputSize : DEFAULT_INPUT_BUFFER_SIZE;
|
||||
decoder =
|
||||
new FfmpegDecoder(
|
||||
NUM_BUFFERS, NUM_BUFFERS, initialInputBufferSize, format, shouldUseFloatOutput(format));
|
||||
return decoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Format getOutputFormat() {
|
||||
Assertions.checkNotNull(decoder);
|
||||
int channelCount = decoder.getChannelCount();
|
||||
int sampleRate = decoder.getSampleRate();
|
||||
@C.PcmEncoding int encoding = decoder.getEncoding();
|
||||
return Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, channelCount, sampleRate, encoding, null, null, 0, null);
|
||||
return Format.createAudioSampleFormat(
|
||||
/* id= */ null,
|
||||
MimeTypes.AUDIO_RAW,
|
||||
/* codecs= */ null,
|
||||
Format.NO_VALUE,
|
||||
Format.NO_VALUE,
|
||||
channelCount,
|
||||
sampleRate,
|
||||
encoding,
|
||||
Collections.emptyList(),
|
||||
/* drmInitData= */ null,
|
||||
/* selectionFlags= */ 0,
|
||||
/* language= */ null);
|
||||
}
|
||||
|
||||
private boolean isOutputSupported(Format inputFormat) {
|
||||
|
@ -125,6 +149,7 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
|
|||
}
|
||||
|
||||
private boolean shouldUseFloatOutput(Format inputFormat) {
|
||||
Assertions.checkNotNull(inputFormat.sampleMimeType);
|
||||
if (!enableFloatOutput || !supportsOutputEncoding(C.ENCODING_PCM_FLOAT)) {
|
||||
return false;
|
||||
}
|
|
@ -13,14 +13,17 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.telegram.messenger.exoplayer2.ext.ffmpeg;
|
||||
package com.google.android.exoplayer2.ext.ffmpeg;
|
||||
|
||||
import org.telegram.messenger.exoplayer2.C;
|
||||
import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import org.telegram.messenger.exoplayer2.decoder.SimpleDecoder;
|
||||
import org.telegram.messenger.exoplayer2.decoder.SimpleOutputBuffer;
|
||||
import org.telegram.messenger.exoplayer2.util.MimeTypes;
|
||||
import org.telegram.messenger.exoplayer2.util.ParsableByteArray;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.decoder.SimpleDecoder;
|
||||
import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -30,13 +33,12 @@ import java.util.List;
|
|||
/* package */ final class FfmpegDecoder extends
|
||||
SimpleDecoder<DecoderInputBuffer, SimpleOutputBuffer, FfmpegDecoderException> {
|
||||
|
||||
// Space for 64 ms of 48 kHz 8 channel 16-bit PCM audio.
|
||||
private static final int OUTPUT_BUFFER_SIZE_16BIT = 64 * 48 * 8 * 2;
|
||||
// Space for 64 ms of 48 KhZ 8 channel 32-bit PCM audio.
|
||||
// Output buffer sizes when decoding PCM mu-law streams, which is the maximum FFmpeg outputs.
|
||||
private static final int OUTPUT_BUFFER_SIZE_16BIT = 65536;
|
||||
private static final int OUTPUT_BUFFER_SIZE_32BIT = OUTPUT_BUFFER_SIZE_16BIT * 2;
|
||||
|
||||
private final String codecName;
|
||||
private final byte[] extraData;
|
||||
private final @Nullable byte[] extraData;
|
||||
private final @C.Encoding int encoding;
|
||||
private final int outputBufferSize;
|
||||
|
||||
|
@ -45,15 +47,23 @@ import java.util.List;
|
|||
private volatile int channelCount;
|
||||
private volatile int sampleRate;
|
||||
|
||||
public FfmpegDecoder(int numInputBuffers, int numOutputBuffers, int initialInputBufferSize,
|
||||
String mimeType, List<byte[]> initializationData, boolean outputFloat)
|
||||
public FfmpegDecoder(
|
||||
int numInputBuffers,
|
||||
int numOutputBuffers,
|
||||
int initialInputBufferSize,
|
||||
Format format,
|
||||
boolean outputFloat)
|
||||
throws FfmpegDecoderException {
|
||||
super(new DecoderInputBuffer[numInputBuffers], new SimpleOutputBuffer[numOutputBuffers]);
|
||||
codecName = FfmpegLibrary.getCodecName(mimeType);
|
||||
extraData = getExtraData(mimeType, initializationData);
|
||||
Assertions.checkNotNull(format.sampleMimeType);
|
||||
codecName =
|
||||
Assertions.checkNotNull(
|
||||
FfmpegLibrary.getCodecName(format.sampleMimeType, format.pcmEncoding));
|
||||
extraData = getExtraData(format.sampleMimeType, format.initializationData);
|
||||
encoding = outputFloat ? C.ENCODING_PCM_FLOAT : C.ENCODING_PCM_16BIT;
|
||||
outputBufferSize = outputFloat ? OUTPUT_BUFFER_SIZE_32BIT : OUTPUT_BUFFER_SIZE_16BIT;
|
||||
nativeContext = ffmpegInitialize(codecName, extraData, outputFloat);
|
||||
nativeContext =
|
||||
ffmpegInitialize(codecName, extraData, outputFloat, format.sampleRate, format.channelCount);
|
||||
if (nativeContext == 0) {
|
||||
throw new FfmpegDecoderException("Initialization failed.");
|
||||
}
|
||||
|
@ -81,7 +91,7 @@ import java.util.List;
|
|||
}
|
||||
|
||||
@Override
|
||||
protected FfmpegDecoderException decode(
|
||||
protected @Nullable FfmpegDecoderException decode(
|
||||
DecoderInputBuffer inputBuffer, SimpleOutputBuffer outputBuffer, boolean reset) {
|
||||
if (reset) {
|
||||
nativeContext = ffmpegReset(nativeContext, extraData);
|
||||
|
@ -100,6 +110,7 @@ import java.util.List;
|
|||
channelCount = ffmpegGetChannelCount(nativeContext);
|
||||
sampleRate = ffmpegGetSampleRate(nativeContext);
|
||||
if (sampleRate == 0 && "alac".equals(codecName)) {
|
||||
Assertions.checkNotNull(extraData);
|
||||
// ALAC decoder did not set the sample rate in earlier versions of FFMPEG.
|
||||
// See https://trac.ffmpeg.org/ticket/6096
|
||||
ParsableByteArray parsableExtraData = new ParsableByteArray(extraData);
|
||||
|
@ -145,7 +156,7 @@ import java.util.List;
|
|||
* Returns FFmpeg-compatible codec-specific initialization data ("extra data"), or {@code null} if
|
||||
* not required.
|
||||
*/
|
||||
private static byte[] getExtraData(String mimeType, List<byte[]> initializationData) {
|
||||
private static @Nullable byte[] getExtraData(String mimeType, List<byte[]> initializationData) {
|
||||
switch (mimeType) {
|
||||
case MimeTypes.AUDIO_AAC:
|
||||
case MimeTypes.AUDIO_ALAC:
|
||||
|
@ -170,12 +181,20 @@ import java.util.List;
|
|||
}
|
||||
}
|
||||
|
||||
private native long ffmpegInitialize(String codecName, byte[] extraData, boolean outputFloat);
|
||||
private native long ffmpegInitialize(
|
||||
String codecName,
|
||||
@Nullable byte[] extraData,
|
||||
boolean outputFloat,
|
||||
int rawSampleRate,
|
||||
int rawChannelCount);
|
||||
|
||||
private native int ffmpegDecode(long context, ByteBuffer inputData, int inputSize,
|
||||
ByteBuffer outputData, int outputSize);
|
||||
private native int ffmpegGetChannelCount(long context);
|
||||
private native int ffmpegGetSampleRate(long context);
|
||||
private native long ffmpegReset(long context, byte[] extraData);
|
||||
|
||||
private native long ffmpegReset(long context, @Nullable byte[] extraData);
|
||||
|
||||
private native void ffmpegRelease(long context);
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue