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 Original line Diff line number Diff line
@@ -146,6 +146,7 @@ cc_library {
        "spatializer-aidl-cpp",
        "spatializer-aidl-cpp",
        "framework-permission-aidl-cpp",
        "framework-permission-aidl-cpp",
        "libbinder",
        "libbinder",
        "libmediametrics",
    ],
    ],


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


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


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


    export_header_lib_headers: [
        "libmediautils_headers",
    ],

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


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


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


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


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


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


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


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

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


    // Log when no data is returned from the callback.
    // 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.
    // 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->size > 0, "callbackwrapper: empty buffer returned");
    unlock();
    return actualSize;
}


        buffer->size = actualSize;
void MediaPlayerService::AudioOutput::CallbackData::onStreamEnd() {
        } break;
    lock();

    sp<AudioOutput> me = getOutput();
    case AudioTrack::EVENT_STREAM_END:
    if (me == nullptr) {
        // currently only occurs for offloaded callbacks
        unlock();
        return;
    }
    ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
    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);
            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");
    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);
            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
    // This occurs when there is no data available, typically
    // when there is a failure to supply data to the AudioTrack.  It can also
    // 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.
    // 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
    // The underrun event is sent once per track underrun; the condition is reset
    // when more data is sent to the AudioTrack.
    // when more data is sent to the AudioTrack.
    ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)");
    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
audio_session_t MediaPlayerService::AudioOutput::getSessionId() const
+13 −7
Original line number Original line Diff line number Diff line
@@ -30,9 +30,11 @@
#include <media/AidlConversion.h>
#include <media/AidlConversion.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
#include <media/MediaPlayerInterface.h>
#include <media/MediaPlayerInterface.h>
#include <media/Metadata.h>
#include <media/Metadata.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/ABase.h>
#include <mediautils/Synchronization.h>
#include <android/content/AttributionSourceState.h>
#include <android/content/AttributionSourceState.h>


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


using content::AttributionSourceState;
using content::AttributionSourceState;


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