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

Commit 4dc66dc2 authored by Atneya Nair's avatar Atneya Nair
Browse files

Implement AudioTrackCallback in MediaPlayerService

Modify MediaPlayerService to implement AudioTrackCallback rather
than passing a static function callback.

Test: YT music offline playback successful. Data callbacks logged.
Test: MediaPlayerTest
Change-Id: I8864125025011f04b7114f3c5ffec560c11ac5bd
parent 902666b8
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);