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

Commit 7d789191 authored by Pavan Chikkala's avatar Pavan Chikkala Committed by Ethan Chen
Browse files

frameworks/av: port fixes in LPA and Tunnel mode playback

No History was maintained during porting. Updating the
Description and CR's of all the fixes.
LPA Mode:
LPAPlayer synchronization fixes.
Fixes for seek, pause/resume, EOS handling
Fixes for synchronization b/w the decoder thread, TimedEventQueue and player thread.
Convert mono to stereo for LPA clips - CRs-Fixed: 421639
Add support to change clip duration to enable LPA
Set correct device while creating effects - CRs-Fixed: 496866
Fix the LPA-AudioEffects dead lock issue - CRs-Fixed: 477511
fix volume not updated in pause state of direct track - CRs-Fixed: 490592
Tunnel Mode:
Use tunnel player only for music stream
Exceptions in using Tunnel mode decode - CRs-Fixed: 432080
Enable Tunnel Decode for select formats - CRs-Fixed:437651
Use software decoder for ADTS content. - CRs-fixed: 431096
Skip tunnel mode for playback through AudioCache - CRs-Fixed: 437539
Fix stability crash on tunnel playback. - CRs-Fixed: 498386
support multiple tunnel instances - CRs-Fixed: 483603
Fix ANR repeated next with tunnel clips on BT/AOA - CRs-Fixed: 482966
Update condition to ignore a seek request - CRs-Fixed: 461908
Return seek position until seek has been processed - CRs-Fixed: 454825
TunnelPlayer performance tweaks for audio video playback - CRs-Fixed: 444041
Stability fixes for Tunnel Player (part 2) - CRs-Fixed: 449122
Adjustment for TunnelPlayer buffer size - CRs-Fixed: 447274, 442365
Remove unnecessary code from TunnelPlayer - CRs-Fixed: 442365
update condition to send SEEK_COMPLETE - CRs-Fixed: 441411
Stop extractor source after start in TunnelPlayer - CRs-Fixed: 440239
Handling of EOS, and triggering EOS was wrong in TunnelPlayer.
EOS should not be posted till seek is complete
Disable tunnel mode playback for streaming use cases to avoid jittery playback
CRs-Fixed: 433346 432233 429868
APIs for returning correct timestamps were implemented
Check whether sink is open before flushing or closing it.
Check for mIsAudioRouted is good to know if we are closing it
Seekbar freezes after seek and pause
Check pause status before writing.
Changes Cherry picked from Iea150f8d75aa9aa6d14da078695e920a3742dd81

Change-Id: I8b968ddad235f6e1a36404f0c9c6eda7cae41419
parent 8c6297e4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ public:
        virtual ssize_t     channelCount() const = 0;
        virtual ssize_t     frameSize() const = 0;
        virtual uint32_t    latency() const = 0;
        virtual audio_stream_type_t    streamType() const {return AUDIO_STREAM_DEFAULT;}
        virtual float       msecsPerFrame() const = 0;
        virtual status_t    getPosition(uint32_t *position) const = 0;
        virtual status_t    getTimestamp(AudioTimestamp &ts) const = 0;
+8 −107
Original line number Diff line number Diff line
@@ -21,18 +21,12 @@
#define LPA_PLAYER_H_

#include "AudioPlayer.h"
#include <media/IAudioFlinger.h>
#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Vector.h>
#include <fcntl.h>
#include <pthread.h>
#include <binder/IServiceManager.h>
#include <linux/unistd.h>
#include <include/TimedEventQueue.h>
#include <binder/BinderService.h>
#include <binder/MemoryDealer.h>
#include <powermanager/IPowerManager.h>

// Pause timeout = 3sec
#define LPA_PAUSE_TIMEOUT_USEC 3000000
@@ -80,7 +74,7 @@ public:
    virtual bool isSeeking();
    virtual bool reachedEOS(status_t *finalStatus);

    static int objectsAlive;
    static int mObjectsAlive;
private:
    int64_t mPositionTimeMediaUs;
    int64_t mPositionTimeRealUs;
@@ -88,7 +82,6 @@ private:
    bool mIsAudioRouted;
    bool mStarted;
    bool mPaused;
    bool mA2DPEnabled;
    int32_t mChannelMask;
    int32_t mNumOutputChannels;
    int32_t mNumInputChannels;
