diff options
Diffstat (limited to 'media/libmedia/AudioTrack.cpp')
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 142 |
1 files changed, 97 insertions, 45 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index ab3d66a..946c118 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 @@ -167,7 +169,8 @@ AudioTrack::AudioTrack() 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; @@ -197,7 +200,8 @@ AudioTrack::AudioTrack( 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, @@ -227,7 +231,8 @@ AudioTrack::AudioTrack( 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, @@ -541,6 +546,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 +717,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; @@ -846,6 +857,15 @@ 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 PCM track + if (property_get_bool("audio.offload.track.enable", false) && + (mFormat == AUDIO_FORMAT_PCM_16_BIT) && (mOffloadInfo == NULL) && + (mFlags == AUDIO_OUTPUT_FLAG_NONE)) { + mPlaybackRateSet = true; + android_atomic_or(CBLK_INVALID, &mCblk->mFlags); + } + return NO_ERROR; } @@ -1001,10 +1021,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 +1157,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," @@ -1203,6 +1236,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; @@ -1838,6 +1872,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 +1916,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; + } + } mCbf(EVENT_STREAM_END, mUserData, NULL); { AutoMutex lock(mLock); @@ -1872,36 +1942,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; @@ -2232,14 +2272,21 @@ 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; + //do not call Timestamp if its PCM offloaded + if (!AVMediaUtils::get()->AudioTrackIsPcmOffloaded(mFormat)) { + // 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)) { if (isOffloaded_l() && (mState == STATE_PAUSED || mState == STATE_PAUSED_STOPPING)) { // use cached paused position in case another offloaded track is running. timestamp.mPosition = mPausedPosition; @@ -2297,6 +2344,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. |