diff options
Diffstat (limited to 'media/libmedia/AudioTrack.cpp')
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 171 |
1 files changed, 113 insertions, 58 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index ff5fe1d..ae016ef 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -30,6 +30,8 @@ #include <media/IAudioFlinger.h> #include <media/AudioPolicyHelper.h> #include <media/AudioResamplerPublic.h> +#include "media/AVMediaExtensions.h" +#include <cutils/properties.h> #define WAIT_PERIOD_MS 10 #define WAIT_STREAM_END_TIMEOUT_SEC 120 @@ -163,11 +165,13 @@ status_t AudioTrack::getMinFrameCount( AudioTrack::AudioTrack() : mStatus(NO_INIT), + mState(STATE_STOPPED), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), - mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), + mPlaybackRateSet(false) { mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN; mAttributes.usage = AUDIO_USAGE_UNKNOWN; @@ -193,11 +197,13 @@ AudioTrack::AudioTrack( const audio_attributes_t* pAttributes, bool doNotReconnect) : mStatus(NO_INIT), + mState(STATE_STOPPED), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), - mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), + mPlaybackRateSet(false) { mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, @@ -223,11 +229,13 @@ AudioTrack::AudioTrack( const audio_attributes_t* pAttributes, bool doNotReconnect) : mStatus(NO_INIT), + mState(STATE_STOPPED), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), - mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), + mPlaybackRateSet(false) { mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, @@ -473,7 +481,6 @@ status_t AudioTrack::set( } mStatus = NO_ERROR; - mState = STATE_STOPPED; mUserData = user; mLoopCount = 0; mLoopStart = 0; @@ -541,6 +548,12 @@ status_t AudioTrack::start() // force refresh of remaining frames by processAudioBuffer() as last // write before stop could be partial. mRefreshRemaining = true; + + // for static track, clear the old flags when start from stopped state + if (mSharedBuffer != 0) + android_atomic_and( + ~(CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END), + &mCblk->mFlags); } mNewPosition = mPosition + mUpdatePeriod; int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags); @@ -706,7 +719,7 @@ status_t AudioTrack::setVolume(float left, float right) mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right))); - if (isOffloaded_l()) { + if (isOffloaded_l() && mAudioTrack != NULL) { mAudioTrack->signal(); } return NO_ERROR; @@ -831,13 +844,13 @@ status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) } // Check resampler ratios are within bounds - if (effectiveRate > mSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) { + if ((uint64_t)effectiveRate > (uint64_t)mSampleRate * (uint64_t)AUDIO_RESAMPLER_DOWN_RATIO_MAX) { ALOGV("setPlaybackRate(%f, %f) failed. Resample rate exceeds max accepted value", playbackRate.mSpeed, playbackRate.mPitch); return BAD_VALUE; } - if (effectiveRate * AUDIO_RESAMPLER_UP_RATIO_MAX < mSampleRate) { + if ((uint64_t)effectiveRate * (uint64_t)AUDIO_RESAMPLER_UP_RATIO_MAX < (uint64_t)mSampleRate) { ALOGV("setPlaybackRate(%f, %f) failed. Resample rate below min accepted value", playbackRate.mSpeed, playbackRate.mPitch); return BAD_VALUE; @@ -846,6 +859,14 @@ status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) //set effective rates mProxy->setPlaybackRate(playbackRateTemp); mProxy->setSampleRate(effectiveRate); // FIXME: not quite "atomic" with setPlaybackRate + + // fallback out of Direct PCM if setPlaybackRate is called on a track offloaded + // session. Do this by setting mPlaybackRateSet to true + if (mTrackOffloaded) { + mPlaybackRateSet = true; + android_atomic_or(CBLK_INVALID, &mCblk->mFlags); + } + return NO_ERROR; } @@ -1001,10 +1022,18 @@ status_t AudioTrack::getPosition(uint32_t *position) return NO_ERROR; } + if (AVMediaUtils::get()->AudioTrackIsPcmOffloaded(mFormat) && + AVMediaUtils::get()->AudioTrackGetPosition(this, position) == NO_ERROR) { + return NO_ERROR; + } + if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t halFrames; // actually unused - (void) AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames); - // FIXME: on getRenderPosition() error, we return OK with frame position 0. + status_t status = AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames); + if (status != NO_ERROR) { + ALOGW("failed to getRenderPosition for offload session status %d", status); + return INVALID_OPERATION; + } } // FIXME: dspFrames may not be zero in (mState == STATE_STOPPED || mState == STATE_FLUSHED) // due to hardware latency. We leave this behavior for now. @@ -1129,11 +1158,16 @@ status_t AudioTrack::createTrack_l() audio_stream_type_t streamType = mStreamType; audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL; - status_t status; - status = AudioSystem::getOutputForAttr(attr, &output, + audio_offload_info_t tOffloadInfo = AUDIO_INFO_INITIALIZER; + if (mPlaybackRateSet == true && mOffloadInfo == NULL && mFormat == AUDIO_FORMAT_PCM_16_BIT) { + mOffloadInfo = &tOffloadInfo; + } + status_t status = AudioSystem::getOutputForAttr(attr, &output, (audio_session_t)mSessionId, &streamType, mClientUid, mSampleRate, mFormat, mChannelMask, mFlags, mSelectedDeviceId, mOffloadInfo); + //reset offload info if forced + mOffloadInfo = (mOffloadInfo == &tOffloadInfo) ? NULL : mOffloadInfo; if (status != NO_ERROR || output == AUDIO_IO_HANDLE_NONE) { ALOGE("Could not get audio output for session %d, stream type %d, usage %d, sample rate %u, format %#x," @@ -1141,6 +1175,7 @@ status_t AudioTrack::createTrack_l() mSessionId, streamType, mAttributes.usage, mSampleRate, mFormat, mChannelMask, mFlags); return BAD_VALUE; } + mTrackOffloaded = AVMediaUtils::get()->AudioTrackIsTrackOffloaded(output); { // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger, // we must release it ourselves if anything goes wrong. @@ -1203,6 +1238,7 @@ status_t AudioTrack::createTrack_l() frameCount = mSharedBuffer->size(); } else if (frameCount == 0) { frameCount = mAfFrameCount; + frameCount = AVMediaUtils::get()->AudioTrackGetOffloadFrameCount(frameCount); } if (mNotificationFramesAct != frameCount) { mNotificationFramesAct = frameCount; @@ -1263,7 +1299,7 @@ status_t AudioTrack::createTrack_l() trackFlags |= IAudioFlinger::TRACK_OFFLOAD; } - if (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { + if ((mFlags & AUDIO_OUTPUT_FLAG_DIRECT) || mTrackOffloaded) { trackFlags |= IAudioFlinger::TRACK_DIRECT; } @@ -1838,6 +1874,36 @@ nsecs_t AudioTrack::processAudioBuffer() // get anchor time to account for callbacks. const nsecs_t timeBeforeCallbacks = systemTime(); + // perform callbacks while unlocked + if (newUnderrun) { + mCbf(EVENT_UNDERRUN, mUserData, NULL); + } + while (loopCountNotifications > 0) { + mCbf(EVENT_LOOP_END, mUserData, NULL); + --loopCountNotifications; + } + if (flags & CBLK_BUFFER_END) { + mCbf(EVENT_BUFFER_END, mUserData, NULL); + } + if (markerReached) { + mCbf(EVENT_MARKER, mUserData, &markerPosition); + } + while (newPosCount > 0) { + size_t temp = newPosition; + mCbf(EVENT_NEW_POS, mUserData, &temp); + newPosition += updatePeriod; + newPosCount--; + } + + if (mObservedSequence != sequence) { + mObservedSequence = sequence; + mCbf(EVENT_NEW_IAUDIOTRACK, mUserData, NULL); + // for offloaded tracks, just wait for the upper layers to recreate the track + if (isOffloadedOrDirect()) { + return NS_INACTIVE; + } + } + if (waitStreamEnd) { // FIXME: Instead of blocking in proxy->waitStreamEndDone(), Callback thread // should wait on proxy futex and handle CBLK_STREAM_END_DONE within this function @@ -1852,6 +1918,12 @@ nsecs_t AudioTrack::processAudioBuffer() case NO_ERROR: case DEAD_OBJECT: case TIMED_OUT: + if (isOffloaded_l()) { + if (mCblk->mFlags & (CBLK_INVALID)){ + // will trigger EVENT_STREAM_END in next iteration + return 0; + } + } if (status != DEAD_OBJECT) { // for DEAD_OBJECT, we do not send a EVENT_STREAM_END after stop(); // instead, the application should handle the EVENT_NEW_IAUDIOTRACK. @@ -1876,36 +1948,6 @@ nsecs_t AudioTrack::processAudioBuffer() return 0; } - // perform callbacks while unlocked - if (newUnderrun) { - mCbf(EVENT_UNDERRUN, mUserData, NULL); - } - while (loopCountNotifications > 0) { - mCbf(EVENT_LOOP_END, mUserData, NULL); - --loopCountNotifications; - } - if (flags & CBLK_BUFFER_END) { - mCbf(EVENT_BUFFER_END, mUserData, NULL); - } - if (markerReached) { - mCbf(EVENT_MARKER, mUserData, &markerPosition); - } - while (newPosCount > 0) { - size_t temp = newPosition; - mCbf(EVENT_NEW_POS, mUserData, &temp); - newPosition += updatePeriod; - newPosCount--; - } - - if (mObservedSequence != sequence) { - mObservedSequence = sequence; - mCbf(EVENT_NEW_IAUDIOTRACK, mUserData, NULL); - // for offloaded tracks, just wait for the upper layers to recreate the track - if (isOffloadedOrDirect()) { - return NS_INACTIVE; - } - } - // if inactive, then don't run me again until re-started if (!active) { return NS_INACTIVE; @@ -2161,8 +2203,7 @@ uint32_t AudioTrack::updateAndGetPosition_l() { // This is the sole place to read server consumed frames uint32_t newServer = mProxy->getPosition(); - int32_t delta = newServer - mServer; - mServer = newServer; + uint32_t delta = newServer > mServer ? newServer - mServer : 0; // TODO There is controversy about whether there can be "negative jitter" in server position. // This should be investigated further, and if possible, it should be addressed. // A more definite failure mode is infrequent polling by client. @@ -2171,11 +2212,12 @@ uint32_t AudioTrack::updateAndGetPosition_l() // That should ensure delta never goes negative for infrequent polling // unless the server has more than 2^31 frames in its buffer, // in which case the use of uint32_t for these counters has bigger issues. - if (delta < 0) { - ALOGE("detected illegal retrograde motion by the server: mServer advanced by %d", delta); - delta = 0; + if (newServer < mServer) { + ALOGE("detected illegal retrograde motion by the server: mServer advanced by %d", + (int32_t) newServer - mServer); } - return mPosition += (uint32_t) delta; + mServer = newServer; + return mPosition += delta; } bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const @@ -2237,14 +2279,22 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) } } - // The presented frame count must always lag behind the consumed frame count. - // To avoid a race, read the presented frames first. This ensures that presented <= consumed. - status_t status = mAudioTrack->getTimestamp(timestamp); - if (status != NO_ERROR) { - ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status); - return status; + status_t status = UNKNOWN_ERROR; + //call Timestamp only if its NOT PCM offloaded and NOT Track Offloaded + if (!AVMediaUtils::get()->AudioTrackIsPcmOffloaded(mFormat) && !mTrackOffloaded) { + // The presented frame count must always lag behind the consumed frame count. + // To avoid a race, read the presented frames first. This ensures that presented <= consumed. + + status = mAudioTrack->getTimestamp(timestamp); + if (status != NO_ERROR) { + ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status); + return status; + } + } - if (isOffloadedOrDirect_l()) { + + if (isOffloadedOrDirect_l() && !AVMediaUtils::get()->AudioTrackIsPcmOffloaded(mFormat) + && !mTrackOffloaded) { if (isOffloaded_l() && (mState == STATE_PAUSED || mState == STATE_PAUSED_STOPPING)) { // use cached paused position in case another offloaded track is running. timestamp.mPosition = mPausedPosition; @@ -2302,6 +2352,11 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) } } else { // Update the mapping between local consumed (mPosition) and server consumed (mServer) + + if (AVMediaUtils::get()->AudioTrackGetTimestamp(this, ×tamp) == NO_ERROR) { + return NO_ERROR; + } + (void) updateAndGetPosition_l(); // Server consumed (mServer) and presented both use the same server time base, // and server consumed is always >= presented. @@ -2315,9 +2370,9 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) // Convert timestamp position from server time base to client time base. // TODO The following code should work OK now because timestamp.mPosition is 32-bit. // But if we change it to 64-bit then this could fail. - // If (mPosition - mServer) can be negative then should use: - // (int32_t)(mPosition - mServer) - timestamp.mPosition += mPosition - mServer; + // Split this out instead of using += to prevent unsigned overflow + // checks in the outer sum. + timestamp.mPosition = timestamp.mPosition + static_cast<int32_t>(mPosition) - mServer; // Immediately after a call to getPosition_l(), mPosition and // mServer both represent the same frame position. mPosition is // in client's point of view, and mServer is in server's point of |