@@ -99,122 +92,36 @@ private:
    int64_t mTimePlayed;
    int64_t mNumFramesPlayed;
    int64_t mNumFramesPlayedSysTimeUs;
    int64_t mNumA2DPBytesPlayed;

    void clearPowerManager();

    class PMDeathRecipient : public IBinder::DeathRecipient {
        public:
                        PMDeathRecipient(void *obj){parentClass = (LPAPlayer *)obj;}
            virtual     ~PMDeathRecipient() {}

            // IBinder::DeathRecipient
            virtual     void        binderDied(const wp<IBinder>& who);

        private:
                        LPAPlayer *parentClass;
                        PMDeathRecipient(const PMDeathRecipient&);
                        PMDeathRecipient& operator = (const PMDeathRecipient&);

        friend class LPAPlayer;
    };

    friend class PMDeathRecipient;

    void        acquireWakeLock();
    void        releaseWakeLock();

    sp<IPowerManager>       mPowerManager;
    sp<IBinder>             mWakeLockToken;
    sp<PMDeathRecipient>    mDeathRecipient;

    pthread_t decoderThread;

    pthread_t A2DPNotificationThread;
    pthread_t mDecoderThread;

    //Kill Thread boolean
    bool killDecoderThread;



    bool killA2DPNotificationThread;
    bool mKillDecoderThread;

    //Thread alive boolean
    bool decoderThreadAlive;


    bool a2dpNotificationThreadAlive;
    bool mDecoderThreadAlive;

    //Declare the condition Variables and Mutex

    pthread_mutex_t decoder_mutex;

    pthread_mutex_t audio_sink_setup_mutex;

    pthread_mutex_t a2dp_notification_mutex;



    pthread_cond_t decoder_cv;


    pthread_cond_t a2dp_notification_cv;
    pthread_mutex_t mDecoderMutex;

    pthread_cond_t mDecoderCv;

    // make sure Decoder thread has exited
    void requestAndWaitForDecoderThreadExit();


    // make sure the Effects thread also exited
    void requestAndWaitForA2DPNotificationThreadExit();

    static void *decoderThreadWrapper(void *me);
    void decoderThreadEntry();
    static void *A2DPNotificationThreadWrapper(void *me);
    void A2DPNotificationThreadEntry();

    void createThreads();

    volatile bool mIsA2DPEnabled;

    //Structure to recieve the BT notification from the flinger.
    class AudioFlingerLPAdecodeClient: public IBinder::DeathRecipient, public BnAudioFlingerClient {
    public:
        AudioFlingerLPAdecodeClient(void *obj);

        LPAPlayer *pBaseClass;
        // DeathRecipient
        virtual void binderDied(const wp<IBinder>& who);

        // IAudioFlingerClient

        // indicate a change in the configuration of an output or input: keeps the cached
        // values for output/input parameters upto date in client process
        virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2);

        friend class LPAPlayer;
    };

    sp<IAudioFlinger> mAudioFlinger;

    // helper function to obtain AudioFlinger service handle
    void getAudioFlinger();

    void handleA2DPSwitch();
    void onPauseTimeOut();

    int64_t getMediaTimeUs_l();
    bool seekTooClose(int64_t);

    sp<AudioFlingerLPAdecodeClient> AudioFlingerClient;
    friend class AudioFlingerLPAdecodeClient;
    Mutex AudioFlingerLock;
    sp<MediaSource> mSource;

    MediaBuffer *mInputBuffer;

    Mutex mLock;
    Mutex mResumeLock;

    bool mSeeking;
    bool mReachedEOS;
@@ -241,14 +148,7 @@ private:
        void *data, size_t size, void *me,
        MediaPlayerBase::AudioSink::cb_event_t event);

    enum A2DPState {
        A2DP_ENABLED,
        A2DP_DISABLED,
        A2DP_CONNECT,
        A2DP_DISCONNECT
    };

    int64_t getTimeStamp(A2DPState state);
    int64_t getTimeStamp();

    size_t fillBuffer(void *data, size_t size);

@@ -261,6 +161,7 @@ private:
        MediaPlayerBase::AudioSink *audioSink,
        void *buffer, size_t size, void *cookie);
    size_t AudioCallback(void *cookie, void *data, size_t size);
    int64_t getMediaTimeUs_l();

    void convertMonoToStereo(int16_t *data, size_t size);

