Loading include/media/AudioResamplerPublic.h +11 −0 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,8 @@ #define AUDIO_TIMESTRETCH_PITCH_MAX 2.0f #define AUDIO_TIMESTRETCH_PITCH_MAX 2.0f #define AUDIO_TIMESTRETCH_PITCH_NORMAL 1.0f #define AUDIO_TIMESTRETCH_PITCH_NORMAL 1.0f // TODO: Consider putting these inlines into a class scope // Returns the source frames needed to resample to destination frames. This is not a precise // Returns the source frames needed to resample to destination frames. This is not a precise // value and depends on the resampler (and possibly how it handles rounding internally). // value and depends on the resampler (and possibly how it handles rounding internally). // Nevertheless, this should be an upper bound on the requirements of the resampler. // Nevertheless, this should be an upper bound on the requirements of the resampler. Loading @@ -66,4 +68,13 @@ static inline size_t destinationFramesPossible(size_t srcFrames, uint32_t srcSam return dstFrames > 2 ? dstFrames - 2 : 0; return dstFrames > 2 ? dstFrames - 2 : 0; } } static inline size_t sourceFramesNeededWithTimestretch( uint32_t srcSampleRate, size_t dstFramesRequired, uint32_t dstSampleRate, float speed) { // required is the number of input frames the resampler needs size_t required = sourceFramesNeeded(srcSampleRate, dstFramesRequired, dstSampleRate); // to deliver this, the time stretcher requires: return required * (double)speed + 1 + 1; // accounting for rounding dependencies } #endif // ANDROID_AUDIO_RESAMPLER_PUBLIC_H #endif // ANDROID_AUDIO_RESAMPLER_PUBLIC_H include/media/AudioTrack.h +20 −0 Original line number Original line Diff line number Diff line Loading @@ -359,6 +359,21 @@ public: /* Return current source sample rate in Hz */ /* Return current source sample rate in Hz */ uint32_t getSampleRate() const; uint32_t getSampleRate() const; /* Set source playback rate for timestretch * 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster * 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch * * AUDIO_TIMESTRETCH_SPEED_MIN <= speed <= AUDIO_TIMESTRETCH_SPEED_MAX * AUDIO_TIMESTRETCH_PITCH_MIN <= pitch <= AUDIO_TIMESTRETCH_PITCH_MAX * * Speed increases the playback rate of media, but does not alter pitch. * Pitch increases the "tonal frequency" of media, but does not affect the playback rate. */ status_t setPlaybackRate(float speed, float pitch); /* Return current playback rate */ void getPlaybackRate(float *speed, float *pitch) const; /* Enables looping and sets the start and end points of looping. /* Enables looping and sets the start and end points of looping. * Only supported for static buffer mode. * Only supported for static buffer mode. * * Loading Loading @@ -719,6 +734,9 @@ protected: // increment mPosition by the delta of mServer, and return new value of mPosition // increment mPosition by the delta of mServer, and return new value of mPosition uint32_t updateAndGetPosition_l(); uint32_t updateAndGetPosition_l(); // check sample rate and speed is compatible with AudioTrack bool isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const; // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0 // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0 sp<IAudioTrack> mAudioTrack; sp<IAudioTrack> mAudioTrack; sp<IMemory> mCblkMemory; sp<IMemory> mCblkMemory; Loading @@ -730,6 +748,8 @@ protected: float mVolume[2]; float mVolume[2]; float mSendLevel; float mSendLevel; mutable uint32_t mSampleRate; // mutable because getSampleRate() can update it mutable uint32_t mSampleRate; // mutable because getSampleRate() can update it float mSpeed; // timestretch: 1.0f for normal speed. float mPitch; // timestretch: 1.0f for normal pitch. size_t mFrameCount; // corresponds to current IAudioTrack, value is size_t mFrameCount; // corresponds to current IAudioTrack, value is // reported back by AudioFlinger to the client // reported back by AudioFlinger to the client size_t mReqFrameCount; // frame count to request the first or next time size_t mReqFrameCount; // frame count to request the first or next time Loading include/private/media/AudioTrackShared.h +34 −2 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <utils/Log.h> #include <utils/Log.h> #include <utils/RefBase.h> #include <utils/RefBase.h> #include <audio_utils/roundup.h> #include <audio_utils/roundup.h> #include <media/AudioResamplerPublic.h> #include <media/SingleStateQueue.h> #include <media/SingleStateQueue.h> namespace android { namespace android { Loading Loading @@ -113,6 +114,14 @@ struct AudioTrackSharedStatic { mPosLoopQueue; mPosLoopQueue; }; }; struct AudioTrackPlaybackRate { float mSpeed; float mPitch; }; typedef SingleStateQueue<AudioTrackPlaybackRate> AudioTrackPlaybackRateQueue; // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Important: do not add any virtual methods, including ~ // Important: do not add any virtual methods, including ~ Loading Loading @@ -159,6 +168,8 @@ private: uint32_t mSampleRate; // AudioTrack only: client's requested sample rate in Hz uint32_t mSampleRate; // AudioTrack only: client's requested sample rate in Hz // or 0 == default. Write-only client, read-only server. // or 0 == default. Write-only client, read-only server. AudioTrackPlaybackRateQueue::Shared mPlaybackRateQueue; // client write-only, server read-only // client write-only, server read-only uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0 uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0 Loading Loading @@ -313,7 +324,8 @@ public: AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool clientInServer = false) size_t frameSize, bool clientInServer = false) : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer) { } clientInServer), mPlaybackRateMutator(&cblk->mPlaybackRateQueue) { } virtual ~AudioTrackClientProxy() { } virtual ~AudioTrackClientProxy() { } // No barriers on the following operations, so the ordering of loads/stores // No barriers on the following operations, so the ordering of loads/stores Loading @@ -333,6 +345,13 @@ public: mCblk->mSampleRate = sampleRate; mCblk->mSampleRate = sampleRate; } } void setPlaybackRate(float speed, float pitch) { AudioTrackPlaybackRate playbackRate; playbackRate.mSpeed = speed; playbackRate.mPitch = pitch; mPlaybackRateMutator.push(playbackRate); } virtual void flush(); virtual void flush(); virtual uint32_t getUnderrunFrames() const { virtual uint32_t getUnderrunFrames() const { Loading @@ -344,6 +363,9 @@ public: bool getStreamEndDone() const; bool getStreamEndDone() const; status_t waitStreamEndDone(const struct timespec *requested); status_t waitStreamEndDone(const struct timespec *requested); private: AudioTrackPlaybackRateQueue::Mutator mPlaybackRateMutator; }; }; class StaticAudioTrackClientProxy : public AudioTrackClientProxy { class StaticAudioTrackClientProxy : public AudioTrackClientProxy { Loading Loading @@ -458,8 +480,11 @@ class AudioTrackServerProxy : public ServerProxy { public: public: AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0) size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0) : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer) { : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer), mPlaybackRateObserver(&cblk->mPlaybackRateQueue) { mCblk->mSampleRate = sampleRate; mCblk->mSampleRate = sampleRate; mPlaybackRate.mSpeed = AUDIO_TIMESTRETCH_SPEED_NORMAL; mPlaybackRate.mPitch = AUDIO_TIMESTRETCH_PITCH_NORMAL; } } protected: protected: virtual ~AudioTrackServerProxy() { } virtual ~AudioTrackServerProxy() { } Loading Loading @@ -493,6 +518,13 @@ public: // Return the total number of frames that AudioFlinger has obtained and released // Return the total number of frames that AudioFlinger has obtained and released virtual size_t framesReleased() const { return mCblk->mServer; } virtual size_t framesReleased() const { return mCblk->mServer; } // Return the playback speed and pitch read atomically. Not multi-thread safe on server side. void getPlaybackRate(float *speed, float *pitch); private: AudioTrackPlaybackRate mPlaybackRate; // last observed playback rate AudioTrackPlaybackRateQueue::Observer mPlaybackRateObserver; }; }; class StaticAudioTrackServerProxy : public AudioTrackServerProxy { class StaticAudioTrackServerProxy : public AudioTrackServerProxy { Loading media/libmedia/AudioTrack.cpp +118 −15 Original line number Original line Diff line number Diff line Loading @@ -56,6 +56,24 @@ static int64_t getNowUs() return convertTimespecToUs(tv); return convertTimespecToUs(tv); } } // Must match similar computation in createTrack_l in Threads.cpp. // TODO: Move to a common library static size_t calculateMinFrameCount( uint32_t afLatencyMs, uint32_t afFrameCount, uint32_t afSampleRate, uint32_t sampleRate, float speed) { // Ensure that buffer depth covers at least audio hardware latency uint32_t minBufCount = afLatencyMs / ((1000 * afFrameCount) / afSampleRate); if (minBufCount < 2) { minBufCount = 2; } ALOGV("calculateMinFrameCount afLatency %u afFrameCount %u afSampleRate %u " "sampleRate %u speed %f minBufCount: %u", afLatencyMs, afFrameCount, afSampleRate, sampleRate, speed, minBufCount); return minBufCount * sourceFramesNeededWithTimestretch( sampleRate, afFrameCount, afSampleRate, speed); } // static // static status_t AudioTrack::getMinFrameCount( status_t AudioTrack::getMinFrameCount( size_t* frameCount, size_t* frameCount, Loading Loading @@ -94,13 +112,10 @@ status_t AudioTrack::getMinFrameCount( return status; return status; } } // Ensure that buffer depth covers at least audio hardware latency // When called from createTrack, speed is 1.0f (normal speed). uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate); // This is rechecked again on setting playback rate (TODO: on setting sample rate, too). if (minBufCount < 2) { *frameCount = calculateMinFrameCount(afLatency, afFrameCount, afSampleRate, sampleRate, 1.0f); minBufCount = 2; } *frameCount = minBufCount * sourceFramesNeeded(sampleRate, afFrameCount, afSampleRate); // The formula above should always produce a non-zero value under normal circumstances: // The formula above should always produce a non-zero value under normal circumstances: // AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX. // AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX. // Return error in the unlikely event that it does not, as that's part of the API contract. // Return error in the unlikely event that it does not, as that's part of the API contract. Loading @@ -109,8 +124,8 @@ status_t AudioTrack::getMinFrameCount( streamType, sampleRate); streamType, sampleRate); return BAD_VALUE; return BAD_VALUE; } } ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, minBufCount=%u, afSampleRate=%u, afLatency=%u", ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, afSampleRate=%u, afLatency=%u", *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency); *frameCount, afFrameCount, afSampleRate, afLatency); return NO_ERROR; return NO_ERROR; } } Loading Loading @@ -360,6 +375,8 @@ status_t AudioTrack::set( return BAD_VALUE; return BAD_VALUE; } } mSampleRate = sampleRate; mSampleRate = sampleRate; mSpeed = AUDIO_TIMESTRETCH_SPEED_NORMAL; mPitch = AUDIO_TIMESTRETCH_PITCH_NORMAL; // Make copy of input parameter offloadInfo so that in the future: // Make copy of input parameter offloadInfo so that in the future: // (a) createTrack_l doesn't need it as an input parameter // (a) createTrack_l doesn't need it as an input parameter Loading Loading @@ -689,6 +706,7 @@ status_t AudioTrack::setSampleRate(uint32_t rate) if (rate == 0 || rate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) { if (rate == 0 || rate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) { return BAD_VALUE; return BAD_VALUE; } } // TODO: Should we also check if the buffer size is compatible? mSampleRate = rate; mSampleRate = rate; mProxy->setSampleRate(rate); mProxy->setSampleRate(rate); Loading Loading @@ -719,6 +737,42 @@ uint32_t AudioTrack::getSampleRate() const return mSampleRate; return mSampleRate; } } status_t AudioTrack::setPlaybackRate(float speed, float pitch) { if (speed < AUDIO_TIMESTRETCH_SPEED_MIN || speed > AUDIO_TIMESTRETCH_SPEED_MAX || pitch < AUDIO_TIMESTRETCH_PITCH_MIN || pitch > AUDIO_TIMESTRETCH_PITCH_MAX) { return BAD_VALUE; } AutoMutex lock(mLock); if (speed == mSpeed && pitch == mPitch) { return NO_ERROR; } if (mIsTimed || isOffloadedOrDirect_l()) { return INVALID_OPERATION; } if (mFlags & AUDIO_OUTPUT_FLAG_FAST) { return INVALID_OPERATION; } // Check if the buffer size is compatible. if (!isSampleRateSpeedAllowed_l(mSampleRate, speed)) { ALOGV("setPlaybackRate(%f, %f) failed", speed, pitch); return BAD_VALUE; } mSpeed = speed; mPitch = pitch; mProxy->setPlaybackRate(speed, pitch); return NO_ERROR; } void AudioTrack::getPlaybackRate(float *speed, float *pitch) const { AutoMutex lock(mLock); *speed = mSpeed; *pitch = mPitch; } status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount) status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount) { { if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) { if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) { Loading Loading @@ -1086,8 +1140,16 @@ status_t AudioTrack::createTrack_l() // there _is_ a frameCount parameter. We silently ignore it. // there _is_ a frameCount parameter. We silently ignore it. frameCount = mSharedBuffer->size() / mFrameSize; frameCount = mSharedBuffer->size() / mFrameSize; } else { } else { // For fast and normal streaming tracks, // For fast tracks the frame count calculations and checks are done by server // the frame count calculations and checks are done by server if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) == 0) { // for normal tracks precompute the frame count based on speed. const size_t minFrameCount = calculateMinFrameCount( afLatency, afFrameCount, afSampleRate, mSampleRate, mSpeed); if (frameCount < minFrameCount) { frameCount = minFrameCount; } } } } IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT; IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT; Loading Loading @@ -1230,6 +1292,7 @@ status_t AudioTrack::createTrack_l() } } mAudioTrack->attachAuxEffect(mAuxEffectId); mAudioTrack->attachAuxEffect(mAuxEffectId); // FIXME doesn't take into account speed or future sample rate changes (until restoreTrack) // FIXME don't believe this lie // FIXME don't believe this lie mLatency = afLatency + (1000*frameCount) / mSampleRate; mLatency = afLatency + (1000*frameCount) / mSampleRate; Loading @@ -1255,6 +1318,7 @@ status_t AudioTrack::createTrack_l() mProxy->setSendLevel(mSendLevel); mProxy->setSendLevel(mSendLevel); mProxy->setSampleRate(mSampleRate); mProxy->setSampleRate(mSampleRate); mProxy->setPlaybackRate(mSpeed, mPitch); mProxy->setMinimum(mNotificationFramesAct); mProxy->setMinimum(mNotificationFramesAct); mDeathNotifier = new DeathNotifier(this); mDeathNotifier = new DeathNotifier(this); Loading Loading @@ -1617,6 +1681,7 @@ nsecs_t AudioTrack::processAudioBuffer() // Cache other fields that will be needed soon // Cache other fields that will be needed soon uint32_t sampleRate = mSampleRate; uint32_t sampleRate = mSampleRate; float speed = mSpeed; uint32_t notificationFrames = mNotificationFramesAct; uint32_t notificationFrames = mNotificationFramesAct; if (mRefreshRemaining) { if (mRefreshRemaining) { mRefreshRemaining = false; mRefreshRemaining = false; Loading Loading @@ -1745,7 +1810,7 @@ nsecs_t AudioTrack::processAudioBuffer() if (minFrames != (uint32_t) ~0) { if (minFrames != (uint32_t) ~0) { // This "fudge factor" avoids soaking CPU, and compensates for late progress by server // This "fudge factor" avoids soaking CPU, and compensates for late progress by server static const nsecs_t kFudgeNs = 10000000LL; // 10 ms static const nsecs_t kFudgeNs = 10000000LL; // 10 ms ns = ((minFrames * 1000000000LL) / sampleRate) + kFudgeNs; ns = ((double)minFrames * 1000000000) / ((double)sampleRate * speed) + kFudgeNs; } } // If not supplying data by EVENT_MORE_DATA, then we're done // If not supplying data by EVENT_MORE_DATA, then we're done Loading Loading @@ -1786,7 +1851,8 @@ nsecs_t AudioTrack::processAudioBuffer() if (mRetryOnPartialBuffer && !isOffloaded()) { if (mRetryOnPartialBuffer && !isOffloaded()) { mRetryOnPartialBuffer = false; mRetryOnPartialBuffer = false; if (avail < mRemainingFrames) { if (avail < mRemainingFrames) { int64_t myns = ((mRemainingFrames - avail) * 1100000000LL) / sampleRate; int64_t myns = ((double)(mRemainingFrames - avail) * 1100000000) / ((double)sampleRate * speed); if (ns < 0 || myns < ns) { if (ns < 0 || myns < ns) { ns = myns; ns = myns; } } Loading Loading @@ -1841,7 +1907,7 @@ nsecs_t AudioTrack::processAudioBuffer() // that total to a sum == notificationFrames. // that total to a sum == notificationFrames. if (0 < misalignment && misalignment <= mRemainingFrames) { if (0 < misalignment && misalignment <= mRemainingFrames) { mRemainingFrames = misalignment; mRemainingFrames = misalignment; return (mRemainingFrames * 1100000000LL) / sampleRate; return ((double)mRemainingFrames * 1100000000) / ((double)sampleRate * speed); } } #endif #endif Loading Loading @@ -1936,6 +2002,41 @@ uint32_t AudioTrack::updateAndGetPosition_l() return mPosition += (uint32_t) delta; return mPosition += (uint32_t) delta; } } bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const { // applicable for mixing tracks only (not offloaded or direct) if (mStaticProxy != 0) { return true; // static tracks do not have issues with buffer sizing. } status_t status; uint32_t afLatency; status = AudioSystem::getLatency(mOutput, &afLatency); if (status != NO_ERROR) { ALOGE("getLatency(%d) failed status %d", mOutput, status); return false; } size_t afFrameCount; status = AudioSystem::getFrameCount(mOutput, &afFrameCount); if (status != NO_ERROR) { ALOGE("getFrameCount(output=%d) status %d", mOutput, status); return false; } uint32_t afSampleRate; status = AudioSystem::getSamplingRate(mOutput, &afSampleRate); if (status != NO_ERROR) { ALOGE("getSamplingRate(output=%d) status %d", mOutput, status); return false; } const size_t minFrameCount = calculateMinFrameCount(afLatency, afFrameCount, afSampleRate, sampleRate, speed); ALOGV("isSampleRateSpeedAllowed_l mFrameCount %zu minFrameCount %zu", mFrameCount, minFrameCount); return mFrameCount >= minFrameCount; } status_t AudioTrack::setParameters(const String8& keyValuePairs) status_t AudioTrack::setParameters(const String8& keyValuePairs) { { AutoMutex lock(mLock); AutoMutex lock(mLock); Loading Loading @@ -2001,7 +2102,8 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) return WOULD_BLOCK; // stale timestamp time, occurs before start. return WOULD_BLOCK; // stale timestamp time, occurs before start. } } const int64_t deltaTimeUs = timestampTimeUs - mStartUs; const int64_t deltaTimeUs = timestampTimeUs - mStartUs; const int64_t deltaPositionByUs = timestamp.mPosition * 1000000LL / mSampleRate; const int64_t deltaPositionByUs = (double)timestamp.mPosition * 1000000 / ((double)mSampleRate * mSpeed); if (deltaPositionByUs > deltaTimeUs + kTimeJitterUs) { if (deltaPositionByUs > deltaTimeUs + kTimeJitterUs) { // Verify that the counter can't count faster than the sample rate // Verify that the counter can't count faster than the sample rate Loading Loading @@ -2088,7 +2190,8 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args __unused) const snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%zu)\n", mFormat, snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%zu)\n", mFormat, mChannelCount, mFrameCount); mChannelCount, mFrameCount); result.append(buffer); result.append(buffer); snprintf(buffer, 255, " sample rate(%u), status(%d)\n", mSampleRate, mStatus); snprintf(buffer, 255, " sample rate(%u), speed(%f), status(%d)\n", mSampleRate, mSpeed, mStatus); result.append(buffer); result.append(buffer); snprintf(buffer, 255, " state(%d), latency (%d)\n", mState, mLatency); snprintf(buffer, 255, " state(%d), latency (%d)\n", mState, mLatency); result.append(buffer); result.append(buffer); Loading media/libmedia/AudioTrackShared.cpp +10 −0 Original line number Original line Diff line number Diff line Loading @@ -793,6 +793,16 @@ void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount) (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags); (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags); } } void AudioTrackServerProxy::getPlaybackRate(float *speed, float *pitch) { // do not call from multiple threads without holding lock AudioTrackPlaybackRate playbackRate; if (mPlaybackRateObserver.poll(playbackRate)) { mPlaybackRate = playbackRate; } *speed = mPlaybackRate.mSpeed; *pitch = mPlaybackRate.mPitch; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, Loading Loading
include/media/AudioResamplerPublic.h +11 −0 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,8 @@ #define AUDIO_TIMESTRETCH_PITCH_MAX 2.0f #define AUDIO_TIMESTRETCH_PITCH_MAX 2.0f #define AUDIO_TIMESTRETCH_PITCH_NORMAL 1.0f #define AUDIO_TIMESTRETCH_PITCH_NORMAL 1.0f // TODO: Consider putting these inlines into a class scope // Returns the source frames needed to resample to destination frames. This is not a precise // Returns the source frames needed to resample to destination frames. This is not a precise // value and depends on the resampler (and possibly how it handles rounding internally). // value and depends on the resampler (and possibly how it handles rounding internally). // Nevertheless, this should be an upper bound on the requirements of the resampler. // Nevertheless, this should be an upper bound on the requirements of the resampler. Loading @@ -66,4 +68,13 @@ static inline size_t destinationFramesPossible(size_t srcFrames, uint32_t srcSam return dstFrames > 2 ? dstFrames - 2 : 0; return dstFrames > 2 ? dstFrames - 2 : 0; } } static inline size_t sourceFramesNeededWithTimestretch( uint32_t srcSampleRate, size_t dstFramesRequired, uint32_t dstSampleRate, float speed) { // required is the number of input frames the resampler needs size_t required = sourceFramesNeeded(srcSampleRate, dstFramesRequired, dstSampleRate); // to deliver this, the time stretcher requires: return required * (double)speed + 1 + 1; // accounting for rounding dependencies } #endif // ANDROID_AUDIO_RESAMPLER_PUBLIC_H #endif // ANDROID_AUDIO_RESAMPLER_PUBLIC_H
include/media/AudioTrack.h +20 −0 Original line number Original line Diff line number Diff line Loading @@ -359,6 +359,21 @@ public: /* Return current source sample rate in Hz */ /* Return current source sample rate in Hz */ uint32_t getSampleRate() const; uint32_t getSampleRate() const; /* Set source playback rate for timestretch * 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster * 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch * * AUDIO_TIMESTRETCH_SPEED_MIN <= speed <= AUDIO_TIMESTRETCH_SPEED_MAX * AUDIO_TIMESTRETCH_PITCH_MIN <= pitch <= AUDIO_TIMESTRETCH_PITCH_MAX * * Speed increases the playback rate of media, but does not alter pitch. * Pitch increases the "tonal frequency" of media, but does not affect the playback rate. */ status_t setPlaybackRate(float speed, float pitch); /* Return current playback rate */ void getPlaybackRate(float *speed, float *pitch) const; /* Enables looping and sets the start and end points of looping. /* Enables looping and sets the start and end points of looping. * Only supported for static buffer mode. * Only supported for static buffer mode. * * Loading Loading @@ -719,6 +734,9 @@ protected: // increment mPosition by the delta of mServer, and return new value of mPosition // increment mPosition by the delta of mServer, and return new value of mPosition uint32_t updateAndGetPosition_l(); uint32_t updateAndGetPosition_l(); // check sample rate and speed is compatible with AudioTrack bool isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const; // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0 // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0 sp<IAudioTrack> mAudioTrack; sp<IAudioTrack> mAudioTrack; sp<IMemory> mCblkMemory; sp<IMemory> mCblkMemory; Loading @@ -730,6 +748,8 @@ protected: float mVolume[2]; float mVolume[2]; float mSendLevel; float mSendLevel; mutable uint32_t mSampleRate; // mutable because getSampleRate() can update it mutable uint32_t mSampleRate; // mutable because getSampleRate() can update it float mSpeed; // timestretch: 1.0f for normal speed. float mPitch; // timestretch: 1.0f for normal pitch. size_t mFrameCount; // corresponds to current IAudioTrack, value is size_t mFrameCount; // corresponds to current IAudioTrack, value is // reported back by AudioFlinger to the client // reported back by AudioFlinger to the client size_t mReqFrameCount; // frame count to request the first or next time size_t mReqFrameCount; // frame count to request the first or next time Loading
include/private/media/AudioTrackShared.h +34 −2 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <utils/Log.h> #include <utils/Log.h> #include <utils/RefBase.h> #include <utils/RefBase.h> #include <audio_utils/roundup.h> #include <audio_utils/roundup.h> #include <media/AudioResamplerPublic.h> #include <media/SingleStateQueue.h> #include <media/SingleStateQueue.h> namespace android { namespace android { Loading Loading @@ -113,6 +114,14 @@ struct AudioTrackSharedStatic { mPosLoopQueue; mPosLoopQueue; }; }; struct AudioTrackPlaybackRate { float mSpeed; float mPitch; }; typedef SingleStateQueue<AudioTrackPlaybackRate> AudioTrackPlaybackRateQueue; // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Important: do not add any virtual methods, including ~ // Important: do not add any virtual methods, including ~ Loading Loading @@ -159,6 +168,8 @@ private: uint32_t mSampleRate; // AudioTrack only: client's requested sample rate in Hz uint32_t mSampleRate; // AudioTrack only: client's requested sample rate in Hz // or 0 == default. Write-only client, read-only server. // or 0 == default. Write-only client, read-only server. AudioTrackPlaybackRateQueue::Shared mPlaybackRateQueue; // client write-only, server read-only // client write-only, server read-only uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0 uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0 Loading Loading @@ -313,7 +324,8 @@ public: AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool clientInServer = false) size_t frameSize, bool clientInServer = false) : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer) { } clientInServer), mPlaybackRateMutator(&cblk->mPlaybackRateQueue) { } virtual ~AudioTrackClientProxy() { } virtual ~AudioTrackClientProxy() { } // No barriers on the following operations, so the ordering of loads/stores // No barriers on the following operations, so the ordering of loads/stores Loading @@ -333,6 +345,13 @@ public: mCblk->mSampleRate = sampleRate; mCblk->mSampleRate = sampleRate; } } void setPlaybackRate(float speed, float pitch) { AudioTrackPlaybackRate playbackRate; playbackRate.mSpeed = speed; playbackRate.mPitch = pitch; mPlaybackRateMutator.push(playbackRate); } virtual void flush(); virtual void flush(); virtual uint32_t getUnderrunFrames() const { virtual uint32_t getUnderrunFrames() const { Loading @@ -344,6 +363,9 @@ public: bool getStreamEndDone() const; bool getStreamEndDone() const; status_t waitStreamEndDone(const struct timespec *requested); status_t waitStreamEndDone(const struct timespec *requested); private: AudioTrackPlaybackRateQueue::Mutator mPlaybackRateMutator; }; }; class StaticAudioTrackClientProxy : public AudioTrackClientProxy { class StaticAudioTrackClientProxy : public AudioTrackClientProxy { Loading Loading @@ -458,8 +480,11 @@ class AudioTrackServerProxy : public ServerProxy { public: public: AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0) size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0) : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer) { : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer), mPlaybackRateObserver(&cblk->mPlaybackRateQueue) { mCblk->mSampleRate = sampleRate; mCblk->mSampleRate = sampleRate; mPlaybackRate.mSpeed = AUDIO_TIMESTRETCH_SPEED_NORMAL; mPlaybackRate.mPitch = AUDIO_TIMESTRETCH_PITCH_NORMAL; } } protected: protected: virtual ~AudioTrackServerProxy() { } virtual ~AudioTrackServerProxy() { } Loading Loading @@ -493,6 +518,13 @@ public: // Return the total number of frames that AudioFlinger has obtained and released // Return the total number of frames that AudioFlinger has obtained and released virtual size_t framesReleased() const { return mCblk->mServer; } virtual size_t framesReleased() const { return mCblk->mServer; } // Return the playback speed and pitch read atomically. Not multi-thread safe on server side. void getPlaybackRate(float *speed, float *pitch); private: AudioTrackPlaybackRate mPlaybackRate; // last observed playback rate AudioTrackPlaybackRateQueue::Observer mPlaybackRateObserver; }; }; class StaticAudioTrackServerProxy : public AudioTrackServerProxy { class StaticAudioTrackServerProxy : public AudioTrackServerProxy { Loading
media/libmedia/AudioTrack.cpp +118 −15 Original line number Original line Diff line number Diff line Loading @@ -56,6 +56,24 @@ static int64_t getNowUs() return convertTimespecToUs(tv); return convertTimespecToUs(tv); } } // Must match similar computation in createTrack_l in Threads.cpp. // TODO: Move to a common library static size_t calculateMinFrameCount( uint32_t afLatencyMs, uint32_t afFrameCount, uint32_t afSampleRate, uint32_t sampleRate, float speed) { // Ensure that buffer depth covers at least audio hardware latency uint32_t minBufCount = afLatencyMs / ((1000 * afFrameCount) / afSampleRate); if (minBufCount < 2) { minBufCount = 2; } ALOGV("calculateMinFrameCount afLatency %u afFrameCount %u afSampleRate %u " "sampleRate %u speed %f minBufCount: %u", afLatencyMs, afFrameCount, afSampleRate, sampleRate, speed, minBufCount); return minBufCount * sourceFramesNeededWithTimestretch( sampleRate, afFrameCount, afSampleRate, speed); } // static // static status_t AudioTrack::getMinFrameCount( status_t AudioTrack::getMinFrameCount( size_t* frameCount, size_t* frameCount, Loading Loading @@ -94,13 +112,10 @@ status_t AudioTrack::getMinFrameCount( return status; return status; } } // Ensure that buffer depth covers at least audio hardware latency // When called from createTrack, speed is 1.0f (normal speed). uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate); // This is rechecked again on setting playback rate (TODO: on setting sample rate, too). if (minBufCount < 2) { *frameCount = calculateMinFrameCount(afLatency, afFrameCount, afSampleRate, sampleRate, 1.0f); minBufCount = 2; } *frameCount = minBufCount * sourceFramesNeeded(sampleRate, afFrameCount, afSampleRate); // The formula above should always produce a non-zero value under normal circumstances: // The formula above should always produce a non-zero value under normal circumstances: // AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX. // AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX. // Return error in the unlikely event that it does not, as that's part of the API contract. // Return error in the unlikely event that it does not, as that's part of the API contract. Loading @@ -109,8 +124,8 @@ status_t AudioTrack::getMinFrameCount( streamType, sampleRate); streamType, sampleRate); return BAD_VALUE; return BAD_VALUE; } } ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, minBufCount=%u, afSampleRate=%u, afLatency=%u", ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, afSampleRate=%u, afLatency=%u", *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency); *frameCount, afFrameCount, afSampleRate, afLatency); return NO_ERROR; return NO_ERROR; } } Loading Loading @@ -360,6 +375,8 @@ status_t AudioTrack::set( return BAD_VALUE; return BAD_VALUE; } } mSampleRate = sampleRate; mSampleRate = sampleRate; mSpeed = AUDIO_TIMESTRETCH_SPEED_NORMAL; mPitch = AUDIO_TIMESTRETCH_PITCH_NORMAL; // Make copy of input parameter offloadInfo so that in the future: // Make copy of input parameter offloadInfo so that in the future: // (a) createTrack_l doesn't need it as an input parameter // (a) createTrack_l doesn't need it as an input parameter Loading Loading @@ -689,6 +706,7 @@ status_t AudioTrack::setSampleRate(uint32_t rate) if (rate == 0 || rate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) { if (rate == 0 || rate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) { return BAD_VALUE; return BAD_VALUE; } } // TODO: Should we also check if the buffer size is compatible? mSampleRate = rate; mSampleRate = rate; mProxy->setSampleRate(rate); mProxy->setSampleRate(rate); Loading Loading @@ -719,6 +737,42 @@ uint32_t AudioTrack::getSampleRate() const return mSampleRate; return mSampleRate; } } status_t AudioTrack::setPlaybackRate(float speed, float pitch) { if (speed < AUDIO_TIMESTRETCH_SPEED_MIN || speed > AUDIO_TIMESTRETCH_SPEED_MAX || pitch < AUDIO_TIMESTRETCH_PITCH_MIN || pitch > AUDIO_TIMESTRETCH_PITCH_MAX) { return BAD_VALUE; } AutoMutex lock(mLock); if (speed == mSpeed && pitch == mPitch) { return NO_ERROR; } if (mIsTimed || isOffloadedOrDirect_l()) { return INVALID_OPERATION; } if (mFlags & AUDIO_OUTPUT_FLAG_FAST) { return INVALID_OPERATION; } // Check if the buffer size is compatible. if (!isSampleRateSpeedAllowed_l(mSampleRate, speed)) { ALOGV("setPlaybackRate(%f, %f) failed", speed, pitch); return BAD_VALUE; } mSpeed = speed; mPitch = pitch; mProxy->setPlaybackRate(speed, pitch); return NO_ERROR; } void AudioTrack::getPlaybackRate(float *speed, float *pitch) const { AutoMutex lock(mLock); *speed = mSpeed; *pitch = mPitch; } status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount) status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount) { { if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) { if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) { Loading Loading @@ -1086,8 +1140,16 @@ status_t AudioTrack::createTrack_l() // there _is_ a frameCount parameter. We silently ignore it. // there _is_ a frameCount parameter. We silently ignore it. frameCount = mSharedBuffer->size() / mFrameSize; frameCount = mSharedBuffer->size() / mFrameSize; } else { } else { // For fast and normal streaming tracks, // For fast tracks the frame count calculations and checks are done by server // the frame count calculations and checks are done by server if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) == 0) { // for normal tracks precompute the frame count based on speed. const size_t minFrameCount = calculateMinFrameCount( afLatency, afFrameCount, afSampleRate, mSampleRate, mSpeed); if (frameCount < minFrameCount) { frameCount = minFrameCount; } } } } IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT; IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT; Loading Loading @@ -1230,6 +1292,7 @@ status_t AudioTrack::createTrack_l() } } mAudioTrack->attachAuxEffect(mAuxEffectId); mAudioTrack->attachAuxEffect(mAuxEffectId); // FIXME doesn't take into account speed or future sample rate changes (until restoreTrack) // FIXME don't believe this lie // FIXME don't believe this lie mLatency = afLatency + (1000*frameCount) / mSampleRate; mLatency = afLatency + (1000*frameCount) / mSampleRate; Loading @@ -1255,6 +1318,7 @@ status_t AudioTrack::createTrack_l() mProxy->setSendLevel(mSendLevel); mProxy->setSendLevel(mSendLevel); mProxy->setSampleRate(mSampleRate); mProxy->setSampleRate(mSampleRate); mProxy->setPlaybackRate(mSpeed, mPitch); mProxy->setMinimum(mNotificationFramesAct); mProxy->setMinimum(mNotificationFramesAct); mDeathNotifier = new DeathNotifier(this); mDeathNotifier = new DeathNotifier(this); Loading Loading @@ -1617,6 +1681,7 @@ nsecs_t AudioTrack::processAudioBuffer() // Cache other fields that will be needed soon // Cache other fields that will be needed soon uint32_t sampleRate = mSampleRate; uint32_t sampleRate = mSampleRate; float speed = mSpeed; uint32_t notificationFrames = mNotificationFramesAct; uint32_t notificationFrames = mNotificationFramesAct; if (mRefreshRemaining) { if (mRefreshRemaining) { mRefreshRemaining = false; mRefreshRemaining = false; Loading Loading @@ -1745,7 +1810,7 @@ nsecs_t AudioTrack::processAudioBuffer() if (minFrames != (uint32_t) ~0) { if (minFrames != (uint32_t) ~0) { // This "fudge factor" avoids soaking CPU, and compensates for late progress by server // This "fudge factor" avoids soaking CPU, and compensates for late progress by server static const nsecs_t kFudgeNs = 10000000LL; // 10 ms static const nsecs_t kFudgeNs = 10000000LL; // 10 ms ns = ((minFrames * 1000000000LL) / sampleRate) + kFudgeNs; ns = ((double)minFrames * 1000000000) / ((double)sampleRate * speed) + kFudgeNs; } } // If not supplying data by EVENT_MORE_DATA, then we're done // If not supplying data by EVENT_MORE_DATA, then we're done Loading Loading @@ -1786,7 +1851,8 @@ nsecs_t AudioTrack::processAudioBuffer() if (mRetryOnPartialBuffer && !isOffloaded()) { if (mRetryOnPartialBuffer && !isOffloaded()) { mRetryOnPartialBuffer = false; mRetryOnPartialBuffer = false; if (avail < mRemainingFrames) { if (avail < mRemainingFrames) { int64_t myns = ((mRemainingFrames - avail) * 1100000000LL) / sampleRate; int64_t myns = ((double)(mRemainingFrames - avail) * 1100000000) / ((double)sampleRate * speed); if (ns < 0 || myns < ns) { if (ns < 0 || myns < ns) { ns = myns; ns = myns; } } Loading Loading @@ -1841,7 +1907,7 @@ nsecs_t AudioTrack::processAudioBuffer() // that total to a sum == notificationFrames. // that total to a sum == notificationFrames. if (0 < misalignment && misalignment <= mRemainingFrames) { if (0 < misalignment && misalignment <= mRemainingFrames) { mRemainingFrames = misalignment; mRemainingFrames = misalignment; return (mRemainingFrames * 1100000000LL) / sampleRate; return ((double)mRemainingFrames * 1100000000) / ((double)sampleRate * speed); } } #endif #endif Loading Loading @@ -1936,6 +2002,41 @@ uint32_t AudioTrack::updateAndGetPosition_l() return mPosition += (uint32_t) delta; return mPosition += (uint32_t) delta; } } bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const { // applicable for mixing tracks only (not offloaded or direct) if (mStaticProxy != 0) { return true; // static tracks do not have issues with buffer sizing. } status_t status; uint32_t afLatency; status = AudioSystem::getLatency(mOutput, &afLatency); if (status != NO_ERROR) { ALOGE("getLatency(%d) failed status %d", mOutput, status); return false; } size_t afFrameCount; status = AudioSystem::getFrameCount(mOutput, &afFrameCount); if (status != NO_ERROR) { ALOGE("getFrameCount(output=%d) status %d", mOutput, status); return false; } uint32_t afSampleRate; status = AudioSystem::getSamplingRate(mOutput, &afSampleRate); if (status != NO_ERROR) { ALOGE("getSamplingRate(output=%d) status %d", mOutput, status); return false; } const size_t minFrameCount = calculateMinFrameCount(afLatency, afFrameCount, afSampleRate, sampleRate, speed); ALOGV("isSampleRateSpeedAllowed_l mFrameCount %zu minFrameCount %zu", mFrameCount, minFrameCount); return mFrameCount >= minFrameCount; } status_t AudioTrack::setParameters(const String8& keyValuePairs) status_t AudioTrack::setParameters(const String8& keyValuePairs) { { AutoMutex lock(mLock); AutoMutex lock(mLock); Loading Loading @@ -2001,7 +2102,8 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) return WOULD_BLOCK; // stale timestamp time, occurs before start. return WOULD_BLOCK; // stale timestamp time, occurs before start. } } const int64_t deltaTimeUs = timestampTimeUs - mStartUs; const int64_t deltaTimeUs = timestampTimeUs - mStartUs; const int64_t deltaPositionByUs = timestamp.mPosition * 1000000LL / mSampleRate; const int64_t deltaPositionByUs = (double)timestamp.mPosition * 1000000 / ((double)mSampleRate * mSpeed); if (deltaPositionByUs > deltaTimeUs + kTimeJitterUs) { if (deltaPositionByUs > deltaTimeUs + kTimeJitterUs) { // Verify that the counter can't count faster than the sample rate // Verify that the counter can't count faster than the sample rate Loading Loading @@ -2088,7 +2190,8 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args __unused) const snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%zu)\n", mFormat, snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%zu)\n", mFormat, mChannelCount, mFrameCount); mChannelCount, mFrameCount); result.append(buffer); result.append(buffer); snprintf(buffer, 255, " sample rate(%u), status(%d)\n", mSampleRate, mStatus); snprintf(buffer, 255, " sample rate(%u), speed(%f), status(%d)\n", mSampleRate, mSpeed, mStatus); result.append(buffer); result.append(buffer); snprintf(buffer, 255, " state(%d), latency (%d)\n", mState, mLatency); snprintf(buffer, 255, " state(%d), latency (%d)\n", mState, mLatency); result.append(buffer); result.append(buffer); Loading
media/libmedia/AudioTrackShared.cpp +10 −0 Original line number Original line Diff line number Diff line Loading @@ -793,6 +793,16 @@ void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount) (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags); (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags); } } void AudioTrackServerProxy::getPlaybackRate(float *speed, float *pitch) { // do not call from multiple threads without holding lock AudioTrackPlaybackRate playbackRate; if (mPlaybackRateObserver.poll(playbackRate)) { mPlaybackRate = playbackRate; } *speed = mPlaybackRate.mSpeed; *pitch = mPlaybackRate.mPitch; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, Loading