Merge "MediaPlayer2: directly pass AudioAttributes to AudioTrack without native parcel conversion"

gugelfrei
Dichen Zhang 6 years ago committed by Android (Google) Code Review
commit f8274c19f9

@ -35,7 +35,7 @@ JAudioTrack::JAudioTrack( // < Usages of the argumen
void* user, // Offload
size_t frameCount, // bufferSizeInBytes
audio_session_t sessionId, // AudioTrack
const audio_attributes_t* pAttributes, // AudioAttributes
const jobject attributes, // AudioAttributes
float maxRequiredSpeed) { // bufferSizeInBytes
JNIEnv *env = JavaVMHelper::getJNIEnv();
@ -65,13 +65,17 @@ JAudioTrack::JAudioTrack( // < Usages of the argumen
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);
if (attributes != NULL) {
mAudioAttributesObj = new JObjectHolder(attributes);
} else {
mAudioAttributesObj = new JObjectHolder(
JAudioAttributes::createAudioAttributesObj(env, NULL));
}
jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
"(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioAttributes, mAudioAttributesObj);
jBuilderObj = env->CallObjectMethod(jBuilderObj,
jSetAudioAttributes, mAudioAttributesObj->getJObject());
jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
"(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
@ -125,7 +129,6 @@ JAudioTrack::~JAudioTrack() {
JNIEnv *env = JavaVMHelper::getJNIEnv();
env->DeleteGlobalRef(mAudioTrackCls);
env->DeleteGlobalRef(mAudioTrackObj);
env->DeleteGlobalRef(mAudioAttributesObj);
}
size_t JAudioTrack::frameCount() {
@ -509,11 +512,15 @@ status_t JAudioTrack::setPreferredDevice(jobject device) {
}
audio_stream_type_t JAudioTrack::getAudioStreamType() {
if (mAudioAttributesObj == NULL) {
return AUDIO_STREAM_DEFAULT;
}
JNIEnv *env = JavaVMHelper::getJNIEnv();
jclass jAudioAttributesCls = env->FindClass("android/media/AudioAttributes");
jmethodID jGetVolumeControlStream = env->GetMethodID(jAudioAttributesCls,
"getVolumeControlStream", "()I");
int javaAudioStreamType = env->CallIntMethod(mAudioAttributesObj, jGetVolumeControlStream);
int javaAudioStreamType = env->CallIntMethod(
mAudioAttributesObj->getJObject(), jGetVolumeControlStream);
return (audio_stream_type_t)javaAudioStreamType;
}

@ -60,7 +60,7 @@ status_t MediaPlayer2AudioOutput::dump(int fd, const Vector<String16>& args) con
}
MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
const audio_attributes_t* attr, std::vector<jobject>& routingDelegatesBackup)
const jobject attributes, std::vector<jobject>& routingDelegatesBackup)
: mCallback(nullptr),
mCallbackCookie(nullptr),
mCallbackData(nullptr),
@ -76,13 +76,12 @@ MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(audio_session_t sessionId, uid_
mAuxEffectId(0),
mFlags(AUDIO_OUTPUT_FLAG_NONE) {
ALOGV("MediaPlayer2AudioOutput(%d)", sessionId);
if (attr != nullptr) {
mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
if (mAttributes != nullptr) {
memcpy(mAttributes, attr, sizeof(audio_attributes_t));
}
} else {
mAttributes = nullptr;
if (mAttributes != nullptr) {
mAttributes->~JObjectHolder();
}
if (attributes != nullptr) {
mAttributes = new JObjectHolder(attributes);
}
setMinBufferCount();
@ -99,7 +98,6 @@ MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
JAudioTrack::removeGlobalRef(routingDelegate.second);
}
close();
free(mAttributes);
delete mCallbackData;
}
@ -251,16 +249,13 @@ status_t MediaPlayer2AudioOutput::getFramesWritten(uint32_t *frameswritten) cons
return status;
}
void MediaPlayer2AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) {
void MediaPlayer2AudioOutput::setAudioAttributes(const jobject attributes) {
Mutex::Autolock lock(mLock);
if (attributes == nullptr) {
free(mAttributes);
mAttributes = nullptr;
} else {
if (mAttributes == nullptr) {
mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
}
memcpy(mAttributes, attributes, sizeof(audio_attributes_t));
if (mAttributes != nullptr) {
mAttributes->~JObjectHolder();
}
if (attributes != nullptr) {
mAttributes = new JObjectHolder(attributes);
}
}
@ -325,7 +320,7 @@ status_t MediaPlayer2AudioOutput::open(
newcbd,
frameCount,
mSessionId,
mAttributes,
mAttributes != nullptr ? mAttributes->getJObject() : nullptr,
1.0f); // default value for maxRequiredSpeed
} else {
// TODO: Due to buffer memory concerns, we use a max target playback speed
@ -344,7 +339,7 @@ status_t MediaPlayer2AudioOutput::open(
nullptr,
frameCount,
mSessionId,
mAttributes,
mAttributes != nullptr ? mAttributes->getJObject() : nullptr,
targetSpeed);
}

@ -25,7 +25,7 @@
#include <media/VolumeShaper.h>
#include <system/audio.h>
#include <utils/Errors.h>
#include <mediaplayer2/JObjectHolder.h>
#include <media/AudioTimestamp.h> // It has dependency on audio.h/Errors.h, but doesn't
// include them in it. Therefore it is included here at last.
@ -115,7 +115,7 @@ public:
void* user,
size_t frameCount = 0,
audio_session_t sessionId = AUDIO_SESSION_ALLOCATE,
const audio_attributes_t* pAttributes = NULL,
const jobject pAttributes = NULL,
float maxRequiredSpeed = 1.0f);
/*
@ -446,7 +446,7 @@ private:
jclass mAudioTrackCls;
jobject mAudioTrackObj;
jobject mAudioAttributesObj;
sp<JObjectHolder> mAudioAttributesObj;
/* Creates a Java VolumeShaper.Configuration object from VolumeShaper::Configuration */
jobject createVolumeShaperConfigurationObj(

@ -41,7 +41,7 @@ public:
MediaPlayer2AudioOutput(audio_session_t sessionId,
uid_t uid,
int pid,
const audio_attributes_t * attr,
const jobject attributes,
std::vector<jobject>& routingDelegatesBackup);
virtual ~MediaPlayer2AudioOutput();
@ -76,7 +76,7 @@ public:
virtual void flush();
virtual void pause();
virtual void close();
void setAudioAttributes(const audio_attributes_t * attributes);
void setAudioAttributes(const jobject attributes);
virtual audio_stream_type_t getAudioStreamType() const;
void setVolume(float volume);
@ -112,7 +112,7 @@ private:
AudioCallback mCallback;
void * mCallbackCookie;
CallbackData * mCallbackData;
audio_attributes_t * mAttributes;
sp<JObjectHolder> mAttributes;
float mVolume;
AudioPlaybackRate mPlaybackRate;
uint32_t mSampleRateHz; // sample rate of the content, as set in open()

@ -24,6 +24,7 @@
#include <media/mediaplayer_common.h>
#include <mediaplayer2/MediaPlayer2Interface.h>
#include <mediaplayer2/MediaPlayer2Types.h>
#include <mediaplayer2/JObjectHolder.h>
#include <vector>
#include <jni.h>
@ -100,7 +101,8 @@ public:
audio_session_t getAudioSessionId();
status_t setAuxEffectSendLevel(float level);
status_t attachAuxEffect(int effectId);
status_t setParameter(int key, const Parcel& request);
status_t setAudioAttributes(const jobject attributes);
jobject getAudioAttributes();
status_t getParameter(int key, Parcel* reply);
// Modular DRM
@ -121,14 +123,14 @@ private:
// Disconnect from the currently connected ANativeWindow.
void disconnectNativeWindow_l();
status_t setAudioAttributes_l(const Parcel &request);
status_t setAudioAttributes_l(const jobject attributes);
void clear_l();
status_t seekTo_l(int64_t msec, MediaPlayer2SeekMode mode);
status_t prepareAsync_l();
status_t getDuration_l(int64_t *msec);
status_t reset_l();
status_t checkStateForKeySet_l(int key);
status_t checkState_l();
pid_t mPid;
uid_t mUid;
@ -145,13 +147,12 @@ private:
int64_t mSeekPosition;
MediaPlayer2SeekMode mSeekMode;
audio_stream_type_t mStreamType;
Parcel* mAudioAttributesParcel;
bool mLoop;
float mVolume;
int mVideoWidth;
int mVideoHeight;
audio_session_t mAudioSessionId;
audio_attributes_t * mAudioAttributes;
sp<JObjectHolder> mAudioAttributes;
float mSendLevel;
std::vector<jobject> mRoutingDelegates;
sp<ANativeWindowWrapper> mConnectedWindow;

@ -53,57 +53,6 @@ namespace {
const int kDumpLockRetries = 50;
const int kDumpLockSleepUs = 20000;
// marshalling tag indicating flattened utf16 tags
// keep in sync with frameworks/base/media/java/android/media/AudioAttributes.java
const int32_t kAudioAttributesMarshallTagFlattenTags = 1;
// Audio attributes format in a parcel:
//
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | usage |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | content_type |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | source |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | flags |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | kAudioAttributesMarshallTagFlattenTags | // ignore tags if not found
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | flattened tags in UTF16 |
// | ... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// @param p Parcel that contains audio attributes.
// @param[out] attributes On exit points to an initialized audio_attributes_t structure
// @param[out] status On exit contains the status code to be returned.
void unmarshallAudioAttributes(const Parcel& parcel, audio_attributes_t *attributes) {
attributes->usage = (audio_usage_t) parcel.readInt32();
attributes->content_type = (audio_content_type_t) parcel.readInt32();
attributes->source = (audio_source_t) parcel.readInt32();
attributes->flags = (audio_flags_mask_t) parcel.readInt32();
const bool hasFlattenedTag = (parcel.readInt32() == kAudioAttributesMarshallTagFlattenTags);
if (hasFlattenedTag) {
// the tags are UTF16, convert to UTF8
String16 tags = parcel.readString16();
ssize_t realTagSize = utf16_to_utf8_length(tags.string(), tags.size());
if (realTagSize <= 0) {
strcpy(attributes->tags, "");
} else {
// copy the flattened string into the attributes as the destination for the conversion:
// copying array size -1, array for tags was calloc'd, no need to NULL-terminate it
size_t tagSize = realTagSize > AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 ?
AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 : realTagSize;
utf16_to_utf8(tags.string(), tagSize, attributes->tags,
sizeof(attributes->tags) / sizeof(attributes->tags[0]));
}
} else {
ALOGE("unmarshallAudioAttributes() received unflattened tags, ignoring tag values");
strcpy(attributes->tags, "");
}
}
class proxyListener : public MediaPlayer2InterfaceListener {
public:
proxyListener(const wp<MediaPlayer2> &player)
@ -293,7 +242,7 @@ MediaPlayer2::MediaPlayer2() {
mLockThreadId = 0;
mListener = NULL;
mStreamType = AUDIO_STREAM_MUSIC;
mAudioAttributesParcel = NULL;
mAudioAttributes = NULL;
mCurrentPosition = -1;
mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
mSeekPosition = -1;
@ -309,22 +258,13 @@ MediaPlayer2::MediaPlayer2() {
// TODO: get pid and uid from JAVA
mPid = IPCThreadState::self()->getCallingPid();
mUid = IPCThreadState::self()->getCallingUid();
mAudioAttributes = NULL;
}
MediaPlayer2::~MediaPlayer2() {
ALOGV("destructor");
if (mAudioAttributesParcel != NULL) {
delete mAudioAttributesParcel;
mAudioAttributesParcel = NULL;
}
AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
disconnect();
removePlayer(this);
if (mAudioAttributes != NULL) {
free(mAudioAttributes);
}
}
bool MediaPlayer2::init() {
@ -418,7 +358,8 @@ status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd) {
player->setListener(new proxyListener(this));
mAudioOutput = new MediaPlayer2AudioOutput(mAudioSessionId, mUid,
mPid, mAudioAttributes, mRoutingDelegates);
mPid, mAudioAttributes != NULL ? mAudioAttributes->getJObject() : NULL,
mRoutingDelegates);
player->setAudioSink(mAudioOutput);
err = player->setDataSource(dsd);
@ -568,22 +509,9 @@ status_t MediaPlayer2::setBufferingSettings(const BufferingSettings& buffering)
return mPlayer->setBufferingSettings(buffering);
}
status_t MediaPlayer2::setAudioAttributes_l(const Parcel &parcel) {
if (mAudioAttributes != NULL) {
free(mAudioAttributes);
}
mAudioAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
if (mAudioAttributes == NULL) {
return NO_MEMORY;
}
unmarshallAudioAttributes(parcel, mAudioAttributes);
ALOGV("setAudioAttributes_l() usage=%d content=%d flags=0x%x tags=%s",
mAudioAttributes->usage, mAudioAttributes->content_type, mAudioAttributes->flags,
mAudioAttributes->tags);
if (mAudioOutput != 0) {
mAudioOutput->setAudioAttributes(mAudioAttributes);
status_t MediaPlayer2::setAudioAttributes_l(const jobject attributes) {
if (mAudioOutput != NULL) {
mAudioOutput->setAudioAttributes(attributes);
}
return NO_ERROR;
}
@ -592,8 +520,8 @@ status_t MediaPlayer2::prepareAsync() {
ALOGV("prepareAsync");
Mutex::Autolock _l(mLock);
if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER2_INITIALIZED)) {
if (mAudioAttributesParcel != NULL) {
status_t err = setAudioAttributes_l(*mAudioAttributesParcel);
if (mAudioAttributes != NULL) {
status_t err = setAudioAttributes_l(mAudioAttributes->getJObject());
if (err != OK) {
return err;
}
@ -1015,67 +943,37 @@ status_t MediaPlayer2::attachAuxEffect(int effectId) {
}
// always call with lock held
status_t MediaPlayer2::checkStateForKeySet_l(int key) {
switch(key) {
case MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES:
if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE) ) {
// Can't change the audio attributes after prepare
ALOGE("trying to set audio attributes called in state %d", mCurrentState);
return INVALID_OPERATION;
}
break;
default:
// parameter doesn't require player state check
break;
status_t MediaPlayer2::checkState_l() {
if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE) ) {
// Can't change the audio attributes after prepare
ALOGE("trying to set audio attributes called in state %d", mCurrentState);
return INVALID_OPERATION;
}
return OK;
}
status_t MediaPlayer2::setParameter(int key, const Parcel& request) {
ALOGV("MediaPlayer2::setParameter(%d)", key);
status_t MediaPlayer2::setAudioAttributes(const jobject attributes) {
ALOGV("MediaPlayer2::setAudioAttributes");
status_t status = INVALID_OPERATION;
Mutex::Autolock _l(mLock);
if (checkStateForKeySet_l(key) != OK) {
if (checkState_l() != OK) {
return status;
}
switch (key) {
case MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES:
// save the marshalled audio attributes
if (mAudioAttributesParcel != NULL) {
delete mAudioAttributesParcel;
}
mAudioAttributesParcel = new Parcel();
mAudioAttributesParcel->appendFrom(&request, 0, request.dataSize());
status = setAudioAttributes_l(request);
if (status != OK) {
return status;
}
break;
default:
ALOGV_IF(mPlayer == NULL, "setParameter: no active player");
break;
}
if (mPlayer != NULL) {
status = mPlayer->setParameter(key, request);
}
mAudioAttributes = new JObjectHolder(attributes);
status = setAudioAttributes_l(attributes);
return status;
}
jobject MediaPlayer2::getAudioAttributes() {
ALOGV("MediaPlayer2::getAudioAttributes)");
Mutex::Autolock _l(mLock);
return mAudioAttributes != NULL ? mAudioAttributes->getJObject() : NULL;
}
status_t MediaPlayer2::getParameter(int key, Parcel *reply) {
ALOGV("MediaPlayer2::getParameter(%d)", key);
Mutex::Autolock _l(mLock);
if (key == MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES) {
if (reply == NULL) {
return BAD_VALUE;
}
if (mAudioAttributesParcel != NULL) {
reply->appendFrom(mAudioAttributesParcel, 0, mAudioAttributesParcel->dataSize());
}
return OK;
}
if (mPlayer == NULL) {
ALOGV("getParameter: no active player");
return INVALID_OPERATION;

Loading…
Cancel
Save