+4 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
 * Not a Contribution
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
@@ -174,6 +177,7 @@ enum {
    // Similar to MediaFormat.KEY_IS_FORCED_SUBTITLE but pertains to av tracks as well.
    kKeyTrackIsForced     = 'frcd', // bool (int32_t)

    kKeyTunnelException   = 'Ntnl', // not tunnel
    // Indicate if it is OK to hold on to the MediaBuffer and not
    // release it immediately
    kKeyCanDeferRelease   = 'drel', // bool (int32_t)
+8 −87
Original line number Diff line number Diff line
@@ -21,18 +21,12 @@
#define TUNNEL_PLAYER_H_

#include "AudioPlayer.h"
#include <media/IAudioFlinger.h>
#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Vector.h>
#include <fcntl.h>
#include <pthread.h>
#include <binder/IServiceManager.h>
#include <linux/unistd.h>
#include <include/TimedEventQueue.h>
#include <binder/BinderService.h>
#include <binder/MemoryDealer.h>
#include <powermanager/IPowerManager.h>

// Pause timeout = 3sec
#define TUNNEL_PAUSE_TIMEOUT_USEC 3000000
@@ -75,6 +69,7 @@ public:


    static int mTunnelObjectsAlive;
    static const int getTunnelObjectsAliveMax();
private:
    int64_t mPositionTimeMediaUs;
    int64_t mPositionTimeRealUs;
@@ -82,7 +77,6 @@ private:
    bool mIsAudioRouted;
    bool mStarted;
    bool mPaused;
    bool mA2DPEnabled;
    int32_t mChannelMask;
    int32_t numChannels;
    int32_t mSampleRate;
@@ -92,49 +86,22 @@ private:
    int64_t mNumFramesPlayedSysTimeUs;
    audio_format_t mFormat;
    bool mHasVideo;
    void clearPowerManager();

    class PMDeathRecipient : public IBinder::DeathRecipient {
        public:
                        PMDeathRecipient(void *obj){parentClass = (TunnelPlayer *)obj;}
            virtual     ~PMDeathRecipient() {}

            // IBinder::DeathRecipient
            virtual     void        binderDied(const wp<IBinder>& who);

        private:
                        TunnelPlayer *parentClass;
                        PMDeathRecipient(const PMDeathRecipient&);
                        PMDeathRecipient& operator = (const PMDeathRecipient&);

        friend class TunnelPlayer;
    };

    friend class PMDeathRecipient;

    void        acquireWakeLock();
    void        releaseWakeLock();

    sp<IPowerManager>       mPowerManager;
    sp<IBinder>             mWakeLockToken;
    sp<PMDeathRecipient>    mDeathRecipient;

    pthread_t extractorThread;
    pthread_t mExtractorThread;

    //Kill Thread boolean
    bool killExtractorThread;
    bool mKillExtractorThread;

    //Thread alive boolean
    bool extractorThreadAlive;

    bool mExtractorThreadAlive;

    //Declare the condition Variables and Mutex

    Condition mExtractorCV;
    Mutex mExtractorMutex;
    Condition mExtractorCv;


    // make sure Decoder thread has exited
    void requestAndWaitForExtractorThreadExit();
    void requestAndWaitForExtractorThreadExit_l();


    static void *extractorThreadWrapper(void *me);
@@ -142,40 +109,12 @@ private:

    void createThreads();

    volatile bool mIsA2DPEnabled;

    //Structure to recieve the BT notification from the flinger.
    class AudioFlingerTunneldecodeClient: public IBinder::DeathRecipient, public BnAudioFlingerClient {
    public:
        AudioFlingerTunneldecodeClient(void *obj);

        TunnelPlayer *pBaseClass;
        // DeathRecipient
        virtual void binderDied(const wp<IBinder>& who);

        // IAudioFlingerClient

        // indicate a change in the configuration of an output or input: keeps the cached
        // values for output/input parameters upto date in client process
        virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2);

        friend class TunnelPlayer;
    };

    sp<IAudioFlinger> mAudioFlinger;

    // helper function to obtain AudioFlinger service handle
    void getAudioFlinger();
    void onPauseTimeOut();

    sp<AudioFlingerTunneldecodeClient> mAudioFlingerClient;
    friend class AudioFlingerTunneldecodeClient;
    Mutex mAudioFlingerLock;
    sp<MediaSource> mSource;

    MediaBuffer *mInputBuffer;

    Mutex pmLock;
    Mutex mLock;

    bool mSeeking;
