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

Commit 7aa6a95f authored by Atneya Nair's avatar Atneya Nair Committed by Android (Google) Code Review
Browse files

Merge "Implement AudioTrackCallback in MediaPlayerService"

parents 0f8f6871 4dc66dc2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ cc_library {
        "spatializer-aidl-cpp",
        "framework-permission-aidl-cpp",
        "libbinder",
        "libmediametrics",
    ],

    include_dirs: [
+5 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ cc_library {

    header_libs: [
        "media_plugin_headers",
        "libmediautils_headers",
    ],

    static_libs: [
@@ -85,6 +86,10 @@ cc_library {
        "framework-permission-aidl-cpp",
    ],

    export_header_lib_headers: [
        "libmediautils_headers",
    ],

    include_dirs: [
        "frameworks/av/media/libstagefright/rtsp",
        "frameworks/av/media/libstagefright/webm",
+68 −79
Original line number Diff line number Diff line
@@ -1831,7 +1831,6 @@ MediaPlayerService::AudioOutput::~AudioOutput()
{
    close();
    free(mAttributes);
    delete mCallbackData;
}

//static
@@ -2052,8 +2051,7 @@ void MediaPlayerService::AudioOutput::deleteRecycledTrack_l()

        mRecycledTrack.clear();
        close_l();
        delete mCallbackData;
        mCallbackData = NULL;
        mCallbackData.clear();
    }
}

@@ -2174,7 +2172,7 @@ status_t MediaPlayerService::AudioOutput::open(
    }

    sp<AudioTrack> t;
    CallbackData *newcbd = NULL;
    sp<CallbackData> newcbd;

    // We don't attempt to create a new track if we are recycling an
    // offloaded track. But, if we are recycling a non-offloaded or we
@@ -2184,8 +2182,8 @@ status_t MediaPlayerService::AudioOutput::open(
    if (!(reuse && bothOffloaded)) {
        ALOGV("creating new AudioTrack");

        if (mCallback != NULL) {
            newcbd = new CallbackData(this);
        if (mCallback != nullptr) {
            newcbd = sp<CallbackData>::make(wp<AudioOutput>::fromExisting(this));
            t = new AudioTrack(
                    mStreamType,
                    sampleRate,
@@ -2193,7 +2191,6 @@ status_t MediaPlayerService::AudioOutput::open(
                    channelMask,
                    frameCount,
                    flags,
                    CallbackWrapper,
                    newcbd,
                    0,  // notification frames
                    mSessionId,
@@ -2237,8 +2234,7 @@ status_t MediaPlayerService::AudioOutput::open(
        t->setCallerName("media");
        if ((t == 0) || (t->initCheck() != NO_ERROR)) {
            ALOGE("Unable to create audio track");
            delete newcbd;
            // t goes out of scope, so reference count drops to zero
            // t, newcbd goes out of scope, so reference count drops to zero
            return NO_INIT;
        } else {
            // successful AudioTrack initialization implies a legacy stream type was generated
@@ -2272,7 +2268,6 @@ status_t MediaPlayerService::AudioOutput::open(
            if (mCallbackData != NULL) {
                mCallbackData->setOutput(this);
            }
            delete newcbd;
            return updateTrack();
        }
    }
@@ -2378,7 +2373,7 @@ void MediaPlayerService::AudioOutput::switchToNextOutput() {
            if (mCallbackData != NULL) {
                // two alternative approaches
#if 1
                CallbackData *callbackData = mCallbackData;
                sp<CallbackData> callbackData = mCallbackData;
                mLock.unlock();
                // proper acquisition sequence
                callbackData->lock();
@@ -2415,9 +2410,8 @@ void MediaPlayerService::AudioOutput::switchToNextOutput() {
            // for example, the next player could be prepared and seeked.
            //
            // Presuming it isn't advisable to force the track over.
             if (mNextOutput->mTrack == NULL) {
             if (mNextOutput->mTrack == nullptr) {
                ALOGD("Recycling track for gapless playback");
                delete mNextOutput->mCallbackData;
                mNextOutput->mCallbackData = mCallbackData;
                mNextOutput->mRecycledTrack = mTrack;
                mNextOutput->mSampleRateHz = mSampleRateHz;
@@ -2425,11 +2419,11 @@ void MediaPlayerService::AudioOutput::switchToNextOutput() {
                mNextOutput->mFlags = mFlags;
                mNextOutput->mFrameSize = mFrameSize;
                close_l();
                mCallbackData = NULL;  // destruction handled by mNextOutput
                mCallbackData.clear();
            } else {
                ALOGW("Ignoring gapless playback because next player has already started");
                // remove track in case resource needed for future players.
                if (mCallbackData != NULL) {
                if (mCallbackData != nullptr) {
                    mCallbackData->endTrackSwitch();  // release lock for callbacks before close.
                }
                close_l();
@@ -2656,29 +2650,16 @@ sp<VolumeShaper::State> MediaPlayerService::AudioOutput::getVolumeShaperState(in
    }
}

// static
void MediaPlayerService::AudioOutput::CallbackWrapper(
        int event, void *cookie, void *info) {
    //ALOGV("callbackwrapper");
    CallbackData *data = (CallbackData*)cookie;
    // lock to ensure we aren't caught in the middle of a track switch.
    data->lock();
    AudioOutput *me = data->getOutput();
    AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
    if (me == NULL) {
        // 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;
        }
        return;
size_t MediaPlayerService::AudioOutput::CallbackData::onMoreData(const AudioTrack::Buffer& buffer) {
    ALOGD("data callback");
    lock();
    sp<AudioOutput> me = getOutput();
    if (me == nullptr) {
        unlock();
        return 0;
    }

    switch(event) {
    case AudioTrack::EVENT_MORE_DATA: {
    size_t actualSize = (*me->mCallback)(
                me, buffer->raw, buffer->size, me->mCallbackCookie,
            me.get(), buffer.raw, buffer.size, me->mCallbackCookie,
            CB_EVENT_FILL_BUFFER);

    // Log when no data is returned from the callback.
@@ -2691,24 +2672,38 @@ void MediaPlayerService::AudioOutput::CallbackWrapper(
    // 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");
    unlock();
    return actualSize;
}

        buffer->size = actualSize;
        } break;

    case AudioTrack::EVENT_STREAM_END:
        // currently only occurs for offloaded callbacks
void MediaPlayerService::AudioOutput::CallbackData::onStreamEnd() {
    lock();
    sp<AudioOutput> me = getOutput();
    if (me == nullptr) {
        unlock();
        return;
    }
    ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
        (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
    (*me->mCallback)(me.get(), NULL /* buffer */, 0 /* size */,
            me->mCallbackCookie, CB_EVENT_STREAM_END);
        break;
    unlock();
}


    case AudioTrack::EVENT_NEW_IAUDIOTRACK :
void MediaPlayerService::AudioOutput::CallbackData::onNewIAudioTrack() {
    lock();
    sp<AudioOutput> me = getOutput();
    if (me == nullptr) {
        unlock();
        return;
    }
    ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
        (*me->mCallback)(me,  NULL /* buffer */, 0 /* size */,
    (*me->mCallback)(me.get(),  NULL /* buffer */, 0 /* size */,
            me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
        break;
    unlock();
}

    case AudioTrack::EVENT_UNDERRUN:
void MediaPlayerService::AudioOutput::CallbackData::onUnderrun() {
    // 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.
@@ -2719,13 +2714,7 @@ void MediaPlayerService::AudioOutput::CallbackWrapper(
    // The underrun event is sent once per track underrun; the condition is reset
    // when more data is sent to the AudioTrack.
    ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)");
        break;

    default:
        ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
    }

    data->unlock();
}

audio_session_t MediaPlayerService::AudioOutput::getSessionId() const
+13 −7
Original line number Diff line number Diff line
@@ -30,9 +30,11 @@
#include <media/AidlConversion.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
#include <media/MediaPlayerInterface.h>
#include <media/Metadata.h>
#include <media/stagefright/foundation/ABase.h>
#include <mediautils/Synchronization.h>
#include <android/content/AttributionSourceState.h>

#include <system/audio.h>
@@ -41,7 +43,6 @@ namespace android {

using content::AttributionSourceState;

class AudioTrack;
struct AVSyncSettings;
class DeathNotifier;
class IDataSource;
@@ -161,7 +162,7 @@ class MediaPlayerService : public BnMediaPlayerService
        sp<AudioOutput>         mNextOutput;
        AudioCallback           mCallback;
        void *                  mCallbackCookie;
        CallbackData *          mCallbackData;
        sp<CallbackData>        mCallbackData;
        audio_stream_type_t     mStreamType;
        audio_attributes_t *    mAttributes;
        float                   mLeftVolume;
@@ -189,15 +190,15 @@ class MediaPlayerService : public BnMediaPlayerService
        // CallbackData is what is passed to the AudioTrack as the "user" data.
        // We need to be able to target this to a different Output on the fly,
        // so we can't use the Output itself for this.
        class CallbackData {
        class CallbackData : public AudioTrack::IAudioTrackCallback {
            friend AudioOutput;
        public:
            explicit CallbackData(AudioOutput *cookie) {
            explicit CallbackData(const wp<AudioOutput>& cookie) {
                mData = cookie;
                mSwitching = false;
            }
            AudioOutput *   getOutput() const { return mData; }
            void            setOutput(AudioOutput* newcookie) { mData = newcookie; }
            sp<AudioOutput> getOutput() const { return mData.load().promote(); }
            void            setOutput(const wp<AudioOutput>& newcookie) { mData.store(newcookie); }
            // lock/unlock are used by the callback before accessing the payload of this object
            void            lock() const { mLock.lock(); }
            void            unlock() const { mLock.unlock(); }
@@ -220,8 +221,13 @@ class MediaPlayerService : public BnMediaPlayerService
                }
                mSwitching = false;
            }
        protected:
            size_t onMoreData(const AudioTrack::Buffer& buffer) override;
            void onUnderrun() override;
            void onStreamEnd() override;
            void onNewIAudioTrack() override;
        private:
            AudioOutput *   mData;
            mediautils::atomic_wp<AudioOutput> mData;
            mutable Mutex   mLock; // a recursive mutex might make this unnecessary.
            bool            mSwitching;
            DISALLOW_EVIL_CONSTRUCTORS(CallbackData);