1
0
mirror of https://github.com/MGislv/NekoX.git synced 2024-06-30 10:14:04 +00:00

Update to 4.9.1

This commit is contained in:
DrKLO 2018-08-27 11:33:11 +03:00
parent d073b80063
commit fe599cd519
663 changed files with 40241 additions and 34380 deletions

View File

@ -11,26 +11,29 @@ configurations {
} }
dependencies { dependencies {
compile 'com.google.firebase:firebase-messaging:17.1.0' compileOnly 'org.checkerframework:checker-qual:2.5.0'
compile 'com.google.firebase:firebase-config:16.0.0' compileOnly 'org.checkerframework:checker-compat-qual:2.5.0'
compile 'com.google.android.gms:play-services-maps:15.0.1' implementation 'com.google.firebase:firebase-core:16.0.3'
compile 'com.google.android.gms:play-services-vision:15.0.2' implementation 'com.google.firebase:firebase-messaging:17.3.0'
compile 'com.google.android.gms:play-services-wallet:15.0.1' implementation 'com.google.firebase:firebase-config:16.0.0'
compile 'com.google.android.gms:play-services-wearable:15.0.1' implementation 'com.google.android.gms:play-services-maps:15.0.1'
implementation 'com.android.support:support-core-ui:27.1.1' implementation 'com.google.android.gms:play-services-vision:15.0.2'
implementation 'com.android.support:support-compat:27.1.1' implementation 'com.google.android.gms:play-services-wallet:16.0.0'
implementation 'com.android.support:support-core-utils:27.1.1' implementation 'com.google.android.gms:play-services-wearable:15.0.1'
implementation 'com.android.support:support-v13:27.1.1' implementation 'com.android.support:support-core-ui:28.0.0-rc01'
implementation 'com.android.support:palette-v7:27.1.1' implementation 'com.android.support:support-compat:28.0.0-rc01'
implementation 'com.android.support:exifinterface:27.1.1' implementation 'com.android.support:support-core-utils:28.0.0-rc01'
compile 'net.hockeyapp.android:HockeySDK:5.1.0' implementation 'com.android.support:support-v13:28.0.0-rc01'
compile 'com.googlecode.mp4parser:isoparser:1.0.6' implementation 'com.android.support:palette-v7:28.0.0-rc01'
compile 'com.stripe:stripe-android:2.0.2' 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 { android {
compileSdkVersion 27 compileSdkVersion 28
buildToolsVersion '27.0.3' buildToolsVersion '28.0.2'
defaultConfig.applicationId = "org.telegram.messenger" defaultConfig.applicationId = "org.telegram.messenger"
@ -52,8 +55,8 @@ android {
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_8
} }
signingConfigs { signingConfigs {
@ -98,7 +101,7 @@ android {
} }
} }
defaultConfig.versionCode = 1340 defaultConfig.versionCode = 1358
sourceSets.debug { sourceSets.debug {
manifest.srcFile 'config/debug/AndroidManifest.xml' manifest.srcFile 'config/debug/AndroidManifest.xml'
@ -235,7 +238,7 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 27 targetSdkVersion 27
versionName "4.9.0" versionName "4.9.1"
vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi'] vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi']

View File

@ -387,7 +387,7 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false 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 := -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 += -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 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

View File

@ -142,10 +142,12 @@ jlong Java_org_telegram_SQLite_SQLiteDatabase_opendb(JNIEnv *env, jobject object
char const *fileNameStr = env->GetStringUTFChars(fileName, 0); char const *fileNameStr = env->GetStringUTFChars(fileName, 0);
char const *tempDirStr = env->GetStringUTFChars(tempDir, 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); sqlite3_free(sqlite3_temp_directory);
} }
sqlite3_temp_directory = sqlite3_mprintf("%s", tempDirStr); if (sqlite3_temp_directory == 0) {
sqlite3_temp_directory = sqlite3_mprintf("%s", tempDirStr);
}
sqlite3 *handle = 0; sqlite3 *handle = 0;
int err = sqlite3_open(fileNameStr, &handle); int err = sqlite3_open(fileNameStr, &handle);

View File

@ -39,6 +39,8 @@ jmethodID jclass_ConnectionsManager_onProxyError;
jmethodID jclass_ConnectionsManager_getHostByName; jmethodID jclass_ConnectionsManager_getHostByName;
jmethodID jclass_ConnectionsManager_getInitFlags; 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) { /*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) { if (encKey != nullptr && encIv == nullptr || encKey == nullptr && encIv != nullptr || extension == nullptr || dest == nullptr || temp == nullptr) {
return 0; return 0;
@ -196,7 +198,13 @@ void sendRequest(JNIEnv *env, jclass c, jint instanceNum, jlong object, jobject
ptr = (jlong) resp->response.get(); ptr = (jlong) resp->response.get();
} else if (error != nullptr) { } else if (error != nullptr) {
errorCode = error->code; 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) { if (onComplete != nullptr) {
jniEnv[instanceNum]->CallVoidMethod(onComplete, jclass_RequestDelegateInternal_run, ptr, errorCode, errorText, networkType); 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; 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);
}

View File

@ -36,10 +36,10 @@ extern "C" {
__VA_ARGS__)) __VA_ARGS__))
#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \ #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, ...) \ #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 #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. * provided extraData as initialization data for the decoder if it is non-NULL.
* Returns the created context. * Returns the created context.
*/ */
AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
jbyteArray extraData, jboolean outputFloat); jboolean outputFloat, jint rawSampleRate,
jint rawChannelCount);
/** /**
* Decodes the packet into the output buffer, returning the number of bytes * 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, DECODER_FUNC(jlong, ffmpegInitialize, jstring codecName, jbyteArray extraData,
jboolean outputFloat) { jboolean outputFloat, jint rawSampleRate, jint rawChannelCount) {
AVCodec *codec = getCodecByName(env, codecName); AVCodec *codec = getCodecByName(env, codecName);
if (!codec) { if (!codec) {
LOGE("Codec not found."); LOGE("Codec not found.");
return 0L; 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, 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); LOGE("Unexpected error finding codec %d.", codecId);
return 0L; return 0L;
} }
return (jlong) createContext(env, codec, extraData, jboolean outputFloat =
context->request_sample_fmt == OUTPUT_FORMAT_PCM_FLOAT); (jboolean)(context->request_sample_fmt == OUTPUT_FORMAT_PCM_FLOAT);
return (jlong)createContext(env, codec, extraData, outputFloat,
/* rawSampleRate= */ -1,
/* rawChannelCount= */ -1);
} }
avcodec_flush_buffers(context); avcodec_flush_buffers(context);
@ -173,7 +178,7 @@ DECODER_FUNC(void, ffmpegRelease, jlong context) {
} }
} }
AVCodec *getCodecByName(JNIEnv *env, jstring codecName) { AVCodec *getCodecByName(JNIEnv* env, jstring codecName) {
if (!codecName) { if (!codecName) {
return NULL; return NULL;
} }
@ -183,8 +188,9 @@ AVCodec *getCodecByName(JNIEnv *env, jstring codecName) {
return codec; return codec;
} }
AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
jbyteArray extraData, jboolean outputFloat) { jboolean outputFloat, jint rawSampleRate,
jint rawChannelCount) {
AVCodecContext *context = avcodec_alloc_context3(codec); AVCodecContext *context = avcodec_alloc_context3(codec);
if (!context) { if (!context) {
LOGE("Failed to allocate context."); LOGE("Failed to allocate context.");
@ -204,6 +210,12 @@ AVCodecContext *createContext(JNIEnv *env, AVCodec *codec,
} }
env->GetByteArrayRegion(extraData, 0, size, (jbyte *) context->extradata); 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); int result = avcodec_open2(context, codec, NULL);
if (result < 0) { if (result < 0) {
logError("avcodec_open2", result); logError("avcodec_open2", result);
@ -244,7 +256,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
// Resample output. // Resample output.
AVSampleFormat sampleFormat = context->sample_fmt; AVSampleFormat sampleFormat = context->sample_fmt;
int channelCount = context->channels; int channelCount = context->channels;
uint64_t channelLayout = context->channel_layout; int channelLayout = context->channel_layout;
int sampleRate = context->sample_rate; int sampleRate = context->sample_rate;
int sampleCount = frame->nb_samples; int sampleCount = frame->nb_samples;
int dataSize = av_samples_get_buffer_size(NULL, channelCount, sampleCount, int dataSize = av_samples_get_buffer_size(NULL, channelCount, sampleCount,
@ -254,7 +266,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
resampleContext = (AVAudioResampleContext *) context->opaque; resampleContext = (AVAudioResampleContext *) context->opaque;
} else { } else {
resampleContext = avresample_alloc_context(); resampleContext = avresample_alloc_context();
av_opt_set_int(resampleContext, "in_channel_layout", channelLayout, 0); av_opt_set_int(resampleContext, "in_channel_layout", channelLayout, 0);
av_opt_set_int(resampleContext, "out_channel_layout", channelLayout, 0); av_opt_set_int(resampleContext, "out_channel_layout", channelLayout, 0);
av_opt_set_int(resampleContext, "in_sample_rate", sampleRate, 0); av_opt_set_int(resampleContext, "in_sample_rate", sampleRate, 0);
av_opt_set_int(resampleContext, "out_sample_rate", sampleRate, 0); av_opt_set_int(resampleContext, "out_sample_rate", sampleRate, 0);

View File

@ -19,150 +19,152 @@
#include "include/flac_parser.h" #include "include/flac_parser.h"
#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \ #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 { class JavaDataSource : public DataSource {
public: public:
void setFlacDecoderJni(JNIEnv *env, jobject flacDecoderJni) { void setFlacDecoderJni(JNIEnv *env, jobject flacDecoderJni) {
this->env = env; this->env = env;
this->flacDecoderJni = flacDecoderJni; this->flacDecoderJni = flacDecoderJni;
if (mid == NULL) { if (mid == NULL) {
jclass cls = env->GetObjectClass(flacDecoderJni); jclass cls = env->GetObjectClass(this->flacDecoderJni);
mid = env->GetMethodID(cls, "read", "(Ljava/nio/ByteBuffer;)I"); mid = env->GetMethodID(cls, "read", "(Ljava/nio/ByteBuffer;)I");
env->DeleteLocalRef(cls); env->DeleteLocalRef(cls);
}
} }
}
ssize_t readAt(off64_t offset, void *const data, size_t size) { ssize_t readAt(off64_t offset, void *const data, size_t size) {
jobject byteBuffer = env->NewDirectByteBuffer(data, size); jobject byteBuffer = env->NewDirectByteBuffer(data, size);
int result = env->CallIntMethod(flacDecoderJni, mid, byteBuffer); int result = env->CallIntMethod(flacDecoderJni, mid, byteBuffer);
if (env->ExceptionCheck()) { if (env->ExceptionCheck()) {
// Exception is thrown in Java when returning from the native call. // Exception is thrown in Java when returning from the native call.
result = -1; result = -1;
}
env->DeleteLocalRef(byteBuffer);
return result;
} }
env->DeleteLocalRef(byteBuffer);
return result;
}
private: private:
JNIEnv *env; JNIEnv *env;
jobject flacDecoderJni; jobject flacDecoderJni;
jmethodID mid; jmethodID mid;
}; };
struct Context { struct Context {
JavaDataSource *source; JavaDataSource *source;
FLACParser *parser; FLACParser *parser;
Context() { Context() {
source = new JavaDataSource(); source = new JavaDataSource();
parser = new FLACParser(source); parser = new FLACParser(source);
} }
~Context() { ~Context() {
delete parser; delete parser;
delete source; delete source;
} }
}; };
extern "C" { extern "C" {
DECODER_FUNC(jlong, flacInit) { DECODER_FUNC(jlong, flacInit) {
Context *context = new Context; Context *context = new Context;
if (!context->parser->init()) { if (!context->parser->init()) {
delete context; delete context;
return 0; return 0;
} }
return reinterpret_cast<intptr_t>(context); return reinterpret_cast<intptr_t>(context);
} }
DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) { DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
context->source->setFlacDecoderJni(env, thiz); context->source->setFlacDecoderJni(env, thiz);
if (!context->parser->decodeMetadata()) { if (!context->parser->decodeMetadata()) {
return NULL; return NULL;
} }
const FLAC__StreamMetadata_StreamInfo &streamInfo = const FLAC__StreamMetadata_StreamInfo &streamInfo =
context->parser->getStreamInfo(); context->parser->getStreamInfo();
jclass cls = env->FindClass("org/telegram/messenger/exoplayer2/util/FlacStreamInfo"); jclass cls = env->FindClass(
jmethodID constructor = env->GetMethodID(cls, "<init>", "(IIIIIIIJ)V"); "com/google/android/exoplayer2/util/"
"FlacStreamInfo");
jmethodID constructor = env->GetMethodID(cls, "<init>", "(IIIIIIIJ)V");
return env->NewObject(cls, constructor, streamInfo.min_blocksize, return env->NewObject(cls, constructor, streamInfo.min_blocksize,
streamInfo.max_blocksize, streamInfo.min_framesize, streamInfo.max_blocksize, streamInfo.min_framesize,
streamInfo.max_framesize, streamInfo.sample_rate, streamInfo.max_framesize, streamInfo.sample_rate,
streamInfo.channels, streamInfo.bits_per_sample, streamInfo.channels, streamInfo.bits_per_sample,
streamInfo.total_samples); streamInfo.total_samples);
} }
DECODER_FUNC(jint, flacDecodeToBuffer, jlong jContext, jobject jOutputBuffer) { DECODER_FUNC(jint, flacDecodeToBuffer, jlong jContext, jobject jOutputBuffer) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
context->source->setFlacDecoderJni(env, thiz); context->source->setFlacDecoderJni(env, thiz);
void *outputBuffer = env->GetDirectBufferAddress(jOutputBuffer); void *outputBuffer = env->GetDirectBufferAddress(jOutputBuffer);
jint outputSize = env->GetDirectBufferCapacity(jOutputBuffer); jint outputSize = env->GetDirectBufferCapacity(jOutputBuffer);
return context->parser->readBuffer(outputBuffer, outputSize); return context->parser->readBuffer(outputBuffer, outputSize);
} }
DECODER_FUNC(jint, flacDecodeToArray, jlong jContext, jbyteArray jOutputArray) { DECODER_FUNC(jint, flacDecodeToArray, jlong jContext, jbyteArray jOutputArray) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
context->source->setFlacDecoderJni(env, thiz); context->source->setFlacDecoderJni(env, thiz);
jbyte *outputBuffer = env->GetByteArrayElements(jOutputArray, NULL); jbyte *outputBuffer = env->GetByteArrayElements(jOutputArray, NULL);
jint outputSize = env->GetArrayLength(jOutputArray); jint outputSize = env->GetArrayLength(jOutputArray);
int count = context->parser->readBuffer(outputBuffer, outputSize); int count = context->parser->readBuffer(outputBuffer, outputSize);
env->ReleaseByteArrayElements(jOutputArray, outputBuffer, 0); env->ReleaseByteArrayElements(jOutputArray, outputBuffer, 0);
return count; return count;
} }
DECODER_FUNC(jlong, flacGetDecodePosition, jlong jContext) { DECODER_FUNC(jlong, flacGetDecodePosition, jlong jContext) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->getDecodePosition(); return context->parser->getDecodePosition();
} }
DECODER_FUNC(jlong, flacGetLastFrameTimestamp, jlong jContext) { DECODER_FUNC(jlong, flacGetLastFrameTimestamp, jlong jContext) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->getLastFrameTimestamp(); return context->parser->getLastFrameTimestamp();
} }
DECODER_FUNC(jlong, flacGetLastFrameFirstSampleIndex, jlong jContext) { DECODER_FUNC(jlong, flacGetLastFrameFirstSampleIndex, jlong jContext) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->getLastFrameFirstSampleIndex(); return context->parser->getLastFrameFirstSampleIndex();
} }
DECODER_FUNC(jlong, flacGetNextFrameFirstSampleIndex, jlong jContext) { DECODER_FUNC(jlong, flacGetNextFrameFirstSampleIndex, jlong jContext) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->getNextFrameFirstSampleIndex(); return context->parser->getNextFrameFirstSampleIndex();
} }
DECODER_FUNC(jlong, flacGetSeekPosition, jlong jContext, jlong timeUs) { DECODER_FUNC(jlong, flacGetSeekPosition, jlong jContext, jlong timeUs) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->getSeekPosition(timeUs); return context->parser->getSeekPosition(timeUs);
} }
DECODER_FUNC(jstring, flacGetStateString, jlong jContext) { DECODER_FUNC(jstring, flacGetStateString, jlong jContext) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
const char *str = context->parser->getDecoderStateString(); const char *str = context->parser->getDecoderStateString();
return env->NewStringUTF(str); return env->NewStringUTF(str);
} }
DECODER_FUNC(jboolean, flacIsDecoderAtEndOfStream, jlong jContext) { DECODER_FUNC(jboolean, flacIsDecoderAtEndOfStream, jlong jContext) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->isDecoderAtEndOfStream(); return context->parser->isDecoderAtEndOfStream();
} }
DECODER_FUNC(void, flacFlush, jlong jContext) { DECODER_FUNC(void, flacFlush, jlong jContext) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
context->parser->flush(); context->parser->flush();
} }
DECODER_FUNC(void, flacReset, jlong jContext, jlong newPosition) { DECODER_FUNC(void, flacReset, jlong jContext, jlong newPosition) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
context->parser->reset(newPosition); context->parser->reset(newPosition);
} }
DECODER_FUNC(void, flacRelease, jlong jContext) { DECODER_FUNC(void, flacRelease, jlong jContext) {
Context *context = reinterpret_cast<Context *>(jContext); Context *context = reinterpret_cast<Context *>(jContext);
delete context; delete context;
} }
} }

View File

@ -52,31 +52,31 @@ const int endian = 1;
// with the same parameter list, but discard redundant information. // with the same parameter list, but discard redundant information.
FLAC__StreamDecoderReadStatus FLACParser::read_callback( FLAC__StreamDecoderReadStatus FLACParser::read_callback(
const FLAC__StreamDecoder * /* decoder */, FLAC__byte buffer[], const FLAC__StreamDecoder * /* decoder */, FLAC__byte buffer[],
size_t *bytes, void *client_data) { size_t *bytes, void *client_data) {
return reinterpret_cast<FLACParser *>(client_data) return reinterpret_cast<FLACParser *>(client_data)
->readCallback(buffer, bytes); ->readCallback(buffer, bytes);
} }
FLAC__StreamDecoderSeekStatus FLACParser::seek_callback( FLAC__StreamDecoderSeekStatus FLACParser::seek_callback(
const FLAC__StreamDecoder * /* decoder */, const FLAC__StreamDecoder * /* decoder */,
FLAC__uint64 absolute_byte_offset, void *client_data) { FLAC__uint64 absolute_byte_offset, void *client_data) {
return reinterpret_cast<FLACParser *>(client_data) return reinterpret_cast<FLACParser *>(client_data)
->seekCallback(absolute_byte_offset); ->seekCallback(absolute_byte_offset);
} }
FLAC__StreamDecoderTellStatus FLACParser::tell_callback( FLAC__StreamDecoderTellStatus FLACParser::tell_callback(
const FLAC__StreamDecoder * /* decoder */, const FLAC__StreamDecoder * /* decoder */,
FLAC__uint64 *absolute_byte_offset, void *client_data) { FLAC__uint64 *absolute_byte_offset, void *client_data) {
return reinterpret_cast<FLACParser *>(client_data) return reinterpret_cast<FLACParser *>(client_data)
->tellCallback(absolute_byte_offset); ->tellCallback(absolute_byte_offset);
} }
FLAC__StreamDecoderLengthStatus FLACParser::length_callback( FLAC__StreamDecoderLengthStatus FLACParser::length_callback(
const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 *stream_length, const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 *stream_length,
void *client_data) { void *client_data) {
return reinterpret_cast<FLACParser *>(client_data) return reinterpret_cast<FLACParser *>(client_data)
->lengthCallback(stream_length); ->lengthCallback(stream_length);
} }
FLAC__bool FLACParser::eof_callback(const FLAC__StreamDecoder * /* decoder */, FLAC__bool FLACParser::eof_callback(const FLAC__StreamDecoder * /* decoder */,
@ -85,10 +85,10 @@ FLAC__bool FLACParser::eof_callback(const FLAC__StreamDecoder * /* decoder */,
} }
FLAC__StreamDecoderWriteStatus FLACParser::write_callback( FLAC__StreamDecoderWriteStatus FLACParser::write_callback(
const FLAC__StreamDecoder * /* decoder */, const FLAC__Frame *frame, const FLAC__StreamDecoder * /* decoder */, const FLAC__Frame *frame,
const FLAC__int32 *const buffer[], void *client_data) { const FLAC__int32 *const buffer[], void *client_data) {
return reinterpret_cast<FLACParser *>(client_data) return reinterpret_cast<FLACParser *>(client_data)
->writeCallback(frame, buffer); ->writeCallback(frame, buffer);
} }
void FLACParser::metadata_callback(const FLAC__StreamDecoder * /* decoder */, void FLACParser::metadata_callback(const FLAC__StreamDecoder * /* decoder */,
@ -125,27 +125,27 @@ FLAC__StreamDecoderReadStatus FLACParser::readCallback(FLAC__byte buffer[],
} }
FLAC__StreamDecoderSeekStatus FLACParser::seekCallback( FLAC__StreamDecoderSeekStatus FLACParser::seekCallback(
FLAC__uint64 absolute_byte_offset) { FLAC__uint64 absolute_byte_offset) {
mCurrentPos = absolute_byte_offset; mCurrentPos = absolute_byte_offset;
mEOF = false; mEOF = false;
return FLAC__STREAM_DECODER_SEEK_STATUS_OK; return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
} }
FLAC__StreamDecoderTellStatus FLACParser::tellCallback( FLAC__StreamDecoderTellStatus FLACParser::tellCallback(
FLAC__uint64 *absolute_byte_offset) { FLAC__uint64 *absolute_byte_offset) {
*absolute_byte_offset = mCurrentPos; *absolute_byte_offset = mCurrentPos;
return FLAC__STREAM_DECODER_TELL_STATUS_OK; return FLAC__STREAM_DECODER_TELL_STATUS_OK;
} }
FLAC__StreamDecoderLengthStatus FLACParser::lengthCallback( FLAC__StreamDecoderLengthStatus FLACParser::lengthCallback(
FLAC__uint64 *stream_length) { FLAC__uint64 *stream_length) {
return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
} }
FLAC__bool FLACParser::eofCallback() { return mEOF; } FLAC__bool FLACParser::eofCallback() { return mEOF; }
FLAC__StreamDecoderWriteStatus FLACParser::writeCallback( FLAC__StreamDecoderWriteStatus FLACParser::writeCallback(
const FLAC__Frame *frame, const FLAC__int32 *const buffer[]) { const FLAC__Frame *frame, const FLAC__int32 *const buffer[]) {
if (mWriteRequested) { if (mWriteRequested) {
mWriteRequested = false; mWriteRequested = false;
// FLAC parser doesn't free or realloc buffer until next frame or finish // FLAC parser doesn't free or realloc buffer until next frame or finish
@ -168,13 +168,13 @@ void FLACParser::metadataCallback(const FLAC__StreamMetadata *metadata) {
} else { } else {
ALOGE("FLACParser::metadataCallback unexpected STREAMINFO"); ALOGE("FLACParser::metadataCallback unexpected STREAMINFO");
} }
break; break;
case FLAC__METADATA_TYPE_SEEKTABLE: case FLAC__METADATA_TYPE_SEEKTABLE:
mSeekTable = &metadata->data.seek_table; mSeekTable = &metadata->data.seek_table;
break; break;
default: default:
ALOGE("FLACParser::metadataCallback unexpected type %u", metadata->type); ALOGE("FLACParser::metadataCallback unexpected type %u", metadata->type);
break; break;
} }
} }
@ -195,7 +195,7 @@ static void copyToByteArrayBigEndian(int8_t *dst, const int *const *src,
// and then skip the first few bytes (most significant bytes) // and then skip the first few bytes (most significant bytes)
// depending on the bit depth // depending on the bit depth
const int8_t *byteSrc = const int8_t *byteSrc =
reinterpret_cast<const int8_t *>(&src[c][i]) + 4 - bytesPerSample; reinterpret_cast<const int8_t *>(&src[c][i]) + 4 - bytesPerSample;
memcpy(dst, byteSrc, bytesPerSample); memcpy(dst, byteSrc, bytesPerSample);
dst = dst + bytesPerSample; dst = dst + bytesPerSample;
} }
@ -225,18 +225,18 @@ static void copyTrespass(int8_t * /* dst */, const int *const * /* src */,
// FLACParser // FLACParser
FLACParser::FLACParser(DataSource *source) FLACParser::FLACParser(DataSource *source)
: mDataSource(source), : mDataSource(source),
mCopy(copyTrespass), mCopy(copyTrespass),
mDecoder(NULL), mDecoder(NULL),
mSeekTable(NULL), mSeekTable(NULL),
firstFrameOffset(0LL), firstFrameOffset(0LL),
mCurrentPos(0LL), mCurrentPos(0LL),
mEOF(false), mEOF(false),
mStreamInfoValid(false), mStreamInfoValid(false),
mWriteRequested(false), mWriteRequested(false),
mWriteCompleted(false), mWriteCompleted(false),
mWriteBuffer(NULL), mWriteBuffer(NULL),
mErrorStatus((FLAC__StreamDecoderErrorStatus)-1) { mErrorStatus((FLAC__StreamDecoderErrorStatus)-1) {
ALOGV("FLACParser::FLACParser"); ALOGV("FLACParser::FLACParser");
memset(&mStreamInfo, 0, sizeof(mStreamInfo)); memset(&mStreamInfo, 0, sizeof(mStreamInfo));
memset(&mWriteHeader, 0, sizeof(mWriteHeader)); memset(&mWriteHeader, 0, sizeof(mWriteHeader));
@ -268,9 +268,9 @@ bool FLACParser::init() {
FLAC__METADATA_TYPE_SEEKTABLE); FLAC__METADATA_TYPE_SEEKTABLE);
FLAC__StreamDecoderInitStatus initStatus; FLAC__StreamDecoderInitStatus initStatus;
initStatus = FLAC__stream_decoder_init_stream( initStatus = FLAC__stream_decoder_init_stream(
mDecoder, read_callback, seek_callback, tell_callback, length_callback, mDecoder, read_callback, seek_callback, tell_callback, length_callback,
eof_callback, write_callback, metadata_callback, error_callback, eof_callback, write_callback, metadata_callback, error_callback,
reinterpret_cast<void *>(this)); reinterpret_cast<void *>(this));
if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) { if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
// A failure here probably indicates a programming error and so is // A failure here probably indicates a programming error and so is
// unlikely to happen. But we check and log here similarly to above. // unlikely to happen. But we check and log here similarly to above.
@ -304,7 +304,7 @@ bool FLACParser::decodeMetadata() {
break; break;
default: default:
ALOGE("unsupported bits per sample %u", getBitsPerSample()); ALOGE("unsupported bits per sample %u", getBitsPerSample());
return false; return false;
} }
// check sample rate // check sample rate
switch (getSampleRate()) { switch (getSampleRate()) {
@ -324,7 +324,7 @@ bool FLACParser::decodeMetadata() {
break; break;
default: default:
ALOGE("unsupported sample rate %u", getSampleRate()); ALOGE("unsupported sample rate %u", getSampleRate());
return false; return false;
} }
// configure the appropriate copy function based on device endianness. // configure the appropriate copy function based on device endianness.
if (isBigEndian()) { if (isBigEndian()) {
@ -367,11 +367,11 @@ size_t FLACParser::readBuffer(void *output, size_t output_size) {
mWriteHeader.channels != getChannels() || mWriteHeader.channels != getChannels() ||
mWriteHeader.bits_per_sample != getBitsPerSample()) { mWriteHeader.bits_per_sample != getBitsPerSample()) {
ALOGE( ALOGE(
"FLACParser::readBuffer write changed parameters mid-stream: %d/%d/%d " "FLACParser::readBuffer write changed parameters mid-stream: %d/%d/%d "
"-> %d/%d/%d", "-> %d/%d/%d",
getSampleRate(), getChannels(), getBitsPerSample(), getSampleRate(), getChannels(), getBitsPerSample(),
mWriteHeader.sample_rate, mWriteHeader.channels, mWriteHeader.sample_rate, mWriteHeader.channels,
mWriteHeader.bits_per_sample); mWriteHeader.bits_per_sample);
return -1; return -1;
} }
@ -379,9 +379,9 @@ size_t FLACParser::readBuffer(void *output, size_t output_size) {
size_t bufferSize = blocksize * getChannels() * bytesPerSample; size_t bufferSize = blocksize * getChannels() * bytesPerSample;
if (bufferSize > output_size) { if (bufferSize > output_size) {
ALOGE( ALOGE(
"FLACParser::readBuffer not enough space in output buffer " "FLACParser::readBuffer not enough space in output buffer "
"%zu < %zu", "%zu < %zu",
output_size, bufferSize); output_size, bufferSize);
return -1; return -1;
} }
@ -402,7 +402,7 @@ int64_t FLACParser::getSeekPosition(int64_t timeUs) {
int64_t sample = (timeUs * getSampleRate()) / 1000000LL; int64_t sample = (timeUs * getSampleRate()) / 1000000LL;
if (sample >= getTotalSamples()) { if (sample >= getTotalSamples()) {
sample = getTotalSamples(); sample = getTotalSamples();
} }
FLAC__StreamMetadata_SeekPoint* points = mSeekTable->points; FLAC__StreamMetadata_SeekPoint* points = mSeekTable->points;

View File

@ -28,10 +28,10 @@
__VA_ARGS__)) __VA_ARGS__))
#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \ #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, ...) \ #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. // JNI references for SimpleOutputBuffer class.
static jmethodID outputBufferInit; static jmethodID outputBufferInit;
@ -65,7 +65,7 @@ DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount,
// Populate JNI References. // Populate JNI References.
const jclass outputBufferClass = env->FindClass( const jclass outputBufferClass = env->FindClass(
"org/telegram/messenger/exoplayer2/decoder/SimpleOutputBuffer"); "com/google/android/exoplayer2/decoder/SimpleOutputBuffer");
outputBufferInit = env->GetMethodID(outputBufferClass, "init", outputBufferInit = env->GetMethodID(outputBufferClass, "init",
"(JI)Ljava/nio/ByteBuffer;"); "(JI)Ljava/nio/ByteBuffer;");

View File

@ -5,6 +5,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#include <openssl/aes.h> #include <openssl/aes.h>
#include <openssl/evp.h>
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include <sys/stat.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); (*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) { 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; jbyte *what = (*env)->GetDirectBufferAddress(env, buffer) + offset;
unsigned char *keyBuff = (unsigned char *)(*env)->GetByteArrayElements(env, key, NULL); unsigned char *keyBuff = (unsigned char *)(*env)->GetByteArrayElements(env, key, NULL);

@ -1 +1 @@
Subproject commit 8faf6f670037a8049ede4b85a004c40bdd359c6a Subproject commit 23ae67306d7fa1c4d5a8a9c8653f63ab93100f88

View File

@ -4,9 +4,12 @@
@com.google.android.gms.common.annotation.KeepName *; @com.google.android.gms.common.annotation.KeepName *;
} }
-keep class org.telegram.** { *; } -keep class org.telegram.** { *; }
-keep class com.google.android.exoplayer2.** { *; }
-keep class com.coremedia.** { *; } -keep class com.coremedia.** { *; }
-keep class com.googlecode.mp4parser.** { *; }
-dontwarn com.coremedia.** -dontwarn com.coremedia.**
-dontwarn org.telegram.** -dontwarn org.telegram.**
-dontwarn com.google.android.exoplayer2.**
-dontwarn com.google.android.gms.** -dontwarn com.google.android.gms.**
-dontwarn com.google.common.cache.** -dontwarn com.google.common.cache.**
-dontwarn com.google.common.primitives.** -dontwarn com.google.common.primitives.**

