diff options
| -rw-r--r-- | include/media/stagefright/foundation/ADebug.h | 10 | ||||
| -rw-r--r-- | media/libmedia/AudioSystem.cpp | 19 | ||||
| -rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 168 | ||||
| -rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.h | 32 | ||||
| -rw-r--r-- | media/libstagefright/ACodec.cpp | 16 | ||||
| -rw-r--r-- | media/libstagefright/foundation/ADebug.cpp | 38 | ||||
| -rw-r--r-- | media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp | 15 | ||||
| -rw-r--r-- | media/libstagefright/tests/Utils_test.cpp | 22 | ||||
| -rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 28 | ||||
| -rw-r--r-- | services/audioflinger/AudioFlinger.h | 3 | ||||
| -rw-r--r-- | services/audioflinger/Threads.cpp | 27 | ||||
| -rw-r--r-- | services/audioflinger/Threads.h | 20 | ||||
| -rwxr-xr-x | services/audiopolicy/common/include/policy.h | 10 | ||||
| -rw-r--r-- | services/audiopolicy/managerdefault/AudioPolicyManager.cpp | 4 | 
14 files changed, 288 insertions, 124 deletions
diff --git a/include/media/stagefright/foundation/ADebug.h b/include/media/stagefright/foundation/ADebug.h index 24df85a..65f415a 100644 --- a/include/media/stagefright/foundation/ADebug.h +++ b/include/media/stagefright/foundation/ADebug.h @@ -117,7 +117,7 @@ struct ADebug {      }; -    // parse the property or string to get the debug level for a component name +    // parse the property or string to get a long-type level for a component name      // string format is:      // <level>[:<glob>][,<level>[:<glob>]...]      // - <level> is 0-5 corresponding to ADebug::Level @@ -125,10 +125,14 @@ struct ADebug {      //   matches all components      // - string is read left-to-right, and the last matching level is returned, or      //   the def if no terms matched +    static long GetLevelFromSettingsString( +            const char *name, const char *value, long def); +    static long GetLevelFromProperty( +            const char *name, const char *value, long def); + +    // same for ADebug::Level - performs clamping to valid debug ranges      static Level GetDebugLevelFromProperty(              const char *name, const char *propertyName, Level def = kDebugNone); -    static Level GetDebugLevelFromString( -            const char *name, const char *value, Level def = kDebugNone);      // remove redundant segments of a codec name, and return a newly allocated      // string suitable for debugging diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index f13bcf3..3bfb09a 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -476,11 +476,13 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even          switch (event) {          case AUDIO_OUTPUT_OPENED:          case AUDIO_INPUT_OPENED: { -            if (getIoDescriptor(ioDesc->mIoHandle) != 0) { -                ALOGV("ioConfigChanged() opening already existing output! %d", ioDesc->mIoHandle); -                break; +            sp<AudioIoDescriptor> oldDesc = getIoDescriptor(ioDesc->mIoHandle); +            if (oldDesc == 0) { +                mIoDescriptors.add(ioDesc->mIoHandle, ioDesc); +            } else { +                deviceId = oldDesc->getDeviceId(); +                mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);              } -            mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);              if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {                  deviceId = ioDesc->getDeviceId(); @@ -1074,7 +1076,14 @@ status_t AudioSystem::addAudioDeviceCallback(      if (afc == 0) {          return NO_INIT;      } -    return afc->addAudioDeviceCallback(callback, audioIo); +    status_t status = afc->addAudioDeviceCallback(callback, audioIo); +    if (status == NO_ERROR) { +        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); +        if (af != 0) { +            af->registerClient(afc); +        } +    } +    return status;  }  status_t AudioSystem::removeAudioDeviceCallback( diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index ae869d6..0ecfb1e 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1335,21 +1335,23 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid,        mCallbackCookie(NULL),        mCallbackData(NULL),        mBytesWritten(0), +      mStreamType(AUDIO_STREAM_MUSIC), +      mAttributes(attr), +      mLeftVolume(1.0), +      mRightVolume(1.0), +      mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT), +      mSampleRateHz(0), +      mMsecsPerFrame(0), +      mFrameSize(0),        mSessionId(sessionId),        mUid(uid),        mPid(pid), -      mFlags(AUDIO_OUTPUT_FLAG_NONE) { +      mSendLevel(0.0), +      mAuxEffectId(0), +      mFlags(AUDIO_OUTPUT_FLAG_NONE) +{      ALOGV("AudioOutput(%d)", sessionId); -    mStreamType = AUDIO_STREAM_MUSIC; -    mLeftVolume = 1.0; -    mRightVolume = 1.0; -    mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT; -    mSampleRateHz = 0; -    mMsecsPerFrame = 0; -    mAuxEffectId = 0; -    mSendLevel = 0.0;      setMinBufferCount(); -    mAttributes = attr;  }  MediaPlayerService::AudioOutput::~AudioOutput() @@ -1358,6 +1360,7 @@ MediaPlayerService::AudioOutput::~AudioOutput()      delete mCallbackData;  } +//static  void MediaPlayerService::AudioOutput::setMinBufferCount()  {      char value[PROPERTY_VALUE_MAX]; @@ -1367,92 +1370,105 @@ void MediaPlayerService::AudioOutput::setMinBufferCount()      }  } +// static  bool MediaPlayerService::AudioOutput::isOnEmulator()  { -    setMinBufferCount(); +    setMinBufferCount(); // benign race wrt other threads      return mIsOnEmulator;  } +// static  int MediaPlayerService::AudioOutput::getMinBufferCount()  { -    setMinBufferCount(); +    setMinBufferCount(); // benign race wrt other threads      return mMinBufferCount;  }  ssize_t MediaPlayerService::AudioOutput::bufferSize() const  { +    Mutex::Autolock lock(mLock);      if (mTrack == 0) return NO_INIT; -    return mTrack->frameCount() * frameSize(); +    return mTrack->frameCount() * mFrameSize;  }  ssize_t MediaPlayerService::AudioOutput::frameCount() const  { +    Mutex::Autolock lock(mLock);      if (mTrack == 0) return NO_INIT;      return mTrack->frameCount();  }  ssize_t MediaPlayerService::AudioOutput::channelCount() const  { +    Mutex::Autolock lock(mLock);      if (mTrack == 0) return NO_INIT;      return mTrack->channelCount();  }  ssize_t MediaPlayerService::AudioOutput::frameSize() const  { +    Mutex::Autolock lock(mLock);      if (mTrack == 0) return NO_INIT; -    return mTrack->frameSize(); +    return mFrameSize;  }  uint32_t MediaPlayerService::AudioOutput::latency () const  { +    Mutex::Autolock lock(mLock);      if (mTrack == 0) return 0;      return mTrack->latency();  }  float MediaPlayerService::AudioOutput::msecsPerFrame() const  { +    Mutex::Autolock lock(mLock);      return mMsecsPerFrame;  }  status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position) const  { +    Mutex::Autolock lock(mLock);      if (mTrack == 0) return NO_INIT;      return mTrack->getPosition(position);  }  status_t MediaPlayerService::AudioOutput::getTimestamp(AudioTimestamp &ts) const  { +    Mutex::Autolock lock(mLock);      if (mTrack == 0) return NO_INIT;      return mTrack->getTimestamp(ts);  }  status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const  { +    Mutex::Autolock lock(mLock);      if (mTrack == 0) return NO_INIT; -    *frameswritten = mBytesWritten / frameSize(); +    *frameswritten = mBytesWritten / mFrameSize;      return OK;  }  status_t MediaPlayerService::AudioOutput::setParameters(const String8& keyValuePairs)  { +    Mutex::Autolock lock(mLock);      if (mTrack == 0) return NO_INIT;      return mTrack->setParameters(keyValuePairs);  }  String8  MediaPlayerService::AudioOutput::getParameters(const String8& keys)  { +    Mutex::Autolock lock(mLock);      if (mTrack == 0) return String8::empty();      return mTrack->getParameters(keys);  }  void MediaPlayerService::AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) { +    Mutex::Autolock lock(mLock);      mAttributes = attributes;  } -void MediaPlayerService::AudioOutput::deleteRecycledTrack() +void MediaPlayerService::AudioOutput::deleteRecycledTrack_l()  { -    ALOGV("deleteRecycledTrack"); - +    ALOGV("deleteRecycledTrack_l");      if (mRecycledTrack != 0) {          if (mCallbackData != NULL) { @@ -1470,12 +1486,17 @@ void MediaPlayerService::AudioOutput::deleteRecycledTrack()          // AudioFlinger to drain the track.          mRecycledTrack.clear(); +        close_l();          delete mCallbackData;          mCallbackData = NULL; -        close();      }  } +void MediaPlayerService::AudioOutput::close_l() +{ +    mTrack.clear(); +} +  status_t MediaPlayerService::AudioOutput::open(          uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,          audio_format_t format, int bufferCount, @@ -1535,6 +1556,7 @@ status_t MediaPlayerService::AudioOutput::open(          }      } +    Mutex::Autolock lock(mLock);      mCallback = cb;      mCallbackCookie = cookie; @@ -1577,7 +1599,7 @@ status_t MediaPlayerService::AudioOutput::open(      // we must close the previous output before opening a new one      if (bothOffloaded && !reuse) {          ALOGV("both offloaded and not recycling"); -        deleteRecycledTrack(); +        deleteRecycledTrack_l();      }      sp<AudioTrack> t; @@ -1655,7 +1677,7 @@ status_t MediaPlayerService::AudioOutput::open(          if (reuse) {              ALOGV("chaining to next output and recycling track"); -            close(); +            close_l();              mTrack = mRecycledTrack;              mRecycledTrack.clear();              if (mCallbackData != NULL) { @@ -1669,7 +1691,7 @@ status_t MediaPlayerService::AudioOutput::open(      // we're not going to reuse the track, unblock and flush it      // this was done earlier if both tracks are offloaded      if (!bothOffloaded) { -        deleteRecycledTrack(); +        deleteRecycledTrack_l();      }      CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL))); @@ -1681,9 +1703,10 @@ status_t MediaPlayerService::AudioOutput::open(      mSampleRateHz = sampleRate;      mFlags = t->getFlags(); // we suggest the flags above, but new AudioTrack() may not grant it.      mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate); +    mFrameSize = t->frameSize();      uint32_t pos;      if (t->getPosition(&pos) == OK) { -        mBytesWritten = uint64_t(pos) * t->frameSize(); +        mBytesWritten = uint64_t(pos) * mFrameSize;      }      mTrack = t; @@ -1704,6 +1727,7 @@ status_t MediaPlayerService::AudioOutput::open(  status_t MediaPlayerService::AudioOutput::start()  {      ALOGV("start"); +    Mutex::Autolock lock(mLock);      if (mCallbackData != NULL) {          mCallbackData->endTrackSwitch();      } @@ -1716,30 +1740,88 @@ status_t MediaPlayerService::AudioOutput::start()  }  void MediaPlayerService::AudioOutput::setNextOutput(const sp<AudioOutput>& nextOutput) { +    Mutex::Autolock lock(mLock);      mNextOutput = nextOutput;  } -  void MediaPlayerService::AudioOutput::switchToNextOutput() {      ALOGV("switchToNextOutput"); -    if (mNextOutput != NULL) { -        if (mCallbackData != NULL) { -            mCallbackData->beginTrackSwitch(); + +    // Try to acquire the callback lock before moving track (without incurring deadlock). +    const unsigned kMaxSwitchTries = 100; +    Mutex::Autolock lock(mLock); +    for (unsigned tries = 0;;) { +        if (mTrack == 0) { +            return;          } -        delete mNextOutput->mCallbackData; -        mNextOutput->mCallbackData = mCallbackData; -        mCallbackData = NULL; -        mNextOutput->mRecycledTrack = mTrack; -        mTrack.clear(); -        mNextOutput->mSampleRateHz = mSampleRateHz; -        mNextOutput->mMsecsPerFrame = mMsecsPerFrame; -        mNextOutput->mBytesWritten = mBytesWritten; -        mNextOutput->mFlags = mFlags; +        if (mNextOutput != NULL && mNextOutput != this) { +            if (mCallbackData != NULL) { +                // two alternative approaches +#if 1 +                CallbackData *callbackData = mCallbackData; +                mLock.unlock(); +                // proper acquisition sequence +                callbackData->lock(); +                mLock.lock(); +                // Caution: it is unlikely that someone deleted our callback or changed our target +                if (callbackData != mCallbackData || mNextOutput == NULL || mNextOutput == this) { +                    // fatal if we are starved out. +                    LOG_ALWAYS_FATAL_IF(++tries > kMaxSwitchTries, +                            "switchToNextOutput() cannot obtain correct lock sequence"); +                    callbackData->unlock(); +                    continue; +                } +                callbackData->mSwitching = true; // begin track switch +#else +                // tryBeginTrackSwitch() returns false if the callback has the lock. +                if (!mCallbackData->tryBeginTrackSwitch()) { +                    // fatal if we are starved out. +                    LOG_ALWAYS_FATAL_IF(++tries > kMaxSwitchTries, +                            "switchToNextOutput() cannot obtain callback lock"); +                    mLock.unlock(); +                    usleep(5 * 1000 /* usec */); // allow callback to use AudioOutput +                    mLock.lock(); +                    continue; +                } +#endif +            } + +            Mutex::Autolock nextLock(mNextOutput->mLock); + +            // If the next output track is not NULL, then it has been +            // opened already for playback. +            // This is possible even without the next player being started, +            // for example, the next player could be prepared and seeked. +            // +            // Presuming it isn't advisable to force the track over. +             if (mNextOutput->mTrack == NULL) { +                ALOGD("Recycling track for gapless playback"); +                delete mNextOutput->mCallbackData; +                mNextOutput->mCallbackData = mCallbackData; +                mNextOutput->mRecycledTrack = mTrack; +                mNextOutput->mSampleRateHz = mSampleRateHz; +                mNextOutput->mMsecsPerFrame = mMsecsPerFrame; +                mNextOutput->mBytesWritten = mBytesWritten; +                mNextOutput->mFlags = mFlags; +                mNextOutput->mFrameSize = mFrameSize; +                close_l(); +                mCallbackData = NULL;  // destruction handled by mNextOutput +            } else { +                ALOGW("Ignoring gapless playback because next player has already started"); +                // remove track in case resource needed for future players. +                if (mCallbackData != NULL) { +                    mCallbackData->endTrackSwitch();  // release lock for callbacks before close. +                } +                close_l(); +            } +        } +        break;      }  }  ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size, bool blocking)  { +    Mutex::Autolock lock(mLock);      LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");      //ALOGV("write(%p, %u)", buffer, size); @@ -1756,6 +1838,7 @@ ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size,  void MediaPlayerService::AudioOutput::stop()  {      ALOGV("stop"); +    Mutex::Autolock lock(mLock);      mBytesWritten = 0;      if (mTrack != 0) mTrack->stop();  } @@ -1763,6 +1846,7 @@ void MediaPlayerService::AudioOutput::stop()  void MediaPlayerService::AudioOutput::flush()  {      ALOGV("flush"); +    Mutex::Autolock lock(mLock);      mBytesWritten = 0;      if (mTrack != 0) mTrack->flush();  } @@ -1770,18 +1854,21 @@ void MediaPlayerService::AudioOutput::flush()  void MediaPlayerService::AudioOutput::pause()  {      ALOGV("pause"); +    Mutex::Autolock lock(mLock);      if (mTrack != 0) mTrack->pause();  }  void MediaPlayerService::AudioOutput::close()  {      ALOGV("close"); -    mTrack.clear(); +    Mutex::Autolock lock(mLock); +    close_l();  }  void MediaPlayerService::AudioOutput::setVolume(float left, float right)  {      ALOGV("setVolume(%f, %f)", left, right); +    Mutex::Autolock lock(mLock);      mLeftVolume = left;      mRightVolume = right;      if (mTrack != 0) { @@ -1793,6 +1880,7 @@ status_t MediaPlayerService::AudioOutput::setPlaybackRate(const AudioPlaybackRat  {      ALOGV("setPlaybackRate(%f %f %d %d)",                  rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode); +    Mutex::Autolock lock(mLock);      if (mTrack == 0) {          // remember rate so that we can set it when the track is opened          mPlaybackRate = rate; @@ -1814,6 +1902,7 @@ status_t MediaPlayerService::AudioOutput::setPlaybackRate(const AudioPlaybackRat  status_t MediaPlayerService::AudioOutput::getPlaybackRate(AudioPlaybackRate *rate)  {      ALOGV("setPlaybackRate"); +    Mutex::Autolock lock(mLock);      if (mTrack == 0) {          return NO_INIT;      } @@ -1824,6 +1913,7 @@ status_t MediaPlayerService::AudioOutput::getPlaybackRate(AudioPlaybackRate *rat  status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)  {      ALOGV("setAuxEffectSendLevel(%f)", level); +    Mutex::Autolock lock(mLock);      mSendLevel = level;      if (mTrack != 0) {          return mTrack->setAuxEffectSendLevel(level); @@ -1834,6 +1924,7 @@ status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)  status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)  {      ALOGV("attachAuxEffect(%d)", effectId); +    Mutex::Autolock lock(mLock);      mAuxEffectId = effectId;      if (mTrack != 0) {          return mTrack->attachAuxEffect(effectId); @@ -1846,6 +1937,7 @@ 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; @@ -1915,11 +2007,13 @@ void MediaPlayerService::AudioOutput::CallbackWrapper(  int MediaPlayerService::AudioOutput::getSessionId() const  { +    Mutex::Autolock lock(mLock);      return mSessionId;  }  uint32_t MediaPlayerService::AudioOutput::getSampleRate() const  { +    Mutex::Autolock lock(mLock);      if (mTrack == 0) return 0;      return mTrack->getSampleRate();  } diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 7527506..9e6ca52 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -132,7 +132,8 @@ class MediaPlayerService : public BnMediaPlayerService          static void             setMinBufferCount();          static void             CallbackWrapper(                  int event, void *me, void *info); -               void             deleteRecycledTrack(); +               void             deleteRecycledTrack_l(); +               void             close_l();          sp<AudioTrack>          mTrack;          sp<AudioTrack>          mRecycledTrack; @@ -148,32 +149,47 @@ class MediaPlayerService : public BnMediaPlayerService          AudioPlaybackRate       mPlaybackRate;          uint32_t                mSampleRateHz; // sample rate of the content, as set in open()          float                   mMsecsPerFrame; +        size_t                  mFrameSize;          int                     mSessionId;          int                     mUid;          int                     mPid;          float                   mSendLevel;          int                     mAuxEffectId; +        audio_output_flags_t    mFlags; +        mutable Mutex           mLock; + +        // static variables below not protected by mutex          static bool             mIsOnEmulator;          static int              mMinBufferCount;  // 12 for emulator; otherwise 4 -        audio_output_flags_t    mFlags;          // 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 { +            friend AudioOutput;          public:              CallbackData(AudioOutput *cookie) {                  mData = cookie;                  mSwitching = false;              } -            AudioOutput *   getOutput() { return mData;} +            AudioOutput *   getOutput() const { return mData; }              void            setOutput(AudioOutput* newcookie) { mData = newcookie; }              // lock/unlock are used by the callback before accessing the payload of this object -            void            lock() { mLock.lock(); } -            void            unlock() { mLock.unlock(); } -            // beginTrackSwitch/endTrackSwitch are used when this object is being handed over +            void            lock() const { mLock.lock(); } +            void            unlock() const { mLock.unlock(); } + +            // tryBeginTrackSwitch/endTrackSwitch are used when the CallbackData is handed over              // to the next sink. -            void            beginTrackSwitch() { mLock.lock(); mSwitching = true; } + +            // tryBeginTrackSwitch() returns true only if it obtains the lock. +            bool            tryBeginTrackSwitch() { +                LOG_ALWAYS_FATAL_IF(mSwitching, "tryBeginTrackSwitch() already called"); +                if (mLock.tryLock() != OK) { +                    return false; +                } +                mSwitching = true; +                return true; +            }              void            endTrackSwitch() {                  if (mSwitching) {                      mLock.unlock(); @@ -182,7 +198,7 @@ class MediaPlayerService : public BnMediaPlayerService              }          private:              AudioOutput *   mData; -            mutable Mutex   mLock; +            mutable Mutex   mLock; // a recursive mutex might make this unnecessary.              bool            mSwitching;              DISALLOW_EVIL_CONSTRUCTORS(CallbackData);          }; diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 7d7c2a6..9206b5c 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -1063,9 +1063,11 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() {      for (OMX_U32 i = cancelStart; i < cancelEnd; i++) {          BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i); -        status_t error = cancelBufferToNativeWindow(info); -        if (err == 0) { -            err = error; +        if (info->mStatus == BufferInfo::OWNED_BY_US) { +            status_t error = cancelBufferToNativeWindow(info); +            if (err == 0) { +                err = error; +            }          }      } @@ -1152,9 +1154,11 @@ status_t ACodec::allocateOutputMetadataBuffers() {          for (OMX_U32 i = 0; i < mBuffers[kPortIndexOutput].size(); i++) {              BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i); -            status_t error = cancelBufferToNativeWindow(info); -            if (err == OK) { -                err = error; +            if (info->mStatus == BufferInfo::OWNED_BY_US) { +                status_t error = cancelBufferToNativeWindow(info); +                if (err == OK) { +                    err = error; +                }              }          } diff --git a/media/libstagefright/foundation/ADebug.cpp b/media/libstagefright/foundation/ADebug.cpp index 0d1cea4..24fa561 100644 --- a/media/libstagefright/foundation/ADebug.cpp +++ b/media/libstagefright/foundation/ADebug.cpp @@ -32,11 +32,10 @@  namespace android {  //static -ADebug::Level ADebug::GetDebugLevelFromString( -        const char *name, const char *value, ADebug::Level def) { +long ADebug::GetLevelFromSettingsString( +        const char *name, const char *value, long def) {      // split on ,      const char *next = value, *current; -    const unsigned long maxLevel = (unsigned long)kDebugMax;      while (next != NULL) {          current = next;          next = strchr(current, ','); @@ -52,8 +51,8 @@ ADebug::Level ADebug::GetDebugLevelFromString(          // get level          char *end; -        errno = 0;  // strtoul does not clear errno, but it can be set for any return value -        unsigned long level = strtoul(current, &end, 10); +        errno = 0;  // strtol does not clear errno, but it can be set for any return value +        long level = strtol(current, &end, 10);          while (isspace(*end)) {              ++end;          } @@ -77,23 +76,30 @@ ADebug::Level ADebug::GetDebugLevelFromString(              }          } -        // update debug level -        def = (Level)min(level, maxLevel); +        // update value +        def = level;      }      return def;  }  //static -ADebug::Level ADebug::GetDebugLevelFromProperty( -        const char *name, const char *propertyName, ADebug::Level def) { +long ADebug::GetLevelFromProperty( +        const char *name, const char *propertyName, long def) {      char value[PROPERTY_VALUE_MAX];      if (property_get(propertyName, value, NULL)) { -        return GetDebugLevelFromString(name, value, def); +        def = GetLevelFromSettingsString(name, value, def);      }      return def;  }  //static +ADebug::Level ADebug::GetDebugLevelFromProperty( +        const char *name, const char *propertyName, ADebug::Level def) { +    long level = GetLevelFromProperty(name, propertyName, (long)def); +    return (Level)min(max(level, (long)kDebugNone), (long)kDebugMax); +} + +//static  char *ADebug::GetDebugName(const char *name) {      char *debugName = strdup(name);      const char *terms[] = { "omx", "video", "audio" }; @@ -118,6 +124,15 @@ char *ADebug::GetDebugName(const char *name) {  bool ADebug::getExperimentFlag(          bool allow, const char *name, uint64_t modulo,          uint64_t limit, uint64_t plus, uint64_t timeDivisor) { +    // see if this experiment should be disabled/enabled based on properties. +    // default to 2 to allow 0/1 specification +    const int undefined = 2; +    long level = GetLevelFromProperty(name, "debug.stagefright.experiments", undefined); +    if (level != undefined) { +        ALOGI("experiment '%s': %s from property", name, level ? "ENABLED" : "disabled"); +        return level != 0; +    } +      static volatile int32_t haveSerial = 0;      static uint64_t serialNum;      if (!android_atomic_acquire_load(&haveSerial)) { @@ -138,11 +153,10 @@ bool ADebug::getExperimentFlag(                  num = num * 256 + c;              }          } -        ALOGI("got serial");          serialNum = num;          android_atomic_release_store(1, &haveSerial);      } -    ALOGI("serial: %llu, time: %llu", (long long)serialNum, (long long)time(NULL)); +    ALOGD("serial: %llu, time: %lld", (long long unsigned)serialNum, (long long)time(NULL));      // MINOR: use modulo for counter and time, so that their sum does not      // roll over, and mess up the correlation between related experiments.      // e.g. keep (a mod 2N) = 0 impl (a mod N) = 0 diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp index aae3e9f..cbe9673 100644 --- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp @@ -264,8 +264,19 @@ status_t MPEG2TSExtractor::feedMore() {      if (event.isInit()) {          for (size_t i = 0; i < mSourceImpls.size(); ++i) {              if (mSourceImpls[i].get() == event.getMediaSource().get()) { -                mSyncPoints.editItemAt(i).add( -                        event.getTimeUs(), event.getOffset()); +                KeyedVector<int64_t, off64_t> *syncPoints = &mSyncPoints.editItemAt(i); +                syncPoints->add(event.getTimeUs(), event.getOffset()); +                // We're keeping the size of the sync points at most 5mb per a track. +                size_t size = syncPoints->size(); +                if (size >= 327680) { +                    int64_t firstTimeUs = syncPoints->keyAt(0); +                    int64_t lastTimeUs = syncPoints->keyAt(size - 1); +                    if (event.getTimeUs() - firstTimeUs > lastTimeUs - event.getTimeUs()) { +                        syncPoints->removeItemsAt(0, 4096); +                    } else { +                        syncPoints->removeItemsAt(size - 4096, 4096); +                    } +                }                  break;              }          } diff --git a/media/libstagefright/tests/Utils_test.cpp b/media/libstagefright/tests/Utils_test.cpp index c1e663c..d736501 100644 --- a/media/libstagefright/tests/Utils_test.cpp +++ b/media/libstagefright/tests/Utils_test.cpp @@ -109,21 +109,21 @@ TEST_F(UtilsTest, TestStringUtils) {  TEST_F(UtilsTest, TestDebug) {  #define LVL(x) (ADebug::Level)(x) -    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "", LVL(5)), LVL(5)); -    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "   \t  \n ", LVL(2)), LVL(2)); -    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "3", LVL(5)), LVL(3)); -    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "3:*deo", LVL(5)), LVL(3)); -    ASSERT_EQ(ADebug::GetDebugLevelFromString( +    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "", LVL(5)), LVL(5)); +    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "   \t  \n ", LVL(2)), LVL(2)); +    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "3", LVL(5)), LVL(3)); +    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "3:*deo", LVL(5)), LVL(3)); +    ASSERT_EQ(ADebug::GetLevelFromSettingsString(              "video", "\t\n 3 \t\n:\t\n video \t\n", LVL(5)), LVL(3)); -    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "3:*deo,2:vid*", LVL(5)), LVL(2)); -    ASSERT_EQ(ADebug::GetDebugLevelFromString( +    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "3:*deo,2:vid*", LVL(5)), LVL(2)); +    ASSERT_EQ(ADebug::GetLevelFromSettingsString(              "avideo", "\t\n 3 \t\n:\t\n avideo \t\n,\t\n 2 \t\n:\t\n video \t\n", LVL(5)), LVL(3)); -    ASSERT_EQ(ADebug::GetDebugLevelFromString( +    ASSERT_EQ(ADebug::GetLevelFromSettingsString(              "audio.omx", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(2)); -    ASSERT_EQ(ADebug::GetDebugLevelFromString( +    ASSERT_EQ(ADebug::GetLevelFromSettingsString(              "video.omx", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(3)); -    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(3)); -    ASSERT_EQ(ADebug::GetDebugLevelFromString("omx", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(4)); +    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(3)); +    ASSERT_EQ(ADebug::GetLevelFromSettingsString("omx", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(4));  #undef LVL  } diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 52fce34..8f1e050 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1252,11 +1252,9 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)      if (client == 0) {          return;      } -    bool clientAdded = false; +    pid_t pid = IPCThreadState::self()->getCallingPid();      {          Mutex::Autolock _cl(mClientLock); - -        pid_t pid = IPCThreadState::self()->getCallingPid();          if (mNotificationClients.indexOfKey(pid) < 0) {              sp<NotificationClient> notificationClient = new NotificationClient(this,                                                                                  client, @@ -1267,22 +1265,19 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)              sp<IBinder> binder = IInterface::asBinder(client);              binder->linkToDeath(notificationClient); -            clientAdded = true;          }      }      // mClientLock should not be held here because ThreadBase::sendIoConfigEvent() will lock the      // ThreadBase mutex and the locking order is ThreadBase::mLock then AudioFlinger::mClientLock. -    if (clientAdded) { -        // the config change is always sent from playback or record threads to avoid deadlock -        // with AudioSystem::gLock -        for (size_t i = 0; i < mPlaybackThreads.size(); i++) { -            mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED); -        } +    // the config change is always sent from playback or record threads to avoid deadlock +    // with AudioSystem::gLock +    for (size_t i = 0; i < mPlaybackThreads.size(); i++) { +        mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED, pid); +    } -        for (size_t i = 0; i < mRecordThreads.size(); i++) { -            mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED); -        } +    for (size_t i = 0; i < mRecordThreads.size(); i++) { +        mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED, pid);      }  } @@ -1316,12 +1311,15 @@ void AudioFlinger::removeNotificationClient(pid_t pid)  }  void AudioFlinger::ioConfigChanged(audio_io_config_event event, -                                   const sp<AudioIoDescriptor>& ioDesc) +                                   const sp<AudioIoDescriptor>& ioDesc, +                                   pid_t pid)  {      Mutex::Autolock _l(mClientLock);      size_t size = mNotificationClients.size();      for (size_t i = 0; i < size; i++) { -        mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioDesc); +        if ((pid == 0) || (mNotificationClients.keyAt(i) == pid)) { +            mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioDesc); +        }      }  } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index d087ced..4f7e27d 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -559,7 +559,8 @@ private:                float streamVolume_l(audio_stream_type_t stream) const                                  { return mStreamTypes[stream].volume; }                void ioConfigChanged(audio_io_config_event event, -                                   const sp<AudioIoDescriptor>& ioDesc); +                                   const sp<AudioIoDescriptor>& ioDesc, +                                   pid_t pid = 0);                // Allocate an audio_io_handle_t, session ID, effect ID, or audio_module_handle_t.                // They all share the same ID space, but the namespaces are actually independent diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index d3ea9d8..0880c5d 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -532,7 +532,8 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio          // RecordThread::readInputParameters_l()          //FIXME: mStandby should be true here. Is this some kind of hack?          mStandby(false), mOutDevice(outDevice), mInDevice(inDevice), -        mPrevInDevice(AUDIO_DEVICE_NONE), mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id), +        mPrevOutDevice(AUDIO_DEVICE_NONE), mPrevInDevice(AUDIO_DEVICE_NONE), +        mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),          // mName will be set by concrete (non-virtual) subclass          mDeathRecipient(new PMDeathRecipient(this)),          mSystemReady(systemReady) @@ -627,16 +628,16 @@ status_t AudioFlinger::ThreadBase::sendConfigEvent_l(sp<ConfigEvent>& event)      return status;  } -void AudioFlinger::ThreadBase::sendIoConfigEvent(audio_io_config_event event) +void AudioFlinger::ThreadBase::sendIoConfigEvent(audio_io_config_event event, pid_t pid)  {      Mutex::Autolock _l(mLock); -    sendIoConfigEvent_l(event); +    sendIoConfigEvent_l(event, pid);  }  // sendIoConfigEvent_l() must be called with ThreadBase::mLock held -void AudioFlinger::ThreadBase::sendIoConfigEvent_l(audio_io_config_event event) +void AudioFlinger::ThreadBase::sendIoConfigEvent_l(audio_io_config_event event, pid_t pid)  { -    sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event); +    sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event, pid);      sendConfigEvent_l(configEvent);  } @@ -706,7 +707,7 @@ void AudioFlinger::ThreadBase::processConfigEvents_l()          } break;          case CFG_EVENT_IO: {              IoConfigEventData *data = (IoConfigEventData *)event->mData.get(); -            ioConfigChanged(data->mEvent); +            ioConfigChanged(data->mEvent, data->mPid);          } break;          case CFG_EVENT_SET_PARAMETER: {              SetParameterConfigEventData *data = (SetParameterConfigEventData *)event->mData.get(); @@ -1999,7 +2000,7 @@ String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)      return out_s8;  } -void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event) { +void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {      sp<AudioIoDescriptor> desc = new AudioIoDescriptor();      ALOGV("PlaybackThread::ioConfigChanged, thread %p, event %d", this, event); @@ -2021,7 +2022,7 @@ void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event)      default:          break;      } -    mAudioFlinger->ioConfigChanged(event, desc); +    mAudioFlinger->ioConfigChanged(event, desc, pid);  }  void AudioFlinger::PlaybackThread::writeCallback() @@ -3133,7 +3134,10 @@ status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_pat      for (size_t i = 0; i < mEffectChains.size(); i++) {          mEffectChains[i]->setDevice_l(type);      } -    bool configChanged = mOutDevice != type; + +    // mPrevOutDevice is the latest device set by createAudioPatch_l(). It is not set when +    // the thread is created so that the first patch creation triggers an ioConfigChanged callback +    bool configChanged = mPrevOutDevice != type;      mOutDevice = type;      mPatch = *patch; @@ -3163,6 +3167,7 @@ status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_pat          *handle = AUDIO_PATCH_HANDLE_NONE;      }      if (configChanged) { +        mPrevOutDevice = type;          sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);      }      return status; @@ -6868,7 +6873,7 @@ String8 AudioFlinger::RecordThread::getParameters(const String8& keys)      return out_s8;  } -void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event) { +void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {      sp<AudioIoDescriptor> desc = new AudioIoDescriptor();      desc->mIoHandle = mId; @@ -6888,7 +6893,7 @@ void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event) {      default:          break;      } -    mAudioFlinger->ioConfigChanged(event, desc); +    mAudioFlinger->ioConfigChanged(event, desc, pid);  }  void AudioFlinger::RecordThread::readInputParameters_l() diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 0783371..46ac300 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -104,21 +104,22 @@ public:      class IoConfigEventData : public ConfigEventData {      public: -        IoConfigEventData(audio_io_config_event event) : -            mEvent(event) {} +        IoConfigEventData(audio_io_config_event event, pid_t pid) : +            mEvent(event), mPid(pid) {}          virtual  void dump(char *buffer, size_t size) {              snprintf(buffer, size, "IO event: event %d\n", mEvent);          }          const audio_io_config_event mEvent; +        const pid_t                 mPid;      };      class IoConfigEvent : public ConfigEvent {      public: -        IoConfigEvent(audio_io_config_event event) : +        IoConfigEvent(audio_io_config_event event, pid_t pid) :              ConfigEvent(CFG_EVENT_IO) { -            mData = new IoConfigEventData(event); +            mData = new IoConfigEventData(event, pid);          }          virtual ~IoConfigEvent() {}      }; @@ -255,13 +256,13 @@ public:                                                      status_t& status) = 0;      virtual     status_t    setParameters(const String8& keyValuePairs);      virtual     String8     getParameters(const String8& keys) = 0; -    virtual     void        ioConfigChanged(audio_io_config_event event) = 0; +    virtual     void        ioConfigChanged(audio_io_config_event event, pid_t pid = 0) = 0;                  // sendConfigEvent_l() must be called with ThreadBase::mLock held                  // Can temporarily release the lock if waiting for a reply from                  // processConfigEvents_l().                  status_t    sendConfigEvent_l(sp<ConfigEvent>& event); -                void        sendIoConfigEvent(audio_io_config_event event); -                void        sendIoConfigEvent_l(audio_io_config_event event); +                void        sendIoConfigEvent(audio_io_config_event event, pid_t pid = 0); +                void        sendIoConfigEvent_l(audio_io_config_event event, pid_t pid = 0);                  void        sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio);                  void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);                  status_t    sendSetParameterConfigEvent_l(const String8& keyValuePair); @@ -436,6 +437,7 @@ protected:                  bool                    mStandby;     // Whether thread is currently in standby.                  audio_devices_t         mOutDevice;   // output device                  audio_devices_t         mInDevice;    // input device +                audio_devices_t         mPrevOutDevice;   // previous output device                  audio_devices_t         mPrevInDevice;    // previous input device                  struct audio_patch      mPatch;                  audio_source_t          mAudioSource; @@ -572,7 +574,7 @@ public:                                  { return android_atomic_acquire_load(&mSuspended) > 0; }      virtual     String8     getParameters(const String8& keys); -    virtual     void        ioConfigChanged(audio_io_config_event event); +    virtual     void        ioConfigChanged(audio_io_config_event event, pid_t pid = 0);                  status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);                  // FIXME rename mixBuffer() to sinkBuffer() and remove int16_t* dependency.                  // Consider also removing and passing an explicit mMainBuffer initialization @@ -1254,7 +1256,7 @@ public:                                                 status_t& status);      virtual void        cacheParameters_l() {}      virtual String8     getParameters(const String8& keys); -    virtual void        ioConfigChanged(audio_io_config_event event); +    virtual void        ioConfigChanged(audio_io_config_event event, pid_t pid = 0);      virtual status_t    createAudioPatch_l(const struct audio_patch *patch,                                             audio_patch_handle_t *handle);      virtual status_t    releaseAudioPatch_l(const audio_patch_handle_t handle); diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h index 4eef02f..4b73e3c 100755 --- a/services/audiopolicy/common/include/policy.h +++ b/services/audiopolicy/common/include/policy.h @@ -37,8 +37,9 @@   * A device mask for all audio input and output devices where matching inputs/outputs on device   * type alone is not enough: the address must match too   */ -#define APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX | \ -                                            AUDIO_DEVICE_OUT_REMOTE_SUBMIX) +#define APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL (AUDIO_DEVICE_OUT_REMOTE_SUBMIX) + +#define APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX)  /**   * Check if the state given correspond to an in call state. @@ -80,5 +81,8 @@ static inline bool is_virtual_input_device(audio_devices_t device)   */  static inline bool device_distinguishes_on_address(audio_devices_t device)  { -    return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL & ~AUDIO_DEVICE_BIT_IN) != 0); +    return (((device & AUDIO_DEVICE_BIT_IN) != 0) && +            ((~AUDIO_DEVICE_BIT_IN & device & APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL) != 0)) || +           (((device & AUDIO_DEVICE_BIT_IN) == 0) && +            ((device & APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL) != 0));  } diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index de204e5..6d99640 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1076,6 +1076,9 @@ status_t AudioPolicyManager::startSource(sp<AudioOutputDescriptor> outputDesc,          beaconMuteLatency = handleEventForBeacon(STARTING_OUTPUT);      } +    // check active before incrementing usage count +    bool force = !outputDesc->isActive(); +      // increment usage count for this stream on the requested output:      // NOTE that the usage count is the same for duplicated output and hardware output which is      // necessary for a correct control of hardware output routing by startOutput() and stopOutput() @@ -1091,7 +1094,6 @@ status_t AudioPolicyManager::startSource(sp<AudioOutputDescriptor> outputDesc,                              (strategy == STRATEGY_SONIFICATION_RESPECTFUL) ||                              (beaconMuteLatency > 0);          uint32_t waitMs = beaconMuteLatency; -        bool force = false;          for (size_t i = 0; i < mOutputs.size(); i++) {              sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);              if (desc != outputDesc) {  | 
