Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9d7fa08 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

Support for audio attributes on audio output of media player

Change-Id: Iae4995c98e64add1ab9e6c8ae6501515032755f5
parent f92f22be
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -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
+5 −1
Original line number Diff line number Diff line
@@ -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<IMediaPlayer>& player);
            status_t        reset_l();
            status_t        doSetRetransmitEndpoint(const sp<IMediaPlayer>& player);
            status_t        checkStateForKeySet_l(int key);

    sp<IMediaPlayer>            mPlayer;
    thread_id_t                 mLockThreadId;
+7 −5
Original line number Diff line number Diff line
@@ -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",
+22 −0
Original line number Diff line number Diff line
@@ -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);
    }
+101 −7
Original line number Diff line number Diff line
@@ -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> client(this);
    disconnect();
    mService->removeClient(client);
    if (mAudioAttributes != NULL) {
        free(mAudioAttributes);
    }
}

void MediaPlayerService::Client::disconnect()
@@ -587,7 +645,7 @@ sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(

    if (!p->hardwareOutput()) {
        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
                mPid);
                mPid, mAudioAttributes);
        static_cast<MediaPlayerInterface*>(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,10 +1090,18 @@ status_t MediaPlayerService::Client::attachAuxEffect(int effectId)

status_t MediaPlayerService::Client::setParameter(int key, const Parcel &request) {
    ALOGV("[%d] setParameter(%d)", mConnId, key);
    switch (key) {
    case KEY_PARAMETER_AUDIO_ATTRIBUTES:
    {
        Mutex::Autolock l(mLock);
        return setAudioAttributes_l(request);
    }
    default:
        sp<MediaPlayerBase> p = getPlayer();
    if (p == 0) return UNKNOWN_ERROR;
        if (p == 0) { return UNKNOWN_ERROR; }
        return p->setParameter(key, request);
    }
}

status_t MediaPlayerService::Client::getParameter(int key, Parcel *reply) {
    ALOGV("[%d] getParameter(%d)", mConnId, key);
@@ -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();
        }
    }

Loading