View File

@ -20,6 +20,7 @@
<uses-feature android:name="android.hardware.camera2" android:required="false" /> <uses-feature android:name="android.hardware.camera2" android:required="false" />
<uses-permission android:name="android.permission.INTERNET" /> <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.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@ -231,9 +232,9 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name=".CallReceiver" > <receiver android:name=".CallReceiver">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.PHONE_STATE" /> <action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter> </intent-filter>
</receiver> </receiver>

View File

@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import org.telegram.messenger.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
import org.telegram.messenger.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import org.telegram.messenger.exoplayer2.util.MediaClock; import com.google.android.exoplayer2.util.MediaClock;
import java.io.IOException; import java.io.IOException;
/** /**

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
@ -23,8 +23,8 @@ import android.media.MediaCodec;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import android.view.Surface; import android.view.Surface;
import org.telegram.messenger.exoplayer2.PlayerMessage.Target; import com.google.android.exoplayer2.PlayerMessage.Target;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.UUID; import java.util.UUID;
@ -77,6 +77,12 @@ public final class C {
*/ */
public static final long NANOS_PER_SECOND = 1000000000L; 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. * The name of the ASCII charset.
*/ */
@ -136,6 +142,8 @@ public final class C {
ENCODING_PCM_24BIT, ENCODING_PCM_24BIT,
ENCODING_PCM_32BIT, ENCODING_PCM_32BIT,
ENCODING_PCM_FLOAT, ENCODING_PCM_FLOAT,
ENCODING_PCM_MU_LAW,
ENCODING_PCM_A_LAW,
ENCODING_AC3, ENCODING_AC3,
ENCODING_E_AC3, ENCODING_E_AC3,
ENCODING_DTS, ENCODING_DTS,
@ -144,12 +152,19 @@ public final class C {
}) })
public @interface Encoding {} 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) @Retention(RetentionPolicy.SOURCE)
@IntDef({Format.NO_VALUE, ENCODING_INVALID, ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, @IntDef({
ENCODING_PCM_24BIT, ENCODING_PCM_32BIT, ENCODING_PCM_FLOAT}) 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 {} public @interface PcmEncoding {}
/** @see AudioFormat#ENCODING_INVALID */ /** @see AudioFormat#ENCODING_INVALID */
public static final int ENCODING_INVALID = 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; public static final int ENCODING_PCM_32BIT = 0x40000000;
/** @see AudioFormat#ENCODING_PCM_FLOAT */ /** @see AudioFormat#ENCODING_PCM_FLOAT */
public static final int ENCODING_PCM_FLOAT = 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 */ /** @see AudioFormat#ENCODING_AC3 */
public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3; public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3;
/** @see AudioFormat#ENCODING_E_AC3 */ /** @see AudioFormat#ENCODING_E_AC3 */
@ -226,7 +245,7 @@ public final class C {
public static final int STREAM_TYPE_DEFAULT = STREAM_TYPE_MUSIC; 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) @Retention(RetentionPolicy.SOURCE)
@IntDef({CONTENT_TYPE_MOVIE, CONTENT_TYPE_MUSIC, CONTENT_TYPE_SONIFICATION, CONTENT_TYPE_SPEECH, @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; 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> * <p>
* Note that {@code FLAG_HW_AV_SYNC} is not available because the player takes care of setting the * 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. * flag when tunneling is enabled via a track selector.
@ -272,7 +291,7 @@ public final class C {
android.media.AudioAttributes.FLAG_AUDIBILITY_ENFORCED; 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) @Retention(RetentionPolicy.SOURCE)
@IntDef({USAGE_ALARM, USAGE_ASSISTANCE_ACCESSIBILITY, USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, @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 * 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 * 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 * underlying audio track. If not set, the default audio attributes will be used. They are
* suitable for general media playback. * suitable for general media playback.
* *
@ -797,6 +816,45 @@ public final class C {
*/ */
public static final int PRIORITY_DOWNLOAD = PRIORITY_PLAYBACK - 1000; 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 * Converts a time in microseconds to the corresponding time in milliseconds, preserving
* {@link #TIME_UNSET} and {@link #TIME_END_OF_SOURCE} values. * {@link #TIME_UNSET} and {@link #TIME_END_OF_SOURCE} values.

View File

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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}. * Dispatches operations to the {@link Player}.

View File

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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 * Default {@link ControlDispatcher} that dispatches all operations to the player without

View File

@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import org.telegram.messenger.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import org.telegram.messenger.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import org.telegram.messenger.exoplayer2.upstream.DefaultAllocator; import com.google.android.exoplayer2.upstream.DefaultAllocator;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import org.telegram.messenger.exoplayer2.util.PriorityTaskManager; import com.google.android.exoplayer2.util.PriorityTaskManager;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
/** /**
* The default {@link LoadControl} implementation. * The default {@link LoadControl} implementation.

View File

@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Clock;
import org.telegram.messenger.exoplayer2.util.MediaClock; import com.google.android.exoplayer2.util.MediaClock;
import org.telegram.messenger.exoplayer2.util.StandaloneMediaClock; import com.google.android.exoplayer2.util.StandaloneMediaClock;
/** /**
* Default {@link MediaClock} which uses a renderer media clock and falls back to a * Default {@link MediaClock} which uses a renderer media clock and falls back to a

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.content.Context; import android.content.Context;
import android.os.Handler; import android.os.Handler;
@ -21,20 +21,20 @@ import android.os.Looper;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import org.telegram.messenger.exoplayer2.audio.AudioCapabilities; import com.google.android.exoplayer2.audio.AudioCapabilities;
import org.telegram.messenger.exoplayer2.audio.AudioProcessor; import com.google.android.exoplayer2.audio.AudioProcessor;
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import org.telegram.messenger.exoplayer2.audio.MediaCodecAudioRenderer; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer;
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
import org.telegram.messenger.exoplayer2.metadata.MetadataOutput; import com.google.android.exoplayer2.metadata.MetadataOutput;
import org.telegram.messenger.exoplayer2.metadata.MetadataRenderer; import com.google.android.exoplayer2.metadata.MetadataRenderer;
import org.telegram.messenger.exoplayer2.text.TextOutput; import com.google.android.exoplayer2.text.TextOutput;
import org.telegram.messenger.exoplayer2.text.TextRenderer; import com.google.android.exoplayer2.text.TextRenderer;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import org.telegram.messenger.exoplayer2.video.MediaCodecVideoRenderer; import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener; import com.google.android.exoplayer2.video.VideoRendererEventListener;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -221,13 +221,13 @@ public class DefaultRenderersFactory implements RenderersFactory {
try { try {
// Full class names used for constructor args so the LINT rule triggers if any of them move. // Full class names used for constructor args so the LINT rule triggers if any of them move.
// LINT.IfChange // 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 = Constructor<?> constructor =
clazz.getConstructor( clazz.getConstructor(
boolean.class, boolean.class,
long.class, long.class,
android.os.Handler.class, android.os.Handler.class,
org.telegram.messenger.exoplayer2.video.VideoRendererEventListener.class, com.google.android.exoplayer2.video.VideoRendererEventListener.class,
int.class); int.class);
// LINT.ThenChange(../../../../../../../proguard-rules.txt) // LINT.ThenChange(../../../../../../../proguard-rules.txt)
Renderer renderer = Renderer renderer =
@ -288,12 +288,12 @@ public class DefaultRenderersFactory implements RenderersFactory {
try { try {
// Full class names used for constructor args so the LINT rule triggers if any of them move. // Full class names used for constructor args so the LINT rule triggers if any of them move.
// LINT.IfChange // 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 = Constructor<?> constructor =
clazz.getConstructor( clazz.getConstructor(
android.os.Handler.class, android.os.Handler.class,
org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.class, com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
org.telegram.messenger.exoplayer2.audio.AudioProcessor[].class); com.google.android.exoplayer2.audio.AudioProcessor[].class);
// LINT.ThenChange(../../../../../../../proguard-rules.txt) // LINT.ThenChange(../../../../../../../proguard-rules.txt)
Renderer renderer = Renderer renderer =
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); (Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors);
@ -309,12 +309,12 @@ public class DefaultRenderersFactory implements RenderersFactory {
try { try {
// Full class names used for constructor args so the LINT rule triggers if any of them move. // Full class names used for constructor args so the LINT rule triggers if any of them move.
// LINT.IfChange // 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 = Constructor<?> constructor =
clazz.getConstructor( clazz.getConstructor(
android.os.Handler.class, android.os.Handler.class,
org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.class, com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
org.telegram.messenger.exoplayer2.audio.AudioProcessor[].class); com.google.android.exoplayer2.audio.AudioProcessor[].class);
// LINT.ThenChange(../../../../../../../proguard-rules.txt) // LINT.ThenChange(../../../../../../../proguard-rules.txt)
Renderer renderer = Renderer renderer =
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); (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. // Full class names used for constructor args so the LINT rule triggers if any of them move.
// LINT.IfChange // LINT.IfChange
Class<?> clazz = Class<?> clazz =
Class.forName("org.telegram.messenger.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer"); Class.forName("com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer");
Constructor<?> constructor = Constructor<?> constructor =
clazz.getConstructor( clazz.getConstructor(
android.os.Handler.class, android.os.Handler.class,
org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.class, com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
org.telegram.messenger.exoplayer2.audio.AudioProcessor[].class); com.google.android.exoplayer2.audio.AudioProcessor[].class);
// LINT.ThenChange(../../../../../../../proguard-rules.txt) // LINT.ThenChange(../../../../../../../proguard-rules.txt)
Renderer renderer = Renderer renderer =
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors); (Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors);

View File

@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import org.telegram.messenger.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;

View File

@ -13,24 +13,24 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.os.Looper; import android.os.Looper;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.audio.MediaCodecAudioRenderer; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer;
import org.telegram.messenger.exoplayer2.metadata.MetadataRenderer; import com.google.android.exoplayer2.metadata.MetadataRenderer;
import org.telegram.messenger.exoplayer2.source.ClippingMediaSource; import com.google.android.exoplayer2.source.ClippingMediaSource;
import org.telegram.messenger.exoplayer2.source.ConcatenatingMediaSource; import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
import org.telegram.messenger.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.ExtractorMediaSource;
import org.telegram.messenger.exoplayer2.source.LoopingMediaSource; import com.google.android.exoplayer2.source.LoopingMediaSource;
import org.telegram.messenger.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import org.telegram.messenger.exoplayer2.source.MergingMediaSource; import com.google.android.exoplayer2.source.MergingMediaSource;
import org.telegram.messenger.exoplayer2.source.SingleSampleMediaSource; import com.google.android.exoplayer2.source.SingleSampleMediaSource;
import org.telegram.messenger.exoplayer2.text.TextRenderer; import com.google.android.exoplayer2.text.TextRenderer;
import org.telegram.messenger.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import org.telegram.messenger.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import org.telegram.messenger.exoplayer2.video.MediaCodecVideoRenderer; import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
/** /**
* An extensible media player that plays {@link MediaSource}s. Instances can be obtained from {@link * 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"> * model">
* *
* <ul> * <ul>
* <li>It is strongly recommended that ExoPlayer instances are created and accessed from a single * <li>ExoPlayer instances must be accessed from the thread associated with {@link
* application thread. The application's main thread is ideal. Accessing an instance from * #getApplicationLooper()}. This Looper can be specified when creating the player, or this is
* multiple threads is discouraged as it may cause synchronization problems. * the Looper of the thread the player is created on, or the Looper of the application's main
* <li>Registered listeners are called on the thread that created the ExoPlayer instance, unless * thread if the player is created on a thread without Looper.
* the thread that created the ExoPlayer instance does not have a {@link Looper}. In that * <li>Registered listeners are called on the thread thread associated with {@link
* case, registered listeners will be called on the application's main thread. * #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 * <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 * Renderers, MediaSources, TrackSelectors and LoadControls are called by the player on this
* thread. * thread.
@ -178,13 +179,15 @@ public interface ExoPlayer extends Player {
@Deprecated @Deprecated
@RepeatMode int REPEAT_MODE_ALL = Player.REPEAT_MODE_ALL; @RepeatMode int REPEAT_MODE_ALL = Player.REPEAT_MODE_ALL;
/** /** Returns the {@link Looper} associated with the playback thread. */
* Gets the {@link Looper} associated with the playback thread.
*
* @return The {@link Looper} associated with the playback thread.
*/
Looper getPlaybackLooper(); 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 * Prepares the player to play the provided {@link MediaSource}. Equivalent to
* {@code prepare(mediaSource, true, true)}. * {@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. * @param seekParameters The seek parameters, or {@code null} to use the defaults.
*/ */
void setSeekParameters(@Nullable SeekParameters seekParameters); void setSeekParameters(@Nullable SeekParameters seekParameters);
/** Returns the currently active {@link SeekParameters} of the player. */
SeekParameters getSeekParameters();
} }

View File

@ -13,21 +13,27 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.content.Context; import android.content.Context;
import android.os.Looper;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.analytics.AnalyticsCollector; import com.google.android.exoplayer2.analytics.AnalyticsCollector;
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import org.telegram.messenger.exoplayer2.util.Clock; 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. * A factory for {@link ExoPlayer} instances.
*/ */
public final class ExoPlayerFactory { public final class ExoPlayerFactory {
private static @Nullable BandwidthMeter singletonBandwidthMeter;
private ExoPlayerFactory() {} private ExoPlayerFactory() {}
/** /**
@ -155,8 +161,12 @@ public final class ExoPlayerFactory {
*/ */
public static SimpleExoPlayer newSimpleInstance(RenderersFactory renderersFactory, public static SimpleExoPlayer newSimpleInstance(RenderersFactory renderersFactory,
TrackSelector trackSelector, LoadControl loadControl) { TrackSelector trackSelector, LoadControl loadControl) {
return new SimpleExoPlayer( return newSimpleInstance(
renderersFactory, trackSelector, loadControl, /* drmSessionManager= */ null); renderersFactory,
trackSelector,
loadControl,
/* drmSessionManager= */ null,
Util.getLooper());
} }
/** /**
@ -173,7 +183,34 @@ public final class ExoPlayerFactory {
TrackSelector trackSelector, TrackSelector trackSelector,
LoadControl loadControl, LoadControl loadControl,
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) { @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, LoadControl loadControl,
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
AnalyticsCollector.Factory analyticsCollectorFactory) { 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( 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, public static ExoPlayer newInstance(Renderer[] renderers, TrackSelector trackSelector,
LoadControl loadControl) { 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;
}
} }

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.os.Handler; import android.os.Handler;
@ -22,19 +22,22 @@ import android.os.Message;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import org.telegram.messenger.exoplayer2.PlayerMessage.Target; import com.google.android.exoplayer2.PlayerMessage.Target;
import org.telegram.messenger.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import org.telegram.messenger.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectorResult; import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import org.telegram.messenger.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Assertions;
import org.telegram.messenger.exoplayer2.util.Util; 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.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
/** /**
@ -53,6 +56,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
private final CopyOnWriteArraySet<Player.EventListener> listeners; private final CopyOnWriteArraySet<Player.EventListener> listeners;
private final Timeline.Window window; private final Timeline.Window window;
private final Timeline.Period period; private final Timeline.Period period;
private final ArrayDeque<PlaybackInfoUpdate> pendingPlaybackInfoUpdates;
private boolean playWhenReady; private boolean playWhenReady;
private @RepeatMode int repeatMode; private @RepeatMode int repeatMode;
@ -61,6 +65,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
private boolean hasPendingPrepare; private boolean hasPendingPrepare;
private boolean hasPendingSeek; private boolean hasPendingSeek;
private PlaybackParameters playbackParameters; private PlaybackParameters playbackParameters;
private SeekParameters seekParameters;
private @Nullable ExoPlaybackException playbackError; private @Nullable ExoPlaybackException playbackError;
// Playback information when there is no pending seek/set source operation. // 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 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 trackSelector The {@link TrackSelector} that will be used by the instance.
* @param loadControl The {@link LoadControl} 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 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") @SuppressLint("HandlerLeak")
public ExoPlayerImpl( 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)) + " [" Log.i(TAG, "Init " + Integer.toHexString(System.identityHashCode(this)) + " ["
+ ExoPlayerLibraryInfo.VERSION_SLASHY + "] [" + Util.DEVICE_DEBUG_INFO + "]"); + ExoPlayerLibraryInfo.VERSION_SLASHY + "] [" + Util.DEVICE_DEBUG_INFO + "]");
Assertions.checkState(renderers.length > 0); Assertions.checkState(renderers.length > 0);
@ -99,25 +112,23 @@ import java.util.concurrent.CopyOnWriteArraySet;
window = new Timeline.Window(); window = new Timeline.Window();
period = new Timeline.Period(); period = new Timeline.Period();
playbackParameters = PlaybackParameters.DEFAULT; playbackParameters = PlaybackParameters.DEFAULT;
Looper eventLooper = Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper(); seekParameters = SeekParameters.DEFAULT;
eventHandler = new Handler(eventLooper) { eventHandler =
@Override new Handler(looper) {
public void handleMessage(Message msg) { @Override
ExoPlayerImpl.this.handleEvent(msg); public void handleMessage(Message msg) {
} ExoPlayerImpl.this.handleEvent(msg);
}; }
playbackInfo = };
new PlaybackInfo( playbackInfo = PlaybackInfo.createDummy(/* startPositionUs= */ 0, emptyTrackSelectorResult);
Timeline.EMPTY, pendingPlaybackInfoUpdates = new ArrayDeque<>();
/* startPositionUs= */ 0,
TrackGroupArray.EMPTY,
emptyTrackSelectorResult);
internalPlayer = internalPlayer =
new ExoPlayerImplInternal( new ExoPlayerImplInternal(
renderers, renderers,
trackSelector, trackSelector,
emptyTrackSelectorResult, emptyTrackSelectorResult,
loadControl, loadControl,
bandwidthMeter,
playWhenReady, playWhenReady,
repeatMode, repeatMode,
shuffleModeEnabled, shuffleModeEnabled,
@ -127,6 +138,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper()); internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper());
} }
@Override
public AudioComponent getAudioComponent() {
return null;
}
@Override @Override
public VideoComponent getVideoComponent() { public VideoComponent getVideoComponent() {
return null; return null;
@ -142,6 +158,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
return internalPlayer.getPlaybackLooper(); return internalPlayer.getPlaybackLooper();
} }
@Override
public Looper getApplicationLooper() {
return eventHandler.getLooper();
}
@Override @Override
public void addListener(Player.EventListener listener) { public void addListener(Player.EventListener listener) {
listeners.add(listener); listeners.add(listener);
@ -185,7 +206,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* positionDiscontinuity= */ false, /* positionDiscontinuity= */ false,
/* ignored */ DISCONTINUITY_REASON_INTERNAL, /* ignored */ DISCONTINUITY_REASON_INTERNAL,
TIMELINE_CHANGE_REASON_RESET, TIMELINE_CHANGE_REASON_RESET,
/* seekProcessed= */ false); /* seekProcessed= */ false,
/* playWhenReadyChanged= */ false);
} }
@Override @Override
@ -193,10 +215,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
if (this.playWhenReady != playWhenReady) { if (this.playWhenReady != playWhenReady) {
this.playWhenReady = playWhenReady; this.playWhenReady = playWhenReady;
internalPlayer.setPlayWhenReady(playWhenReady); internalPlayer.setPlayWhenReady(playWhenReady);
PlaybackInfo playbackInfo = this.playbackInfo; updatePlaybackInfo(
for (Player.EventListener listener : listeners) { playbackInfo,
listener.onPlayerStateChanged(playWhenReady, playbackInfo.playbackState); /* 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 { } else {
long windowPositionUs = positionMs == C.TIME_UNSET long windowPositionUs = positionMs == C.TIME_UNSET
? timeline.getWindow(windowIndex, window).getDefaultPositionUs() : C.msToUs(positionMs); ? timeline.getWindow(windowIndex, window).getDefaultPositionUs() : C.msToUs(positionMs);
Pair<Integer, Long> periodIndexAndPositon = Pair<Integer, Long> periodIndexAndPosition =
timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs); timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs);
maskingWindowPositionMs = C.usToMs(windowPositionUs); maskingWindowPositionMs = C.usToMs(windowPositionUs);
maskingPeriodIndex = periodIndexAndPositon.first; maskingPeriodIndex = periodIndexAndPosition.first;
} }
internalPlayer.seekTo(timeline, windowIndex, C.msToUs(positionMs)); internalPlayer.seekTo(timeline, windowIndex, C.msToUs(positionMs));
for (Player.EventListener listener : listeners) { for (Player.EventListener listener : listeners) {
@ -315,7 +340,15 @@ import java.util.concurrent.CopyOnWriteArraySet;
if (seekParameters == null) { if (seekParameters == null) {
seekParameters = SeekParameters.DEFAULT; seekParameters = SeekParameters.DEFAULT;
} }
internalPlayer.setSeekParameters(seekParameters); if (!this.seekParameters.equals(seekParameters)) {
this.seekParameters = seekParameters;
internalPlayer.setSeekParameters(seekParameters);
}
}
@Override
public SeekParameters getSeekParameters() {
return seekParameters;
} }
@Override @Override
@ -352,7 +385,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* positionDiscontinuity= */ false, /* positionDiscontinuity= */ false,
/* ignored */ DISCONTINUITY_REASON_INTERNAL, /* ignored */ DISCONTINUITY_REASON_INTERNAL,
TIMELINE_CHANGE_REASON_RESET, TIMELINE_CHANGE_REASON_RESET,
/* seekProcessed= */ false); /* seekProcessed= */ false,
/* playWhenReadyChanged= */ false);
} }
@Override @Override
@ -461,29 +495,37 @@ import java.util.concurrent.CopyOnWriteArraySet;
public long getCurrentPosition() { public long getCurrentPosition() {
if (shouldMaskPosition()) { if (shouldMaskPosition()) {
return maskingWindowPositionMs; return maskingWindowPositionMs;
} else if (playbackInfo.periodId.isAd()) {
return C.usToMs(playbackInfo.positionUs);
} else { } else {
return playbackInfoPositionUsToWindowPositionMs(playbackInfo.positionUs); return periodPositionUsToWindowPositionMs(playbackInfo.periodId, playbackInfo.positionUs);
} }
} }
@Override @Override
public long getBufferedPosition() { public long getBufferedPosition() {
// TODO - Implement this properly. if (isPlayingAd()) {
if (shouldMaskPosition()) { return playbackInfo.loadingMediaPeriodId.equals(playbackInfo.periodId)
return maskingWindowPositionMs; ? C.usToMs(playbackInfo.bufferedPositionUs)
} else { : getDuration();
return playbackInfoPositionUsToWindowPositionMs(playbackInfo.bufferedPositionUs);
} }
return getContentBufferedPosition();
} }
@Override @Override
public int getBufferedPercentage() { public int getBufferedPercentage() {
long position = getBufferedPosition(); long position = getBufferedPosition();
long duration = getDuration(); 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)); : (duration == 0 ? 100 : Util.constrainValue((int) ((position * 100) / duration), 0, 100));
} }
@Override
public long getTotalBufferedDuration() {
return Math.max(0, C.usToMs(playbackInfo.totalBufferedDurationUs));
}
@Override @Override
public boolean isCurrentWindowDynamic() { public boolean isCurrentWindowDynamic() {
Timeline timeline = playbackInfo.timeline; 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 @Override
public int getRendererCount() { public int getRendererCount() {
return renderers.length; return renderers.length;
@ -615,7 +680,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
positionDiscontinuity, positionDiscontinuity,
positionDiscontinuityReason, positionDiscontinuityReason,
timelineChangeReason, timelineChangeReason,
seekProcessed); seekProcessed,
/* playWhenReadyChanged= */ false);
} }
} }
@ -639,68 +705,133 @@ import java.util.concurrent.CopyOnWriteArraySet;
playbackState, playbackState,
/* isLoading= */ false, /* isLoading= */ false,
resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups, resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult); resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
playbackInfo.periodId,
playbackInfo.startPositionUs,
/* totalBufferedDurationUs= */ 0,
playbackInfo.startPositionUs);
} }
private void updatePlaybackInfo( private void updatePlaybackInfo(
PlaybackInfo newPlaybackInfo, PlaybackInfo playbackInfo,
boolean positionDiscontinuity, boolean positionDiscontinuity,
@Player.DiscontinuityReason int positionDiscontinuityReason, @Player.DiscontinuityReason int positionDiscontinuityReason,
@Player.TimelineChangeReason int timelineChangeReason, @Player.TimelineChangeReason int timelineChangeReason,
boolean seekProcessed) { boolean seekProcessed,
boolean timelineOrManifestChanged = boolean playWhenReadyChanged) {
playbackInfo.timeline != newPlaybackInfo.timeline boolean isRunningRecursiveListenerNotification = !pendingPlaybackInfoUpdates.isEmpty();
|| playbackInfo.manifest != newPlaybackInfo.manifest; pendingPlaybackInfoUpdates.addLast(
boolean playbackStateChanged = playbackInfo.playbackState != newPlaybackInfo.playbackState; new PlaybackInfoUpdate(
boolean isLoadingChanged = playbackInfo.isLoading != newPlaybackInfo.isLoading; playbackInfo,
boolean trackSelectorResultChanged = /* previousPlaybackInfo= */ this.playbackInfo,
playbackInfo.trackSelectorResult != newPlaybackInfo.trackSelectorResult; listeners,
playbackInfo = newPlaybackInfo; trackSelector,
if (timelineOrManifestChanged || timelineChangeReason == TIMELINE_CHANGE_REASON_PREPARED) { positionDiscontinuity,
for (Player.EventListener listener : listeners) { positionDiscontinuityReason,
listener.onTimelineChanged( timelineChangeReason,
playbackInfo.timeline, playbackInfo.manifest, timelineChangeReason); seekProcessed,
} playWhenReady,
playWhenReadyChanged));
// Assign playback info immediately such that all getters return the right values.
this.playbackInfo = playbackInfo;
if (isRunningRecursiveListenerNotification) {
return;
} }
if (positionDiscontinuity) { while (!pendingPlaybackInfoUpdates.isEmpty()) {
for (Player.EventListener listener : listeners) { pendingPlaybackInfoUpdates.peekFirst().notifyListeners();
listener.onPositionDiscontinuity(positionDiscontinuityReason); pendingPlaybackInfoUpdates.removeFirst();
}
}
if (trackSelectorResultChanged) {
trackSelector.onSelectionActivated(playbackInfo.trackSelectorResult.info);
for (Player.EventListener listener : listeners) {
listener.onTracksChanged(
playbackInfo.trackGroups, playbackInfo.trackSelectorResult.selections);
}
}
if (isLoadingChanged) {
for (Player.EventListener listener : listeners) {
listener.onLoadingChanged(playbackInfo.isLoading);
}
}
if (playbackStateChanged) {
for (Player.EventListener listener : listeners) {
listener.onPlayerStateChanged(playWhenReady, playbackInfo.playbackState);
}
}
if (seekProcessed) {
for (Player.EventListener listener : listeners) {
listener.onSeekProcessed();
}
} }
} }
private long playbackInfoPositionUsToWindowPositionMs(long positionUs) { private long periodPositionUsToWindowPositionMs(MediaPeriodId periodId, long positionUs) {
long positionMs = C.usToMs(positionUs); long positionMs = C.usToMs(positionUs);
if (!playbackInfo.periodId.isAd()) { playbackInfo.timeline.getPeriod(periodId.periodIndex, period);
playbackInfo.timeline.getPeriod(playbackInfo.periodId.periodIndex, period); positionMs += period.getPositionInWindowMs();
positionMs += period.getPositionInWindowMs();
}
return positionMs; return positionMs;
} }
private boolean shouldMaskPosition() { private boolean shouldMaskPosition() {
return playbackInfo.timeline.isEmpty() || pendingOperationAcks > 0; 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(
playbackInfo.timeline, playbackInfo.manifest, timelineChangeReason);
}
}
if (positionDiscontinuity) {
for (Player.EventListener listener : listeners) {
listener.onPositionDiscontinuity(positionDiscontinuityReason);
}
}
if (trackSelectorResultChanged) {
trackSelector.onSelectionActivated(playbackInfo.trackSelectorResult.info);
for (Player.EventListener listener : listeners) {
listener.onTracksChanged(
playbackInfo.trackGroups, playbackInfo.trackSelectorResult.selections);
}
}
if (isLoadingChanged) {
for (Player.EventListener listener : listeners) {
listener.onLoadingChanged(playbackInfo.isLoading);
}
}
if (playbackStateOrPlayWhenReadyChanged) {
for (Player.EventListener listener : listeners) {
listener.onPlayerStateChanged(playWhenReady, playbackInfo.playbackState);
}
}
if (seekProcessed) {
for (Player.EventListener listener : listeners) {
listener.onSeekProcessed();
}
}
}
}
} }

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
@ -25,21 +25,22 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import org.telegram.messenger.exoplayer2.DefaultMediaClock.PlaybackParameterListener; import com.google.android.exoplayer2.DefaultMediaClock.PlaybackParameterListener;
import org.telegram.messenger.exoplayer2.Player.DiscontinuityReason; import com.google.android.exoplayer2.Player.DiscontinuityReason;
import org.telegram.messenger.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import org.telegram.messenger.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import org.telegram.messenger.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
import org.telegram.messenger.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectorResult; import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import org.telegram.messenger.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Assertions;
import org.telegram.messenger.exoplayer2.util.HandlerWrapper; import com.google.android.exoplayer2.util.Clock;
import org.telegram.messenger.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.HandlerWrapper;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; 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_SET_SHUFFLE_ENABLED = 13;
private static final int MSG_SEND_MESSAGE = 14; private static final int MSG_SEND_MESSAGE = 14;
private static final int MSG_SEND_MESSAGE_TO_TARGET_THREAD = 15; 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 PREPARING_SOURCE_INTERVAL_MS = 10;
private static final int RENDERING_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 TrackSelector trackSelector;
private final TrackSelectorResult emptyTrackSelectorResult; private final TrackSelectorResult emptyTrackSelectorResult;
private final LoadControl loadControl; private final LoadControl loadControl;
private final BandwidthMeter bandwidthMeter;
private final HandlerWrapper handler; private final HandlerWrapper handler;
private final HandlerThread internalPlaybackThread; private final HandlerThread internalPlaybackThread;
private final Handler eventHandler; private final Handler eventHandler;
@ -123,6 +126,7 @@ import java.util.Collections;
TrackSelector trackSelector, TrackSelector trackSelector,
TrackSelectorResult emptyTrackSelectorResult, TrackSelectorResult emptyTrackSelectorResult,
LoadControl loadControl, LoadControl loadControl,
BandwidthMeter bandwidthMeter,
boolean playWhenReady, boolean playWhenReady,
@Player.RepeatMode int repeatMode, @Player.RepeatMode int repeatMode,
boolean shuffleModeEnabled, boolean shuffleModeEnabled,
@ -133,6 +137,7 @@ import java.util.Collections;
this.trackSelector = trackSelector; this.trackSelector = trackSelector;
this.emptyTrackSelectorResult = emptyTrackSelectorResult; this.emptyTrackSelectorResult = emptyTrackSelectorResult;
this.loadControl = loadControl; this.loadControl = loadControl;
this.bandwidthMeter = bandwidthMeter;
this.playWhenReady = playWhenReady; this.playWhenReady = playWhenReady;
this.repeatMode = repeatMode; this.repeatMode = repeatMode;
this.shuffleModeEnabled = shuffleModeEnabled; this.shuffleModeEnabled = shuffleModeEnabled;
@ -146,11 +151,7 @@ import java.util.Collections;
seekParameters = SeekParameters.DEFAULT; seekParameters = SeekParameters.DEFAULT;
playbackInfo = playbackInfo =
new PlaybackInfo( PlaybackInfo.createDummy(/* startPositionUs= */ C.TIME_UNSET, emptyTrackSelectorResult);
Timeline.EMPTY,
/* startPositionUs= */ C.TIME_UNSET,
TrackGroupArray.EMPTY,
emptyTrackSelectorResult);
playbackInfoUpdate = new PlaybackInfoUpdate(); playbackInfoUpdate = new PlaybackInfoUpdate();
rendererCapabilities = new RendererCapabilities[renderers.length]; rendererCapabilities = new RendererCapabilities[renderers.length];
for (int i = 0; i < renderers.length; i++) { for (int i = 0; i < renderers.length; i++) {
@ -162,7 +163,7 @@ import java.util.Collections;
enabledRenderers = new Renderer[0]; enabledRenderers = new Renderer[0];
window = new Timeline.Window(); window = new Timeline.Window();
period = new Timeline.Period(); period = new Timeline.Period();
trackSelector.init(this); trackSelector.init(/* listener= */ this, bandwidthMeter);
// Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can // Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can
// not normally change to this priority" is incorrect. // not normally change to this priority" is incorrect.
@ -271,8 +272,9 @@ import java.util.Collections;
@Override @Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
eventHandler.obtainMessage(MSG_PLAYBACK_PARAMETERS_CHANGED, playbackParameters).sendToTarget(); handler
updateTrackSelectionPlaybackSpeed(playbackParameters.speed); .obtainMessage(MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL, playbackParameters)
.sendToTarget();
} }
// Handler.Callback implementation. // Handler.Callback implementation.
@ -324,6 +326,9 @@ import java.util.Collections;
case MSG_TRACK_SELECTION_INVALIDATED: case MSG_TRACK_SELECTION_INVALIDATED:
reselectTracksInternal(); reselectTracksInternal();
break; break;
case MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL:
handlePlaybackParameters((PlaybackParameters) msg.obj);
break;
case MSG_SEND_MESSAGE: case MSG_SEND_MESSAGE:
sendMessageInternal((PlayerMessage) msg.obj); sendMessageInternal((PlayerMessage) msg.obj);
break; break;
@ -393,7 +398,11 @@ import java.util.Collections;
loadControl.onPrepared(); loadControl.onPrepared();
this.mediaSource = mediaSource; this.mediaSource = mediaSource;
setState(Player.STATE_BUFFERING); 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); handler.sendEmptyMessage(MSG_DO_SOME_WORK);
} }
@ -419,6 +428,7 @@ import java.util.Collections;
if (!queue.updateRepeatMode(repeatMode)) { if (!queue.updateRepeatMode(repeatMode)) {
seekToCurrentPosition(/* sendDiscontinuity= */ true); seekToCurrentPosition(/* sendDiscontinuity= */ true);
} }
updateLoadingMediaPeriodId();
} }
private void setShuffleModeEnabledInternal(boolean shuffleModeEnabled) private void setShuffleModeEnabledInternal(boolean shuffleModeEnabled)
@ -427,6 +437,7 @@ import java.util.Collections;
if (!queue.updateShuffleModeEnabled(shuffleModeEnabled)) { if (!queue.updateShuffleModeEnabled(shuffleModeEnabled)) {
seekToCurrentPosition(/* sendDiscontinuity= */ true); seekToCurrentPosition(/* sendDiscontinuity= */ true);
} }
updateLoadingMediaPeriodId();
} }
private void seekToCurrentPosition(boolean sendDiscontinuity) throws ExoPlaybackException { private void seekToCurrentPosition(boolean sendDiscontinuity) throws ExoPlaybackException {
@ -483,11 +494,12 @@ import java.util.Collections;
playbackInfo.positionUs = periodPositionUs; playbackInfo.positionUs = periodPositionUs;
} }
// Update the buffered position. // Update the buffered position and total buffered duration.
MediaPeriodHolder loadingPeriod = queue.getLoadingPeriod();
playbackInfo.bufferedPositionUs = playbackInfo.bufferedPositionUs =
enabledRenderers.length == 0 loadingPeriod.getBufferedPositionUs(/* convertEosToDuration= */ true);
? playingPeriodHolder.info.durationUs playbackInfo.totalBufferedDurationUs =
: playingPeriodHolder.getBufferedPositionUs(/* convertEosToDuration= */ true); playbackInfo.bufferedPositionUs - loadingPeriod.toPeriodTime(rendererPositionUs);
} }
private void doSomeWork() throws ExoPlaybackException, IOException { private void doSomeWork() throws ExoPlaybackException, IOException {
@ -587,7 +599,7 @@ import java.util.Collections;
if (resolvedSeekPosition == null) { if (resolvedSeekPosition == null) {
// The seek position was valid for the timeline that it was performed into, but the // 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. // 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; periodPositionUs = C.TIME_UNSET;
contentPositionUs = C.TIME_UNSET; contentPositionUs = C.TIME_UNSET;
seekPositionAdjusted = true; seekPositionAdjusted = true;
@ -660,7 +672,7 @@ import java.util.Collections;
MediaPeriodHolder oldPlayingPeriodHolder = queue.getPlayingPeriod(); MediaPeriodHolder oldPlayingPeriodHolder = queue.getPlayingPeriod();
MediaPeriodHolder newPlayingPeriodHolder = oldPlayingPeriodHolder; MediaPeriodHolder newPlayingPeriodHolder = oldPlayingPeriodHolder;
while (newPlayingPeriodHolder != null) { while (newPlayingPeriodHolder != null) {
if (shouldKeepPeriodHolder(periodId, periodPositionUs, newPlayingPeriodHolder)) { if (periodId.equals(newPlayingPeriodHolder.info.id) && newPlayingPeriodHolder.prepared) {
queue.removeAfter(newPlayingPeriodHolder); queue.removeAfter(newPlayingPeriodHolder);
break; break;
} }
@ -691,23 +703,11 @@ import java.util.Collections;
resetRendererPosition(periodPositionUs); resetRendererPosition(periodPositionUs);
} }
updateLoadingMediaPeriodId();
handler.sendEmptyMessage(MSG_DO_SOME_WORK); handler.sendEmptyMessage(MSG_DO_SOME_WORK);
return periodPositionUs; 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 { private void resetRendererPosition(long periodPositionUs) throws ExoPlaybackException {
rendererPositionUs = rendererPositionUs =
!queue.hasPlayingPeriod() !queue.hasPlayingPeriod()
@ -749,12 +749,15 @@ import java.util.Collections;
} }
} }
private int getFirstPeriodIndex() { private MediaPeriodId getFirstMediaPeriodId() {
Timeline timeline = playbackInfo.timeline; Timeline timeline = playbackInfo.timeline;
return timeline.isEmpty() if (timeline.isEmpty()) {
? 0 return PlaybackInfo.DUMMY_MEDIA_PERIOD_ID;
: timeline.getWindow(timeline.getFirstWindowIndex(shuffleModeEnabled), window) }
int firstPeriodIndex =
timeline.getWindow(timeline.getFirstWindowIndex(shuffleModeEnabled), window)
.firstPeriodIndex; .firstPeriodIndex;
return new MediaPeriodId(firstPeriodIndex);
} }
private void resetInternal( private void resetInternal(
@ -785,18 +788,25 @@ import java.util.Collections;
pendingMessages.clear(); pendingMessages.clear();
nextPendingMessageIndex = 0; 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 = playbackInfo =
new PlaybackInfo( new PlaybackInfo(
resetState ? Timeline.EMPTY : playbackInfo.timeline, resetState ? Timeline.EMPTY : playbackInfo.timeline,
resetState ? null : playbackInfo.manifest, resetState ? null : playbackInfo.manifest,
resetPosition ? new MediaPeriodId(getFirstPeriodIndex()) : playbackInfo.periodId, mediaPeriodId,
// Set the start position to TIME_UNSET so that a subsequent seek to 0 isn't ignored. startPositionUs,
resetPosition ? C.TIME_UNSET : playbackInfo.positionUs, contentPositionUs,
resetPosition ? C.TIME_UNSET : playbackInfo.contentPositionUs,
playbackInfo.playbackState, playbackInfo.playbackState,
/* isLoading= */ false, /* isLoading= */ false,
resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups, resetState ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult); resetState ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
mediaPeriodId,
startPositionUs,
/* totalBufferedDurationUs= */ 0,
startPositionUs);
if (releaseMediaSource) { if (releaseMediaSource) {
if (mediaSource != null) { if (mediaSource != null) {
mediaSource.releaseSource(/* listener= */ this); mediaSource.releaseSource(/* listener= */ this);
@ -892,7 +902,7 @@ import java.util.Collections;
pendingMessageInfo.setResolvedPosition( pendingMessageInfo.setResolvedPosition(
periodPosition.first, periodPosition.first,
periodPosition.second, periodPosition.second,
playbackInfo.timeline.getPeriod(periodPosition.first, period, true).uid); playbackInfo.timeline.getUidOfPeriod(periodPosition.first));
} else { } else {
// Position has been resolved for a previous timeline. Try to find the updated period index. // Position has been resolved for a previous timeline. Try to find the updated period index.
int index = playbackInfo.timeline.getIndexOfPeriod(pendingMessageInfo.resolvedPeriodUid); int index = playbackInfo.timeline.getIndexOfPeriod(pendingMessageInfo.resolvedPeriodUid);
@ -1051,6 +1061,7 @@ import java.util.Collections;
updateLoadControlTrackSelection(periodHolder.trackGroups, periodHolder.trackSelectorResult); updateLoadControlTrackSelection(periodHolder.trackGroups, periodHolder.trackSelectorResult);
} }
} }
updateLoadingMediaPeriodId();
if (playbackInfo.playbackState != Player.STATE_ENDED) { if (playbackInfo.playbackState != Player.STATE_ENDED) {
maybeContinueLoading(); maybeContinueLoading();
updatePlaybackPositions(); updatePlaybackPositions();
@ -1142,8 +1153,15 @@ import java.util.Collections;
playbackInfoUpdate.incrementPendingOperationAcks(pendingPrepareCount); playbackInfoUpdate.incrementPendingOperationAcks(pendingPrepareCount);
pendingPrepareCount = 0; pendingPrepareCount = 0;
if (pendingInitialSeekPosition != null) { if (pendingInitialSeekPosition != null) {
Pair<Integer, Long> periodPosition = Pair<Integer, Long> periodPosition;
resolveSeekPosition(pendingInitialSeekPosition, /* trySubsequentPeriods= */ true); try {
periodPosition =
resolveSeekPosition(pendingInitialSeekPosition, /* trySubsequentPeriods= */ true);
} catch (IllegalSeekPositionException e) {
playbackInfo =
playbackInfo.fromNewPosition(getFirstMediaPeriodId(), C.TIME_UNSET, C.TIME_UNSET);
throw e;
}
pendingInitialSeekPosition = null; pendingInitialSeekPosition = null;
if (periodPosition == null) { if (periodPosition == null) {
// The seek position was valid for the timeline that it was performed into, but the // The seek position was valid for the timeline that it was performed into, but the
@ -1176,22 +1194,28 @@ import java.util.Collections;
return; return;
} }
int playingPeriodIndex = playbackInfo.periodId.periodIndex;
long contentPositionUs = playbackInfo.contentPositionUs;
if (oldTimeline.isEmpty()) { if (oldTimeline.isEmpty()) {
// If the old timeline is empty, the period queue is also empty. // If the old timeline is empty, the period queue is also empty.
if (!timeline.isEmpty()) { if (!timeline.isEmpty()) {
MediaPeriodId periodId = Pair<Integer, Long> defaultPosition =
queue.resolveMediaPeriodIdForAds(playingPeriodIndex, contentPositionUs); getPeriodPosition(
timeline, timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET);
int periodIndex = defaultPosition.first;
long startPositionUs = defaultPosition.second;
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodIndex, startPositionUs);
playbackInfo = playbackInfo =
playbackInfo.fromNewPosition( playbackInfo.fromNewPosition(
periodId, periodId.isAd() ? 0 : contentPositionUs, contentPositionUs); periodId,
/* startPositionUs= */ periodId.isAd() ? 0 : startPositionUs,
/* contentPositionUs= */ startPositionUs);
} }
return; return;
} }
MediaPeriodHolder periodHolder = queue.getFrontPeriod(); MediaPeriodHolder periodHolder = queue.getFrontPeriod();
Object playingPeriodUid = periodHolder == null int playingPeriodIndex = playbackInfo.periodId.periodIndex;
? oldTimeline.getPeriod(playingPeriodIndex, period, true).uid : periodHolder.uid; long contentPositionUs = playbackInfo.contentPositionUs;
Object playingPeriodUid =
periodHolder == null ? oldTimeline.getUidOfPeriod(playingPeriodIndex) : periodHolder.uid;
int periodIndex = timeline.getIndexOfPeriod(playingPeriodUid); int periodIndex = timeline.getIndexOfPeriod(playingPeriodUid);
if (periodIndex == C.INDEX_UNSET) { if (periodIndex == C.INDEX_UNSET) {
// We didn't find the current period in the new timeline. Attempt to resolve a subsequent // 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; newPeriodIndex = defaultPosition.first;
contentPositionUs = defaultPosition.second; contentPositionUs = defaultPosition.second;
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(newPeriodIndex, contentPositionUs); MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(newPeriodIndex, contentPositionUs);
timeline.getPeriod(newPeriodIndex, period, true);
if (periodHolder != null) { if (periodHolder != null) {
// Clear the index of each holder that doesn't contain the default position. If a holder // 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. // 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); periodHolder.info = periodHolder.info.copyWithPeriodIndex(C.INDEX_UNSET);
while (periodHolder.next != null) { while (periodHolder.next != null) {
periodHolder = periodHolder.next; periodHolder = periodHolder.next;
@ -1249,6 +1272,7 @@ import java.util.Collections;
if (!queue.updateQueuedPeriods(playingPeriodId, rendererPositionUs)) { if (!queue.updateQueuedPeriods(playingPeriodId, rendererPositionUs)) {
seekToCurrentPosition(/* sendDiscontinuity= */ false); seekToCurrentPosition(/* sendDiscontinuity= */ false);
} }
updateLoadingMediaPeriodId();
} }
private void handleSourceInfoRefreshEndedPlayback() { private void handleSourceInfoRefreshEndedPlayback() {
@ -1279,8 +1303,7 @@ import java.util.Collections;
// We've reached the end of the old timeline. // We've reached the end of the old timeline.
break; break;
} }
newPeriodIndex = newTimeline.getIndexOfPeriod( newPeriodIndex = newTimeline.getIndexOfPeriod(oldTimeline.getUidOfPeriod(oldPeriodIndex));
oldTimeline.getPeriod(oldPeriodIndex, period, true).uid);
} }
return newPeriodIndex; return newPeriodIndex;
} }
@ -1324,8 +1347,7 @@ import java.util.Collections;
return periodPosition; return periodPosition;
} }
// Attempt to find the mapped period in the internal timeline. // Attempt to find the mapped period in the internal timeline.
int periodIndex = timeline.getIndexOfPeriod( int periodIndex = timeline.getIndexOfPeriod(seekTimeline.getUidOfPeriod(periodPosition.first));
seekTimeline.getPeriod(periodPosition.first, period, true).uid);
if (periodIndex != C.INDEX_UNSET) { if (periodIndex != C.INDEX_UNSET) {
// We successfully located the period in the internal timeline. // We successfully located the period in the internal timeline.
return Pair.create(periodIndex, periodPosition.second); return Pair.create(periodIndex, periodPosition.second);
@ -1483,7 +1505,7 @@ import java.util.Collections;
if (info == null) { if (info == null) {
mediaSource.maybeThrowSourceInfoRefreshError(); mediaSource.maybeThrowSourceInfoRefreshError();
} else { } else {
Object uid = playbackInfo.timeline.getPeriod(info.id.periodIndex, period, true).uid; Object uid = playbackInfo.timeline.getUidOfPeriod(info.id.periodIndex);
MediaPeriod mediaPeriod = MediaPeriod mediaPeriod =
queue.enqueueNextMediaPeriod( queue.enqueueNextMediaPeriod(
rendererCapabilities, rendererCapabilities,
@ -1494,6 +1516,7 @@ import java.util.Collections;
info); info);
mediaPeriod.prepare(this, info.startPositionUs); mediaPeriod.prepare(this, info.startPositionUs);
setIsLoading(true); setIsLoading(true);
updateLoadingMediaPeriodId();
} }
} }
} }
@ -1525,6 +1548,17 @@ import java.util.Collections;
maybeContinueLoading(); 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() { private void maybeContinueLoading() {
MediaPeriodHolder loadingPeriodHolder = queue.getLoadingPeriod(); MediaPeriodHolder loadingPeriodHolder = queue.getLoadingPeriod();
long nextLoadPositionUs = loadingPeriodHolder.getNextLoadPositionUs(); long nextLoadPositionUs = loadingPeriodHolder.getNextLoadPositionUs();
@ -1543,6 +1577,7 @@ import java.util.Collections;
} }
} }
@SuppressWarnings("ParameterNotNullable")
private void updatePlayingPeriodRenderers(@Nullable MediaPeriodHolder oldPlayingPeriodHolder) private void updatePlayingPeriodRenderers(@Nullable MediaPeriodHolder oldPlayingPeriodHolder)
throws ExoPlaybackException { throws ExoPlaybackException {
MediaPeriodHolder newPlayingPeriodHolder = queue.getPlayingPeriod(); MediaPeriodHolder newPlayingPeriodHolder = queue.getPlayingPeriod();
@ -1619,6 +1654,13 @@ import java.util.Collections;
&& renderer.hasReadStreamToEnd(); && renderer.hasReadStreamToEnd();
} }
private void updateLoadingMediaPeriodId() {
MediaPeriodHolder loadingMediaPeriodHolder = queue.getLoadingPeriod();
MediaPeriodId loadingMediaPeriodId =
loadingMediaPeriodHolder == null ? playbackInfo.periodId : loadingMediaPeriodHolder.info.id;
playbackInfo = playbackInfo.copyWithLoadingMediaPeriodId(loadingMediaPeriodId);
}
@NonNull @NonNull
private static Format[] getFormats(TrackSelection newSelection) { private static Format[] getFormats(TrackSelection newSelection) {
// Build an array of formats contained by the selection. // Build an array of formats contained by the selection.

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import java.util.HashSet; 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". */ /** 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. // 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}. */ /** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. // 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. * 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). * integer version 123045006 (123-045-006).
*/ */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. // 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. * checks enabled.
*/ */
public static final boolean ASSERTIONS_ENABLED = true; 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. * trace enabled.
*/ */
public static final boolean TRACE_ENABLED = true; public static final boolean TRACE_ENABLED = true;

View File

@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.support.annotation.Nullable;
/** /**
* Holds a {@link Format}. * Holds a {@link Format}.
*/ */
public final class FormatHolder { public final class FormatHolder {
/** /** The held {@link Format}. */
* The held {@link Format}. public @Nullable Format format;
*/
public Format format;
} }

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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 * Thrown when an attempt is made to seek to a position that does not exist in the player's

View File

@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import org.telegram.messenger.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import org.telegram.messenger.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import org.telegram.messenger.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
/** /**
* Controls buffering of media. * Controls buffering of media.

View File

@ -13,21 +13,21 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.util.Log; import android.util.Log;
import org.telegram.messenger.exoplayer2.source.ClippingMediaPeriod; import com.google.android.exoplayer2.source.ClippingMediaPeriod;
import org.telegram.messenger.exoplayer2.source.EmptySampleStream; import com.google.android.exoplayer2.source.EmptySampleStream;
import org.telegram.messenger.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import org.telegram.messenger.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import org.telegram.messenger.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
import org.telegram.messenger.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectorResult; import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
import org.telegram.messenger.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
/** Holds a {@link MediaPeriod} with information required to play it as part of a timeline. */ /** Holds a {@link MediaPeriod} with information required to play it as part of a timeline. */
/* package */ final class MediaPeriodHolder { /* package */ final class MediaPeriodHolder {
@ -82,13 +82,13 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
sampleStreams = new SampleStream[rendererCapabilities.length]; sampleStreams = new SampleStream[rendererCapabilities.length];
mayRetainStreamFlags = new boolean[rendererCapabilities.length]; mayRetainStreamFlags = new boolean[rendererCapabilities.length];
MediaPeriod mediaPeriod = mediaSource.createPeriod(info.id, allocator); 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 = mediaPeriod =
new ClippingMediaPeriod( new ClippingMediaPeriod(
mediaPeriod, mediaPeriod,
/* enableInitialDiscontinuity= */ true, /* enableInitialDiscontinuity= */ true,
/* startUs= */ 0, /* startUs= */ 0,
info.endPositionUs); info.id.endPositionUs);
} }
this.mediaPeriod = mediaPeriod; this.mediaPeriod = mediaPeriod;
} }
@ -127,7 +127,8 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
if (!prepared) { if (!prepared) {
return info.startPositionUs; 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 return bufferedPositionUs == C.TIME_END_OF_SOURCE && convertEosToDuration
? info.durationUs ? info.durationUs
: bufferedPositionUs; : bufferedPositionUs;
@ -218,7 +219,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
public void release() { public void release() {
updatePeriodTrackSelectorResult(null); updatePeriodTrackSelectorResult(null);
try { try {
if (info.endPositionUs != C.TIME_END_OF_SOURCE) { if (info.id.endPositionUs != C.TIME_END_OF_SOURCE) {
mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod); mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod);
} else { } else {
mediaSource.releasePeriod(mediaPeriod); mediaSource.releasePeriod(mediaPeriod);

View File

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import org.telegram.messenger.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
/** Stores the information required to load and play a {@link MediaPeriod}. */ /** Stores the information required to load and play a {@link MediaPeriod}. */
/* package */ final class MediaPeriodInfo { /* package */ final class MediaPeriodInfo {
@ -25,18 +25,13 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
public final MediaPeriodId id; public final MediaPeriodId id;
/** The start position of the media to play within the media period, in microseconds. */ /** The start position of the media to play within the media period, in microseconds. */
public final long startPositionUs; 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} * If this is an ad, the position to play in the next content media period. {@link C#TIME_UNSET}
* otherwise. * otherwise.
*/ */
public final long contentPositionUs; 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 * C#TIME_END_OF_SOURCE} resolved to the timeline period duration. May be {@link C#TIME_UNSET} if
* the end position is not known. * the end position is not known.
*/ */
@ -55,14 +50,12 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
MediaPeriodInfo( MediaPeriodInfo(
MediaPeriodId id, MediaPeriodId id,
long startPositionUs, long startPositionUs,
long endPositionUs,
long contentPositionUs, long contentPositionUs,
long durationUs, long durationUs,
boolean isLastInTimelinePeriod, boolean isLastInTimelinePeriod,
boolean isFinal) { boolean isFinal) {
this.id = id; this.id = id;
this.startPositionUs = startPositionUs; this.startPositionUs = startPositionUs;
this.endPositionUs = endPositionUs;
this.contentPositionUs = contentPositionUs; this.contentPositionUs = contentPositionUs;
this.durationUs = durationUs; this.durationUs = durationUs;
this.isLastInTimelinePeriod = isLastInTimelinePeriod; this.isLastInTimelinePeriod = isLastInTimelinePeriod;
@ -77,7 +70,6 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
return new MediaPeriodInfo( return new MediaPeriodInfo(
id.copyWithPeriodIndex(periodIndex), id.copyWithPeriodIndex(periodIndex),
startPositionUs, startPositionUs,
endPositionUs,
contentPositionUs, contentPositionUs,
durationUs, durationUs,
isLastInTimelinePeriod, isLastInTimelinePeriod,
@ -89,7 +81,6 @@ import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId;
return new MediaPeriodInfo( return new MediaPeriodInfo(
id, id,
startPositionUs, startPositionUs,
endPositionUs,
contentPositionUs, contentPositionUs,
durationUs, durationUs,
isLastInTimelinePeriod, isLastInTimelinePeriod,

View File

@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Pair; import android.util.Pair;
import org.telegram.messenger.exoplayer2.Player.RepeatMode; import com.google.android.exoplayer2.Player.RepeatMode;
import org.telegram.messenger.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import org.telegram.messenger.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import org.telegram.messenger.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
/** /**
* Holds a queue of media periods, from the currently playing media period at the front to the * 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 Timeline timeline;
private @RepeatMode int repeatMode; private @RepeatMode int repeatMode;
private boolean shuffleModeEnabled; private boolean shuffleModeEnabled;
private MediaPeriodHolder playing; private @Nullable MediaPeriodHolder playing;
private MediaPeriodHolder reading; private @Nullable MediaPeriodHolder reading;
private MediaPeriodHolder loading; private @Nullable MediaPeriodHolder loading;
private int length; private int length;
private Object oldFrontPeriodUid; private @Nullable Object oldFrontPeriodUid;
private long oldFrontPeriodWindowSequenceNumber; private long oldFrontPeriodWindowSequenceNumber;
/** Creates a new media period queue. */ /** Creates a new media period queue. */
public MediaPeriodQueue() { public MediaPeriodQueue() {
period = new Timeline.Period(); period = new Timeline.Period();
window = new Timeline.Window(); window = new Timeline.Window();
timeline = Timeline.EMPTY;
} }
/** /**
@ -228,11 +229,13 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
reading = playing.next; reading = playing.next;
} }
playing.release(); playing.release();
playing = playing.next;
length--; length--;
if (length == 0) { if (length == 0) {
loading = null; loading = null;
oldFrontPeriodUid = playing.uid;
oldFrontPeriodWindowSequenceNumber = playing.info.id.windowSequenceNumber;
} }
playing = playing.next;
} else { } else {
playing = loading; playing = loading;
reading = loading; reading = loading;
@ -312,7 +315,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
} else { } else {
// Check this period holder still follows the previous one, based on the new timeline. // Check this period holder still follows the previous one, based on the new timeline.
if (periodIndex == C.INDEX_UNSET 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. // The holder uid is inconsistent with the new timeline.
return !removeAfter(previousPeriodHolder); return !removeAfter(previousPeriodHolder);
} }
@ -389,7 +392,12 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
timeline.getPeriod(periodIndex, period); timeline.getPeriod(periodIndex, period);
int adGroupIndex = period.getAdGroupIndexForPositionUs(positionUs); int adGroupIndex = period.getAdGroupIndexForPositionUs(positionUs);
if (adGroupIndex == C.INDEX_UNSET) { 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 { } else {
int adIndexInAdGroup = period.getFirstAdIndexToPlay(adGroupIndex); int adIndexInAdGroup = period.getFirstAdIndexToPlay(adGroupIndex);
return new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); 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) { private boolean canKeepMediaPeriodHolder(MediaPeriodHolder periodHolder, MediaPeriodInfo info) {
MediaPeriodInfo periodHolderInfo = periodHolder.info; MediaPeriodInfo periodHolderInfo = periodHolder.info;
return periodHolderInfo.startPositionUs == info.startPositionUs return periodHolderInfo.startPositionUs == info.startPositionUs
&& periodHolderInfo.endPositionUs == info.endPositionUs
&& periodHolderInfo.id.equals(info.id); && periodHolderInfo.id.equals(info.id);
} }
@ -591,14 +598,14 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
mediaPeriodInfo.contentPositionUs, mediaPeriodInfo.contentPositionUs,
currentPeriodId.windowSequenceNumber); 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. // 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) { if (nextAdGroupIndex == C.INDEX_UNSET) {
// The next ad group can't be played. Play content from the ad group position instead. // The next ad group can't be played. Play content from the ad group position instead.
return getMediaPeriodInfoForContent( return getMediaPeriodInfoForContent(
currentPeriodId.periodIndex, currentPeriodId.periodIndex,
mediaPeriodInfo.endPositionUs, mediaPeriodInfo.id.endPositionUs,
currentPeriodId.windowSequenceNumber); currentPeriodId.windowSequenceNumber);
} }
int adIndexInAdGroup = period.getFirstAdIndexToPlay(nextAdGroupIndex); int adIndexInAdGroup = period.getFirstAdIndexToPlay(nextAdGroupIndex);
@ -608,7 +615,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
currentPeriodId.periodIndex, currentPeriodId.periodIndex,
nextAdGroupIndex, nextAdGroupIndex,
adIndexInAdGroup, adIndexInAdGroup,
mediaPeriodInfo.endPositionUs, mediaPeriodInfo.id.endPositionUs,
currentPeriodId.windowSequenceNumber); currentPeriodId.windowSequenceNumber);
} else { } else {
// Check if the postroll ad should be played. // 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) { private MediaPeriodInfo getUpdatedMediaPeriodInfo(MediaPeriodInfo info, MediaPeriodId newId) {
long startPositionUs = info.startPositionUs; long startPositionUs = info.startPositionUs;
long endPositionUs = info.endPositionUs; boolean isLastInPeriod = isLastInPeriod(newId);
boolean isLastInPeriod = isLastInPeriod(newId, endPositionUs);
boolean isLastInTimeline = isLastInTimeline(newId, isLastInPeriod); boolean isLastInTimeline = isLastInTimeline(newId, isLastInPeriod);
timeline.getPeriod(newId.periodIndex, period); timeline.getPeriod(newId.periodIndex, period);
long durationUs = long durationUs =
newId.isAd() newId.isAd()
? period.getAdDurationUs(newId.adGroupIndex, newId.adIndexInAdGroup) ? 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( return new MediaPeriodInfo(
newId, newId,
startPositionUs, startPositionUs,
endPositionUs,
info.contentPositionUs, info.contentPositionUs,
durationUs, durationUs,
isLastInPeriod, isLastInPeriod,
@ -681,7 +688,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
long windowSequenceNumber) { long windowSequenceNumber) {
MediaPeriodId id = MediaPeriodId id =
new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber);
boolean isLastInPeriod = isLastInPeriod(id, C.TIME_END_OF_SOURCE); boolean isLastInPeriod = isLastInPeriod(id);
boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod);
long durationUs = long durationUs =
timeline timeline
@ -694,7 +701,6 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
return new MediaPeriodInfo( return new MediaPeriodInfo(
id, id,
startPositionUs, startPositionUs,
C.TIME_END_OF_SOURCE,
contentPositionUs, contentPositionUs,
durationUs, durationUs,
isLastInPeriod, isLastInPeriod,
@ -703,21 +709,22 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
private MediaPeriodInfo getMediaPeriodInfoForContent( private MediaPeriodInfo getMediaPeriodInfoForContent(
int periodIndex, long startPositionUs, long windowSequenceNumber) { int periodIndex, long startPositionUs, long windowSequenceNumber) {
MediaPeriodId id = new MediaPeriodId(periodIndex, windowSequenceNumber);
timeline.getPeriod(id.periodIndex, period);
int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(startPositionUs); int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(startPositionUs);
long endUs = long endPositionUs =
nextAdGroupIndex == C.INDEX_UNSET nextAdGroupIndex == C.INDEX_UNSET
? C.TIME_END_OF_SOURCE ? C.TIME_END_OF_SOURCE
: period.getAdGroupTimeUs(nextAdGroupIndex); : 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); 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( 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(); int adGroupCount = timeline.getPeriod(id.periodIndex, period).getAdGroupCount();
if (adGroupCount == 0) { if (adGroupCount == 0) {
return true; return true;
@ -727,7 +734,7 @@ import org.telegram.messenger.exoplayer2.util.Assertions;
boolean isAd = id.isAd(); boolean isAd = id.isAd();
if (period.getAdGroupTimeUs(lastAdGroupIndex) != C.TIME_END_OF_SOURCE) { if (period.getAdGroupTimeUs(lastAdGroupIndex) != C.TIME_END_OF_SOURCE) {
// There's no postroll ad. // 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); int postrollAdCount = period.getAdCountInAdGroup(lastAdGroupIndex);

View File

@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import org.telegram.messenger.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import org.telegram.messenger.exoplayer2.util.MediaClock; import com.google.android.exoplayer2.util.MediaClock;
import java.io.IOException; import java.io.IOException;
/** /**

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import java.io.IOException; import java.io.IOException;

View 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);
}
}

View File

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.support.annotation.Nullable; 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. * The parameters that apply to playback.

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
/** Called to prepare a playback. */ /** Called to prepare a playback. */
public interface PlaybackPreparer { public interface PlaybackPreparer {

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.os.Looper; import android.os.Looper;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
@ -22,10 +22,13 @@ import android.view.Surface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.TextureView; import android.view.TextureView;
import org.telegram.messenger.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.audio.AudioAttributes;
import org.telegram.messenger.exoplayer2.text.TextOutput; import com.google.android.exoplayer2.audio.AudioListener;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import org.telegram.messenger.exoplayer2.video.VideoListener; 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.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -50,6 +53,58 @@ import java.lang.annotation.RetentionPolicy;
*/ */
public interface Player { 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}. */ /** The video component of a {@link Player}. */
interface VideoComponent { interface VideoComponent {
@ -97,7 +152,7 @@ public interface Player {
* *
* @param surface The {@link Surface}. * @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. * 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 { interface EventListener {
/** /**
* Called when the timeline and/or manifest has been refreshed. * 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. * <p>Note that if the timeline has changed then a position discontinuity may also have
* For example, the current period index may have changed as a result of periods being added or * occurred. For example, the current period index may have changed as a result of periods being
* removed from the timeline. This will <em>not</em> be reported via a separate call to * added or removed from the timeline. This will <em>not</em> be reported via a separate call to
* {@link #onPositionDiscontinuity(int)}. * {@link #onPositionDiscontinuity(int)}.
* *
* @param timeline The latest timeline. Never null, but may be empty. * @param timeline The latest timeline. Never null, but may be empty.
* @param manifest The latest manifest. May be null. * @param manifest The latest manifest. May be null.
* @param reason The {@link TimelineChangeReason} responsible for this timeline change. * @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. * 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 * @param trackSelections The track selections for each renderer. Never null and always of
* length {@link #getRendererCount()}, but may contain null elements. * 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. * Called when the player starts or stops loading the source.
* *
* @param isLoading Whether the source is currently being loaded. * @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 * Called when the value returned from either {@link #getPlayWhenReady()} or {@link
* {@link #getPlaybackState()} changes. * #getPlaybackState()} changes.
* *
* @param playWhenReady Whether playback will proceed when ready. * @param playWhenReady Whether playback will proceed when ready.
* @param playbackState One of the {@code STATE} constants. * @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. * Called when the value of {@link #getRepeatMode()} changes.
* *
* @param repeatMode The {@link RepeatMode} used for playback. * @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. * Called when the value of {@link #getShuffleModeEnabled()} changes.
* *
* @param shuffleModeEnabled Whether shuffling of windows is enabled. * @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} * 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 * immediately after this method is called. The player instance can still be used, and {@link
* {@link #release()} must still be called on the player should it no longer be required. * #release()} must still be called on the player should it no longer be required.
* *
* @param error The error. * @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 * 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 * 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 * jumps within the period currently being played (as a result of a seek being performed, or
* when the source introduces a discontinuity internally). * 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 * <p>When a position discontinuity occurs as a result of a change to the timeline this method
* <em>not</em> called. {@link #onTimelineChanged(Timeline, Object, int)} is called in this * is <em>not</em> called. {@link #onTimelineChanged(Timeline, Object, int)} is called in this
* case. * case.
* *
* @param reason The {@link DiscontinuityReason} responsible for the discontinuity. * @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 * 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. * @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 * 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 * to happen after any necessary changes to the player state were reported to {@link
* {@link #onPlayerStateChanged(boolean, int)}. * #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 { abstract class DefaultEventListener implements EventListener {
@Override @Override
@ -287,60 +346,11 @@ public interface Player {
onTimelineChanged(timeline, manifest); onTimelineChanged(timeline, manifest);
} }
@Override /** @deprecated Use {@link EventListener#onTimelineChanged(Timeline, Object, int)} instead. */
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 @Deprecated
public void onTimelineChanged(Timeline timeline, Object manifest) { public void onTimelineChanged(Timeline timeline, Object manifest) {
// Do nothing. // Do nothing.
} }
} }
/** /**
@ -428,6 +438,10 @@ public interface Player {
*/ */
int TIMELINE_CHANGE_REASON_DYNAMIC = 2; 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. */ /** Returns the component of this player for video output, or null if video is not supported. */
@Nullable @Nullable
VideoComponent getVideoComponent(); VideoComponent getVideoComponent();
@ -678,23 +692,27 @@ public interface Player {
*/ */
long getDuration(); long getDuration();
/** /** Returns the playback position in the current content window or ad, in milliseconds. */
* Returns the playback position in the current window, in milliseconds.
*/
long getCurrentPosition(); long getCurrentPosition();
/** /**
* Returns an estimate of the position in the current window up to which data is buffered, in * Returns an estimate of the position in the current content window or ad up to which data is
* milliseconds. * buffered, in milliseconds.
*/ */
long getBufferedPosition(); long getBufferedPosition();
/** /**
* Returns an estimate of the percentage in the current window up to which data is buffered, or 0 * Returns an estimate of the percentage in the current content window or ad up to which data is
* if no estimate is available. * buffered, or 0 if no estimate is available.
*/ */
int getBufferedPercentage(); 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 * Returns whether the current window is dynamic, or {@code false} if the {@link Timeline} is
* empty. * empty.
@ -735,4 +753,10 @@ public interface Player {
*/ */
long getContentPosition(); 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();
} }

View File

@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.Nullable; 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 * Defines a player message which can be sent with a {@link Sender} and received by a {@link

View File

@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import org.telegram.messenger.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
import org.telegram.messenger.exoplayer2.util.MediaClock; import com.google.android.exoplayer2.util.MediaClock;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -192,6 +192,18 @@ public interface Renderer extends PlayerMessage.Target {
*/ */
void resetPosition(long positionUs) throws ExoPlaybackException; 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}. * Incrementally renders the {@link SampleStream}.
* <p> * <p>

View File

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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}. * Defines the capabilities of a {@link Renderer}.

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;

View File

@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import org.telegram.messenger.exoplayer2.metadata.MetadataOutput; import com.google.android.exoplayer2.metadata.MetadataOutput;
import org.telegram.messenger.exoplayer2.text.TextOutput; import com.google.android.exoplayer2.text.TextOutput;
import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener; import com.google.android.exoplayer2.video.VideoRendererEventListener;
/** /**
* Builds {@link Renderer} instances for use by a {@link SimpleExoPlayer}. * Builds {@link Renderer} instances for use by a {@link SimpleExoPlayer}.

View File

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
/** /**
* Parameters that apply to seeking. * Parameters that apply to seeking.

View File

@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.graphics.Rect;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.PlaybackParams; import android.media.PlaybackParams;
@ -27,25 +28,27 @@ import android.view.Surface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.TextureView; import android.view.TextureView;
import org.telegram.messenger.exoplayer2.analytics.AnalyticsCollector; import com.google.android.exoplayer2.analytics.AnalyticsCollector;
import org.telegram.messenger.exoplayer2.analytics.AnalyticsListener; import com.google.android.exoplayer2.analytics.AnalyticsListener;
import org.telegram.messenger.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioListener;
import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionManager; import com.google.android.exoplayer2.decoder.DecoderCounters;
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; import com.google.android.exoplayer2.drm.DrmSessionManager;
import org.telegram.messenger.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import org.telegram.messenger.exoplayer2.metadata.MetadataOutput; import com.google.android.exoplayer2.metadata.Metadata;
import org.telegram.messenger.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.metadata.MetadataOutput;
import org.telegram.messenger.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.MediaSource;
import org.telegram.messenger.exoplayer2.text.Cue; import com.google.android.exoplayer2.source.TrackGroupArray;
import org.telegram.messenger.exoplayer2.text.TextOutput; import com.google.android.exoplayer2.text.Cue;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.text.TextOutput;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import org.telegram.messenger.exoplayer2.util.Clock; import com.google.android.exoplayer2.trackselection.TrackSelector;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener; 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.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -56,11 +59,12 @@ import java.util.concurrent.CopyOnWriteArraySet;
* be obtained from {@link ExoPlayerFactory}. * be obtained from {@link ExoPlayerFactory}.
*/ */
@TargetApi(16) @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 @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"; private static final String TAG = "SimpleExoPlayer";
@ -69,12 +73,14 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
private final ExoPlayer player; private final ExoPlayer player;
private final Handler eventHandler; private final Handler eventHandler;
private final ComponentListener componentListener; private final ComponentListener componentListener;
private final CopyOnWriteArraySet<org.telegram.messenger.exoplayer2.video.VideoListener> private final CopyOnWriteArraySet<com.google.android.exoplayer2.video.VideoListener>
videoListeners; videoListeners;
private final CopyOnWriteArraySet<AudioListener> audioListeners;
private final CopyOnWriteArraySet<TextOutput> textOutputs; private final CopyOnWriteArraySet<TextOutput> textOutputs;
private final CopyOnWriteArraySet<MetadataOutput> metadataOutputs; private final CopyOnWriteArraySet<MetadataOutput> metadataOutputs;
private final CopyOnWriteArraySet<VideoRendererEventListener> videoDebugListeners; private final CopyOnWriteArraySet<VideoRendererEventListener> videoDebugListeners;
private final CopyOnWriteArraySet<AudioRendererEventListener> audioDebugListeners; private final CopyOnWriteArraySet<AudioRendererEventListener> audioDebugListeners;
private final BandwidthMeter bandwidthMeter;
private final AnalyticsCollector analyticsCollector; private final AnalyticsCollector analyticsCollector;
private Format videoFormat; private Format videoFormat;
@ -84,10 +90,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
private Surface surface; private Surface surface;
private boolean ownsSurface; private boolean ownsSurface;
@C.VideoScalingMode private @C.VideoScalingMode int videoScalingMode;
private int videoScalingMode;
private SurfaceHolder surfaceHolder; private SurfaceHolder surfaceHolder;
private TextureView textureView; private TextureView textureView;
private int surfaceWidth;
private int surfaceHeight;
private DecoderCounters videoDecoderCounters; private DecoderCounters videoDecoderCounters;
private DecoderCounters audioDecoderCounters; private DecoderCounters audioDecoderCounters;
private int audioSessionId; 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 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 trackSelector The {@link TrackSelector} that will be used by the instance.
* @param loadControl The {@link LoadControl} 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 * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
* will not be used for DRM protected playbacks. * 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( protected SimpleExoPlayer(
RenderersFactory renderersFactory, RenderersFactory renderersFactory,
TrackSelector trackSelector, TrackSelector trackSelector,
LoadControl loadControl, LoadControl loadControl,
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) { BandwidthMeter bandwidthMeter,
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
Looper looper) {
this( this(
renderersFactory, renderersFactory,
trackSelector, trackSelector,
loadControl, loadControl,
drmSessionManager, 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 loadControl The {@link LoadControl} that will be used by the instance.
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
* will not be used for DRM protected playbacks. * 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 * @param analyticsCollectorFactory A factory for creating the {@link AnalyticsCollector} that
* will collect and forward all player events. * 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( protected SimpleExoPlayer(
RenderersFactory renderersFactory, RenderersFactory renderersFactory,
TrackSelector trackSelector, TrackSelector trackSelector,
LoadControl loadControl, LoadControl loadControl,
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
AnalyticsCollector.Factory analyticsCollectorFactory) { BandwidthMeter bandwidthMeter,
AnalyticsCollector.Factory analyticsCollectorFactory,
Looper looper) {
this( this(
renderersFactory, renderersFactory,
trackSelector, trackSelector,
loadControl, loadControl,
drmSessionManager, drmSessionManager,
bandwidthMeter,
analyticsCollectorFactory, 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 loadControl The {@link LoadControl} that will be used by the instance.
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
* will not be used for DRM protected playbacks. * 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 * @param analyticsCollectorFactory A factory for creating the {@link AnalyticsCollector} that
* will collect and forward all player events. * will collect and forward all player events.
* @param clock The {@link Clock} that will be used by the instance. Should always be {@link * @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. * 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( protected SimpleExoPlayer(
RenderersFactory renderersFactory, RenderersFactory renderersFactory,
TrackSelector trackSelector, TrackSelector trackSelector,
LoadControl loadControl, LoadControl loadControl,
@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, @Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
BandwidthMeter bandwidthMeter,
AnalyticsCollector.Factory analyticsCollectorFactory, AnalyticsCollector.Factory analyticsCollectorFactory,
Clock clock) { Clock clock,
Looper looper) {
this.bandwidthMeter = bandwidthMeter;
componentListener = new ComponentListener(); componentListener = new ComponentListener();
videoListeners = new CopyOnWriteArraySet<>(); videoListeners = new CopyOnWriteArraySet<>();
audioListeners = new CopyOnWriteArraySet<>();
textOutputs = new CopyOnWriteArraySet<>(); textOutputs = new CopyOnWriteArraySet<>();
metadataOutputs = new CopyOnWriteArraySet<>(); metadataOutputs = new CopyOnWriteArraySet<>();
videoDebugListeners = new CopyOnWriteArraySet<>(); videoDebugListeners = new CopyOnWriteArraySet<>();
audioDebugListeners = new CopyOnWriteArraySet<>(); audioDebugListeners = new CopyOnWriteArraySet<>();
Looper eventLooper = Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper(); eventHandler = new Handler(looper);
eventHandler = new Handler(eventLooper);
renderers = renderers =
renderersFactory.createRenderers( renderersFactory.createRenderers(
eventHandler, eventHandler,
@ -183,17 +210,26 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
currentCues = Collections.emptyList(); currentCues = Collections.emptyList();
// Build the player and associated objects. // 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); analyticsCollector = analyticsCollectorFactory.createAnalyticsCollector(player, clock);
addListener(analyticsCollector); addListener(analyticsCollector);
videoDebugListeners.add(analyticsCollector); videoDebugListeners.add(analyticsCollector);
videoListeners.add(analyticsCollector);
audioDebugListeners.add(analyticsCollector); audioDebugListeners.add(analyticsCollector);
audioListeners.add(analyticsCollector);
addMetadataOutput(analyticsCollector); addMetadataOutput(analyticsCollector);
bandwidthMeter.addEventListener(eventHandler, analyticsCollector);
if (drmSessionManager instanceof DefaultDrmSessionManager) { if (drmSessionManager instanceof DefaultDrmSessionManager) {
((DefaultDrmSessionManager) drmSessionManager).addListener(eventHandler, analyticsCollector); ((DefaultDrmSessionManager) drmSessionManager).addListener(eventHandler, analyticsCollector);
} }
} }
@Override
public AudioComponent getAudioComponent() {
return this;
}
@Override @Override
public VideoComponent getVideoComponent() { public VideoComponent getVideoComponent() {
return this; return this;
@ -240,6 +276,8 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
public void setVideoSurface(Surface surface) { public void setVideoSurface(Surface surface) {
removeSurfaceCallbacks(); removeSurfaceCallbacks();
setVideoSurfaceInternal(surface, false); setVideoSurfaceInternal(surface, false);
int newSurfaceSize = surface == null ? 0 : C.LENGTH_UNSET;
maybeNotifySurfaceSizeChanged(/* width= */ newSurfaceSize, /* height= */ newSurfaceSize);
} }
@Override @Override
@ -255,10 +293,18 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
this.surfaceHolder = surfaceHolder; this.surfaceHolder = surfaceHolder;
if (surfaceHolder == null) { if (surfaceHolder == null) {
setVideoSurfaceInternal(null, false); setVideoSurfaceInternal(null, false);
maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
} else { } else {
surfaceHolder.addCallback(componentListener); surfaceHolder.addCallback(componentListener);
Surface surface = surfaceHolder.getSurface(); 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; needSetSurface = true;
if (textureView == null) { if (textureView == null) {
setVideoSurfaceInternal(null, true); setVideoSurfaceInternal(null, true);
maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
} else { } else {
if (textureView.getSurfaceTextureListener() != null) { if (textureView.getSurfaceTextureListener() != null) {
Log.w(TAG, "Replacing existing SurfaceTextureListener."); Log.w(TAG, "Replacing existing SurfaceTextureListener.");
@ -296,7 +343,13 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
textureView.setSurfaceTextureListener(componentListener); textureView.setSurfaceTextureListener(componentListener);
SurfaceTexture surfaceTexture = textureView.isAvailable() ? textureView.getSurfaceTexture() SurfaceTexture surfaceTexture = textureView.isAvailable() ? textureView.getSurfaceTexture()
: null; : 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. * Sets the stream type for audio playback, used by the underlying audio track.
* <p> * <p>
@ -361,63 +476,6 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
analyticsCollector.removeListener(listener); 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. * Sets the {@link PlaybackParams} governing audio playback.
* *
@ -451,13 +509,6 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
return audioFormat; 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. * 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 @Override
public void addVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener listener) { public void addVideoListener(com.google.android.exoplayer2.video.VideoListener listener) {
videoListeners.add(listener); videoListeners.add(listener);
} }
@Override @Override
public void removeVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener listener) { public void removeVideoListener(com.google.android.exoplayer2.video.VideoListener listener) {
videoListeners.remove(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. * Sets a listener to receive video events, removing all existing listeners.
* *
* @param listener The listener. * @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 @Deprecated
public void setVideoListener(VideoListener listener) { 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. * @param listener The listener to clear.
* @deprecated Use {@link * @deprecated Use {@link
* #removeVideoListener(org.telegram.messenger.exoplayer2.video.VideoListener)}. * #removeVideoListener(com.google.android.exoplayer2.video.VideoListener)}.
*/ */
@Deprecated @Deprecated
public void clearVideoListener(VideoListener listener) { public void clearVideoListener(VideoListener listener) {
@ -656,6 +707,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
return player.getPlaybackLooper(); return player.getPlaybackLooper();
} }
@Override
public Looper getApplicationLooper() {
return player.getApplicationLooper();
}
@Override @Override
public void addListener(Player.EventListener listener) { public void addListener(Player.EventListener listener) {
player.addListener(listener); player.addListener(listener);
@ -768,6 +824,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
player.setSeekParameters(seekParameters); player.setSeekParameters(seekParameters);
} }
@Override
public SeekParameters getSeekParameters() {
return player.getSeekParameters();
}
@Override @Override
public @Nullable Object getCurrentTag() { public @Nullable Object getCurrentTag() {
return player.getCurrentTag(); return player.getCurrentTag();
@ -802,6 +863,7 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
if (mediaSource != null) { if (mediaSource != null) {
mediaSource.removeEventListener(analyticsCollector); mediaSource.removeEventListener(analyticsCollector);
} }
bandwidthMeter.removeEventListener(analyticsCollector);
currentCues = Collections.emptyList(); currentCues = Collections.emptyList();
} }
@ -890,6 +952,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
return player.getBufferedPercentage(); return player.getBufferedPercentage();
} }
@Override
public long getTotalBufferedDuration() {
return player.getTotalBufferedDuration();
}
@Override @Override
public boolean isCurrentWindowDynamic() { public boolean isCurrentWindowDynamic() {
return player.isCurrentWindowDynamic(); return player.isCurrentWindowDynamic();
@ -920,6 +987,11 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
return player.getContentPosition(); return player.getContentPosition();
} }
@Override
public long getContentBufferedPosition() {
return player.getContentBufferedPosition();
}
// Internal methods. // 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 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 trackSelector The {@link TrackSelector} that will be used by the instance.
* @param loadControl The {@link LoadControl} 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 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. * @return A new {@link ExoPlayer} instance.
*/ */
protected ExoPlayer createExoPlayerImpl( protected ExoPlayer createExoPlayerImpl(
Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl, Clock clock) { Renderer[] renderers,
return new ExoPlayerImpl(renderers, trackSelector, loadControl, clock); TrackSelector trackSelector,
LoadControl loadControl,
BandwidthMeter bandwidthMeter,
Clock clock,
Looper looper) {
return new ExoPlayerImpl(renderers, trackSelector, loadControl, bandwidthMeter, clock, looper);
} }
private void removeSurfaceCallbacks() { private void removeSurfaceCallbacks() {
@ -979,6 +1059,16 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
this.ownsSurface = ownsSurface; 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, private final class ComponentListener implements VideoRendererEventListener,
AudioRendererEventListener, TextOutput, MetadataOutput, SurfaceHolder.Callback, AudioRendererEventListener, TextOutput, MetadataOutput, SurfaceHolder.Callback,
TextureView.SurfaceTextureListener { TextureView.SurfaceTextureListener {
@ -1020,9 +1110,13 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
@Override @Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
float pixelWidthHeightRatio) { float pixelWidthHeightRatio) {
for (org.telegram.messenger.exoplayer2.video.VideoListener videoListener : videoListeners) { for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) {
videoListener.onVideoSizeChanged(width, height, unappliedRotationDegrees, // Prevent duplicate notification if a listener is both a VideoRendererEventListener and
pixelWidthHeightRatio); // a VideoListener, as they have the same method signature.
if (!videoDebugListeners.contains(videoListener)) {
videoListener.onVideoSizeChanged(
width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
}
} }
for (VideoRendererEventListener videoDebugListener : videoDebugListeners) { for (VideoRendererEventListener videoDebugListener : videoDebugListeners) {
videoDebugListener.onVideoSizeChanged(width, height, unappliedRotationDegrees, videoDebugListener.onVideoSizeChanged(width, height, unappliedRotationDegrees,
@ -1033,7 +1127,7 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
@Override @Override
public void onRenderedFirstFrame(Surface surface) { public void onRenderedFirstFrame(Surface surface) {
if (SimpleExoPlayer.this.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(); videoListener.onRenderedFirstFrame();
} }
} }
@ -1063,7 +1157,17 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
@Override @Override
public void onAudioSessionId(int sessionId) { public void onAudioSessionId(int sessionId) {
if (audioSessionId == sessionId) {
return;
}
audioSessionId = sessionId; 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) { for (AudioRendererEventListener audioDebugListener : audioDebugListeners) {
audioDebugListener.onAudioSessionId(sessionId); audioDebugListener.onAudioSessionId(sessionId);
} }
@ -1132,12 +1236,13 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
@Override @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// Do nothing. maybeNotifySurfaceSizeChanged(width, height);
} }
@Override @Override
public void surfaceDestroyed(SurfaceHolder holder) { public void surfaceDestroyed(SurfaceHolder holder) {
setVideoSurfaceInternal(null, false); setVideoSurfaceInternal(null, false);
maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
} }
// TextureView.SurfaceTextureListener implementation // TextureView.SurfaceTextureListener implementation
@ -1148,33 +1253,34 @@ public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player
setVideoSurfaceInternal(new Surface(surfaceTexture), true); setVideoSurfaceInternal(new Surface(surfaceTexture), true);
needSetSurface = false; needSetSurface = false;
} }
maybeNotifySurfaceSizeChanged(width, height);
} }
@Override @Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) { public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
// Do nothing. maybeNotifySurfaceSizeChanged(width, height);
} }
@Override @Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { 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)) { if (videoListener.onSurfaceDestroyed(surfaceTexture)) {
return false; return false;
} }
} }
setVideoSurfaceInternal(null, true); setVideoSurfaceInternal(null, true);
maybeNotifySurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
needSetSurface = true; needSetSurface = true;
return true; return true;
} }
@Override @Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { 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); videoListener.onSurfaceTextureUpdated(surfaceTexture);
} }
// Do nothing. // Do nothing.
} }
} }
} }

View File

@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2; package com.google.android.exoplayer2;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Pair; import android.util.Pair;
import org.telegram.messenger.exoplayer2.source.ads.AdPlaybackState; import com.google.android.exoplayer2.source.ads.AdPlaybackState;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
/** /**
* A flexible representation of the structure of media. A timeline is able to represent the * 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) { public int getIndexOfPeriod(Object uid) {
return C.INDEX_UNSET; 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); 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 * Populates a {@link Period} with data for the period at the specified index. Does not populate
* {@link Period#id} and {@link Period#uid}. * {@link Period#id} and {@link Period#uid}.
@ -770,4 +786,11 @@ public abstract class Timeline {
*/ */
public abstract int getIndexOfPeriod(Object uid); 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);
} }

View File

@ -13,39 +13,43 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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.support.annotation.Nullable;
import android.view.Surface; import android.view.Surface;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import org.telegram.messenger.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import org.telegram.messenger.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import org.telegram.messenger.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Period;
import org.telegram.messenger.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.Timeline.Window;
import org.telegram.messenger.exoplayer2.analytics.AnalyticsListener.EventTime; import com.google.android.exoplayer2.analytics.AnalyticsListener.EventTime;
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioAttributes;
import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.audio.AudioListener;
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionEventListener; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import org.telegram.messenger.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.decoder.DecoderCounters;
import org.telegram.messenger.exoplayer2.metadata.MetadataOutput; import com.google.android.exoplayer2.drm.DefaultDrmSessionEventListener;
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.metadata.Metadata;
import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener; import com.google.android.exoplayer2.metadata.MetadataOutput;
import org.telegram.messenger.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.source.MediaSourceEventListener;
import org.telegram.messenger.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.source.TrackGroupArray;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import org.telegram.messenger.exoplayer2.util.Clock; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import org.telegram.messenger.exoplayer2.video.VideoRendererEventListener; 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.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet; 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 * Data collector which is able to forward analytics events to {@link AnalyticsListener}s by
@ -58,7 +62,9 @@ public class AnalyticsCollector
VideoRendererEventListener, VideoRendererEventListener,
MediaSourceEventListener, MediaSourceEventListener,
BandwidthMeter.EventListener, BandwidthMeter.EventListener,
DefaultDrmSessionEventListener { DefaultDrmSessionEventListener,
VideoListener,
AudioListener {
/** Factory for an analytics collector. */ /** Factory for an analytics collector. */
public static class Factory { public static class Factory {
@ -66,29 +72,34 @@ public class AnalyticsCollector
/** /**
* Creates an analytics collector for the specified 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. * @param clock A {@link Clock} used to generate timestamps.
* @return An analytics collector. * @return An analytics collector.
*/ */
public AnalyticsCollector createAnalyticsCollector(Player player, Clock clock) { public AnalyticsCollector createAnalyticsCollector(@Nullable Player player, Clock clock) {
return new AnalyticsCollector(player, clock); return new AnalyticsCollector(player, clock);
} }
} }
private final CopyOnWriteArraySet<AnalyticsListener> listeners; private final CopyOnWriteArraySet<AnalyticsListener> listeners;
private final Player player;
private final Clock clock; private final Clock clock;
private final Window window; private final Window window;
private final MediaPeriodQueueTracker mediaPeriodQueueTracker; private final MediaPeriodQueueTracker mediaPeriodQueueTracker;
private @MonotonicNonNull Player player;
/** /**
* Creates an analytics collector for the specified 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. * @param clock A {@link Clock} used to generate timestamps.
*/ */
protected AnalyticsCollector(Player player, Clock clock) { protected AnalyticsCollector(@Nullable Player player, Clock clock) {
this.player = Assertions.checkNotNull(player); this.player = player;
this.clock = Assertions.checkNotNull(clock); this.clock = Assertions.checkNotNull(clock);
listeners = new CopyOnWriteArraySet<>(); listeners = new CopyOnWriteArraySet<>();
mediaPeriodQueueTracker = new MediaPeriodQueueTracker(); mediaPeriodQueueTracker = new MediaPeriodQueueTracker();
@ -113,6 +124,17 @@ public class AnalyticsCollector
listeners.remove(listener); 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. // 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 * Resets the analytics collector for a new media source. Should be called before the player is
* prepared with a new media source. * 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 @Override
public final void onAudioDecoderInitialized( public final void onAudioDecoderInitialized(
String decoderName, long initializedTimestampMs, long initializationDurationMs) { 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. // VideoRendererEventListener implementation.
@Override @Override
@ -271,12 +286,12 @@ public class AnalyticsCollector
} }
@Override @Override
public final void onVideoSizeChanged( public final void onVideoDisabled(DecoderCounters counters) {
int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { // The renderers are disabled after we changed the playing media period on the playback thread
EventTime eventTime = generateReadingMediaPeriodEventTime(); // but before this change is reported to the app thread.
EventTime eventTime = generateLastReportedPlayingMediaPeriodEventTime();
for (AnalyticsListener listener : listeners) { for (AnalyticsListener listener : listeners) {
listener.onVideoSizeChanged( listener.onDecoderDisabled(eventTime, C.TRACK_TYPE_VIDEO, counters);
eventTime, width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
} }
} }
@ -288,16 +303,31 @@ public class AnalyticsCollector
} }
} }
// VideoListener implementation.
@Override @Override
public final void onVideoDisabled(DecoderCounters counters) { public final void onVideoSizeChanged(
// The renderers are disabled after we changed the playing media period on the playback thread int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
// but before this change is reported to the app thread. EventTime eventTime = generateReadingMediaPeriodEventTime();
EventTime eventTime = generateLastReportedPlayingMediaPeriodEventTime();
for (AnalyticsListener listener : listeners) { 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. // MediaSourceEventListener implementation.
@Override @Override
@ -420,6 +450,16 @@ public class AnalyticsCollector
} }
} }
@Override
public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
@Override @Override
public final void onLoadingChanged(boolean isLoading) { public final void onLoadingChanged(boolean isLoading) {
EventTime eventTime = generatePlayingMediaPeriodEventTime(); EventTime eventTime = generatePlayingMediaPeriodEventTime();
@ -541,6 +581,7 @@ public class AnalyticsCollector
/** Returns a new {@link EventTime} for the specified window index and media period id. */ /** Returns a new {@link EventTime} for the specified window index and media period id. */
protected EventTime generateEventTime(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) { protected EventTime generateEventTime(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
Assertions.checkNotNull(player);
long realtimeMs = clock.elapsedRealtime(); long realtimeMs = clock.elapsedRealtime();
Timeline timeline = player.getCurrentTimeline(); Timeline timeline = player.getCurrentTimeline();
long eventPositionMs; long eventPositionMs;
@ -565,8 +606,6 @@ public class AnalyticsCollector
// This event is for content in a future window. Assume default start position. // This event is for content in a future window. Assume default start position.
eventPositionMs = timeline.getWindow(windowIndex, window).getDefaultPositionMs(); eventPositionMs = timeline.getWindow(windowIndex, window).getDefaultPositionMs();
} }
// TODO(b/30792113): implement this properly (player.getTotalBufferedDuration()).
long bufferedDurationMs = player.getBufferedPosition() - player.getContentPosition();
return new EventTime( return new EventTime(
realtimeMs, realtimeMs,
timeline, timeline,
@ -574,12 +613,12 @@ public class AnalyticsCollector
mediaPeriodId, mediaPeriodId,
eventPositionMs, eventPositionMs,
player.getCurrentPosition(), player.getCurrentPosition(),
bufferedDurationMs); player.getTotalBufferedDuration());
} }
private EventTime generateEventTime(@Nullable WindowAndMediaPeriodId mediaPeriod) { private EventTime generateEventTime(@Nullable WindowAndMediaPeriodId mediaPeriod) {
if (mediaPeriod == null) { if (mediaPeriod == null) {
int windowIndex = player.getCurrentWindowIndex(); int windowIndex = Assertions.checkNotNull(player).getCurrentWindowIndex();
MediaPeriodId mediaPeriodId = mediaPeriodQueueTracker.tryResolveWindowIndex(windowIndex); MediaPeriodId mediaPeriodId = mediaPeriodQueueTracker.tryResolveWindowIndex(windowIndex);
return generateEventTime(windowIndex, mediaPeriodId); return generateEventTime(windowIndex, mediaPeriodId);
} }
@ -756,8 +795,7 @@ public class AnalyticsCollector
if (newTimeline.isEmpty() || timeline.isEmpty()) { if (newTimeline.isEmpty() || timeline.isEmpty()) {
return mediaPeriod; return mediaPeriod;
} }
Object uid = Object uid = timeline.getUidOfPeriod(mediaPeriod.mediaPeriodId.periodIndex);
timeline.getPeriod(mediaPeriod.mediaPeriodId.periodIndex, period, /* setIds= */ true).uid;
int newPeriodIndex = newTimeline.getIndexOfPeriod(uid); int newPeriodIndex = newTimeline.getIndexOfPeriod(uid);
if (newPeriodIndex == C.INDEX_UNSET) { if (newPeriodIndex == C.INDEX_UNSET) {
return mediaPeriod; return mediaPeriod;

View File

@ -13,27 +13,27 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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.support.annotation.Nullable;
import android.view.Surface; import android.view.Surface;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import org.telegram.messenger.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import org.telegram.messenger.exoplayer2.Player.DiscontinuityReason; import com.google.android.exoplayer2.Player.DiscontinuityReason;
import org.telegram.messenger.exoplayer2.Player.TimelineChangeReason; import com.google.android.exoplayer2.Player.TimelineChangeReason;
import org.telegram.messenger.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import org.telegram.messenger.exoplayer2.audio.AudioSink; import com.google.android.exoplayer2.audio.AudioAttributes;
import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.audio.AudioSink;
import org.telegram.messenger.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.decoder.DecoderCounters;
import org.telegram.messenger.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.metadata.Metadata;
import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.LoadEventInfo; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import org.telegram.messenger.exoplayer2.source.MediaSourceEventListener.MediaLoadData; import com.google.android.exoplayer2.source.MediaSourceEventListener.LoadEventInfo;
import org.telegram.messenger.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.MediaSourceEventListener.MediaLoadData;
import org.telegram.messenger.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import java.io.IOException; 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 * <p>All events are recorded with an {@link EventTime} specifying the elapsed real time and media
* time at the time of the event. * time at the time of the event.
*
* <p>All methods have no-op default implementations to allow selective overrides.
*/ */
public interface AnalyticsListener { public interface AnalyticsListener {
@ -127,7 +129,8 @@ public interface AnalyticsListener {
* @param playWhenReady Whether the playback will proceed when ready. * @param playWhenReady Whether the playback will proceed when ready.
* @param playbackState One of the {@link Player}.STATE constants. * @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. * Called when the timeline changed.
@ -135,7 +138,7 @@ public interface AnalyticsListener {
* @param eventTime The event time. * @param eventTime The event time.
* @param reason The reason for the timeline change. * @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. * Called when a position discontinuity occurred.
@ -143,21 +146,21 @@ public interface AnalyticsListener {
* @param eventTime The event time. * @param eventTime The event time.
* @param reason The reason for the position discontinuity. * @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. * Called when a seek operation started.
* *
* @param eventTime The event time. * @param eventTime The event time.
*/ */
void onSeekStarted(EventTime eventTime); default void onSeekStarted(EventTime eventTime) {}
/** /**
* Called when a seek operation was processed. * Called when a seek operation was processed.
* *
* @param eventTime The event time. * @param eventTime The event time.
*/ */
void onSeekProcessed(EventTime eventTime); default void onSeekProcessed(EventTime eventTime) {}
/** /**
* Called when the playback parameters changed. * Called when the playback parameters changed.
@ -165,7 +168,8 @@ public interface AnalyticsListener {
* @param eventTime The event time. * @param eventTime The event time.
* @param playbackParameters The new playback parameters. * @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. * Called when the repeat mode changed.
@ -173,7 +177,7 @@ public interface AnalyticsListener {
* @param eventTime The event time. * @param eventTime The event time.
* @param repeatMode The new repeat mode. * @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. * Called when the shuffle mode changed.
@ -181,7 +185,7 @@ public interface AnalyticsListener {
* @param eventTime The event time. * @param eventTime The event time.
* @param shuffleModeEnabled Whether the shuffle mode is enabled. * @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. * 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 eventTime The event time.
* @param isLoading Whether the player is loading. * @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. * Called when a fatal player error occurred.
@ -197,7 +201,7 @@ public interface AnalyticsListener {
* @param eventTime The event time. * @param eventTime The event time.
* @param error The error. * @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. * 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 trackGroups The available tracks. May be empty.
* @param trackSelections The track selections for each renderer. May contain null elements. * @param trackSelections The track selections for each renderer. May contain null elements.
*/ */
void onTracksChanged( default void onTracksChanged(
EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections); EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {}
/** /**
* Called when a media source started loading data. * 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 loadEventInfo The {@link LoadEventInfo} defining the load event.
* @param mediaLoadData The {@link MediaLoadData} defining the data being loaded. * @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. * 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 loadEventInfo The {@link LoadEventInfo} defining the load event.
* @param mediaLoadData The {@link MediaLoadData} defining the data being loaded. * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
*/ */
void onLoadCompleted( default void onLoadCompleted(
EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData); EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {}
/** /**
* Called when a media source canceled loading data. * 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 loadEventInfo The {@link LoadEventInfo} defining the load event.
* @param mediaLoadData The {@link MediaLoadData} defining the data being loaded. * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
*/ */
void onLoadCanceled( default void onLoadCanceled(
EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData); EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {}
/** /**
* Called when a media source loading error occurred. These errors are just for informational * 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 error The load error.
* @param wasCanceled Whether the load was canceled as a result of the error. * @param wasCanceled Whether the load was canceled as a result of the error.
*/ */
void onLoadError( default void onLoadError(
EventTime eventTime, EventTime eventTime,
LoadEventInfo loadEventInfo, LoadEventInfo loadEventInfo,
MediaLoadData mediaLoadData, MediaLoadData mediaLoadData,
IOException error, IOException error,
boolean wasCanceled); boolean wasCanceled) {}
/** /**
* Called when the downstream format sent to the renderers changed. * Called when the downstream format sent to the renderers changed.
@ -261,7 +266,7 @@ public interface AnalyticsListener {
* @param eventTime The event time. * @param eventTime The event time.
* @param mediaLoadData The {@link MediaLoadData} defining the newly selected media data. * @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 * 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 eventTime The event time.
* @param mediaLoadData The {@link MediaLoadData} defining the media being discarded. * @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. * Called when a media source created a media period.
* *
* @param eventTime The event time. * @param eventTime The event time.
*/ */
void onMediaPeriodCreated(EventTime eventTime); default void onMediaPeriodCreated(EventTime eventTime) {}
/** /**
* Called when a media source released a media period. * Called when a media source released a media period.
* *
* @param eventTime The event time. * @param eventTime The event time.
*/ */
void onMediaPeriodReleased(EventTime eventTime); default void onMediaPeriodReleased(EventTime eventTime) {}
/** /**
* Called when the player started reading a media period. * Called when the player started reading a media period.
* *
* @param eventTime The event time. * @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. * 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 totalBytesLoaded The total bytes loaded this update is based on.
* @param bitrateEstimate The bandwidth estimate, in bits per second. * @param bitrateEstimate The bandwidth estimate, in bits per second.
*/ */
void onBandwidthEstimate( default void onBandwidthEstimate(
EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate); 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 eventTime The event time.
* @param width The width 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
* @param height The height of the viewport in device-independent pixels (dp). * 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); default void onSurfaceSizeChanged(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);
/** /**
* Called when there is {@link Metadata} associated with the current playback time. * 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 eventTime The event time.
* @param metadata The metadata. * @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. * Called when an audio or video decoder has been enabled.
@ -337,7 +336,8 @@ public interface AnalyticsListener {
* {@link C#TRACK_TYPE_VIDEO}. * {@link C#TRACK_TYPE_VIDEO}.
* @param decoderCounters The accumulated event counters associated with this decoder. * @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. * 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 decoderName The decoder that was created.
* @param initializationDurationMs Time taken to initialize the decoder, in milliseconds. * @param initializationDurationMs Time taken to initialize the decoder, in milliseconds.
*/ */
void onDecoderInitialized( default void onDecoderInitialized(
EventTime eventTime, int trackType, String decoderName, long initializationDurationMs); EventTime eventTime, int trackType, String decoderName, long initializationDurationMs) {}
/** /**
* Called when an audio or video decoder input format changed. * 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}. * C#TRACK_TYPE_AUDIO} or {@link C#TRACK_TYPE_VIDEO}.
* @param format The new input format for the decoder. * @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. * Called when an audio or video decoder has been disabled.
@ -369,7 +369,8 @@ public interface AnalyticsListener {
* {@link C#TRACK_TYPE_VIDEO}. * {@link C#TRACK_TYPE_VIDEO}.
* @param decoderCounters The accumulated event counters associated with this decoder. * @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. * Called when the audio session id is set.
@ -377,7 +378,23 @@ public interface AnalyticsListener {
* @param eventTime The event time. * @param eventTime The event time.
* @param audioSessionId The audio session id. * @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. * 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. * 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. * @param elapsedSinceLastFeedMs The time since the {@link AudioSink} was last fed data.
*/ */
void onAudioUnderrun( default void onAudioUnderrun(
EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs); EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {}
/** /**
* Called after video frames have been dropped. * 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 * 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. * (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 * 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. * since the renderer will apply all necessary rotations internally.
* @param pixelWidthHeightRatio The width to height ratio of each pixel. * @param pixelWidthHeightRatio The width to height ratio of each pixel.
*/ */
void onVideoSizeChanged( default void onVideoSizeChanged(
EventTime eventTime, EventTime eventTime,
int width, int width,
int height, int height,
int unappliedRotationDegrees, int unappliedRotationDegrees,
float pixelWidthHeightRatio); float pixelWidthHeightRatio) {}
/** /**
* Called when a frame is rendered for the first time since setting the surface, and when a frame * 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 * @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}. * 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. * Called each time drm keys are loaded.
* *
* @param eventTime The event time. * @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 * 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 eventTime The event time.
* @param error The error. * @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. * Called each time offline drm keys are restored.
* *
* @param eventTime The event time. * @param eventTime The event time.
*/ */
void onDrmKeysRestored(EventTime eventTime); default void onDrmKeysRestored(EventTime eventTime) {}
/** /**
* Called each time offline drm keys are removed. * Called each time offline drm keys are removed.
* *
* @param eventTime The event time. * @param eventTime The event time.
*/ */
void onDrmKeysRemoved(EventTime eventTime); default void onDrmKeysRemoved(EventTime eventTime) {}
} }

View File

@ -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 {}

View File

@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.audio.Ac3Util.SyncFrameInfo.StreamType; import com.google.android.exoplayer2.audio.Ac3Util.SyncFrameInfo.StreamType;
import org.telegram.messenger.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
import org.telegram.messenger.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import org.telegram.messenger.exoplayer2.util.ParsableBitArray; import com.google.android.exoplayer2.util.ParsableBitArray;
import org.telegram.messenger.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer; 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}; 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 * Returns the AC-3 format given {@code data} containing the AC3SpecificBox according to ETSI TS
* ETSI TS 102 366 Annex F. The reading position of {@code data} will be modified. * 102 366 Annex F. The reading position of {@code data} will be modified.
* *
* @param data The AC3SpecificBox to parse. * @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 language The language to set on the format.
* @param drmInitData {@link DrmInitData} to be included in the format. * @param drmInitData {@link DrmInitData} to be included in the format.
* @return The AC-3 format parsed from data in the header. * @return The AC-3 format parsed from data in the header.
*/ */
public static Format parseAc3AnnexFFormat(ParsableByteArray data, String trackId, public static Format parseAc3AnnexFFormat(
String language, DrmInitData drmInitData) { ParsableByteArray data, String trackId, String language, DrmInitData drmInitData) {
int fscod = (data.readUnsignedByte() & 0xC0) >> 6; int fscod = (data.readUnsignedByte() & 0xC0) >> 6;
int sampleRate = SAMPLE_RATE_BY_FSCOD[fscod]; int sampleRate = SAMPLE_RATE_BY_FSCOD[fscod];
int nextByte = data.readUnsignedByte(); int nextByte = data.readUnsignedByte();
@ -155,22 +155,32 @@ public final class Ac3Util {
if ((nextByte & 0x04) != 0) { // lfeon if ((nextByte & 0x04) != 0) { // lfeon
channelCount++; channelCount++;
} }
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_AC3, null, Format.NO_VALUE, return Format.createAudioSampleFormat(
Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0, language); 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 * Returns the E-AC-3 format given {@code data} containing the EC3SpecificBox according to ETSI TS
* ETSI TS 102 366 Annex F. The reading position of {@code data} will be modified. * 102 366 Annex F. The reading position of {@code data} will be modified.
* *
* @param data The EC3SpecificBox to parse. * @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 language The language to set on the format.
* @param drmInitData {@link DrmInitData} to be included in the format. * @param drmInitData {@link DrmInitData} to be included in the format.
* @return The E-AC-3 format parsed from data in the header. * @return The E-AC-3 format parsed from data in the header.
*/ */
public static Format parseEAc3AnnexFFormat(ParsableByteArray data, String trackId, public static Format parseEAc3AnnexFFormat(
String language, DrmInitData drmInitData) { ParsableByteArray data, String trackId, String language, DrmInitData drmInitData) {
data.skipBytes(2); // data_rate, num_ind_sub data.skipBytes(2); // data_rate, num_ind_sub
// Read the first independent substream. // Read the first independent substream.
@ -200,8 +210,18 @@ public final class Ac3Util {
mimeType = MimeTypes.AUDIO_E_AC3_JOC; mimeType = MimeTypes.AUDIO_E_AC3_JOC;
} }
} }
return Format.createAudioSampleFormat(trackId, mimeType, null, Format.NO_VALUE, return Format.createAudioSampleFormat(
Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0, language); trackId,
mimeType,
/* codecs= */ null,
Format.NO_VALUE,
Format.NO_VALUE,
channelCount,
sampleRate,
/* initializationData= */ null,
drmInitData,
/* selectionFlags= */ 0,
language);
} }
/** /**

View File

@ -13,18 +13,18 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.support.annotation.Nullable; 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 * Attributes for audio playback, which configure the underlying platform
* {@link android.media.AudioTrack}. * {@link android.media.AudioTrack}.
* <p> * <p>
* To set the audio attributes, create an instance using the {@link Builder} and either pass it to * 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. * send a message of type {@link C#MSG_SET_AUDIO_ATTRIBUTES} to the audio renderers.
* <p> * <p>
* This class is based on {@link android.media.AudioAttributes}, but can be used on all supported * 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 { public static final class Builder {
@C.AudioContentType private @C.AudioContentType int contentType;
private int contentType; private @C.AudioFlags int flags;
@C.AudioFlags private @C.AudioUsage int usage;
private int flags;
@C.AudioUsage
private int usage;
/** /**
* Creates a new builder for {@link AudioAttributes}. * Creates a new builder for {@link AudioAttributes}.
@ -91,14 +88,11 @@ public final class AudioAttributes {
} }
@C.AudioContentType public final @C.AudioContentType int contentType;
public final int contentType; public final @C.AudioFlags int flags;
@C.AudioFlags public final @C.AudioUsage int usage;
public final int flags;
@C.AudioUsage
public final int usage;
private android.media.AudioAttributes audioAttributesV21; private @Nullable android.media.AudioAttributes audioAttributesV21;
private AudioAttributes(@C.AudioContentType int contentType, @C.AudioFlags int flags, private AudioAttributes(@C.AudioContentType int contentType, @C.AudioFlags int flags,
@C.AudioUsage int usage) { @C.AudioUsage int usage) {

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
@ -50,7 +50,7 @@ public final class AudioCapabilities {
} }
@SuppressLint("InlinedApi") @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) { if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) {
return DEFAULT_AUDIO_CAPABILITIES; return DEFAULT_AUDIO_CAPABILITIES;
} }

View File

@ -13,15 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.media.AudioManager; import android.media.AudioManager;
import org.telegram.messenger.exoplayer2.util.Assertions; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.util.Util; 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 * 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 Context context;
private final Listener listener; 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. * @param context A context for registering the receiver.

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
/** Thrown when an audio decoder error occurs. */ /** Thrown when an audio decoder error occurs. */
public class AudioDecoderException extends Exception { public class AudioDecoderException extends Exception {

View File

@ -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) {}
}

View File

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;

View File

@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.os.Handler; import android.os.Handler;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
/** /**
* Listener of audio {@link Renderer} events. * Listener of audio {@link Renderer} events.

View File

@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.media.AudioTrack; import android.media.AudioTrack;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**

View File

@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.media.AudioTimestamp; import android.media.AudioTimestamp;
import android.media.AudioTrack; import android.media.AudioTrack;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;

View File

@ -13,15 +13,18 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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.AudioTimestamp;
import android.media.AudioTrack; import android.media.AudioTrack;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import org.telegram.messenger.exoplayer2.C; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -128,10 +131,10 @@ import java.lang.reflect.Method;
private final Listener listener; private final Listener listener;
private final long[] playheadOffsets; private final long[] playheadOffsets;
private AudioTrack audioTrack; private @Nullable AudioTrack audioTrack;
private int outputPcmFrameSize; private int outputPcmFrameSize;
private int bufferSize; private int bufferSize;
private AudioTimestampPoller audioTimestampPoller; private @Nullable AudioTimestampPoller audioTimestampPoller;
private int outputSampleRate; private int outputSampleRate;
private boolean needsPassthroughWorkarounds; private boolean needsPassthroughWorkarounds;
private long bufferSizeUs; private long bufferSizeUs;
@ -139,7 +142,7 @@ import java.lang.reflect.Method;
private long smoothedPlayheadOffsetUs; private long smoothedPlayheadOffsetUs;
private long lastPlayheadSampleTimeUs; private long lastPlayheadSampleTimeUs;
private Method getLatencyMethod; private @Nullable Method getLatencyMethod;
private long latencyUs; private long latencyUs;
private boolean hasData; private boolean hasData;
@ -193,7 +196,7 @@ import java.lang.reflect.Method;
audioTimestampPoller = new AudioTimestampPoller(audioTrack); audioTimestampPoller = new AudioTimestampPoller(audioTrack);
outputSampleRate = audioTrack.getSampleRate(); outputSampleRate = audioTrack.getSampleRate();
needsPassthroughWorkarounds = needsPassthroughWorkarounds(outputEncoding); needsPassthroughWorkarounds = needsPassthroughWorkarounds(outputEncoding);
isOutputPcm = Util.isEncodingPcm(outputEncoding); isOutputPcm = Util.isEncodingLinearPcm(outputEncoding);
bufferSizeUs = isOutputPcm ? framesToDurationUs(bufferSize / outputPcmFrameSize) : C.TIME_UNSET; bufferSizeUs = isOutputPcm ? framesToDurationUs(bufferSize / outputPcmFrameSize) : C.TIME_UNSET;
lastRawPlaybackHeadPosition = 0; lastRawPlaybackHeadPosition = 0;
rawPlaybackHeadWrapCount = 0; rawPlaybackHeadWrapCount = 0;
@ -205,13 +208,14 @@ import java.lang.reflect.Method;
} }
public long getCurrentPositionUs(boolean sourceEnded) { public long getCurrentPositionUs(boolean sourceEnded) {
if (audioTrack.getPlayState() == PLAYSTATE_PLAYING) { if (Assertions.checkNotNull(this.audioTrack).getPlayState() == PLAYSTATE_PLAYING) {
maybeSampleSyncParams(); maybeSampleSyncParams();
} }
// If the device supports it, use the playback timestamp from AudioTrack.getTimestamp. // If the device supports it, use the playback timestamp from AudioTrack.getTimestamp.
// Otherwise, derive a smoothed position by sampling the track's frame position. // Otherwise, derive a smoothed position by sampling the track's frame position.
long systemTimeUs = System.nanoTime() / 1000; long systemTimeUs = System.nanoTime() / 1000;
AudioTimestampPoller audioTimestampPoller = Assertions.checkNotNull(this.audioTimestampPoller);
if (audioTimestampPoller.hasTimestamp()) { if (audioTimestampPoller.hasTimestamp()) {
// Calculate the speed-adjusted position using the timestamp (which may be in the future). // Calculate the speed-adjusted position using the timestamp (which may be in the future).
long timestampPositionFrames = audioTimestampPoller.getTimestampPositionFrames(); long timestampPositionFrames = audioTimestampPoller.getTimestampPositionFrames();
@ -241,12 +245,12 @@ import java.lang.reflect.Method;
/** Starts position tracking. Must be called immediately before {@link AudioTrack#play()}. */ /** Starts position tracking. Must be called immediately before {@link AudioTrack#play()}. */
public void start() { public void start() {
audioTimestampPoller.reset(); Assertions.checkNotNull(audioTimestampPoller).reset();
} }
/** Returns whether the audio track is in the playing state. */ /** Returns whether the audio track is in the playing state. */
public boolean isPlaying() { 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. * @return Whether the caller can write data to the track.
*/ */
public boolean mayHandleBuffer(long writtenFrames) { public boolean mayHandleBuffer(long writtenFrames) {
@PlayState int playState = audioTrack.getPlayState(); @PlayState int playState = Assertions.checkNotNull(audioTrack).getPlayState();
if (needsPassthroughWorkarounds) { if (needsPassthroughWorkarounds) {
// An AC-3 audio track continues to play data written while it is paused. Stop writing so its // An AC-3 audio track continues to play data written while it is paused. Stop writing so its
// buffer empties. See [Internal: b/18899620]. // buffer empties. See [Internal: b/18899620].
@ -339,7 +343,7 @@ import java.lang.reflect.Method;
if (stopTimestampUs == C.TIME_UNSET) { if (stopTimestampUs == C.TIME_UNSET) {
// The audio track is going to be paused, so reset the timestamp poller to ensure it doesn't // The audio track is going to be paused, so reset the timestamp poller to ensure it doesn't
// supply an advancing position. // supply an advancing position.
audioTimestampPoller.reset(); Assertions.checkNotNull(audioTimestampPoller).reset();
return true; return true;
} }
// We've handled the end of the stream already, so there's no need to pause the track. // 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) { private void maybePollAndCheckTimestamp(long systemTimeUs, long playbackPositionUs) {
AudioTimestampPoller audioTimestampPoller = Assertions.checkNotNull(this.audioTimestampPoller);
if (!audioTimestampPoller.maybePollTimestamp(systemTimeUs)) { if (!audioTimestampPoller.maybePollTimestamp(systemTimeUs)) {
return; return;
} }
@ -423,7 +428,9 @@ import java.lang.reflect.Method;
// Compute the audio track latency, excluding the latency due to the buffer (leaving // Compute the audio track latency, excluding the latency due to the buffer (leaving
// latency due to the mixer and audio hardware driver). // latency due to the mixer and audio hardware driver).
latencyUs = 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. // Sanity check that the latency is non-negative.
latencyUs = Math.max(latencyUs, 0); latencyUs = Math.max(latencyUs, 0);
// Sanity check that the latency isn't too large. // Sanity check that the latency isn't too large.
@ -457,7 +464,7 @@ import java.lang.reflect.Method;
*/ */
private boolean forceHasPendingData() { private boolean forceHasPendingData() {
return needsPassthroughWorkarounds return needsPassthroughWorkarounds
&& audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED && Assertions.checkNotNull(audioTrack).getPlayState() == AudioTrack.PLAYSTATE_PAUSED
&& getPlaybackHeadPosition() == 0; && getPlaybackHeadPosition() == 0;
} }
@ -483,6 +490,7 @@ import java.lang.reflect.Method;
* @return The playback head position, in frames. * @return The playback head position, in frames.
*/ */
private long getPlaybackHeadPosition() { private long getPlaybackHeadPosition() {
AudioTrack audioTrack = Assertions.checkNotNull(this.audioTrack);
if (stopTimestampUs != C.TIME_UNSET) { if (stopTimestampUs != C.TIME_UNSET) {
// Simulate the playback head position up to the total number of frames submitted. // Simulate the playback head position up to the total number of frames submitted.
long elapsedTimeSinceStopUs = (SystemClock.elapsedRealtime() * 1000) - stopTimestampUs; long elapsedTimeSinceStopUs = (SystemClock.elapsedRealtime() * 1000) - stopTimestampUs;

View File

@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.C.Encoding; import com.google.android.exoplayer2.C.Encoding;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.Arrays; import java.util.Arrays;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
@ -25,10 +25,10 @@ import android.os.SystemClock;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -371,7 +371,7 @@ public final class DefaultAudioSink implements AudioSink {
@Override @Override
public boolean isEncodingSupported(@C.Encoding int encoding) { 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 // 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 // output from platform API version 21 only. Other integer PCM encodings are resampled by this
// sink to 16-bit PCM. // sink to 16-bit PCM.
@ -405,7 +405,7 @@ public final class DefaultAudioSink implements AudioSink {
this.inputSampleRate = inputSampleRate; this.inputSampleRate = inputSampleRate;
int channelCount = inputChannelCount; int channelCount = inputChannelCount;
int sampleRate = inputSampleRate; int sampleRate = inputSampleRate;
isInputPcm = Util.isEncodingPcm(inputEncoding); isInputPcm = Util.isEncodingLinearPcm(inputEncoding);
shouldConvertHighResIntPcmToFloat = shouldConvertHighResIntPcmToFloat =
enableConvertHighResIntPcmToFloat enableConvertHighResIntPcmToFloat
&& isEncodingSupported(C.ENCODING_PCM_32BIT) && isEncodingSupported(C.ENCODING_PCM_32BIT)

View File

@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
import org.telegram.messenger.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import org.telegram.messenger.exoplayer2.util.ParsableBitArray; import com.google.android.exoplayer2.util.ParsableBitArray;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
@ -74,13 +74,13 @@ public final class DtsUtil {
* subsections 5.3/5.4. * subsections 5.3/5.4.
* *
* @param frame The DTS frame to parse. * @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 language The language to set on the format.
* @param drmInitData {@link DrmInitData} to be included in the format. * @param drmInitData {@link DrmInitData} to be included in the format.
* @return The DTS format parsed from data in the header. * @return The DTS format parsed from data in the header.
*/ */
public static Format parseDtsFormat(byte[] frame, String trackId, String language, public static Format parseDtsFormat(
DrmInitData drmInitData) { byte[] frame, String trackId, String language, DrmInitData drmInitData) {
ParsableBitArray frameBits = getNormalizedFrameHeader(frame); ParsableBitArray frameBits = getNormalizedFrameHeader(frame);
frameBits.skipBits(32 + 1 + 5 + 1 + 7 + 14); // SYNC, FTYPE, SHORT, CPF, NBLKS, FSIZE frameBits.skipBits(32 + 1 + 5 + 1 + 7 + 14); // SYNC, FTYPE, SHORT, CPF, NBLKS, FSIZE
int amode = frameBits.readBits(6); int amode = frameBits.readBits(6);

View File

@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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 org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
@ -25,26 +25,28 @@ import android.media.MediaFormat;
import android.media.audiofx.Virtualizer; import android.media.audiofx.Virtualizer;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import org.telegram.messenger.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import org.telegram.messenger.exoplayer2.PlayerMessage.Target; import com.google.android.exoplayer2.PlayerMessage.Target;
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.EventDispatcher; import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import org.telegram.messenger.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
import org.telegram.messenger.exoplayer2.drm.FrameworkMediaCrypto; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecInfo; import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecRenderer; import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
import org.telegram.messenger.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
import org.telegram.messenger.exoplayer2.mediacodec.MediaFormatUtil; import com.google.android.exoplayer2.mediacodec.MediaFormatUtil;
import org.telegram.messenger.exoplayer2.util.MediaClock; import com.google.android.exoplayer2.util.MediaClock;
import org.telegram.messenger.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.List;
/** /**
* Decodes and renders audio using {@link MediaCodec} and an {@link AudioSink}. * 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 * <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. * 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 * <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. * instance that will configure the underlying audio track.
* </ul> * </ul>
*/ */
@ -229,7 +231,12 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Nullable Handler eventHandler, @Nullable Handler eventHandler,
@Nullable AudioRendererEventListener eventListener, @Nullable AudioRendererEventListener eventListener,
AudioSink audioSink) { 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.context = context.getApplicationContext();
this.audioSink = audioSink; this.audioSink = audioSink;
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(eventHandler, eventListener);
@ -262,15 +269,21 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
requiresSecureDecryption |= drmInitData.get(i).requiresSecureDecryption; requiresSecureDecryption |= drmInitData.get(i).requiresSecureDecryption;
} }
} }
MediaCodecInfo decoderInfo = mediaCodecSelector.getDecoderInfo(mimeType, List<MediaCodecInfo> decoderInfos =
requiresSecureDecryption); mediaCodecSelector.getDecoderInfos(format, requiresSecureDecryption);
if (decoderInfo == null) { if (decoderInfos.isEmpty()) {
return requiresSecureDecryption && mediaCodecSelector.getDecoderInfo(mimeType, false) != null return requiresSecureDecryption
? FORMAT_UNSUPPORTED_DRM : FORMAT_UNSUPPORTED_SUBTYPE; && !mediaCodecSelector
.getDecoderInfos(format, /* requiresSecureDecoder= */ false)
.isEmpty()
? FORMAT_UNSUPPORTED_DRM
: FORMAT_UNSUPPORTED_SUBTYPE;
} }
if (!supportsFormatDrm) { if (!supportsFormatDrm) {
return FORMAT_UNSUPPORTED_DRM; 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. // Note: We assume support for unknown sampleRate and channelCount.
boolean decoderCapable = Util.SDK_INT < 21 boolean decoderCapable = Util.SDK_INT < 21
|| ((format.sampleRate == Format.NO_VALUE || ((format.sampleRate == Format.NO_VALUE
@ -282,15 +295,16 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
} }
@Override @Override
protected MediaCodecInfo getDecoderInfo(MediaCodecSelector mediaCodecSelector, protected List<MediaCodecInfo> getDecoderInfos(
Format format, boolean requiresSecureDecoder) throws DecoderQueryException { MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder)
throws DecoderQueryException {
if (allowPassthrough(format.sampleMimeType)) { if (allowPassthrough(format.sampleMimeType)) {
MediaCodecInfo passthroughDecoderInfo = mediaCodecSelector.getPassthroughDecoderInfo(); MediaCodecInfo passthroughDecoderInfo = mediaCodecSelector.getPassthroughDecoderInfo();
if (passthroughDecoderInfo != null) { 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 @Override
protected void configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format, protected void configureCodec(
MediaCrypto crypto) { MediaCodecInfo codecInfo,
MediaCodec codec,
Format format,
MediaCrypto crypto,
float codecOperatingRate) {
codecMaxInputSize = getCodecMaxInputSize(codecInfo, format, getStreamFormats()); codecMaxInputSize = getCodecMaxInputSize(codecInfo, format, getStreamFormats());
codecNeedsDiscardChannelsWorkaround = codecNeedsDiscardChannelsWorkaround(codecInfo.name); codecNeedsDiscardChannelsWorkaround = codecNeedsDiscardChannelsWorkaround(codecInfo.name);
passthroughEnabled = codecInfo.passthrough; passthroughEnabled = codecInfo.passthrough;
String codecMimeType = codecInfo.mimeType == null ? MimeTypes.AUDIO_RAW : codecInfo.mimeType; 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); codec.configure(mediaFormat, /* surface= */ null, crypto, /* flags= */ 0);
if (passthroughEnabled) { if (passthroughEnabled) {
// Store the input MIME type if we're using the passthrough codec. // 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; 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 @Override
protected void onCodecInitialized(String name, long initializedTimestampMs, protected void onCodecInitialized(String name, long initializedTimestampMs,
long initializationDurationMs) { long initializationDurationMs) {
@ -624,10 +651,13 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
* @param format The format of the media. * @param format The format of the media.
* @param codecMimeType The MIME type handled by the codec. * @param codecMimeType The MIME type handled by the codec.
* @param codecMaxInputSize The maximum input size supported 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. * @return The framework media format.
*/ */
@SuppressLint("InlinedApi") @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(); MediaFormat mediaFormat = new MediaFormat();
// Set format parameters that should always be set. // Set format parameters that should always be set.
mediaFormat.setString(MediaFormat.KEY_MIME, codecMimeType); mediaFormat.setString(MediaFormat.KEY_MIME, codecMimeType);
@ -639,6 +669,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
// Set codec configuration values. // Set codec configuration values.
if (Util.SDK_INT >= 23) { if (Util.SDK_INT >= 23) {
mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */); mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */);
if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET) {
mediaFormat.setFloat(MediaFormat.KEY_OPERATING_RATE, codecOperatingRate);
}
} }
return mediaFormat; return mediaFormat;
} }

View File

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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 org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;

View File

@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;

View File

@ -13,35 +13,36 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.media.audiofx.Virtualizer; import android.media.audiofx.Virtualizer;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import org.telegram.messenger.exoplayer2.BaseRenderer; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.BaseRenderer;
import org.telegram.messenger.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlaybackException;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.ExoPlayer;
import org.telegram.messenger.exoplayer2.FormatHolder; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.FormatHolder;
import org.telegram.messenger.exoplayer2.PlayerMessage.Target; import com.google.android.exoplayer2.PlaybackParameters;
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener.EventDispatcher; import com.google.android.exoplayer2.PlayerMessage.Target;
import org.telegram.messenger.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
import org.telegram.messenger.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderCounters;
import org.telegram.messenger.exoplayer2.decoder.SimpleDecoder; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import org.telegram.messenger.exoplayer2.decoder.SimpleOutputBuffer; import com.google.android.exoplayer2.decoder.SimpleDecoder;
import org.telegram.messenger.exoplayer2.drm.DrmSession; import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
import org.telegram.messenger.exoplayer2.drm.DrmSession.DrmSessionException; import com.google.android.exoplayer2.drm.DrmSession;
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
import org.telegram.messenger.exoplayer2.drm.ExoMediaCrypto; import com.google.android.exoplayer2.drm.DrmSessionManager;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import org.telegram.messenger.exoplayer2.util.MediaClock; import com.google.android.exoplayer2.util.Assertions;
import org.telegram.messenger.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MediaClock;
import org.telegram.messenger.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.MimeTypes;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; 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 * <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. * 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 * <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. * instance that will configure the underlying audio track.
* </ul> * </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 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. * @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) { AudioProcessor... audioProcessors) {
this( this(
eventHandler, 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 * @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. * default capabilities (no encoded audio passthrough support) should be assumed.
*/ */
public SimpleDecoderAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener, public SimpleDecoderAudioRenderer(
AudioCapabilities audioCapabilities) { @Nullable Handler eventHandler,
@Nullable AudioRendererEventListener eventListener,
@Nullable AudioCapabilities audioCapabilities) {
this( this(
eventHandler, eventHandler,
eventListener, eventListener,
@ -164,9 +169,13 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
* has obtained the keys necessary to decrypt encrypted regions of the media. * has obtained the keys necessary to decrypt encrypted regions of the media.
* @param audioProcessors Optional {@link AudioProcessor}s that will process audio before output. * @param audioProcessors Optional {@link AudioProcessor}s that will process audio before output.
*/ */
public SimpleDecoderAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener, public SimpleDecoderAudioRenderer(
AudioCapabilities audioCapabilities, DrmSessionManager<ExoMediaCrypto> drmSessionManager, @Nullable Handler eventHandler,
boolean playClearSamplesWithoutKeys, AudioProcessor... audioProcessors) { @Nullable AudioRendererEventListener eventListener,
@Nullable AudioCapabilities audioCapabilities,
@Nullable DrmSessionManager<ExoMediaCrypto> drmSessionManager,
boolean playClearSamplesWithoutKeys,
AudioProcessor... audioProcessors) {
this(eventHandler, eventListener, drmSessionManager, this(eventHandler, eventListener, drmSessionManager,
playClearSamplesWithoutKeys, new DefaultAudioSink(audioCapabilities, audioProcessors)); 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. * has obtained the keys necessary to decrypt encrypted regions of the media.
* @param audioSink The sink to which audio will be output. * @param audioSink The sink to which audio will be output.
*/ */
public SimpleDecoderAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener, public SimpleDecoderAudioRenderer(
DrmSessionManager<ExoMediaCrypto> drmSessionManager, boolean playClearSamplesWithoutKeys, @Nullable Handler eventHandler,
@Nullable AudioRendererEventListener eventListener,
@Nullable DrmSessionManager<ExoMediaCrypto> drmSessionManager,
boolean playClearSamplesWithoutKeys,
AudioSink audioSink) { AudioSink audioSink) {
super(C.TRACK_TYPE_AUDIO); super(C.TRACK_TYPE_AUDIO);
this.drmSessionManager = drmSessionManager; this.drmSessionManager = drmSessionManager;

View File

@ -14,9 +14,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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.nio.ShortBuffer;
import java.util.Arrays; import java.util.Arrays;
@ -31,60 +31,6 @@ import java.util.Arrays;
private static final int MAXIMUM_PITCH = 400; private static final int MAXIMUM_PITCH = 400;
private static final int AMDF_FREQUENCY = 4000; 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 inputSampleRateHz;
private final int channelCount; private final int channelCount;
private final float speed; private final float speed;
@ -264,14 +210,14 @@ import java.util.Arrays;
return frameCount; return frameCount;
} }
private void downSampleInput(short samples[], int position, int skip) { private void downSampleInput(short[] samples, int position, int skip) {
int numSamples = maxRequiredFrameCount / 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 samplesPerValue = channelCount * skip;
int value;
position *= channelCount; position *= channelCount;
for (int i = 0; i < numSamples; i++) { for (int i = 0; i < frameCount; i++) {
value = 0; int value = 0;
for (int j = 0; j < samplesPerValue; j++) { for (int j = 0; j < samplesPerValue; j++) {
value += samples[position + i * samplesPerValue + j]; value += samples[position + i * samplesPerValue + j];
} }
@ -280,35 +226,35 @@ import java.util.Arrays;
} }
} }
private int findPitchPeriodInRange( private int findPitchPeriodInRange(short[] samples, int position, int minPeriod, int maxPeriod) {
short samples[], // Find the best frequency match in the range, and given a sample skip multiple. For now, just
int position, // find the pitch of the first channel.
int minPeriod, int bestPeriod = 0;
int maxPeriod) int worstPeriod = 255;
{ int minDiff = 1;
int bestPeriod = 0, worstPeriod = 255; int maxDiff = 0;
int minDiff = 1, maxDiff = 0;
position *= channelCount; position *= channelCount;
for(int period = minPeriod; period <= maxPeriod; period++) { for (int period = minPeriod; period <= maxPeriod; period++) {
int diff = 0; int diff = 0;
for(int i = 0; i < period; i++) { for (int i = 0; i < period; i++) {
short sVal = samples[position + i]; short sVal = samples[position + i];
short pVal = samples[position + period + i]; short pVal = samples[position + period + i];
diff += sVal >= pVal? sVal - pVal : pVal - sVal; diff += Math.abs(sVal - pVal);
} }
if(diff*bestPeriod < minDiff*period) { // 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; minDiff = diff;
bestPeriod = period; bestPeriod = period;
} }
if(diff*worstPeriod > maxDiff*period) { if (diff * worstPeriod > maxDiff * period) {
maxDiff = diff; maxDiff = diff;
worstPeriod = period; worstPeriod = period;
} }
} }
this.minDiff = minDiff/bestPeriod; this.minDiff = minDiff / bestPeriod;
this.maxDiff = maxDiff/worstPeriod; this.maxDiff = maxDiff / worstPeriod;
return bestPeriod; return bestPeriod;
} }
@ -316,28 +262,7 @@ import java.util.Arrays;
* Returns whether the previous pitch period estimate is a better approximation, which can occur * Returns whether the previous pitch period estimate is a better approximation, which can occur
* at the abrupt end of voiced words. * at the abrupt end of voiced words.
*/ */
private boolean previousPeriodBetter(int minDiff, int maxDiff, boolean preferNewPeriod) { private boolean previousPeriodBetter(int minDiff, int maxDiff) {
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) {
if (minDiff == 0 || prevPeriod == 0) { if (minDiff == 0 || prevPeriod == 0) {
return false; return false;
} }
@ -350,51 +275,9 @@ import java.util.Arrays;
return false; return false;
} }
return true; 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 // 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 // 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 // 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; prevMinDiff = minDiff;
prevPeriod = period; prevPeriod = period;
return retPeriod; return retPeriod;
}*/ }
private void moveNewSamplesToPitchBuffer(int originalOutputFrameCount) { private void moveNewSamplesToPitchBuffer(int originalOutputFrameCount) {
int frameCount = outputFrameCount - originalOutputFrameCount; int frameCount = outputFrameCount - originalOutputFrameCount;
@ -461,78 +344,6 @@ import java.util.Arrays;
pitchFrameCount -= frameCount; 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) { private short interpolate(short[] in, int inPos, int oldSampleRate, int newSampleRate) {
short left = in[inPos]; short left = in[inPos];
short right = in[inPos + channelCount]; short right = in[inPos + channelCount];
@ -544,26 +355,27 @@ import java.util.Arrays;
return (short) ((ratio * left + (width - ratio) * right) / width); 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 newSampleRate = (int) (inputSampleRateHz / rate);
int oldSampleRate = inputSampleRateHz; 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)) { while (newSampleRate > (1 << 14) || oldSampleRate > (1 << 14)) {
newSampleRate >>= 1; newSampleRate /= 2;
oldSampleRate >>= 1; oldSampleRate /= 2;
} }
moveNewSamplesToPitchBuffer(originalNumOutputSamples); moveNewSamplesToPitchBuffer(originalOutputFrameCount);
// Leave at least one pitch sample in the buffer // Leave at least one pitch sample in the buffer.
for (position = 0; position < pitchFrameCount - 1; position++) { for (int position = 0; position < pitchFrameCount - 1; position++) {
while ((oldRatePosition + 1) * newSampleRate > newRatePosition * oldSampleRate) { while ((oldRatePosition + 1) * newSampleRate > newRatePosition * oldSampleRate) {
outputBuffer = outputBuffer =
ensureSpaceForAdditionalFrames( ensureSpaceForAdditionalFrames(
outputBuffer, outputFrameCount, /* additionalFrameCount= */ 1); outputBuffer, outputFrameCount, /* additionalFrameCount= */ 1);
for (int i = 0; i < channelCount; i++) { for (int i = 0; i < channelCount; i++) {
outputBuffer[outputFrameCount * channelCount + i] = interpolate(pitchBuffer, outputBuffer[outputFrameCount * channelCount + i] =
position * channelCount + i, oldSampleRate, newSampleRate); interpolate(pitchBuffer, position * channelCount + i, oldSampleRate, newSampleRate);
} }
newRatePosition++; newRatePosition++;
outputFrameCount++; outputFrameCount++;
@ -575,7 +387,7 @@ import java.util.Arrays;
newRatePosition = 0; newRatePosition = 0;
} }
} }
removePitchFrames(position); removePitchFrames(pitchFrameCount - 1);
} }
private int skipPitchPeriod(short[] samples, int position, float speed, int period) { private int skipPitchPeriod(short[] samples, int position, float speed, int period) {
@ -635,49 +447,36 @@ import java.util.Arrays;
if (inputFrameCount < maxRequiredFrameCount) { if (inputFrameCount < maxRequiredFrameCount) {
return; return;
} }
int frameCount = inputFrameCount;
int numSamples = inputFrameCount; int positionFrames = 0;
int position = 0, period, newSamples;
do { do {
if (remainingInputToCopyFrameCount > 0) { if (remainingInputToCopyFrameCount > 0) {
newSamples = copyInputToOutput(position); positionFrames += copyInputToOutput(positionFrames);
position += newSamples;
} else { } else {
period = findPitchPeriod(inputBuffer, position, true); int period = findPitchPeriod(inputBuffer, positionFrames);
if (speed > 1.0) { if (speed > 1.0) {
newSamples = skipPitchPeriod(inputBuffer, position, speed, period); positionFrames += period + skipPitchPeriod(inputBuffer, positionFrames, speed, period);
position += period + newSamples;
} else { } else {
newSamples = insertPitchPeriod(inputBuffer, position, speed, period); positionFrames += insertPitchPeriod(inputBuffer, positionFrames, speed, period);
position += newSamples;
} }
} }
} while (position + maxRequiredFrameCount <= numSamples); } while (positionFrames + maxRequiredFrameCount <= frameCount);
removeProcessedInputFrames(position); removeProcessedInputFrames(positionFrames);
} }
private void processStreamInput() { 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 s = speed / pitch;
float r = rate; float r = rate * pitch;
boolean useChordPitch = false;
if (!useChordPitch) {
r *= pitch;
}
if (s > 1.00001 || s < 0.99999) { if (s > 1.00001 || s < 0.99999) {
changeSpeed(s); changeSpeed(s);
} else { } else {
copyToOutput(inputBuffer, 0, inputFrameCount); copyToOutput(inputBuffer, 0, inputFrameCount);
inputFrameCount = 0; inputFrameCount = 0;
} }
if (useChordPitch) { if (r != 1.0f) {
if (pitch != 1.0f) { adjustRate(r, originalOutputFrameCount);
adjustPitch(originalNumOutputSamples);
}
} else if (r != 1.0f) {
adjustRate(r, originalNumOutputSamples);
} }
} }
@ -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;
}
}
}
} }

View File

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.C.Encoding; import com.google.android.exoplayer2.C.Encoding;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;

View File

@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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 org.telegram.messenger.exoplayer2.C.Encoding; import com.google.android.exoplayer2.C.Encoding;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;

View File

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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. * Base class for buffers with flags.

View File

@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.decoder; package com.google.android.exoplayer2.decoder;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
/** /**
* Compatibility wrapper for {@link android.media.MediaCodec.CryptoInfo}. * Compatibility wrapper for {@link android.media.MediaCodec.CryptoInfo}.

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.decoder; package com.google.android.exoplayer2.decoder;
/** /**
* A media decoder. * A media decoder.

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.decoder; package com.google.android.exoplayer2.decoder;
/** /**
* Maintains decoder event counts, for debugging purposes only. * Maintains decoder event counts, for debugging purposes only.

View File

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.decoder; package com.google.android.exoplayer2.decoder;
import android.support.annotation.IntDef; 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.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.decoder; package com.google.android.exoplayer2.decoder;
/** /**
* Output buffer decoded by a {@link Decoder}. * Output buffer decoded by a {@link Decoder}.

View File

@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.decoder; package com.google.android.exoplayer2.decoder;
import org.telegram.messenger.exoplayer2.C; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.C;
import java.util.LinkedList; import com.google.android.exoplayer2.util.Assertions;
import java.util.ArrayDeque;
/** /**
* Base class for {@link Decoder}s that use their own decode thread. * 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 Thread decodeThread;
private final Object lock; private final Object lock;
private final LinkedList<I> queuedInputBuffers; private final ArrayDeque<I> queuedInputBuffers;
private final LinkedList<O> queuedOutputBuffers; private final ArrayDeque<O> queuedOutputBuffers;
private final I[] availableInputBuffers; private final I[] availableInputBuffers;
private final O[] availableOutputBuffers; private final O[] availableOutputBuffers;
@ -48,8 +49,8 @@ public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends Outp
*/ */
protected SimpleDecoder(I[] inputBuffers, O[] outputBuffers) { protected SimpleDecoder(I[] inputBuffers, O[] outputBuffers) {
lock = new Object(); lock = new Object();
queuedInputBuffers = new LinkedList<>(); queuedInputBuffers = new ArrayDeque<>();
queuedOutputBuffers = new LinkedList<>(); queuedOutputBuffers = new ArrayDeque<>();
availableInputBuffers = inputBuffers; availableInputBuffers = inputBuffers;
availableInputBufferCount = inputBuffers.length; availableInputBufferCount = inputBuffers.length;
for (int i = 0; i < availableInputBufferCount; i++) { for (int i = 0; i < availableInputBufferCount; i++) {
@ -142,7 +143,7 @@ public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends Outp
releaseInputBufferInternal(queuedInputBuffers.removeFirst()); releaseInputBufferInternal(queuedInputBuffers.removeFirst());
} }
while (!queuedOutputBuffers.isEmpty()) { 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) { synchronized (lock) {
if (flushed) { if (flushed) {
releaseOutputBufferInternal(outputBuffer); outputBuffer.release();
} else if (outputBuffer.isDecodeOnly()) { } else if (outputBuffer.isDecodeOnly()) {
skippedOutputBufferCount++; skippedOutputBufferCount++;
releaseOutputBufferInternal(outputBuffer); outputBuffer.release();
} else { } else {
outputBuffer.skippedOutputBufferCount = skippedOutputBufferCount; outputBuffer.skippedOutputBufferCount = skippedOutputBufferCount;
skippedOutputBufferCount = 0; 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}. * Decodes the {@code inputBuffer} and stores any decoded output in {@code outputBuffer}.
* *
* @param inputBuffer The buffer to decode. * @param inputBuffer The buffer to decode.
* @param outputBuffer The output buffer to store decoded data. The flag * @param outputBuffer The output buffer to store decoded data. The flag {@link
* {@link C#BUFFER_FLAG_DECODE_ONLY} will be set if the same flag is set on * C#BUFFER_FLAG_DECODE_ONLY} will be set if the same flag is set on {@code inputBuffer}, but
* {@code inputBuffer}, but may be set/unset as required. If the flag is set when the call * may be set/unset as required. If the flag is set when the call returns then the output
* returns then the output buffer will not be made available to dequeue. The output buffer * buffer will not be made available to dequeue. The output buffer may not have been populated
* may not have been populated in this case. * in this case.
* @param reset Whether the decoder must be reset before decoding. * @param reset Whether the decoder must be reset before decoding.
* @return A decoder exception if an error occurred, or null if decoding was successful. * @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);
} }

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.decoder; package com.google.android.exoplayer2.decoder;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;

View File

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.util.Log; 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.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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. * Thrown when a non-platform component fails to decrypt data.

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
@ -22,13 +22,14 @@ import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionEventListener.EventDispatcher; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.DefaultKeyRequest; import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.KeyRequest; import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; import com.google.android.exoplayer2.util.EventDispatcher;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -77,11 +78,10 @@ import java.util.UUID;
private final ExoMediaDrm<T> mediaDrm; private final ExoMediaDrm<T> mediaDrm;
private final ProvisioningManager<T> provisioningManager; private final ProvisioningManager<T> provisioningManager;
private final byte[] initData; private final SchemeData schemeData;
private final String mimeType;
private final @DefaultDrmSessionManager.Mode int mode; private final @DefaultDrmSessionManager.Mode int mode;
private final HashMap<String, String> optionalKeyRequestParameters; private final HashMap<String, String> optionalKeyRequestParameters;
private final EventDispatcher eventDispatcher; private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
private final int initialDrmRequestRetryCount; private final int initialDrmRequestRetryCount;
/* package */ final MediaDrmCallback callback; /* package */ final MediaDrmCallback callback;
@ -97,15 +97,20 @@ import java.util.UUID;
private byte[] sessionId; private byte[] sessionId;
private byte[] offlineLicenseKeySetId; private byte[] offlineLicenseKeySetId;
private Object currentKeyRequest;
private Object currentProvisionRequest;
/** /**
* Instantiates a new DRM session. * Instantiates a new DRM session.
* *
* @param uuid The UUID of the drm scheme. * @param uuid The UUID of the drm scheme.
* @param mediaDrm The media DRM. * @param mediaDrm The media DRM.
* @param provisioningManager The manager for provisioning. * @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 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 optionalKeyRequestParameters The optional key request parameters.
* @param callback The media DRM callback. * @param callback The media DRM callback.
* @param playbackLooper The playback looper. * @param playbackLooper The playback looper.
@ -117,20 +122,20 @@ import java.util.UUID;
UUID uuid, UUID uuid,
ExoMediaDrm<T> mediaDrm, ExoMediaDrm<T> mediaDrm,
ProvisioningManager<T> provisioningManager, ProvisioningManager<T> provisioningManager,
byte[] initData, @Nullable SchemeData schemeData,
String mimeType,
@DefaultDrmSessionManager.Mode int mode, @DefaultDrmSessionManager.Mode int mode,
byte[] offlineLicenseKeySetId, @Nullable byte[] offlineLicenseKeySetId,
HashMap<String, String> optionalKeyRequestParameters, HashMap<String, String> optionalKeyRequestParameters,
MediaDrmCallback callback, MediaDrmCallback callback,
Looper playbackLooper, Looper playbackLooper,
EventDispatcher eventDispatcher, EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher,
int initialDrmRequestRetryCount) { int initialDrmRequestRetryCount) {
this.uuid = uuid; this.uuid = uuid;
this.provisioningManager = provisioningManager; this.provisioningManager = provisioningManager;
this.mediaDrm = mediaDrm; this.mediaDrm = mediaDrm;
this.mode = mode; this.mode = mode;
this.offlineLicenseKeySetId = offlineLicenseKeySetId; this.offlineLicenseKeySetId = offlineLicenseKeySetId;
this.schemeData = offlineLicenseKeySetId == null ? schemeData : null;
this.optionalKeyRequestParameters = optionalKeyRequestParameters; this.optionalKeyRequestParameters = optionalKeyRequestParameters;
this.callback = callback; this.callback = callback;
this.initialDrmRequestRetryCount = initialDrmRequestRetryCount; this.initialDrmRequestRetryCount = initialDrmRequestRetryCount;
@ -141,14 +146,6 @@ import java.util.UUID;
requestHandlerThread = new HandlerThread("DrmRequestHandler"); requestHandlerThread = new HandlerThread("DrmRequestHandler");
requestHandlerThread.start(); requestHandlerThread.start();
postRequestHandler = new PostRequestHandler(requestHandlerThread.getLooper()); postRequestHandler = new PostRequestHandler(requestHandlerThread.getLooper());
if (offlineLicenseKeySetId == null) {
this.initData = initData;
this.mimeType = mimeType;
} else {
this.initData = null;
this.mimeType = null;
}
} }
// Life cycle. // Life cycle.
@ -177,6 +174,8 @@ import java.util.UUID;
requestHandlerThread = null; requestHandlerThread = null;
mediaCrypto = null; mediaCrypto = null;
lastException = null; lastException = null;
currentKeyRequest = null;
currentProvisionRequest = null;
if (sessionId != null) { if (sessionId != null) {
mediaDrm.closeSession(sessionId); mediaDrm.closeSession(sessionId);
sessionId = null; sessionId = null;
@ -187,18 +186,42 @@ import java.util.UUID;
} }
public boolean hasInitData(byte[] initData) { 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) { public boolean hasSessionId(byte[] sessionId) {
return Arrays.equals(this.sessionId, 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. // Provisioning implementation.
public void provision() { public void provision() {
ProvisionRequest request = mediaDrm.getProvisionRequest(); currentProvisionRequest = mediaDrm.getProvisionRequest();
postRequestHandler.obtainMessage(MSG_PROVISION, request, true).sendToTarget(); postRequestHandler.post(MSG_PROVISION, currentProvisionRequest, /* allowRetry= */ true);
} }
public void onProvisionCompleted() { public void onProvisionCompleted() {
@ -271,11 +294,12 @@ import java.util.UUID;
return false; return false;
} }
private void onProvisionResponse(Object response) { private void onProvisionResponse(Object request, Object response) {
if (state != STATE_OPENING && !isOpen()) { if (request != currentProvisionRequest || (state != STATE_OPENING && !isOpen())) {
// This event is stale. // This event is stale.
return; return;
} }
currentProvisionRequest = null;
if (response instanceof Exception) { if (response instanceof Exception) {
provisioningManager.onProvisionError((Exception) response); provisioningManager.onProvisionError((Exception) response);
@ -309,7 +333,7 @@ import java.util.UUID;
onError(new KeysExpiredException()); onError(new KeysExpiredException());
} else { } else {
state = STATE_OPENED_WITH_KEYS; state = STATE_OPENED_WITH_KEYS;
eventDispatcher.drmKeysRestored(); eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysRestored);
} }
} }
break; break;
@ -356,24 +380,30 @@ import java.util.UUID;
private void postKeyRequest(int type, boolean allowRetry) { private void postKeyRequest(int type, boolean allowRetry) {
byte[] scope = type == ExoMediaDrm.KEY_TYPE_RELEASE ? offlineLicenseKeySetId : sessionId; byte[] scope = type == ExoMediaDrm.KEY_TYPE_RELEASE ? offlineLicenseKeySetId : sessionId;
byte[] initData = null;
String mimeType = null;
String licenseServerUrl = null;
if (schemeData != null) {
initData = schemeData.data;
mimeType = schemeData.mimeType;
licenseServerUrl = schemeData.licenseServerUrl;
}
try { try {
KeyRequest request = mediaDrm.getKeyRequest(scope, initData, mimeType, type, KeyRequest mediaDrmKeyRequest =
optionalKeyRequestParameters); mediaDrm.getKeyRequest(scope, initData, mimeType, type, optionalKeyRequestParameters);
if (C.CLEARKEY_UUID.equals(uuid)) { currentKeyRequest = Pair.create(mediaDrmKeyRequest, licenseServerUrl);
request = new DefaultKeyRequest(ClearKeyUtil.adjustRequestData(request.getData()), postRequestHandler.post(MSG_KEYS, currentKeyRequest, allowRetry);
request.getDefaultUrl());
}
postRequestHandler.obtainMessage(MSG_KEYS, request, allowRetry).sendToTarget();
} catch (Exception e) { } catch (Exception e) {
onKeysError(e); onKeysError(e);
} }
} }
private void onKeyResponse(Object response) { private void onKeyResponse(Object request, Object response) {
if (!isOpen()) { if (request != currentKeyRequest || !isOpen()) {
// This event is stale. // This event is stale.
return; return;
} }
currentKeyRequest = null;
if (response instanceof Exception) { if (response instanceof Exception) {
onKeysError((Exception) response); onKeysError((Exception) response);
@ -382,12 +412,9 @@ import java.util.UUID;
try { try {
byte[] responseData = (byte[]) response; byte[] responseData = (byte[]) response;
if (C.CLEARKEY_UUID.equals(uuid)) {
responseData = ClearKeyUtil.adjustResponseData(responseData);
}
if (mode == DefaultDrmSessionManager.MODE_RELEASE) { if (mode == DefaultDrmSessionManager.MODE_RELEASE) {
mediaDrm.provideKeyResponse(offlineLicenseKeySetId, responseData); mediaDrm.provideKeyResponse(offlineLicenseKeySetId, responseData);
eventDispatcher.drmKeysRemoved(); eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysRestored);
} else { } else {
byte[] keySetId = mediaDrm.provideKeyResponse(sessionId, responseData); byte[] keySetId = mediaDrm.provideKeyResponse(sessionId, responseData);
if ((mode == DefaultDrmSessionManager.MODE_DOWNLOAD if ((mode == DefaultDrmSessionManager.MODE_DOWNLOAD
@ -396,7 +423,7 @@ import java.util.UUID;
offlineLicenseKeySetId = keySetId; offlineLicenseKeySetId = keySetId;
} }
state = STATE_OPENED_WITH_KEYS; state = STATE_OPENED_WITH_KEYS;
eventDispatcher.drmKeysLoaded(); eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysLoaded);
} }
} catch (Exception e) { } catch (Exception e) {
onKeysError(e); onKeysError(e);
@ -420,7 +447,7 @@ import java.util.UUID;
private void onError(final Exception e) { private void onError(final Exception e) {
lastException = new DrmSessionException(e); lastException = new DrmSessionException(e);
eventDispatcher.drmSessionManagerError(e); eventDispatcher.dispatch(listener -> listener.onDrmSessionManagerError(e));
if (state != STATE_OPENED_WITH_KEYS) { if (state != STATE_OPENED_WITH_KEYS) {
state = STATE_ERROR; state = STATE_ERROR;
} }
@ -430,30 +457,7 @@ import java.util.UUID;
return state == STATE_OPENED || state == STATE_OPENED_WITH_KEYS; return state == STATE_OPENED || state == STATE_OPENED_WITH_KEYS;
} }
@SuppressWarnings("deprecation") // Internal classes.
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;
}
}
@SuppressLint("HandlerLeak") @SuppressLint("HandlerLeak")
private class PostResponseHandler extends Handler { private class PostResponseHandler extends Handler {
@ -464,12 +468,15 @@ import java.util.UUID;
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
Pair<?, ?> requestAndResponse = (Pair<?, ?>) msg.obj;
Object request = requestAndResponse.first;
Object response = requestAndResponse.second;
switch (msg.what) { switch (msg.what) {
case MSG_PROVISION: case MSG_PROVISION:
onProvisionResponse(msg.obj); onProvisionResponse(request, response);
break; break;
case MSG_KEYS: case MSG_KEYS:
onKeyResponse(msg.obj); onKeyResponse(request, response);
break; break;
default: default:
break; break;
@ -486,21 +493,27 @@ import java.util.UUID;
super(backgroundLooper); super(backgroundLooper);
} }
Message obtainMessage(int what, Object object, boolean allowRetry) { void post(int what, Object request, boolean allowRetry) {
return obtainMessage(what, allowRetry ? 1 : 0 /* allow retry*/, 0 /* error count */, int allowRetryInt = allowRetry ? 1 : 0;
object); int errorCount = 0;
obtainMessage(what, allowRetryInt, errorCount, request).sendToTarget();
} }
@Override @Override
@SuppressWarnings("unchecked")
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
Object request = msg.obj;
Object response; Object response;
try { try {
switch (msg.what) { switch (msg.what) {
case MSG_PROVISION: case MSG_PROVISION:
response = callback.executeProvisionRequest(uuid, (ProvisionRequest) msg.obj); response = callback.executeProvisionRequest(uuid, (ProvisionRequest) request);
break; break;
case MSG_KEYS: 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; break;
default: default:
throw new RuntimeException(); throw new RuntimeException();
@ -511,7 +524,7 @@ import java.util.UUID;
} }
response = e; response = e;
} }
postResponseHandler.obtainMessage(msg.what, response).sendToTarget(); postResponseHandler.obtainMessage(msg.what, Pair.create(request, response)).sendToTarget();
} }
private boolean maybeRetryRequest(Message originalMsg) { private boolean maybeRetryRequest(Message originalMsg) {
@ -534,5 +547,4 @@ import java.util.UUID;
} }
} }
} }

View File

@ -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();
}

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
@ -24,16 +24,15 @@ import android.support.annotation.IntDef;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSession.ProvisioningManager; import com.google.android.exoplayer2.drm.DefaultDrmSession.ProvisioningManager;
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionEventListener.EventDispatcher; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
import org.telegram.messenger.exoplayer2.drm.DrmSession.DrmSessionException; import com.google.android.exoplayer2.drm.ExoMediaDrm.OnEventListener;
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.OnEventListener; import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil;
import org.telegram.messenger.exoplayer2.extractor.mp4.PsshAtomUtil; import com.google.android.exoplayer2.util.Assertions;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.EventDispatcher;
import org.telegram.messenger.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util;
import org.telegram.messenger.exoplayer2.util.Util;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; 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; public static final int INITIAL_DRM_REQUEST_RETRY_COUNT = 3;
private static final String TAG = "DefaultDrmSessionMgr"; private static final String TAG = "DefaultDrmSessionMgr";
private static final String CENC_SCHEME_MIME_TYPE = "cenc";
private final UUID uuid; private final UUID uuid;
private final ExoMediaDrm<T> mediaDrm; private final ExoMediaDrm<T> mediaDrm;
private final MediaDrmCallback callback; private final MediaDrmCallback callback;
private final HashMap<String, String> optionalKeyRequestParameters; private final HashMap<String, String> optionalKeyRequestParameters;
private final EventDispatcher eventDispatcher; private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
private final boolean multiSession; private final boolean multiSession;
private final int initialDrmRequestRetryCount; private final int initialDrmRequestRetryCount;
@ -356,7 +354,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
this.mediaDrm = mediaDrm; this.mediaDrm = mediaDrm;
this.callback = callback; this.callback = callback;
this.optionalKeyRequestParameters = optionalKeyRequestParameters; this.optionalKeyRequestParameters = optionalKeyRequestParameters;
this.eventDispatcher = new EventDispatcher(); this.eventDispatcher = new EventDispatcher<>();
this.multiSession = multiSession; this.multiSession = multiSession;
this.initialDrmRequestRetryCount = initialDrmRequestRetryCount; this.initialDrmRequestRetryCount = initialDrmRequestRetryCount;
mode = MODE_PLAYBACK; mode = MODE_PLAYBACK;
@ -509,17 +507,14 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
} }
} }
byte[] initData = null; SchemeData schemeData = null;
String mimeType = null;
if (offlineLicenseKeySetId == null) { if (offlineLicenseKeySetId == null) {
SchemeData data = getSchemeData(drmInitData, uuid, false); schemeData = getSchemeData(drmInitData, uuid, false);
if (data == null) { if (schemeData == null) {
final MissingSchemeDataException error = new MissingSchemeDataException(uuid); final MissingSchemeDataException error = new MissingSchemeDataException(uuid);
eventDispatcher.drmSessionManagerError(error); eventDispatcher.dispatch(listener -> listener.onDrmSessionManagerError(error));
return new ErrorStateDrmSession<>(new DrmSessionException(error)); return new ErrorStateDrmSession<>(new DrmSessionException(error));
} }
initData = getSchemeInitData(data, uuid);
mimeType = getSchemeMimeType(data, uuid);
} }
DefaultDrmSession<T> session; DefaultDrmSession<T> session;
@ -528,6 +523,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
} else { } else {
// Only use an existing session if it has matching init data. // Only use an existing session if it has matching init data.
session = null; session = null;
byte[] initData = schemeData != null ? schemeData.data : null;
for (DefaultDrmSession<T> existingSession : sessions) { for (DefaultDrmSession<T> existingSession : sessions) {
if (existingSession.hasInitData(initData)) { if (existingSession.hasInitData(initData)) {
session = existingSession; session = existingSession;
@ -543,8 +539,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
uuid, uuid,
mediaDrm, mediaDrm,
this, this,
initData, schemeData,
mimeType,
mode, mode,
offlineLicenseKeySetId, offlineLicenseKeySetId,
optionalKeyRequestParameters, optionalKeyRequestParameters,
@ -650,31 +645,6 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
return matchingSchemeDatas.get(0); 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") @SuppressLint("HandlerLeak")
private class MediaDrmHandler extends Handler { private class MediaDrmHandler extends Handler {

View File

@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
@ -266,9 +266,9 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
* applies to all schemes). * applies to all schemes).
*/ */
private final UUID uuid; private final UUID uuid;
/** /** The URL of the server to which license requests should be made. May be null if unknown. */
* The mimeType of {@link #data}. public final @Nullable String licenseServerUrl;
*/ /** The mimeType of {@link #data}. */
public final String mimeType; public final String mimeType;
/** /**
* The initialization data. May be null for scheme support checks only. * 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}. * @param requiresSecureDecryption See {@link #requiresSecureDecryption}.
*/ */
public SchemeData(UUID uuid, String mimeType, byte[] data, boolean 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.uuid = Assertions.checkNotNull(uuid);
this.licenseServerUrl = licenseServerUrl;
this.mimeType = Assertions.checkNotNull(mimeType); this.mimeType = Assertions.checkNotNull(mimeType);
this.data = data; this.data = data;
this.requiresSecureDecryption = requiresSecureDecryption; this.requiresSecureDecryption = requiresSecureDecryption;
@ -305,6 +323,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
/* package */ SchemeData(Parcel in) { /* package */ SchemeData(Parcel in) {
uuid = new UUID(in.readLong(), in.readLong()); uuid = new UUID(in.readLong(), in.readLong());
licenseServerUrl = in.readString();
mimeType = in.readString(); mimeType = in.readString();
data = in.createByteArray(); data = in.createByteArray();
requiresSecureDecryption = in.readByte() != 0; requiresSecureDecryption = in.readByte() != 0;
@ -346,7 +365,9 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
return true; return true;
} }
SchemeData other = (SchemeData) obj; 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); && Arrays.equals(data, other.data);
} }
@ -354,6 +375,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
public int hashCode() { public int hashCode() {
if (hashCode == 0) { if (hashCode == 0) {
int result = uuid.hashCode(); int result = uuid.hashCode();
result = 31 * result + (licenseServerUrl == null ? 0 : licenseServerUrl.hashCode());
result = 31 * result + mimeType.hashCode(); result = 31 * result + mimeType.hashCode();
result = 31 * result + Arrays.hashCode(data); result = 31 * result + Arrays.hashCode(data);
hashCode = result; hashCode = result;
@ -372,6 +394,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(uuid.getMostSignificantBits()); dest.writeLong(uuid.getMostSignificantBits());
dest.writeLong(uuid.getLeastSignificantBits()); dest.writeLong(uuid.getLeastSignificantBits());
dest.writeString(licenseServerUrl);
dest.writeString(mimeType); dest.writeString(mimeType);
dest.writeByteArray(data); dest.writeByteArray(data);
dest.writeByte((byte) (requiresSecureDecryption ? 1 : 0)); dest.writeByte((byte) (requiresSecureDecryption ? 1 : 0));

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.media.MediaDrm; import android.media.MediaDrm;

View File

@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.os.Looper; import android.os.Looper;
import org.telegram.messenger.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
/** /**
* Manages a DRM session. * Manages a DRM session.

View File

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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; import java.util.Map;
/** A {@link DrmSession} that's in a terminal error state. */ /** A {@link DrmSession} that's in a terminal error state. */

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
/** /**
* An opaque {@link android.media.MediaCrypto} equivalent. * An opaque {@link android.media.MediaCrypto} equivalent.

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.media.DeniedByServerException; import android.media.DeniedByServerException;
import android.media.MediaCryptoException; import android.media.MediaCryptoException;

View File

@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.media.MediaCrypto; 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}. * An {@link ExoMediaCrypto} implementation that wraps the framework {@link MediaCrypto}.

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.media.DeniedByServerException; import android.media.DeniedByServerException;
@ -25,9 +25,11 @@ import android.media.NotProvisionedException;
import android.media.UnsupportedSchemeException; import android.media.UnsupportedSchemeException;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil;
import org.telegram.messenger.exoplayer2.util.Util; 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.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -40,6 +42,8 @@ import java.util.UUID;
@TargetApi(23) @TargetApi(23)
public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto> { public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto> {
private static final String CENC_SCHEME_MIME_TYPE = "cenc";
private final UUID uuid; private final UUID uuid;
private final MediaDrm mediaDrm; 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; uuid = Util.SDK_INT < 27 && C.CLEARKEY_UUID.equals(uuid) ? C.COMMON_PSSH_UUID : uuid;
this.uuid = uuid; this.uuid = uuid;
this.mediaDrm = new MediaDrm(uuid); this.mediaDrm = new MediaDrm(uuid);
if (C.WIDEVINE_UUID.equals(uuid) && needsForceL3Workaround()) {
mediaDrm.setPropertyString("securityLevel", "L3");
}
} }
@Override @Override
@ -116,14 +123,49 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
@Override @Override
public KeyRequest getKeyRequest(byte[] scope, byte[] init, String mimeType, int keyType, public KeyRequest getKeyRequest(byte[] scope, byte[] init, String mimeType, int keyType,
HashMap<String, String> optionalParameters) throws NotProvisionedException { 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, final MediaDrm.KeyRequest request = mediaDrm.getKeyRequest(scope, init, mimeType, keyType,
optionalParameters); 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 @Override
public byte[] provideKeyResponse(byte[] scope, byte[] response) public byte[] provideKeyResponse(byte[] scope, byte[] response)
throws NotProvisionedException, DeniedByServerException { throws NotProvisionedException, DeniedByServerException {
if (C.CLEARKEY_UUID.equals(uuid)) {
response = ClearKeyUtil.adjustResponseData(response);
}
return mediaDrm.provideKeyResponse(scope, response); return mediaDrm.provideKeyResponse(scope, response);
} }
@ -183,4 +225,12 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
forceAllowInsecureDecoderComponents); 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);
}
} }

View File

@ -13,20 +13,21 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.KeyRequest; import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
import org.telegram.messenger.exoplayer2.upstream.DataSourceInputStream; import com.google.android.exoplayer2.upstream.DataSourceInputStream;
import org.telegram.messenger.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
import org.telegram.messenger.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.HttpDataSource;
import org.telegram.messenger.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException; import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import org.telegram.messenger.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -108,13 +109,19 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback {
@Override @Override
public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws IOException { 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); return executePost(dataSourceFactory, url, new byte[0], null);
} }
@Override @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(); String url = request.getDefaultUrl();
if (TextUtils.isEmpty(url)) {
url = mediaProvidedLicenseServerUrl;
}
if (forceDefaultLicenseUrl || TextUtils.isEmpty(url)) { if (forceDefaultLicenseUrl || TextUtils.isEmpty(url)) {
url = defaultLicenseUrl; url = defaultLicenseUrl;
} }

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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. * Thrown when the drm keys loaded into an open session expire.

View File

@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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 android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException; import java.io.IOException;
import java.util.UUID; import java.util.UUID;
@ -44,7 +45,9 @@ public final class LocalMediaDrmCallback implements MediaDrmCallback {
} }
@Override @Override
public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception { public byte[] executeKeyRequest(
UUID uuid, KeyRequest request, @Nullable String mediaProvidedLicenseServerUrl)
throws Exception {
return keyResponse; return keyResponse;
} }

View File

@ -13,10 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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 android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
import java.util.UUID; import java.util.UUID;
/** /**
@ -38,10 +39,13 @@ public interface MediaDrmCallback {
* Executes a key request. * Executes a key request.
* *
* @param uuid The UUID of the content protection scheme. * @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. * @return The response data.
* @throws Exception If an error occurred executing the request. * @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;
} }

View File

@ -13,19 +13,19 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.media.MediaDrm; import android.media.MediaDrm;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.util.Pair; import android.util.Pair;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.drm.DefaultDrmSessionManager.Mode; import com.google.android.exoplayer2.drm.DefaultDrmSessionManager.Mode;
import org.telegram.messenger.exoplayer2.drm.DrmSession.DrmSessionException; import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
import org.telegram.messenger.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.HttpDataSource;
import org.telegram.messenger.exoplayer2.upstream.HttpDataSource.Factory; import com.google.android.exoplayer2.upstream.HttpDataSource.Factory;
import org.telegram.messenger.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import java.util.HashMap; import java.util.HashMap;
import java.util.UUID; import java.util.UUID;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.util.Pair; import android.util.Pair;
import org.telegram.messenger.exoplayer2.C; import com.google.android.exoplayer2.C;
import java.util.Map; import java.util.Map;
/** /**

View File

@ -13,42 +13,41 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.telegram.messenger.exoplayer2.ext.ffmpeg; package com.google.android.exoplayer2.ext.ffmpeg;
import android.os.Handler; import android.os.Handler;
import org.telegram.messenger.exoplayer2.C; import android.support.annotation.Nullable;
import org.telegram.messenger.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.C;
import org.telegram.messenger.exoplayer2.Format; import com.google.android.exoplayer2.ExoPlaybackException;
import org.telegram.messenger.exoplayer2.audio.AudioProcessor; import com.google.android.exoplayer2.Format;
import org.telegram.messenger.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioProcessor;
import org.telegram.messenger.exoplayer2.audio.AudioSink; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import org.telegram.messenger.exoplayer2.audio.DefaultAudioSink; import com.google.android.exoplayer2.audio.AudioSink;
import org.telegram.messenger.exoplayer2.audio.SimpleDecoderAudioRenderer; import com.google.android.exoplayer2.audio.DefaultAudioSink;
import org.telegram.messenger.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.audio.SimpleDecoderAudioRenderer;
import org.telegram.messenger.exoplayer2.drm.ExoMediaCrypto; import com.google.android.exoplayer2.drm.DrmSessionManager;
import org.telegram.messenger.exoplayer2.util.MimeTypes; 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. * Decodes and renders audio using FFmpeg.
*/ */
public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer { 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; private static final int NUM_BUFFERS = 16;
/** /** The default input buffer size. */
* The initial input buffer size. Input buffers are reallocated dynamically if this value is private static final int DEFAULT_INPUT_BUFFER_SIZE = 960 * 6;
* insufficient.
*/
private static final int INITIAL_INPUT_BUFFER_SIZE = 960 * 6;
private final boolean enableFloatOutput; private final boolean enableFloatOutput;
private FfmpegDecoder decoder; private @MonotonicNonNull FfmpegDecoder decoder;
public FfmpegAudioRenderer() { 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 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. * @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) { 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 * 32-bit float output, any audio processing will be disabled, including playback speed/pitch
* adjustment. * adjustment.
*/ */
public FfmpegAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener, public FfmpegAudioRenderer(
AudioSink audioSink, boolean enableFloatOutput) { @Nullable Handler eventHandler,
@Nullable AudioRendererEventListener eventListener,
AudioSink audioSink,
boolean enableFloatOutput) {
super( super(
eventHandler, eventHandler,
eventListener, eventListener,
@ -86,10 +94,11 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
@Override @Override
protected int supportsFormatInternal(DrmSessionManager<ExoMediaCrypto> drmSessionManager, protected int supportsFormatInternal(DrmSessionManager<ExoMediaCrypto> drmSessionManager,
Format format) { Format format) {
String sampleMimeType = format.sampleMimeType; Assertions.checkNotNull(format.sampleMimeType);
if (!MimeTypes.isAudio(sampleMimeType)) { if (!MimeTypes.isAudio(format.sampleMimeType)) {
return FORMAT_UNSUPPORTED_TYPE; 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; return FORMAT_UNSUPPORTED_SUBTYPE;
} else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) { } else if (!supportsFormatDrm(drmSessionManager, format.drmInitData)) {
return FORMAT_UNSUPPORTED_DRM; return FORMAT_UNSUPPORTED_DRM;
@ -106,18 +115,33 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
@Override @Override
protected FfmpegDecoder createDecoder(Format format, ExoMediaCrypto mediaCrypto) protected FfmpegDecoder createDecoder(Format format, ExoMediaCrypto mediaCrypto)
throws FfmpegDecoderException { throws FfmpegDecoderException {
decoder = new FfmpegDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, int initialInputBufferSize =
format.sampleMimeType, format.initializationData, shouldUseFloatOutput(format)); format.maxInputSize != Format.NO_VALUE ? format.maxInputSize : DEFAULT_INPUT_BUFFER_SIZE;
decoder =
new FfmpegDecoder(
NUM_BUFFERS, NUM_BUFFERS, initialInputBufferSize, format, shouldUseFloatOutput(format));
return decoder; return decoder;
} }
@Override @Override
public Format getOutputFormat() { public Format getOutputFormat() {
Assertions.checkNotNull(decoder);
int channelCount = decoder.getChannelCount(); int channelCount = decoder.getChannelCount();
int sampleRate = decoder.getSampleRate(); int sampleRate = decoder.getSampleRate();
@C.PcmEncoding int encoding = decoder.getEncoding(); @C.PcmEncoding int encoding = decoder.getEncoding();
return Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW, null, Format.NO_VALUE, return Format.createAudioSampleFormat(
Format.NO_VALUE, channelCount, sampleRate, encoding, null, null, 0, null); /* 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) { private boolean isOutputSupported(Format inputFormat) {
@ -125,6 +149,7 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
} }
private boolean shouldUseFloatOutput(Format inputFormat) { private boolean shouldUseFloatOutput(Format inputFormat) {
Assertions.checkNotNull(inputFormat.sampleMimeType);
if (!enableFloatOutput || !supportsOutputEncoding(C.ENCODING_PCM_FLOAT)) { if (!enableFloatOutput || !supportsOutputEncoding(C.ENCODING_PCM_FLOAT)) {
return false; return false;
} }

Some files were not shown because too many files have changed in this diff Show More