diff options
Diffstat (limited to 'media/libmedia/AudioTrack.cpp')
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 189 |
1 files changed, 116 insertions, 73 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 7b9eda7..b147d25 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -54,7 +54,7 @@ AudioTrack::AudioTrack( int streamType, uint32_t sampleRate, int format, - int channelCount, + int channels, int frameCount, uint32_t flags, callback_t cbf, @@ -62,7 +62,7 @@ AudioTrack::AudioTrack( int notificationFrames) : mStatus(NO_INIT) { - mStatus = set(streamType, sampleRate, format, channelCount, + mStatus = set(streamType, sampleRate, format, channels, frameCount, flags, cbf, user, notificationFrames, 0); } @@ -70,7 +70,7 @@ AudioTrack::AudioTrack( int streamType, uint32_t sampleRate, int format, - int channelCount, + int channels, const sp<IMemory>& sharedBuffer, uint32_t flags, callback_t cbf, @@ -78,7 +78,7 @@ AudioTrack::AudioTrack( int notificationFrames) : mStatus(NO_INIT) { - mStatus = set(streamType, sampleRate, format, channelCount, + mStatus = set(streamType, sampleRate, format, channels, 0, flags, cbf, user, notificationFrames, sharedBuffer); } @@ -97,6 +97,7 @@ AudioTrack::~AudioTrack() } mAudioTrack.clear(); IPCThreadState::self()->flushCommands(); + AudioSystem::releaseOutput(getOutput()); } } @@ -104,7 +105,7 @@ status_t AudioTrack::set( int streamType, uint32_t sampleRate, int format, - int channelCount, + int channels, int frameCount, uint32_t flags, callback_t cbf, @@ -150,63 +151,84 @@ status_t AudioTrack::set( if (format == 0) { format = AudioSystem::PCM_16_BIT; } - if (channelCount == 0) { - channelCount = 2; + if (channels == 0) { + channels = AudioSystem::CHANNEL_OUT_STEREO; } // validate parameters - if (((format != AudioSystem::PCM_8_BIT) || sharedBuffer != 0) && - (format != AudioSystem::PCM_16_BIT)) { + if (!AudioSystem::isValidFormat(format)) { LOGE("Invalid format"); return BAD_VALUE; } - if (channelCount != 1 && channelCount != 2) { - LOGE("Invalid channel number"); + + // force direct flag if format is not linear PCM + if (!AudioSystem::isLinearPCM(format)) { + flags |= AudioSystem::OUTPUT_FLAG_DIRECT; + } + + if (!AudioSystem::isOutputChannel(channels)) { + LOGE("Invalid channel mask"); return BAD_VALUE; } + uint32_t channelCount = AudioSystem::popCount(channels); - // Ensure that buffer depth covers at least audio hardware latency - uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate); - if (minBufCount < 2) minBufCount = 2; + audio_io_handle_t output = AudioSystem::getOutput((AudioSystem::stream_type)streamType, + sampleRate, format, channels, (AudioSystem::output_flags)flags); - // When playing from shared buffer, playback will start even if last audioflinger - // block is partly filled. - if (sharedBuffer != 0 && minBufCount > 1) { - minBufCount--; + if (output == 0) { + LOGE("Could not get audio output for stream type %d", streamType); + return BAD_VALUE; } - int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate; - - if (sharedBuffer == 0) { - if (frameCount == 0) { - frameCount = minFrameCount; - } - if (notificationFrames == 0) { - notificationFrames = frameCount/2; - } - // Make sure that application is notified with sufficient margin - // before underrun - if (notificationFrames > frameCount/2) { - notificationFrames = frameCount/2; + if (!AudioSystem::isLinearPCM(format)) { + if (sharedBuffer != 0) { + frameCount = sharedBuffer->size(); } } else { - // Ensure that buffer alignment matches channelcount - if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) { - LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount); - return BAD_VALUE; - } - frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t); - } + // Ensure that buffer depth covers at least audio hardware latency + uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate); + if (minBufCount < 2) minBufCount = 2; - if (frameCount < minFrameCount) { - LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount); - return BAD_VALUE; + int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate; + + if (sharedBuffer == 0) { + if (frameCount == 0) { + frameCount = minFrameCount; + } + if (notificationFrames == 0) { + notificationFrames = frameCount/2; + } + // Make sure that application is notified with sufficient margin + // before underrun + if (notificationFrames > frameCount/2) { + notificationFrames = frameCount/2; + } + if (frameCount < minFrameCount) { + LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount); + return BAD_VALUE; + } + } else { + // Ensure that buffer alignment matches channelcount + if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) { + LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount); + return BAD_VALUE; + } + frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t); + } } // create the track status_t status; sp<IAudioTrack> track = audioFlinger->createTrack(getpid(), - streamType, sampleRate, format, channelCount, frameCount, flags, sharedBuffer, &status); + streamType, + sampleRate, + format, + channelCount, + frameCount, + ((uint16_t)flags) << 16, + sharedBuffer, + output, + &status); if (track == 0) { LOGE("AudioFlinger could not create track, status: %d", status); @@ -245,6 +267,7 @@ status_t AudioTrack::set( mVolume[RIGHT] = 1.0f; mStreamType = streamType; mFormat = format; + mChannels = channels; mChannelCount = channelCount; mSharedBuffer = sharedBuffer; mMuted = false; @@ -259,6 +282,7 @@ status_t AudioTrack::set( mMarkerReached = false; mNewPosition = 0; mUpdatePeriod = 0; + mFlags = flags; return NO_ERROR; } @@ -297,7 +321,11 @@ uint32_t AudioTrack::frameCount() const int AudioTrack::frameSize() const { - return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t)); + if (AudioSystem::isLinearPCM(mFormat)) { + return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t)); + } else { + return sizeof(uint8_t); + } } sp<IMemory>& AudioTrack::sharedBuffer() @@ -323,6 +351,7 @@ void AudioTrack::start() } if (android_atomic_or(1, &mActive) == 0) { + AudioSystem::startOutput(getOutput(), (AudioSystem::stream_type)mStreamType); mNewPosition = mCblk->server + mUpdatePeriod; mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; mCblk->waitTimeMs = 0; @@ -367,6 +396,7 @@ void AudioTrack::stop() } else { setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); } + AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType); } if (t != 0) { @@ -382,12 +412,12 @@ bool AudioTrack::stopped() const void AudioTrack::flush() { LOGV("flush"); - + // clear playback marker and periodic update counter mMarkerPosition = 0; mMarkerReached = false; mUpdatePeriod = 0; - + if (!mActive) { mAudioTrack->flush(); @@ -403,6 +433,7 @@ void AudioTrack::pause() if (android_atomic_and(~1, &mActive) == 1) { mActive = 0; mAudioTrack->pause(); + AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType); } } @@ -455,7 +486,6 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount { audio_track_cblk_t* cblk = mCblk; - Mutex::Autolock _l(cblk->lock); if (loopCount == 0) { @@ -476,7 +506,7 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d", loopStart, loopEnd, mFrameCount); return BAD_VALUE; - } + } cblk->loopStart = loopStart; cblk->loopEnd = loopEnd; @@ -555,7 +585,7 @@ status_t AudioTrack::setPosition(uint32_t position) mCblk->server = position; mCblk->forceReady = 1; - + return NO_ERROR; } @@ -571,7 +601,7 @@ status_t AudioTrack::getPosition(uint32_t *position) status_t AudioTrack::reload() { if (!stopped()) return INVALID_OPERATION; - + flush(); mCblk->stepUser(mFrameCount); @@ -579,6 +609,12 @@ status_t AudioTrack::reload() return NO_ERROR; } +audio_io_handle_t AudioTrack::getOutput() +{ + return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType, + mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags); +} + // ------------------------------------------------------------------------- status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) @@ -608,7 +644,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) return WOULD_BLOCK; timeout = 0; result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); - if (__builtin_expect(result!=NO_ERROR, false)) { + if (__builtin_expect(result!=NO_ERROR, false)) { cblk->waitTimeMs += waitTimeMs; if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) { // timing out when a loop has been set and we have already written upto loop end @@ -616,7 +652,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) if (cblk->user < cblk->loopEnd) { LOGW( "obtainBuffer timed out (is the CPU pegged?) %p " "user=%08x, server=%08x", this, cblk->user, cblk->server); - //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140) + //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140) cblk->lock.unlock(); mAudioTrack->start(); cblk->lock.lock(); @@ -624,7 +660,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) } cblk->waitTimeMs = 0; } - + if (--waitCount == 0) { return TIMED_OUT; } @@ -636,7 +672,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) } cblk->waitTimeMs = 0; - + if (framesReq > framesAvail) { framesReq = framesAvail; } @@ -653,12 +689,16 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) "but didn't need to be locked. We recovered, but " "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server); - audioBuffer->flags = mMuted ? Buffer::MUTE : 0; - audioBuffer->channelCount= mChannelCount; - audioBuffer->format = AudioSystem::PCM_16_BIT; - audioBuffer->frameCount = framesReq; - audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t); - audioBuffer->raw = (int8_t *)cblk->buffer(u); + audioBuffer->flags = mMuted ? Buffer::MUTE : 0; + audioBuffer->channelCount = mChannelCount; + audioBuffer->frameCount = framesReq; + audioBuffer->size = framesReq * cblk->frameSize; + if (AudioSystem::isLinearPCM(mFormat)) { + audioBuffer->format = AudioSystem::PCM_16_BIT; + } else { + audioBuffer->format = mFormat; + } + audioBuffer->raw = (int8_t *)cblk->buffer(u); active = mActive; return active ? status_t(NO_ERROR) : status_t(STOPPED); } @@ -690,10 +730,8 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) Buffer audioBuffer; do { - audioBuffer.frameCount = userSize/mChannelCount; - if (mFormat == AudioSystem::PCM_16_BIT) { - audioBuffer.frameCount >>= 1; - } + audioBuffer.frameCount = userSize/frameSize(); + // Calling obtainBuffer() with a negative wait count causes // an (almost) infinite wait time. status_t err = obtainBuffer(&audioBuffer, -1); @@ -705,6 +743,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) } size_t toWrite; + if (mFormat == AudioSystem::PCM_8_BIT) { // Divide capacity by 2 to take expansion into account toWrite = audioBuffer.size>>1; @@ -742,13 +781,13 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) if (mCblk->flowControlFlag == 0) { mCbf(EVENT_UNDERRUN, mUserData, 0); if (mCblk->server == mCblk->frameCount) { - mCbf(EVENT_BUFFER_END, mUserData, 0); + mCbf(EVENT_BUFFER_END, mUserData, 0); } mCblk->flowControlFlag = 1; if (mSharedBuffer != 0) return false; } } - + // Manage loop end callback while (mLoopCount > mCblk->loopCount) { int loopCount = -1; @@ -767,7 +806,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) } // Manage new position callback - if(mUpdatePeriod > 0) { + if (mUpdatePeriod > 0) { while (mCblk->server >= mNewPosition) { mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition); mNewPosition += mUpdatePeriod; @@ -784,10 +823,10 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) do { audioBuffer.frameCount = frames; - - // Calling obtainBuffer() with a wait count of 1 - // limits wait time to WAIT_PERIOD_MS. This prevents from being - // stuck here not being able to handle timed events (position, markers, loops). + + // Calling obtainBuffer() with a wait count of 1 + // limits wait time to WAIT_PERIOD_MS. This prevents from being + // stuck here not being able to handle timed events (position, markers, loops). status_t err = obtainBuffer(&audioBuffer, 1); if (err < NO_ERROR) { if (err != TIMED_OUT) { @@ -832,7 +871,11 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) } audioBuffer.size = writtenSize; - audioBuffer.frameCount = writtenSize/mChannelCount/sizeof(int16_t); + // NOTE: mCblk->frameSize is not equal to AudioTrack::frameSize() for + // 8 bit PCM data: in this case, mCblk->frameSize is based on a sampel size of + // 16 bit. + audioBuffer.frameCount = writtenSize/mCblk->frameSize; + frames -= audioBuffer.frameCount; releaseBuffer(&audioBuffer); @@ -949,7 +992,7 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount) // we switch to normal obtainBuffer() timeout period if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) { bufferTimeoutMs = MAX_RUN_TIMEOUT_MS - 1; - } + } // It is possible that we receive a flush() // while the mixer is processing a block: in this case, // stepServer() is called After the flush() has reset u & s and @@ -981,7 +1024,7 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount) void* audio_track_cblk_t::buffer(uint32_t offset) const { - return (int16_t *)this->buffers + (offset-userBase)*this->channels; + return (int8_t *)this->buffers + (offset - userBase) * this->frameSize; } uint32_t audio_track_cblk_t::framesAvailable() |