@@ -194,39 +133,21 @@ private:
    sp<TimedEventQueue::Event>  mPauseEvent;
    bool                        mPauseEventPending;

    typedef enum {
      NCREATED = -1,
      INITIALIZED,
      RUNNING,
      SLEEPING,
      EXITING,
    } ThreadState;

    sp<MediaPlayerBase::AudioSink> mAudioSink;
    AwesomePlayer *mObserver;
    ThreadState mThreadState;
    bool mStopSinkPending;

    static size_t AudioSinkCallback(
        MediaPlayerBase::AudioSink *audioSink,
        void *data, size_t size, void *me,
        MediaPlayerBase::AudioSink::cb_event_t event);

    enum A2DPState {
        A2DP_ENABLED,
        A2DP_DISABLED,
        A2DP_CONNECT,
        A2DP_DISCONNECT
    };

    void getPlayedTimeFromDSP_l(int64_t *timeStamp);
    void getOffsetRealTime_l(int64_t *offsetTime);

    size_t fillBuffer(void *data, size_t size);

    void reset();
    status_t schedPauseTimeOut();
    status_t stopAudioSink();
    bool seekTooClose(int64_t time_us);

    TunnelPlayer(const TunnelPlayer &);
    TunnelPlayer &operator=(const TunnelPlayer &);
+68 −16
Original line number Diff line number Diff line
@@ -405,9 +405,22 @@ status_t AwesomePlayer::setDataSource_l(
    return OK;
}

void AwesomePlayer::printFileName(int fd) {

    char symName[40] = {0};
    char fileName[256] = {0};

    snprintf(symName, sizeof(symName), "/proc/%d/fd/%d", getpid(), fd);

    if (readlink( symName, fileName, (sizeof(fileName) - 1)) != -1 ) {
        ALOGD("printFileName fd(%d) -> %s", fd, fileName);
    }
}

