Enable JAudioTrack.
MediaPlayer2 AudioOutput using public APIs.
Bug: 112549970
Test: android.media.cts.MediaPlayer2Test, android.media.cts.RoutingTest
Change-Id: Id76d80c040a52fd2ab724999697e222495906aec
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index 75d1df0..2109ad1 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -59,6 +59,7 @@
"libstagefright_player2",
"libstagefright_rtsp",
"libstagefright_timedtext2",
+ "libmedia2_jni_core",
],
export_include_dirs: [
diff --git a/media/libmediaplayer2/JAudioTrack.cpp b/media/libmediaplayer2/JAudioTrack.cpp
index 778ae1b..5c0c6ea 100644
--- a/media/libmediaplayer2/JAudioTrack.cpp
+++ b/media/libmediaplayer2/JAudioTrack.cpp
@@ -28,7 +28,6 @@
// TODO: Store Java class/methodID as a member variable in the class.
// TODO: Add NULL && Exception checks after every JNI call.
JAudioTrack::JAudioTrack( // < Usages of the arguments are below >
- audio_stream_type_t streamType, // AudioAudioAttributes
uint32_t sampleRate, // AudioFormat && bufferSizeInBytes
audio_format_t format, // AudioFormat && bufferSizeInBytes
audio_channel_mask_t channelMask, // AudioFormat && bufferSizeInBytes
@@ -40,8 +39,10 @@
float maxRequiredSpeed) { // bufferSizeInBytes
JNIEnv *env = JavaVMHelper::getJNIEnv();
+
jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
- mAudioTrackCls = (jclass) env->NewGlobalRef(jAudioTrackCls);
+ mAudioTrackCls = reinterpret_cast<jclass>(env->NewGlobalRef(jAudioTrackCls));
+ env->DeleteLocalRef(jAudioTrackCls);
maxRequiredSpeed = std::min(std::max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
@@ -64,10 +65,13 @@
jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
+ jobject jAudioAttributesObj = JAudioAttributes::createAudioAttributesObj(env, pAttributes);
+ mAudioAttributesObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioAttributesObj));
+ env->DeleteLocalRef(jAudioAttributesObj);
+
jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
"(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioAttributes,
- JAudioAttributes::createAudioAttributesObj(env, pAttributes, streamType));
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioAttributes, mAudioAttributesObj);
jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
"(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
@@ -100,7 +104,9 @@
}
jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
- mAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
+ jobject jAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
+ mAudioTrackObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioTrackObj));
+ env->DeleteLocalRef(jBuilderObj);
if (cbf != NULL) {
// Set offload mode callback
@@ -118,6 +124,8 @@
JAudioTrack::~JAudioTrack() {
JNIEnv *env = JavaVMHelper::getJNIEnv();
env->DeleteGlobalRef(mAudioTrackCls);
+ env->DeleteGlobalRef(mAudioTrackObj);
+ env->DeleteGlobalRef(mAudioAttributesObj);
}
size_t JAudioTrack::frameCount() {
@@ -151,21 +159,21 @@
return NO_ERROR;
}
-bool JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
+status_t JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
JNIEnv *env = JavaVMHelper::getJNIEnv();
jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
- jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "L");
- jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "L");
+ jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "J");
+ jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "J");
jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
- "getTimestamp", "(Landroid/media/AudioTimestamp)B");
+ "getTimestamp", "(Landroid/media/AudioTimestamp;)Z");
bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);
if (!success) {
- return false;
+ return NO_INIT;
}
long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
@@ -178,7 +186,7 @@
timestamp.mTime = ts;
timestamp.mPosition = (uint32_t) framePosition;
- return true;
+ return NO_ERROR;
}
status_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
@@ -423,6 +431,35 @@
return audioFormatToNative(javaFormat);
}
+size_t JAudioTrack::frameSize() {
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+
+ // TODO: Calculated here implementing the logic in AudioTrack.java
+ // wait for AudioTrack.java exposing this parameter (i.e. getFrameSizeInBtytes())
+ jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
+ int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
+
+ jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
+ jmethodID jIsEncodingLinearFrames = env->GetStaticMethodID(
+ jAudioFormatCls, "isEncodingLinearFrames", "(I)Z");
+ jboolean javaIsEncodingLinearFrames = env->CallStaticBooleanMethod(
+ jAudioFormatCls, jIsEncodingLinearFrames, javaFormat);
+
+ if (javaIsEncodingLinearFrames == false) {
+ return 1;
+ }
+
+ jmethodID jGetBytesPerSample = env->GetStaticMethodID(jAudioFormatCls,
+ "getBytesPerSample", "(I)I");
+ int javaBytesPerSample = env->CallStaticIntMethod(jAudioFormatCls,
+ jGetBytesPerSample, javaFormat);
+
+ jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
+ int javaChannelCount = env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
+
+ return javaChannelCount * javaBytesPerSample;
+}
+
status_t JAudioTrack::dump(int fd, const Vector<String16>& args __unused) const
{
String8 result;
@@ -432,10 +469,6 @@
// TODO: Remove logs that includes unavailable information from below.
// result.appendFormat(" status(%d), state(%d), session Id(%d), flags(%#x)\n",
// mStatus, mState, mSessionId, mFlags);
-// result.appendFormat(" stream type(%d), left - right volume(%f, %f)\n",
-// (mStreamType == AUDIO_STREAM_DEFAULT) ?
-// audio_attributes_to_stream_type(&mAttributes) : mStreamType,
-// mVolume[AUDIO_INTERLEAVE_LEFT], mVolume[AUDIO_INTERLEAVE_RIGHT]);
// result.appendFormat(" format(%#x), channel mask(%#x), channel count(%u)\n",
// format(), mChannelMask, channelCount());
// result.appendFormat(" sample rate(%u), original sample rate(%u), speed(%f)\n",
@@ -462,7 +495,7 @@
return AUDIO_PORT_HANDLE_NONE;
}
- jclass jAudioDeviceInfoCls = env->FindClass("Landroid/media/AudioDeviceInfo");
+ jclass jAudioDeviceInfoCls = env->FindClass("android/media/AudioDeviceInfo");
jmethodID jGetId = env->GetMethodID(jAudioDeviceInfoCls, "getId", "()I");
jint routedDeviceId = env->CallIntMethod(jAudioDeviceInfoObj, jGetId);
return routedDeviceId;
@@ -478,13 +511,22 @@
status_t JAudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
JNIEnv *env = JavaVMHelper::getJNIEnv();
jclass jMP2ImplCls = env->FindClass("android/media/MediaPlayer2Impl");
- jmethodID jSetAudioOutputDeviceById = env->GetMethodID(
+ jmethodID jSetAudioOutputDeviceById = env->GetStaticMethodID(
jMP2ImplCls, "setAudioOutputDeviceById", "(Landroid/media/AudioTrack;I)Z");
jboolean result = env->CallStaticBooleanMethod(
jMP2ImplCls, jSetAudioOutputDeviceById, mAudioTrackObj, deviceId);
return result == true ? NO_ERROR : BAD_VALUE;
}
+audio_stream_type_t JAudioTrack::getAudioStreamType() {
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+ jclass jAudioAttributesCls = env->FindClass("android/media/AudioAttributes");
+ jmethodID jGetVolumeControlStream = env->GetMethodID(jAudioAttributesCls,
+ "getVolumeControlStream", "()I");
+ int javaAudioStreamType = env->CallIntMethod(mAudioAttributesObj, jGetVolumeControlStream);
+ return (audio_stream_type_t)javaAudioStreamType;
+}
+
status_t JAudioTrack::pendingDuration(int32_t *msec) {
if (msec == nullptr) {
return BAD_VALUE;
@@ -526,18 +568,85 @@
return NO_ERROR;
}
-status_t JAudioTrack::addAudioDeviceCallback(
- const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
- // TODO: Implement this after appropriate Java AudioTrack method is available.
+status_t JAudioTrack::addAudioDeviceCallback(jobject listener, jobject handler) {
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+ jmethodID jAddOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
+ "addOnRoutingChangedListener",
+ "(Landroid/media/AudioRouting$OnRoutingChangedListener;Landroid/os/Handler;)V");
+ env->CallVoidMethod(mAudioTrackObj, jAddOnRoutingChangedListener, listener, handler);
return NO_ERROR;
}
-status_t JAudioTrack::removeAudioDeviceCallback(
- const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
- // TODO: Implement this after appropriate Java AudioTrack method is available.
+status_t JAudioTrack::removeAudioDeviceCallback(jobject listener) {
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+ jmethodID jRemoveOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
+ "removeOnRoutingChangedListener",
+ "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V");
+ env->CallVoidMethod(mAudioTrackObj, jRemoveOnRoutingChangedListener, listener);
return NO_ERROR;
}
+void JAudioTrack::registerRoutingDelegates(
+ std::vector<std::pair<jobject, jobject>>& routingDelegates) {
+ for (std::vector<std::pair<jobject, jobject>>::iterator it = routingDelegates.begin();
+ it != routingDelegates.end(); it++) {
+ addAudioDeviceCallback(it->second, getHandler(it->second));
+ }
+}
+
+/////////////////////////////////////////////////////////////
+/// Static methods begin ///
+/////////////////////////////////////////////////////////////
+jobject JAudioTrack::getListener(const jobject routingDelegateObj) {
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+ jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
+ jmethodID jGetListener = env->GetMethodID(jRoutingDelegateCls,
+ "getListener", "()Landroid/media/AudioRouting$OnRoutingChangedListener;");
+ return env->CallObjectMethod(routingDelegateObj, jGetListener);
+}
+
+jobject JAudioTrack::getHandler(const jobject routingDelegateObj) {
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+ jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
+ jmethodID jGetHandler = env->GetMethodID(jRoutingDelegateCls,
+ "getHandler", "()Landroid/os/Handler;");
+ return env->CallObjectMethod(routingDelegateObj, jGetHandler);
+}
+
+jobject JAudioTrack::addGlobalRef(const jobject obj) {
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+ return reinterpret_cast<jobject>(env->NewGlobalRef(obj));
+}
+
+status_t JAudioTrack::removeGlobalRef(const jobject obj) {
+ if (obj == NULL) {
+ return BAD_VALUE;
+ }
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+ env->DeleteGlobalRef(obj);
+ return NO_ERROR;
+}
+
+jobject JAudioTrack::findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+ for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
+ if (env->IsSameObject(it->first, key)) {
+ return it->second;
+ }
+ }
+ return nullptr;
+}
+
+void JAudioTrack::eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+ for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
+ if (env->IsSameObject(it->first, key)) {
+ mp.erase(it);
+ return;
+ }
+ }
+}
+
/////////////////////////////////////////////////////////////
/// Private method begins ///
/////////////////////////////////////////////////////////////
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
index 6b27ca7..9218fce 100644
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -23,7 +23,6 @@
#include <utils/Log.h>
#include <media/AudioPolicyHelper.h>
-#include <media/AudioTrack.h>
#include <media/stagefright/foundation/ADebug.h>
namespace {
@@ -44,29 +43,27 @@
String8 result;
result.append(" MediaPlayer2AudioOutput\n");
- snprintf(buffer, 255, " stream type(%d), volume(%f)\n",
- mStreamType, mVolume);
+ snprintf(buffer, 255, " volume(%f)\n", mVolume);
result.append(buffer);
snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
- mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
+ mMsecsPerFrame, (mJAudioTrack != nullptr) ? mJAudioTrack->latency() : -1);
result.append(buffer);
snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
mAuxEffectId, mSendLevel);
result.append(buffer);
::write(fd, result.string(), result.size());
- if (mTrack != 0) {
- mTrack->dump(fd, args);
+ if (mJAudioTrack != nullptr) {
+ mJAudioTrack->dump(fd, args);
}
return NO_ERROR;
}
MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
- const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
- : mCallback(NULL),
- mCallbackCookie(NULL),
- mCallbackData(NULL),
- mStreamType(AUDIO_STREAM_MUSIC),
+ const audio_attributes_t* attr, std::vector<jobject>& routingDelegatesBackup)
+ : mCallback(nullptr),
+ mCallbackCookie(nullptr),
+ mCallbackData(nullptr),
mVolume(1.0),
mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
mSampleRateHz(0),
@@ -79,24 +76,30 @@
mAuxEffectId(0),
mFlags(AUDIO_OUTPUT_FLAG_NONE),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
- mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
- mDeviceCallbackEnabled(false),
- mDeviceCallback(deviceCallback) {
+ mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE) {
ALOGV("MediaPlayer2AudioOutput(%d)", sessionId);
- if (attr != NULL) {
+ if (attr != nullptr) {
mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
- if (mAttributes != NULL) {
+ if (mAttributes != nullptr) {
memcpy(mAttributes, attr, sizeof(audio_attributes_t));
- mStreamType = audio_attributes_to_stream_type(attr);
}
} else {
- mAttributes = NULL;
+ mAttributes = nullptr;
}
setMinBufferCount();
+ mRoutingDelegates.clear();
+ for (auto routingDelegate : routingDelegatesBackup) {
+ mRoutingDelegates.push_back(std::pair<jobject, jobject>(
+ JAudioTrack::getListener(routingDelegate), routingDelegate));
+ }
+ routingDelegatesBackup.clear();
}
MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
+ for (auto routingDelegate : mRoutingDelegates) {
+ JAudioTrack::removeGlobalRef(routingDelegate.second);
+ }
close();
free(mAttributes);
delete mCallbackData;
@@ -125,31 +128,31 @@
ssize_t MediaPlayer2AudioOutput::bufferSize() const {
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == nullptr) {
return NO_INIT;
}
- return mTrack->frameCount() * mFrameSize;
+ return mJAudioTrack->frameCount() * mFrameSize;
}
ssize_t MediaPlayer2AudioOutput::frameCount() const {
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == nullptr) {
return NO_INIT;
}
- return mTrack->frameCount();
+ return mJAudioTrack->frameCount();
}
ssize_t MediaPlayer2AudioOutput::channelCount() const {
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == nullptr) {
return NO_INIT;
}
- return mTrack->channelCount();
+ return mJAudioTrack->channelCount();
}
ssize_t MediaPlayer2AudioOutput::frameSize() const {
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == nullptr) {
return NO_INIT;
}
return mFrameSize;
@@ -157,10 +160,10 @@
uint32_t MediaPlayer2AudioOutput::latency () const {
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == nullptr) {
return 0;
}
- return mTrack->latency();
+ return mJAudioTrack->latency();
}
float MediaPlayer2AudioOutput::msecsPerFrame() const {
@@ -170,18 +173,18 @@
status_t MediaPlayer2AudioOutput::getPosition(uint32_t *position) const {
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == nullptr) {
return NO_INIT;
}
- return mTrack->getPosition(position);
+ return mJAudioTrack->getPosition(position);
}
status_t MediaPlayer2AudioOutput::getTimestamp(AudioTimestamp &ts) const {
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == nullptr) {
return NO_INIT;
}
- return mTrack->getTimestamp(ts);
+ return mJAudioTrack->getTimestamp(ts);
}
// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
@@ -194,7 +197,7 @@
// Calculate duration of played samples if played at normal rate (i.e., 1.0).
int64_t MediaPlayer2AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const {
Mutex::Autolock lock(mLock);
- if (mTrack == 0 || mSampleRateHz == 0) {
+ if (mJAudioTrack == nullptr || mSampleRateHz == 0) {
return 0;
}
@@ -202,22 +205,18 @@
int64_t numFramesPlayedAtUs;
AudioTimestamp ts;
- status_t res = mTrack->getTimestamp(ts);
+ status_t res = mJAudioTrack->getTimestamp(ts);
+
if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
numFramesPlayed = ts.mPosition;
numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
//ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
- } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
+ } else { // case 2: transitory state on start of a new track
+ // case 3: transitory at new track or audio fast tracks.
numFramesPlayed = 0;
numFramesPlayedAtUs = nowUs;
//ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
// numFramesPlayed, (long long)numFramesPlayedAtUs);
- } else { // case 3: transitory at new track or audio fast tracks.
- res = mTrack->getPosition(&numFramesPlayed);
- CHECK_EQ(res, (status_t)OK);
- numFramesPlayedAtUs = nowUs;
- numFramesPlayedAtUs += 1000LL * mTrack->latency() / 2; /* XXX */
- //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
}
// CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
@@ -243,57 +242,41 @@
status_t MediaPlayer2AudioOutput::getFramesWritten(uint32_t *frameswritten) const {
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == nullptr) {
return NO_INIT;
}
ExtendedTimestamp ets;
- status_t status = mTrack->getTimestamp(&ets);
+ status_t status = mJAudioTrack->getTimestamp(&ets);
if (status == OK || status == WOULD_BLOCK) {
*frameswritten = (uint32_t)ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT];
}
return status;
}
-status_t MediaPlayer2AudioOutput::setParameters(const String8& keyValuePairs) {
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
- return NO_INIT;
- }
- return mTrack->setParameters(keyValuePairs);
-}
-
-String8 MediaPlayer2AudioOutput::getParameters(const String8& keys) {
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
- return String8::empty();
- }
- return mTrack->getParameters(keys);
-}
-
void MediaPlayer2AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) {
Mutex::Autolock lock(mLock);
- if (attributes == NULL) {
+ if (attributes == nullptr) {
free(mAttributes);
- mAttributes = NULL;
+ mAttributes = nullptr;
} else {
- if (mAttributes == NULL) {
+ if (mAttributes == nullptr) {
mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
}
memcpy(mAttributes, attributes, sizeof(audio_attributes_t));
- mStreamType = audio_attributes_to_stream_type(attributes);
}
}
-void MediaPlayer2AudioOutput::setAudioStreamType(audio_stream_type_t streamType) {
+audio_stream_type_t MediaPlayer2AudioOutput::getAudioStreamType() const {
+ ALOGV("getAudioStreamType");
Mutex::Autolock lock(mLock);
- // do not allow direct stream type modification if attributes have been set
- if (mAttributes == NULL) {
- mStreamType = streamType;
+ if (mJAudioTrack == nullptr) {
+ return AUDIO_STREAM_DEFAULT;
}
+ return mJAudioTrack->getAudioStreamType();
}
void MediaPlayer2AudioOutput::close_l() {
- mTrack.clear();
+ mJAudioTrack.clear();
}
status_t MediaPlayer2AudioOutput::open(
@@ -302,7 +285,6 @@
AudioCallback cb, void *cookie,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo,
- bool doNotReconnect,
uint32_t suggestedFrameCount) {
ALOGV("open(%u, %d, 0x%x, 0x%x, %d 0x%x)", sampleRate, channelCount, channelMask,
format, mSessionId, flags);
@@ -310,7 +292,7 @@
// offloading is only supported in callback mode for now.
// offloadInfo must be present if offload flag is set
if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
- ((cb == NULL) || (offloadInfo == NULL))) {
+ ((cb == nullptr) || (offloadInfo == nullptr))) {
return BAD_VALUE;
}
@@ -330,32 +312,23 @@
mCallback = cb;
mCallbackCookie = cookie;
- sp<AudioTrack> t;
- CallbackData *newcbd = NULL;
+ sp<JAudioTrack> jT;
+ CallbackData *newcbd = nullptr;
- ALOGV("creating new AudioTrack");
+ ALOGV("creating new JAudioTrack");
- if (mCallback != NULL) {
+ if (mCallback != nullptr) {
newcbd = new CallbackData(this);
- t = new AudioTrack(
- mStreamType,
- sampleRate,
- format,
- channelMask,
- frameCount,
- flags,
- CallbackWrapper,
- newcbd,
- 0, // notification frames
- mSessionId,
- AudioTrack::TRANSFER_CALLBACK,
- offloadInfo,
- mUid,
- mPid,
- mAttributes,
- doNotReconnect,
- 1.0f, // default value for maxRequiredSpeed
- mSelectedDeviceId);
+ jT = new JAudioTrack(
+ sampleRate,
+ format,
+ channelMask,
+ CallbackWrapper,
+ newcbd,
+ frameCount,
+ mSessionId,
+ mAttributes,
+ 1.0f); // default value for maxRequiredSpeed
} else {
// TODO: Due to buffer memory concerns, we use a max target playback speed
// based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
@@ -365,73 +338,60 @@
ALOGW_IF(targetSpeed != mPlaybackRate.mSpeed,
"track target speed:%f clamped from playback speed:%f",
targetSpeed, mPlaybackRate.mSpeed);
- t = new AudioTrack(
- mStreamType,
- sampleRate,
- format,
- channelMask,
- frameCount,
- flags,
- NULL, // callback
- NULL, // user data
- 0, // notification frames
- mSessionId,
- AudioTrack::TRANSFER_DEFAULT,
- NULL, // offload info
- mUid,
- mPid,
- mAttributes,
- doNotReconnect,
- targetSpeed,
- mSelectedDeviceId);
+ jT = new JAudioTrack(
+ sampleRate,
+ format,
+ channelMask,
+ nullptr,
+ nullptr,
+ frameCount,
+ mSessionId,
+ mAttributes,
+ targetSpeed);
}
- if ((t == 0) || (t->initCheck() != NO_ERROR)) {
+ if (jT == 0) {
ALOGE("Unable to create audio track");
delete newcbd;
// t goes out of scope, so reference count drops to zero
return NO_INIT;
- } else {
- // successful AudioTrack initialization implies a legacy stream type was generated
- // from the audio attributes
- mStreamType = t->streamType();
}
- CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL)));
+ CHECK((jT != nullptr) && ((mCallback == nullptr) || (newcbd != nullptr)));
mCallbackData = newcbd;
ALOGV("setVolume");
- t->setVolume(mVolume);
+ jT->setVolume(mVolume);
mSampleRateHz = sampleRate;
mFlags = flags;
mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
- mFrameSize = t->frameSize();
- mTrack = t;
+ mFrameSize = jT->frameSize();
+ mJAudioTrack = jT;
return updateTrack_l();
}
status_t MediaPlayer2AudioOutput::updateTrack_l() {
- if (mTrack == NULL) {
+ if (mJAudioTrack == nullptr) {
return NO_ERROR;
}
status_t res = NO_ERROR;
// Note some output devices may give us a direct track even though we don't specify it.
// Example: Line application b/17459982.
- if ((mTrack->getFlags()
+ if ((mJAudioTrack->getFlags()
& (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
- res = mTrack->setPlaybackRate(mPlaybackRate);
+ res = mJAudioTrack->setPlaybackRate(mPlaybackRate);
if (res == NO_ERROR) {
- mTrack->setAuxEffectSendLevel(mSendLevel);
- res = mTrack->attachAuxEffect(mAuxEffectId);
+ mJAudioTrack->setAuxEffectSendLevel(mSendLevel);
+ res = mJAudioTrack->attachAuxEffect(mAuxEffectId);
}
}
- mTrack->setOutputDevice(mSelectedDeviceId);
- if (mDeviceCallbackEnabled) {
- mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
- }
+ mJAudioTrack->setOutputDevice(mSelectedDeviceId);
+
+ mJAudioTrack->registerRoutingDelegates(mRoutingDelegates);
+
ALOGV("updateTrack_l() DONE status %d", res);
return res;
}
@@ -439,13 +399,13 @@
status_t MediaPlayer2AudioOutput::start() {
ALOGV("start");
Mutex::Autolock lock(mLock);
- if (mCallbackData != NULL) {
+ if (mCallbackData != nullptr) {
mCallbackData->endTrackSwitch();
}
- if (mTrack != 0) {
- mTrack->setVolume(mVolume);
- mTrack->setAuxEffectSendLevel(mSendLevel);
- status_t status = mTrack->start();
+ if (mJAudioTrack != nullptr) {
+ mJAudioTrack->setVolume(mVolume);
+ mJAudioTrack->setAuxEffectSendLevel(mSendLevel);
+ status_t status = mJAudioTrack->start();
return status;
}
return NO_INIT;
@@ -453,11 +413,11 @@
ssize_t MediaPlayer2AudioOutput::write(const void* buffer, size_t size, bool blocking) {
Mutex::Autolock lock(mLock);
- LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
+ LOG_ALWAYS_FATAL_IF(mCallback != nullptr, "Don't call write if supplying a callback.");
//ALOGV("write(%p, %u)", buffer, size);
- if (mTrack != 0) {
- return mTrack->write(buffer, size, blocking);
+ if (mJAudioTrack != nullptr) {
+ return mJAudioTrack->write(buffer, size, blocking);
}
return NO_INIT;
}
@@ -465,34 +425,34 @@
void MediaPlayer2AudioOutput::stop() {
ALOGV("stop");
Mutex::Autolock lock(mLock);
- if (mTrack != 0) {
- mTrack->stop();
+ if (mJAudioTrack != nullptr) {
+ mJAudioTrack->stop();
}
}
void MediaPlayer2AudioOutput::flush() {
ALOGV("flush");
Mutex::Autolock lock(mLock);
- if (mTrack != 0) {
- mTrack->flush();
+ if (mJAudioTrack != nullptr) {
+ mJAudioTrack->flush();
}
}
void MediaPlayer2AudioOutput::pause() {
ALOGV("pause");
Mutex::Autolock lock(mLock);
- if (mTrack != 0) {
- mTrack->pause();
+ if (mJAudioTrack != nullptr) {
+ mJAudioTrack->pause();
}
}
void MediaPlayer2AudioOutput::close() {
ALOGV("close");
- sp<AudioTrack> track;
+ sp<JAudioTrack> track;
{
Mutex::Autolock lock(mLock);
- track = mTrack;
- close_l(); // clears mTrack
+ track = mJAudioTrack;
+ close_l(); // clears mJAudioTrack
}
// destruction of the track occurs outside of mutex.
}
@@ -501,8 +461,8 @@
ALOGV("setVolume(%f)", volume);
Mutex::Autolock lock(mLock);
mVolume = volume;
- if (mTrack != 0) {
- mTrack->setVolume(volume);
+ if (mJAudioTrack != nullptr) {
+ mJAudioTrack->setVolume(volume);
}
}
@@ -510,12 +470,12 @@
ALOGV("setPlaybackRate(%f %f %d %d)",
rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == 0) {
// remember rate so that we can set it when the track is opened
mPlaybackRate = rate;
return OK;
}
- status_t res = mTrack->setPlaybackRate(rate);
+ status_t res = mJAudioTrack->setPlaybackRate(rate);
if (res != NO_ERROR) {
return res;
}
@@ -531,10 +491,10 @@
status_t MediaPlayer2AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) {
ALOGV("getPlaybackRate");
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == 0) {
return NO_INIT;
}
- *rate = mTrack->getPlaybackRate();
+ *rate = mJAudioTrack->getPlaybackRate();
return NO_ERROR;
}
@@ -542,8 +502,8 @@
ALOGV("setAuxEffectSendLevel(%f)", level);
Mutex::Autolock lock(mLock);
mSendLevel = level;
- if (mTrack != 0) {
- return mTrack->setAuxEffectSendLevel(level);
+ if (mJAudioTrack != nullptr) {
+ return mJAudioTrack->setAuxEffectSendLevel(level);
}
return NO_ERROR;
}
@@ -552,8 +512,8 @@
ALOGV("attachAuxEffect(%d)", effectId);
Mutex::Autolock lock(mLock);
mAuxEffectId = effectId;
- if (mTrack != 0) {
- return mTrack->attachAuxEffect(effectId);
+ if (mJAudioTrack != nullptr) {
+ return mJAudioTrack->attachAuxEffect(effectId);
}
return NO_ERROR;
}
@@ -562,8 +522,8 @@
ALOGV("setOutputDevice(%d)", deviceId);
Mutex::Autolock lock(mLock);
mSelectedDeviceId = deviceId;
- if (mTrack != 0) {
- return mTrack->setOutputDevice(deviceId);
+ if (mJAudioTrack != nullptr) {
+ return mJAudioTrack->setOutputDevice(deviceId);
}
return NO_ERROR;
}
@@ -571,29 +531,51 @@
status_t MediaPlayer2AudioOutput::getRoutedDeviceId(audio_port_handle_t* deviceId) {
ALOGV("getRoutedDeviceId");
Mutex::Autolock lock(mLock);
- if (mTrack != 0) {
- mRoutedDeviceId = mTrack->getRoutedDeviceId();
+ if (mJAudioTrack != nullptr) {
+ mRoutedDeviceId = mJAudioTrack->getRoutedDeviceId();
}
*deviceId = mRoutedDeviceId;
return NO_ERROR;
}
-status_t MediaPlayer2AudioOutput::enableAudioDeviceCallback(bool enabled) {
- ALOGV("enableAudioDeviceCallback, %d", enabled);
+status_t MediaPlayer2AudioOutput::addAudioDeviceCallback(jobject jRoutingDelegate) {
+ ALOGV("addAudioDeviceCallback");
Mutex::Autolock lock(mLock);
- mDeviceCallbackEnabled = enabled;
- if (mTrack != 0) {
- status_t status;
- if (enabled) {
- status = mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
- } else {
- status = mTrack->removeAudioDeviceCallback(mDeviceCallback.promote());
- }
- return status;
+ jobject listener = JAudioTrack::getListener(jRoutingDelegate);
+ if (mJAudioTrack != nullptr &&
+ JAudioTrack::findByKey(mRoutingDelegates, listener) == nullptr) {
+ jobject handler = JAudioTrack::getHandler(jRoutingDelegate);
+ jobject routingDelegate = JAudioTrack::addGlobalRef(jRoutingDelegate);
+ mRoutingDelegates.push_back(std::pair<jobject, jobject>(listener, routingDelegate));
+ return mJAudioTrack->addAudioDeviceCallback(routingDelegate, handler);
}
return NO_ERROR;
}
+status_t MediaPlayer2AudioOutput::removeAudioDeviceCallback(jobject listener) {
+ ALOGV("removeAudioDeviceCallback");
+ Mutex::Autolock lock(mLock);
+ jobject routingDelegate = nullptr;
+ if (mJAudioTrack != nullptr &&
+ (routingDelegate = JAudioTrack::findByKey(mRoutingDelegates, listener)) != nullptr) {
+ mJAudioTrack->removeAudioDeviceCallback(routingDelegate);
+ JAudioTrack::eraseByKey(mRoutingDelegates, listener);
+ if (JAudioTrack::removeGlobalRef(routingDelegate) != NO_ERROR) {
+ return BAD_VALUE;
+ }
+ }
+ return NO_ERROR;
+}
+
+void MediaPlayer2AudioOutput::copyAudioDeviceCallback(
+ std::vector<jobject>& routingDelegateTarget) {
+ ALOGV("copyAudioDeviceCallback");
+ for (std::vector<std::pair<jobject, jobject>>::iterator it = mRoutingDelegates.begin();
+ it != mRoutingDelegates.end(); it++) {
+ routingDelegateTarget.push_back(it->second);
+ }
+}
+
// static
void MediaPlayer2AudioOutput::CallbackWrapper(
int event, void *cookie, void *info) {
@@ -602,21 +584,21 @@
// lock to ensure we aren't caught in the middle of a track switch.
data->lock();
MediaPlayer2AudioOutput *me = data->getOutput();
- AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
- if (me == NULL) {
+ JAudioTrack::Buffer *buffer = (JAudioTrack::Buffer *)info;
+ if (me == nullptr) {
// no output set, likely because the track was scheduled to be reused
// by another player, but the format turned out to be incompatible.
data->unlock();
- if (buffer != NULL) {
- buffer->size = 0;
+ if (buffer != nullptr) {
+ buffer->mSize = 0;
}
return;
}
switch(event) {
- case AudioTrack::EVENT_MORE_DATA: {
+ case JAudioTrack::EVENT_MORE_DATA: {
size_t actualSize = (*me->mCallback)(
- me, buffer->raw, buffer->size, me->mCallbackCookie,
+ me, buffer->mData, buffer->mSize, me->mCallbackCookie,
CB_EVENT_FILL_BUFFER);
// Log when no data is returned from the callback.
@@ -628,25 +610,25 @@
// This is a benign busy-wait, with the next data request generated 10 ms or more later;
// nevertheless for power reasons, we don't want to see too many of these.
- ALOGV_IF(actualSize == 0 && buffer->size > 0, "callbackwrapper: empty buffer returned");
+ ALOGV_IF(actualSize == 0 && buffer->mSize > 0, "callbackwrapper: empty buffer returned");
- buffer->size = actualSize;
+ buffer->mSize = actualSize;
} break;
- case AudioTrack::EVENT_STREAM_END:
+ case JAudioTrack::EVENT_STREAM_END:
// currently only occurs for offloaded callbacks
ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
- (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
+ (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
me->mCallbackCookie, CB_EVENT_STREAM_END);
break;
- case AudioTrack::EVENT_NEW_IAUDIOTRACK :
+ case JAudioTrack::EVENT_NEW_IAUDIOTRACK :
ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
- (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
+ (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
break;
- case AudioTrack::EVENT_UNDERRUN:
+ case JAudioTrack::EVENT_UNDERRUN:
// This occurs when there is no data available, typically
// when there is a failure to supply data to the AudioTrack. It can also
// occur in non-offloaded mode when the audio device comes out of standby.
@@ -666,29 +648,26 @@
data->unlock();
}
-audio_session_t MediaPlayer2AudioOutput::getSessionId() const
-{
+audio_session_t MediaPlayer2AudioOutput::getSessionId() const {
Mutex::Autolock lock(mLock);
return mSessionId;
}
-uint32_t MediaPlayer2AudioOutput::getSampleRate() const
-{
+uint32_t MediaPlayer2AudioOutput::getSampleRate() const {
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == 0) {
return 0;
}
- return mTrack->getSampleRate();
+ return mJAudioTrack->getSampleRate();
}
-int64_t MediaPlayer2AudioOutput::getBufferDurationInUs() const
-{
+int64_t MediaPlayer2AudioOutput::getBufferDurationInUs() const {
Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
+ if (mJAudioTrack == 0) {
return 0;
}
int64_t duration;
- if (mTrack->getBufferDurationInUs(&duration) != OK) {
+ if (mJAudioTrack->getBufferDurationInUs(&duration) != OK) {
return 0;
}
return duration;
diff --git a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
index 301825b..629968f 100644
--- a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
+++ b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_JAUDIOTRACK_H
#define ANDROID_JAUDIOTRACK_H
+#include <vector>
+#include <utility>
#include <jni.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
@@ -29,7 +31,7 @@
namespace android {
-class JAudioTrack {
+class JAudioTrack : public RefBase {
public:
/* Events used by AudioTrack callback function (callback_t).
@@ -37,6 +39,8 @@
*/
enum event_type {
EVENT_MORE_DATA = 0, // Request to write more data to buffer.
+ EVENT_UNDERRUN = 1, // Buffer underrun occurred. This will not occur for
+ // static tracks.
EVENT_NEW_IAUDIOTRACK = 6, // IAudioTrack was re-created, either due to re-routing and
// voluntary invalidation by mediaserver, or mediaserver crash.
EVENT_STREAM_END = 7, // Sent after all the buffers queued in AF and HW are played
@@ -104,8 +108,7 @@
*
* TODO: Revive removed arguments after offload mode is supported.
*/
- JAudioTrack(audio_stream_type_t streamType,
- uint32_t sampleRate,
+ JAudioTrack(uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
callback_t cbf,
@@ -158,10 +161,10 @@
* Caution: calling this method too often may be inefficient;
* if you need a high resolution mapping between frame position and presentation time,
* consider implementing that at application level, based on the low resolution timestamps.
- * Returns true if timestamp is valid.
- * The timestamp parameter is undefined on return, if false is returned.
+ * Returns NO_ERROR if timestamp is valid.
+ * NO_INIT if finds error, and timestamp parameter will be undefined on return.
*/
- bool getTimestamp(AudioTimestamp& timestamp);
+ status_t getTimestamp(AudioTimestamp& timestamp);
// TODO: This doc is just copied from AudioTrack.h. Revise it after implemenation.
/* Return the extended timestamp, with additional timebase info and improved drain behavior.
@@ -324,6 +327,8 @@
audio_format_t format();
+ size_t frameSize();
+
/*
* Dumps the state of an audio track.
* Not a general-purpose API; intended only for use by media player service to dump its tracks.
@@ -355,6 +360,11 @@
/* Returns the flags */
audio_output_flags_t getFlags() const { return mFlags; }
+ /* We don't keep stream type here,
+ * instead, we keep attributes and call getVolumeControlStream() to get stream type
+ */
+ audio_stream_type_t getAudioStreamType();
+
/* Obtain the pending duration in milliseconds for playback of pure PCM data remaining in
* AudioTrack.
*
@@ -369,33 +379,75 @@
* Replaces any previously installed callback.
*
* Parameters:
- *
- * callback: The callback interface
+ * Listener: the listener to receive notification of rerouting events.
+ * Handler: the handler to handler the rerouting events.
*
* Returns NO_ERROR if successful.
- * INVALID_OPERATION if the same callback is already installed.
- * NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
- * BAD_VALUE if the callback is NULL
+ * (TODO) INVALID_OPERATION if the same callback is already installed.
+ * (TODO) NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
+ * (TODO) BAD_VALUE if the callback is NULL
*/
- status_t addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+ status_t addAudioDeviceCallback(jobject listener, jobject rd);
/* Removes an AudioDeviceCallback.
*
* Parameters:
- *
- * callback: The callback interface
+ * Listener: the listener to receive notification of rerouting events.
*
* Returns NO_ERROR if successful.
- * INVALID_OPERATION if the callback is not installed
- * BAD_VALUE if the callback is NULL
+ * (TODO) INVALID_OPERATION if the callback is not installed
+ * (TODO) BAD_VALUE if the callback is NULL
*/
- status_t removeAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+ status_t removeAudioDeviceCallback(jobject listener);
+
+ /* Register all backed-up routing delegates.
+ *
+ * Parameters:
+ * routingDelegates: backed-up routing delegates
+ *
+ */
+ void registerRoutingDelegates(std::vector<std::pair<jobject, jobject>>& routingDelegates);
+
+ /* get listener from RoutingDelegate object
+ */
+ static jobject getListener(const jobject routingDelegateObj);
+
+ /* get handler from RoutingDelegate object
+ */
+ static jobject getHandler(const jobject routingDelegateObj);
+
+ /* convert local reference to global reference.
+ */
+ static jobject addGlobalRef(const jobject obj);
+
+ /* erase global reference.
+ *
+ * Returns NO_ERROR if succeeds
+ * BAD_VALUE if obj is NULL
+ */
+ static status_t removeGlobalRef(const jobject obj);
+
+ /*
+ * Parameters:
+ * map and key
+ *
+ * Returns value if key is in the map
+ * nullptr if key is not in the map
+ */
+ static jobject findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key);
+
+ /*
+ * Parameters:
+ * map and key
+ */
+ static void eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key);
private:
audio_output_flags_t mFlags;
jclass mAudioTrackCls;
jobject mAudioTrackObj;
+ jobject mAudioAttributesObj;
/* Creates a Java VolumeShaper.Configuration object from VolumeShaper::Configuration */
jobject createVolumeShaperConfigurationObj(
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
index fe1005b..9fca641 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -19,7 +19,10 @@
#define ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
#include <mediaplayer2/MediaPlayer2Interface.h>
+#include <mediaplayer2/JAudioTrack.h>
+#include <vector>
+#include <utility>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -36,11 +39,11 @@
uid_t uid,
int pid,
const audio_attributes_t * attr,
- const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
+ std::vector<jobject>& routingDelegatesBackup);
virtual ~MediaPlayer2AudioOutput();
virtual bool ready() const {
- return mTrack != 0;
+ return mJAudioTrack != nullptr;
}
virtual ssize_t bufferSize() const;
virtual ssize_t frameCount() const;
@@ -62,7 +65,6 @@
AudioCallback cb, void *cookie,
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
const audio_offload_info_t *offloadInfo = NULL,
- bool doNotReconnect = false,
uint32_t suggestedFrameCount = 0);
virtual status_t start();
@@ -71,11 +73,8 @@
virtual void flush();
virtual void pause();
virtual void close();
- void setAudioStreamType(audio_stream_type_t streamType);
- virtual audio_stream_type_t getAudioStreamType() const {
- return mStreamType;
- }
void setAudioAttributes(const audio_attributes_t * attributes);
+ virtual audio_stream_type_t getAudioStreamType() const;
void setVolume(float volume);
virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
@@ -92,13 +91,12 @@
// TODO: return correct value.
//return mNextOutput == NULL;
}
- virtual status_t setParameters(const String8& keyValuePairs);
- virtual String8 getParameters(const String8& keys);
-
// AudioRouting
virtual status_t setOutputDevice(audio_port_handle_t deviceId);
virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
- virtual status_t enableAudioDeviceCallback(bool enabled);
+ virtual status_t addAudioDeviceCallback(jobject routingDelegate);
+ virtual status_t removeAudioDeviceCallback(jobject listener);
+ virtual void copyAudioDeviceCallback(std::vector<jobject>& routingDelegateTarget);
private:
static void setMinBufferCount();
@@ -107,11 +105,10 @@
void close_l();
status_t updateTrack_l();
- sp<AudioTrack> mTrack;
+ sp<JAudioTrack> mJAudioTrack;
AudioCallback mCallback;
void * mCallbackCookie;
CallbackData * mCallbackData;
- audio_stream_type_t mStreamType;
audio_attributes_t * mAttributes;
float mVolume;
AudioPlaybackRate mPlaybackRate;
@@ -126,9 +123,8 @@
audio_output_flags_t mFlags;
audio_port_handle_t mSelectedDeviceId;
audio_port_handle_t mRoutedDeviceId;
- bool mDeviceCallbackEnabled;
- wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
mutable Mutex mLock;
+ std::vector<std::pair<jobject, jobject>> mRoutingDelegates; // <listener, routingDelegate>
// static variables below not protected by mutex
static bool mIsOnEmulator;
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
index 846441e..9a35ed9 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -23,6 +23,7 @@
#include <utils/Errors.h>
#include <utils/String8.h>
#include <utils/RefBase.h>
+#include <jni.h>
#include <media/AVSyncSettings.h>
#include <media/AudioResamplerPublic.h>
@@ -106,7 +107,6 @@
void *cookie = NULL,
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
const audio_offload_info_t *offloadInfo = NULL,
- bool doNotReconnect = false,
uint32_t suggestedFrameCount = 0) = 0;
virtual status_t start() = 0;
@@ -144,7 +144,8 @@
// AudioRouting
virtual status_t setOutputDevice(audio_port_handle_t deviceId);
virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
- virtual status_t enableAudioDeviceCallback(bool enabled);
+ virtual status_t addAudioDeviceCallback(jobject routingDelegate);
+ virtual status_t removeAudioDeviceCallback(jobject listener);
};
MediaPlayer2Interface() : mListener(NULL) { }
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
index 10e07ea..2430289 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
@@ -42,7 +42,6 @@
MEDIA2_SUBTITLE_DATA = 201,
MEDIA2_META_DATA = 202,
MEDIA2_DRM_INFO = 210,
- MEDIA2_AUDIO_ROUTING_CHANGED = 10000,
};
// Generic error codes for the media player framework. Errors are fatal, the
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index 4f73ad3..a1908e6 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -25,6 +25,8 @@
#include <mediaplayer2/MediaPlayer2Interface.h>
#include <mediaplayer2/MediaPlayer2Types.h>
+#include <vector>
+#include <jni.h>
#include <utils/Errors.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
@@ -105,7 +107,8 @@
// AudioRouting
status_t setOutputDevice(audio_port_handle_t deviceId);
audio_port_handle_t getRoutedDeviceId();
- status_t enableAudioDeviceCallback(bool enabled);
+ status_t addAudioDeviceCallback(jobject routingDelegate);
+ status_t removeAudioDeviceCallback(jobject listener);
status_t dump(int fd, const Vector<String16>& args);
@@ -148,7 +151,7 @@
audio_session_t mAudioSessionId;
audio_attributes_t * mAudioAttributes;
float mSendLevel;
-
+ std::vector<jobject> mRoutingDelegates;
sp<ANativeWindowWrapper> mConnectedWindow;
};
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 480a630..4960694 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -104,27 +104,6 @@
}
}
-class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback {
-public:
- AudioDeviceUpdatedNotifier(const sp<MediaPlayer2Interface>& listener)
- : mListener(listener) { }
-
- ~AudioDeviceUpdatedNotifier() { }
-
- virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
- audio_port_handle_t deviceId) override {
- sp<MediaPlayer2Interface> listener = mListener.promote();
- if (listener != NULL) {
- listener->sendEvent(0, MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
- } else {
- ALOGW("listener for process %d death is gone", MEDIA2_AUDIO_ROUTING_CHANGED);
- }
- }
-
-private:
- wp<MediaPlayer2Interface> mListener;
-};
-
class proxyListener : public MediaPlayer2InterfaceListener {
public:
proxyListener(const wp<MediaPlayer2> &player)
@@ -433,9 +412,13 @@
clear_l();
+ if (mAudioOutput != NULL) {
+ mAudioOutput->copyAudioDeviceCallback(mRoutingDelegates);
+ }
+
player->setListener(new proxyListener(this));
mAudioOutput = new MediaPlayer2AudioOutput(mAudioSessionId, mUid,
- mPid, mAudioAttributes, new AudioDeviceUpdatedNotifier(player));
+ mPid, mAudioAttributes, mRoutingDelegates);
player->setAudioSink(mAudioOutput);
err = player->setDataSource(dsd);
@@ -614,8 +597,6 @@
if (err != OK) {
return err;
}
- } else if (mAudioOutput != 0) {
- mAudioOutput->setAudioStreamType(mStreamType);
}
mCurrentState = MEDIA_PLAYER2_PREPARING;
return mPlayer->prepareAsync();
@@ -1306,13 +1287,23 @@
return deviceId;
}
-status_t MediaPlayer2::enableAudioDeviceCallback(bool enabled) {
+status_t MediaPlayer2::addAudioDeviceCallback(jobject routingDelegate) {
+ Mutex::Autolock _l(mLock);
+ if (mAudioOutput == NULL) {
+ ALOGV("addAudioDeviceCallback: player not init");
+ mRoutingDelegates.push_back(routingDelegate);
+ return NO_INIT;
+ }
+ return mAudioOutput->addAudioDeviceCallback(routingDelegate);
+}
+
+status_t MediaPlayer2::removeAudioDeviceCallback(jobject listener) {
Mutex::Autolock _l(mLock);
if (mAudioOutput == NULL) {
ALOGV("addAudioDeviceCallback: player not init");
return NO_INIT;
}
- return mAudioOutput->enableAudioDeviceCallback(enabled);
+ return mAudioOutput->removeAudioDeviceCallback(listener);
}
status_t MediaPlayer2::dump(int fd, const Vector<String16>& args) {
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index bc17d13..c37460b 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -643,6 +643,7 @@
}
void NuPlayer2::onMessageReceived(const sp<AMessage> &msg) {
+
switch (msg->what()) {
case kWhatSetDataSource:
{
@@ -1717,7 +1718,7 @@
mRenderer = new Renderer(mAudioSink, mMediaClock, notify, flags);
mRendererLooper = new ALooper;
mRendererLooper->setName("NuPlayerRenderer");
- mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
+ mRendererLooper->start(false, true, ANDROID_PRIORITY_AUDIO);
mRendererLooper->registerHandler(mRenderer);
status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
index 652cc89..7db78c1 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
@@ -1848,6 +1848,7 @@
bool isStreaming) {
ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)",
offloadOnly, offloadingAudio());
+
bool audioSinkChanged = false;
int32_t numChannels;
@@ -1989,13 +1990,6 @@
const uint32_t frameCount =
(unsigned long long)sampleRate * getAudioSinkPcmMsSetting() / 1000;
- // The doNotReconnect means AudioSink will signal back and let NuPlayer2 to re-construct
- // AudioSink. We don't want this when there's video because it will cause a video seek to
- // the previous I frame. But we do want this when there's only audio because it will give
- // NuPlayer2 a chance to switch from non-offload mode to offload mode.
- // So we only set doNotReconnect when there's no video.
- const bool doNotReconnect = !hasVideo;
-
// We should always be able to set our playback settings if the sink is closed.
LOG_ALWAYS_FATAL_IF(mAudioSink->setPlaybackRate(mPlaybackSettings) != OK,
"onOpenAudioSink: can't set playback rate on closed sink");
@@ -2008,7 +2002,6 @@
mUseAudioCallback ? this : NULL,
(audio_output_flags_t)pcmFlags,
NULL,
- doNotReconnect,
frameCount);
if (err != OK) {
ALOGW("openAudioSink: non offloaded open failed status: %d", err);