From d9d7fa0873796ac661c44a7fcd6ad5ff697ff01f Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 24 Jun 2014 08:01:46 -0700 Subject: Support for audio attributes on audio output of media player Change-Id: Iae4995c98e64add1ab9e6c8ae6501515032755f5 --- include/media/AudioTrack.h | 8 +- include/media/mediaplayer.h | 6 +- media/libmedia/AudioTrack.cpp | 12 ++- media/libmedia/mediaplayer.cpp | 22 +++++ media/libmediaplayerservice/MediaPlayerService.cpp | 108 +++++++++++++++++++-- media/libmediaplayerservice/MediaPlayerService.h | 8 +- 6 files changed, 147 insertions(+), 17 deletions(-) diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index 3492520..a3cc396 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -188,7 +188,8 @@ public: transfer_type transferType = TRANSFER_DEFAULT, const audio_offload_info_t *offloadInfo = NULL, int uid = -1, - pid_t pid = -1); + pid_t pid = -1, + const audio_attributes_t* pAttributes = NULL); /* Creates an audio track and registers it with AudioFlinger. * With this constructor, the track is configured for static buffer mode. @@ -214,7 +215,8 @@ public: transfer_type transferType = TRANSFER_DEFAULT, const audio_offload_info_t *offloadInfo = NULL, int uid = -1, - pid_t pid = -1); + pid_t pid = -1, + const audio_attributes_t* pAttributes = NULL); /* Terminates the AudioTrack and unregisters it from AudioFlinger. * Also destroys all resources associated with the AudioTrack. @@ -254,7 +256,7 @@ public: const audio_offload_info_t *offloadInfo = NULL, int uid = -1, pid_t pid = -1, - audio_attributes_t* pAttributes = NULL); + const audio_attributes_t* pAttributes = NULL); /* Result of constructing the AudioTrack. This must be checked for successful initialization * before using any AudioTrack API (except for set()), because using diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h index 3ca3095..e756368 100644 --- a/include/media/mediaplayer.h +++ b/include/media/mediaplayer.h @@ -160,6 +160,9 @@ enum media_parameter_keys { // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative // values used for rewinding or reverse playback. KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300, // set only + + // Set a Parcel containing the value of a parcelled Java AudioAttribute instance + KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400 // set only }; // Keep INVOKE_ID_* in sync with MediaPlayer.java. @@ -169,7 +172,7 @@ enum media_player_invoke_ids { INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3, INVOKE_ID_SELECT_TRACK = 4, INVOKE_ID_UNSELECT_TRACK = 5, - INVOKE_ID_SET_VIDEO_SCALING_MODE = 6, + INVOKE_ID_SET_VIDEO_SCALING_MODE = 6 }; // Keep MEDIA_TRACK_TYPE_* in sync with MediaPlayer.java. @@ -259,6 +262,7 @@ private: status_t attachNewPlayer(const sp& player); status_t reset_l(); status_t doSetRetransmitEndpoint(const sp& player); + status_t checkStateForKeySet_l(int key); sp mPlayer; thread_id_t mLockThreadId; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 898d58d..b5c9125 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -124,7 +124,8 @@ AudioTrack::AudioTrack( transfer_type transferType, const audio_offload_info_t *offloadInfo, int uid, - pid_t pid) + pid_t pid, + const audio_attributes_t* pAttributes) : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), @@ -134,7 +135,7 @@ AudioTrack::AudioTrack( mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, - offloadInfo, uid, pid, NULL /*no audio attributes*/); + offloadInfo, uid, pid, pAttributes); } AudioTrack::AudioTrack( @@ -151,7 +152,8 @@ AudioTrack::AudioTrack( transfer_type transferType, const audio_offload_info_t *offloadInfo, int uid, - pid_t pid) + pid_t pid, + const audio_attributes_t* pAttributes) : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), @@ -161,7 +163,7 @@ AudioTrack::AudioTrack( mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, - uid, pid, NULL /*no audio attributes*/); + uid, pid, pAttributes); } AudioTrack::~AudioTrack() @@ -205,7 +207,7 @@ status_t AudioTrack::set( const audio_offload_info_t *offloadInfo, int uid, pid_t pid, - audio_attributes_t* pAttributes) + const audio_attributes_t* pAttributes) { ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, " "flags #%x, notificationFrames %u, sessionId %d, transferType %d", diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 406f9f2..889bd7f 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -624,10 +624,32 @@ status_t MediaPlayer::attachAuxEffect(int effectId) return mPlayer->attachAuxEffect(effectId); } +// always call with lock held +status_t MediaPlayer::checkStateForKeySet_l(int key) +{ + switch(key) { + case KEY_PARAMETER_AUDIO_ATTRIBUTES: + if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | + MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_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; + } + return OK; +} + status_t MediaPlayer::setParameter(int key, const Parcel& request) { ALOGV("MediaPlayer::setParameter(%d)", key); Mutex::Autolock _l(mLock); + if (checkStateForKeySet_l(key) != OK) { + return INVALID_OPERATION; + } if (mPlayer != NULL) { return mPlayer->setParameter(key, request); } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 76632a7..7218467 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -186,6 +186,60 @@ bool findMetadata(const Metadata::Filter& filter, const int32_t val) } // anonymous namespace +namespace { +using android::Parcel; +using android::String16; + +// 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 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | 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->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); + } + } else { + ALOGE("unmarshallAudioAttributes() received unflattened tags, ignoring tag values"); + strcpy(attributes->tags, ""); + } +} +} // anonymous namespace + + namespace android { static bool checkPermission(const char* permissionString) { @@ -508,6 +562,7 @@ MediaPlayerService::Client::Client( mAudioSessionId = audioSessionId; mUID = uid; mRetransmitEndpointValid = false; + mAudioAttributes = NULL; #if CALLBACK_ANTAGONIZER ALOGD("create Antagonizer"); @@ -522,6 +577,9 @@ MediaPlayerService::Client::~Client() wp client(this); disconnect(); mService->removeClient(client); + if (mAudioAttributes != NULL) { + free(mAudioAttributes); + } } void MediaPlayerService::Client::disconnect() @@ -587,7 +645,7 @@ sp MediaPlayerService::Client::setDataSource_pre( if (!p->hardwareOutput()) { mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(), - mPid); + mPid, mAudioAttributes); static_cast(p.get())->setAudioSink(mAudioOutput); } @@ -968,6 +1026,22 @@ status_t MediaPlayerService::Client::setAudioStreamType(audio_stream_type_t type return NO_ERROR; } +status_t MediaPlayerService::Client::setAudioAttributes_l(const Parcel &parcel) +{ + if (mAudioAttributes != NULL) { free(mAudioAttributes); } + mAudioAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); + 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); + } + return NO_ERROR; +} + status_t MediaPlayerService::Client::setLooping(int loop) { ALOGV("[%d] setLooping(%d)", mConnId, loop); @@ -1016,9 +1090,17 @@ status_t MediaPlayerService::Client::attachAuxEffect(int effectId) status_t MediaPlayerService::Client::setParameter(int key, const Parcel &request) { ALOGV("[%d] setParameter(%d)", mConnId, key); - sp p = getPlayer(); - if (p == 0) return UNKNOWN_ERROR; - return p->setParameter(key, request); + switch (key) { + case KEY_PARAMETER_AUDIO_ATTRIBUTES: + { + Mutex::Autolock l(mLock); + return setAudioAttributes_l(request); + } + default: + sp p = getPlayer(); + if (p == 0) { return UNKNOWN_ERROR; } + return p->setParameter(key, request); + } } status_t MediaPlayerService::Client::getParameter(int key, Parcel *reply) { @@ -1300,7 +1382,8 @@ Exit: #undef LOG_TAG #define LOG_TAG "AudioSink" -MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid) +MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid, + const audio_attributes_t* attr) : mCallback(NULL), mCallbackCookie(NULL), mCallbackData(NULL), @@ -1319,6 +1402,7 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid) mAuxEffectId = 0; mSendLevel = 0.0; setMinBufferCount(); + mAttributes = attr; } MediaPlayerService::AudioOutput::~AudioOutput() @@ -1408,6 +1492,10 @@ String8 MediaPlayerService::AudioOutput::getParameters(const String8& keys) return mTrack->getParameters(keys); } +void MediaPlayerService::AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) { + mAttributes = attributes; +} + void MediaPlayerService::AudioOutput::deleteRecycledTrack() { ALOGV("deleteRecycledTrack"); @@ -1557,7 +1645,8 @@ status_t MediaPlayerService::AudioOutput::open( AudioTrack::TRANSFER_CALLBACK, offloadInfo, mUid, - mPid); + mPid, + mAttributes); } else { t = new AudioTrack( mStreamType, @@ -1573,13 +1662,18 @@ status_t MediaPlayerService::AudioOutput::open( AudioTrack::TRANSFER_DEFAULT, NULL, // offload info mUid, - mPid); + mPid, + mAttributes); } if ((t == 0) || (t->initCheck() != NO_ERROR)) { ALOGE("Unable to create audio track"); delete newcbd; return NO_INIT; + } else { + // successful AudioTrack initialization implies a legacy stream type was generated + // from the audio attributes + mStreamType = t->streamType(); } } diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 448f27a..2eca6a0 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -72,7 +72,8 @@ class MediaPlayerService : public BnMediaPlayerService class CallbackData; public: - AudioOutput(int sessionId, int uid, int pid); + AudioOutput(int sessionId, int uid, int pid, + const audio_attributes_t * attr); virtual ~AudioOutput(); virtual bool ready() const { return mTrack != 0; } @@ -104,6 +105,7 @@ class MediaPlayerService : public BnMediaPlayerService void setAudioStreamType(audio_stream_type_t streamType) { mStreamType = streamType; } virtual audio_stream_type_t getAudioStreamType() const { return mStreamType; } + void setAudioAttributes(const audio_attributes_t * attributes); void setVolume(float left, float right); virtual status_t setPlaybackRatePermille(int32_t ratePermille); @@ -133,6 +135,7 @@ class MediaPlayerService : public BnMediaPlayerService CallbackData * mCallbackData; uint64_t mBytesWritten; audio_stream_type_t mStreamType; + const audio_attributes_t *mAttributes; float mLeftVolume; float mRightVolume; int32_t mPlaybackRatePermille; @@ -410,6 +413,8 @@ private: // Disconnect from the currently connected ANativeWindow. void disconnectNativeWindow(); + status_t setAudioAttributes_l(const Parcel &request); + mutable Mutex mLock; sp mPlayer; sp mService; @@ -420,6 +425,7 @@ private: bool mLoop; int32_t mConnId; int mAudioSessionId; + audio_attributes_t * mAudioAttributes; uid_t mUID; sp mConnectedWindow; sp mConnectedWindowBinder; -- cgit v1.1