diff options
Diffstat (limited to 'media/libmedia/AudioTrack.cpp')
| -rw-r--r-- | media/libmedia/AudioTrack.cpp | 157 |
1 files changed, 98 insertions, 59 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 8d8f67b..7520ed9 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -35,6 +35,12 @@ #include <binder/Parcel.h> #include <binder/IPCThreadState.h> #include <utils/Timers.h> +#include <utils/Atomic.h> + +#include <cutils/bitops.h> + +#include <system/audio.h> +#include <hardware/audio_policy.h> #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) @@ -164,39 +170,41 @@ status_t AudioTrack::set( } // handle default values first. - if (streamType == AudioSystem::DEFAULT) { - streamType = AudioSystem::MUSIC; + if (streamType == AUDIO_STREAM_DEFAULT) { + streamType = AUDIO_STREAM_MUSIC; } if (sampleRate == 0) { sampleRate = afSampleRate; } // these below should probably come from the audioFlinger too... if (format == 0) { - format = AudioSystem::PCM_16_BIT; + format = AUDIO_FORMAT_PCM_16_BIT; } if (channels == 0) { - channels = AudioSystem::CHANNEL_OUT_STEREO; + channels = AUDIO_CHANNEL_OUT_STEREO; } // validate parameters - if (!AudioSystem::isValidFormat(format)) { + if (!audio_is_valid_format(format)) { LOGE("Invalid format"); return BAD_VALUE; } // force direct flag if format is not linear PCM - if (!AudioSystem::isLinearPCM(format)) { - flags |= AudioSystem::OUTPUT_FLAG_DIRECT; + if (!audio_is_linear_pcm(format)) { + flags |= AUDIO_POLICY_OUTPUT_FLAG_DIRECT; } - if (!AudioSystem::isOutputChannel(channels)) { + if (!audio_is_output_channel(channels)) { LOGE("Invalid channel mask"); return BAD_VALUE; } - uint32_t channelCount = AudioSystem::popCount(channels); + uint32_t channelCount = popcount(channels); - audio_io_handle_t output = AudioSystem::getOutput((AudioSystem::stream_type)streamType, - sampleRate, format, channels, (AudioSystem::output_flags)flags); + audio_io_handle_t output = AudioSystem::getOutput( + (audio_stream_type_t)streamType, + sampleRate,format, channels, + (audio_policy_output_flags_t)flags); if (output == 0) { LOGE("Could not get audio output for stream type %d", streamType); @@ -289,8 +297,8 @@ uint32_t AudioTrack::frameCount() const int AudioTrack::frameSize() const { - if (AudioSystem::isLinearPCM(mFormat)) { - return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t)); + if (audio_is_linear_pcm(mFormat)) { + return channelCount()*((format() == AUDIO_FORMAT_PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t)); } else { return sizeof(uint8_t); } @@ -329,9 +337,10 @@ void AudioTrack::start() if (mActive == 0) { mActive = 1; mNewPosition = cblk->server + mUpdatePeriod; + cblk->lock.lock(); cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; cblk->waitTimeMs = 0; - cblk->flags &= ~CBLK_DISABLED_ON; + android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); if (t != 0) { t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT); } else { @@ -339,13 +348,12 @@ void AudioTrack::start() } LOGV("start %p before lock cblk %p", this, mCblk); - cblk->lock.lock(); if (!(cblk->flags & CBLK_INVALID_MSK)) { cblk->lock.unlock(); status = mAudioTrack->start(); cblk->lock.lock(); if (status == DEAD_OBJECT) { - cblk->flags |= CBLK_INVALID_MSK; + android_atomic_or(CBLK_INVALID_ON, &cblk->flags); } } if (cblk->flags & CBLK_INVALID_MSK) { @@ -546,12 +554,13 @@ status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCou } if (loopStart >= loopEnd || - loopEnd - loopStart > cblk->frameCount) { + loopEnd - loopStart > cblk->frameCount || + cblk->server > loopStart) { LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, cblk->frameCount, cblk->user); return BAD_VALUE; } - if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) { + if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) { LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d", loopStart, loopEnd, cblk->frameCount); return BAD_VALUE; @@ -635,7 +644,7 @@ status_t AudioTrack::setPosition(uint32_t position) if (position > mCblk->user) return BAD_VALUE; mCblk->server = position; - mCblk->flags |= CBLK_FORCEREADY_ON; + android_atomic_or(CBLK_FORCEREADY_ON, &mCblk->flags); return NO_ERROR; } @@ -671,8 +680,8 @@ audio_io_handle_t AudioTrack::getOutput() // must be called with mLock held audio_io_handle_t AudioTrack::getOutput_l() { - return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType, - mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags); + return AudioSystem::getOutput((audio_stream_type_t)mStreamType, + mCblk->sampleRate, mFormat, mChannels, (audio_policy_output_flags_t)mFlags); } int AudioTrack::getSessionId() @@ -725,7 +734,7 @@ status_t AudioTrack::createTrack_l( } mNotificationFramesAct = mNotificationFramesReq; - if (!AudioSystem::isLinearPCM(format)) { + if (!audio_is_linear_pcm(format)) { if (sharedBuffer != 0) { frameCount = sharedBuffer->size(); } @@ -792,7 +801,7 @@ status_t AudioTrack::createTrack_l( mCblkMemory.clear(); mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); - mCblk->flags |= CBLK_DIRECTION_OUT; + android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags); if (sharedBuffer == 0) { mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); } else { @@ -825,6 +834,12 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) uint32_t framesAvail = cblk->framesAvailable(); + cblk->lock.lock(); + if (cblk->flags & CBLK_INVALID_MSK) { + goto create_new_track; + } + cblk->lock.unlock(); + if (framesAvail == 0) { cblk->lock.lock(); goto start_loop_here; @@ -866,7 +881,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) result = mAudioTrack->start(); cblk->lock.lock(); if (result == DEAD_OBJECT) { - cblk->flags |= CBLK_INVALID_MSK; + android_atomic_or(CBLK_INVALID_ON, &cblk->flags); create_new_track: result = restoreTrack_l(cblk, false); } @@ -893,7 +908,7 @@ create_new_track: // restart track if it was disabled by audioflinger due to previous underrun if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) { - cblk->flags &= ~CBLK_DISABLED_ON; + android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); LOGW("obtainBuffer() track %p disabled, restarting", this); mAudioTrack->start(); } @@ -915,8 +930,8 @@ create_new_track: audioBuffer->channelCount = mChannelCount; audioBuffer->frameCount = framesReq; audioBuffer->size = framesReq * cblk->frameSize; - if (AudioSystem::isLinearPCM(mFormat)) { - audioBuffer->format = AudioSystem::PCM_16_BIT; + if (audio_is_linear_pcm(mFormat)) { + audioBuffer->format = AUDIO_FORMAT_PCM_16_BIT; } else { audioBuffer->format = mFormat; } @@ -957,9 +972,10 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) ssize_t written = 0; const int8_t *src = (const int8_t *)buffer; Buffer audioBuffer; + size_t frameSz = (size_t)frameSize(); do { - audioBuffer.frameCount = userSize/frameSize(); + audioBuffer.frameCount = userSize/frameSz; // Calling obtainBuffer() with a negative wait count causes // an (almost) infinite wait time. @@ -973,7 +989,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) size_t toWrite; - if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) { + if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT)) { // Divide capacity by 2 to take expansion into account toWrite = audioBuffer.size>>1; // 8 to 16 bit conversion @@ -991,7 +1007,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) written += toWrite; releaseBuffer(&audioBuffer); - } while (userSize); + } while (userSize >= frameSz); return written; } @@ -1013,14 +1029,13 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) mLock.unlock(); // Manage underrun callback - if (mActive && (cblk->framesReady() == 0)) { + if (mActive && (cblk->framesAvailable() == cblk->frameCount)) { LOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); - if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { + if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) { mCbf(EVENT_UNDERRUN, mUserData, 0); if (cblk->server == cblk->frameCount) { mCbf(EVENT_BUFFER_END, mUserData, 0); } - cblk->flags |= CBLK_UNDERRUN_ON; if (mSharedBuffer != 0) return false; } } @@ -1077,7 +1092,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) // Divide buffer size by 2 to take into account the expansion // due to 8 to 16 bit conversion: the callback must fill only half // of the destination buffer - if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) { + if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT)) { audioBuffer.size >>= 1; } @@ -1096,7 +1111,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) } if (writtenSize > reqSize) writtenSize = reqSize; - if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) { + if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT)) { // 8 to 16 bit conversion const int8_t *src = audioBuffer.i8 + writtenSize-1; int count = writtenSize; @@ -1134,11 +1149,10 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) { status_t result; - if (!(cblk->flags & CBLK_RESTORING_MSK)) { + if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) { LOGW("dead IAudioTrack, creating a new one from %s", fromStart ? "start()" : "obtainBuffer()"); - cblk->flags |= CBLK_RESTORING_ON; // signal old cblk condition so that other threads waiting for available buffers stop // waiting now cblk->cv.broadcast(); @@ -1158,10 +1172,20 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) false); if (result == NO_ERROR) { + // restore write index and set other indexes to reflect empty buffer status + mCblk->user = cblk->user; + mCblk->server = cblk->user; + mCblk->userBase = cblk->user; + mCblk->serverBase = cblk->user; + // restore loop: this is not guaranteed to succeed if new frame count is not + // compatible with loop length + setLoop_l(cblk->loopStart, cblk->loopEnd, cblk->loopCount); if (!fromStart) { mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; } - result = mAudioTrack->start(); + if (mActive) { + result = mAudioTrack->start(); + } if (fromStart && result == NO_ERROR) { mNewPosition = mCblk->server + mUpdatePeriod; } @@ -1171,10 +1195,8 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) } // signal old cblk condition for other threads waiting for restore completion - cblk->lock.lock(); - cblk->flags |= CBLK_RESTORED_MSK; + android_atomic_or(CBLK_RESTORED_ON, &cblk->flags); cblk->cv.broadcast(); - cblk->lock.unlock(); } else { if (!(cblk->flags & CBLK_RESTORED_MSK)) { LOGW("dead IAudioTrack, waiting for a new one"); @@ -1248,11 +1270,12 @@ void AudioTrack::AudioTrackThread::onFirstRef() // ========================================================================= + audio_track_cblk_t::audio_track_cblk_t() : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0), loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), - flags(0), sendLevel(0) + sendLevel(0), flags(0) { } @@ -1279,25 +1302,17 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) this->user = u; // Clear flow control error condition as new data has been written/read to/from buffer. - flags &= ~CBLK_UNDERRUN_MSK; + if (flags & CBLK_UNDERRUN_MSK) { + android_atomic_and(~CBLK_UNDERRUN_MSK, &flags); + } return u; } bool audio_track_cblk_t::stepServer(uint32_t frameCount) { - // the code below simulates lock-with-timeout - // we MUST do this to protect the AudioFlinger server - // as this lock is shared with the client. - status_t err; - - err = lock.tryLock(); - if (err == -EBUSY) { // just wait a bit - usleep(1000); - err = lock.tryLock(); - } - if (err != NO_ERROR) { - // probably, the client just died. + if (!tryLock()) { + LOGW("stepServer() could not lock cblk"); return false; } @@ -1374,18 +1389,42 @@ uint32_t audio_track_cblk_t::framesReady() if (u < loopEnd) { return u - s; } else { - Mutex::Autolock _l(lock); + // do not block on mutex shared with client on AudioFlinger side + if (!tryLock()) { + LOGW("framesReady() could not lock cblk"); + return 0; + } + uint32_t frames = UINT_MAX; if (loopCount >= 0) { - return (loopEnd - loopStart)*loopCount + u - s; - } else { - return UINT_MAX; + frames = (loopEnd - loopStart)*loopCount + u - s; } + lock.unlock(); + return frames; } } else { return s - u; } } +bool audio_track_cblk_t::tryLock() +{ + // the code below simulates lock-with-timeout + // we MUST do this to protect the AudioFlinger server + // as this lock is shared with the client. + status_t err; + + err = lock.tryLock(); + if (err == -EBUSY) { // just wait a bit + usleep(1000); + err = lock.tryLock(); + } + if (err != NO_ERROR) { + // probably, the client just died. + return false; + } + return true; +} + // ------------------------------------------------------------------------- }; // namespace android |