status_t AwesomePlayer::setDataSource(
        int fd, int64_t offset, int64_t length) {
    Mutex::Autolock autoLock(mLock);
    ALOGD("Before reset_l");
    
    reset_l();
    if (fd) {
@@ -1191,10 +1204,10 @@ void AwesomePlayer::createAudioPlayer_l()
            TunnelPlayer::mTunnelObjectsAlive = %d,\
            (mAudioPlayer == NULL) %d",
            mIsTunnelAudio, TunnelPlayer::mTunnelObjectsAlive,
            LPAPlayer::objectsAlive,(mAudioPlayer == NULL));
            LPAPlayer::mObjectsAlive,(mAudioPlayer == NULL));

    if(mIsTunnelAudio && (mAudioPlayer == NULL) &&
            (LPAPlayer::objectsAlive == 0) &&
            (LPAPlayer::mObjectsAlive == 0) &&
            (TunnelPlayer::mTunnelObjectsAlive == 0)) {
        ALOGD("Tunnel player created for  mime %s duration %lld\n",\
            mime, mDurationUs);
@@ -1232,21 +1245,28 @@ void AwesomePlayer::createAudioPlayer_l()
    property_get("lpa.min_duration",minUserDefDuration,"LPA_MIN_DURATION_USEC_DEFAULT");
    minDurationForLPA = atoi(minUserDefDuration);
    if(minDurationForLPA < LPA_MIN_DURATION_USEC_ALLOWED) {
        ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
        if(mAudioPlayer == NULL) {
            ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
            minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
        }
    }
    if((strcmp("true",lpaDecode) == 0) && (mAudioPlayer == NULL) &&
       (tunnelObjectsAlive==0) && (nchannels && (nchannels <= 2)))
#ifdef USE_TUNNEL_MODE
       (tunnelObjectsAlive < TunnelPlayer::getTunnelObjectsAliveMax()) &&
#endif
       (nchannels && (nchannels <= 2)))

    {
        ALOGE("LPAPlayer::getObjectsAlive() %d",LPAPlayer::objectsAlive);
        ALOGE("LPAPlayer::getObjectsAlive() %d",LPAPlayer::mObjectsAlive);
        if ( mDurationUs > minDurationForLPA
             && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC))
             && LPAPlayer::objectsAlive == 0 && mVideoSource == NULL) {
             && LPAPlayer::mObjectsAlive == 0 && mVideoSource == NULL) {
            ALOGE("LPAPlayer created, LPA MODE detected mime %s duration %lld", mime, mDurationUs);
            bool initCheck =  false;
            uint32_t flags = 0;
            mAudioPlayer = new LPAPlayer(mAudioSink, initCheck, this);
            if(!initCheck) {
                 ALOGE("deleting Tunnel Player - initCheck failed");
                 delete mAudioPlayer;
                 mAudioPlayer = NULL;
            }
@@ -1777,9 +1797,10 @@ status_t AwesomePlayer::initAudioDecoder() {
            mime, (TunnelPlayer::mTunnelObjectsAlive), mTunnelAliveAP);

    bool sys_prop_enabled = !strcmp("true",tunnelDecode) || atoi(tunnelDecode);
    ALOGD("maxPossible tunnels = %d", TunnelPlayer::getTunnelObjectsAliveMax());
    //widevine will fallback to software decoder
    if (sys_prop_enabled && (TunnelPlayer::mTunnelObjectsAlive == 0) &&
       (mTunnelAliveAP == 0) && (isADTS == 0) &&
    if (sys_prop_enabled && (TunnelPlayer::mTunnelObjectsAlive < TunnelPlayer::getTunnelObjectsAliveMax()) &&
       (mTunnelAliveAP < TunnelPlayer::getTunnelObjectsAliveMax()) && (isADTS == 0) &&
        mAudioSink->realtime() &&
        inSupportedTunnelFormats(mime)) {

@@ -1796,6 +1817,12 @@ status_t AwesomePlayer::initAudioDecoder() {
            ALOGI("Tunnel Mode Audio Enabled");
            mIsTunnelAudio = true;
        }
#ifdef NO_TUNNEL_MODE_FOR_MULTICHANNEL
        if (nchannels > 2 || nchannels <= 0) {
            ALOGD("Use tunnel mode only for mono and stereo channels");
            mIsTunnelAudio = false;
        }
#endif
    }
    else
       ALOGD("Normal Audio Playback");
@@ -1804,7 +1831,11 @@ status_t AwesomePlayer::initAudioDecoder() {
    checkTunnelExceptions();

    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW) ||
             (mIsTunnelAudio && (mTunnelAliveAP == 0))) {
             (mIsTunnelAudio
#ifdef USE_TUNNEL_MODE
             && (mTunnelAliveAP < TunnelPlayer::getTunnelObjectsAliveMax())
#endif
    )) {
        ALOGD("Set Audio Track as Audio Source");
        if(mIsTunnelAudio) {
            mTunnelAliveAP++;
@@ -1840,7 +1871,7 @@ status_t AwesomePlayer::initAudioDecoder() {
        }
        if ( mDurationUs > minDurationForLPA
             && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC))
             && LPAPlayer::objectsAlive == 0 && mVideoSource == NULL && (strcmp("true",lpaDecode) == 0)
             && LPAPlayer::mObjectsAlive == 0 && mVideoSource == NULL && (strcmp("true",lpaDecode) == 0)
             && (nchannels && (nchannels <= 2)) ) {
            char nonOMXDecoder[128];
            if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
@@ -3614,6 +3645,13 @@ bool AwesomePlayer::inSupportedTunnelFormats(const char * mime) {
    const char * tunnelFormats [ ] = {
        MEDIA_MIMETYPE_AUDIO_MPEG,
        MEDIA_MIMETYPE_AUDIO_AAC,
    #ifdef TUNNEL_MODE_SUPPORTS_AMRWB
        MEDIA_MIMETYPE_AUDIO_AMR_WB,
    #ifdef ENABLE_QC_AV_ENHANCEMENTS
        MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS
    #endif
    #endif

    };

    if (!mime) {
@@ -3643,18 +3681,32 @@ void AwesomePlayer::checkTunnelExceptions()
        mIsTunnelAudio = false;
        return;
    }
#if 0
+    /* exception 2: use tunnel player only for AUDIO_STREAM_MUSIC */

    CHECK(mAudioTrack != NULL);

    /*
     * exception 2: No AAC-LD content,
     * hint given by setting kKeyTunnelException in the track meta
     */
    int32_t exception = 0;
    if (mAudioTrack->getFormat()->findInt32(kKeyTunnelException, &exception) &&
        exception) {
        ALOGV("kKeyTunnelException set, disable tunnel mode");
        mIsTunnelAudio = false;
        return;
    }

    /* exception 3: use tunnel player only for AUDIO_STREAM_MUSIC */

    if (mAudioSink->streamType() != AUDIO_STREAM_MUSIC ) {
        ALOGD("Use tunnel player only for AUDIO_STREAM_MUSIC");
        mIsTunnelAudio = false;
        return;
    }
#endif
    /* below exceptions are only for av content */
    if (mVideoTrack == NULL) return;

    /* exception 2: No avi having video + mp3 */
    /* exception 4: No avi having video + mp3 */
    if (mExtractor == NULL) return;

    sp<MetaData> metaData = mExtractor->getMetaData();
Loading