diff options
Diffstat (limited to 'media/libmedia')
28 files changed, 2193 insertions, 797 deletions
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 54666fb..2c0c3a5 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -13,15 +13,19 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ AudioTrack.cpp \ + AudioTrackShared.cpp \ IAudioFlinger.cpp \ IAudioFlingerClient.cpp \ IAudioTrack.cpp \ IAudioRecord.cpp \ ICrypto.cpp \ + IDrm.cpp \ + IDrmClient.cpp \ IHDCP.cpp \ AudioRecord.cpp \ AudioSystem.cpp \ mediaplayer.cpp \ + IMediaLogService.cpp \ IMediaPlayerService.cpp \ IMediaPlayerClient.cpp \ IMediaRecorderClient.cpp \ @@ -51,10 +55,17 @@ LOCAL_SRC_FILES:= \ SoundPool.cpp \ SoundPoolThread.cpp +LOCAL_SRC_FILES += ../libnbaio/roundup.c + +# for <cutils/atomic-inline.h> +LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0) +LOCAL_SRC_FILES += SingleStateQueue.cpp +LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"' + LOCAL_SHARED_LIBRARIES := \ - libui libcutils libutils libbinder libsonivox libicuuc libexpat \ + libui liblog libcutils libutils libbinder libsonivox libicuuc libexpat \ libcamera_client libstagefright_foundation \ - libgui libdl libaudioutils libmedia_native + libgui libdl libaudioutils LOCAL_WHOLE_STATIC_LIBRARY := libmedia_helper diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp index 680604b..8dfffb3 100644 --- a/media/libmedia/AudioEffect.cpp +++ b/media/libmedia/AudioEffect.cpp @@ -127,7 +127,7 @@ status_t AudioEffect::set(const effect_uuid_t *type, mIEffectClient = new EffectClient(this); - iEffect = audioFlinger->createEffect(getpid(), &mDescriptor, + iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor, mIEffectClient, priority, io, mSessionId, &mStatus, &mId, &enabled); if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) { @@ -152,7 +152,8 @@ status_t AudioEffect::set(const effect_uuid_t *type, mCblk->buffer = (uint8_t *)mCblk + bufOffset; iEffect->asBinder()->linkToDeath(mIEffectClient); - ALOGV("set() %p OK effect: %s id: %d status %d enabled %d", this, mDescriptor.name, mId, mStatus, mEnabled); + ALOGV("set() %p OK effect: %s id: %d status %d enabled %d", this, mDescriptor.name, mId, + mStatus, mEnabled); return mStatus; } @@ -266,9 +267,11 @@ status_t AudioEffect::setParameter(effect_param_t *param) uint32_t size = sizeof(int); uint32_t psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize; - ALOGV("setParameter: param: %d, param2: %d", *(int *)param->data, (param->psize == 8) ? *((int *)param->data + 1): -1); + ALOGV("setParameter: param: %d, param2: %d", *(int *)param->data, + (param->psize == 8) ? *((int *)param->data + 1): -1); - return mIEffect->command(EFFECT_CMD_SET_PARAM, sizeof (effect_param_t) + psize, param, &size, ¶m->status); + return mIEffect->command(EFFECT_CMD_SET_PARAM, sizeof (effect_param_t) + psize, param, &size, + ¶m->status); } status_t AudioEffect::setParameterDeferred(effect_param_t *param) @@ -321,11 +324,14 @@ status_t AudioEffect::getParameter(effect_param_t *param) return BAD_VALUE; } - ALOGV("getParameter: param: %d, param2: %d", *(int *)param->data, (param->psize == 8) ? *((int *)param->data + 1): -1); + ALOGV("getParameter: param: %d, param2: %d", *(int *)param->data, + (param->psize == 8) ? *((int *)param->data + 1): -1); - uint32_t psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize; + uint32_t psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + + param->vsize; - return mIEffect->command(EFFECT_CMD_GET_PARAM, sizeof(effect_param_t) + param->psize, param, &psize, param); + return mIEffect->command(EFFECT_CMD_GET_PARAM, sizeof(effect_param_t) + param->psize, param, + &psize, param); } @@ -346,7 +352,8 @@ void AudioEffect::binderDied() void AudioEffect::controlStatusChanged(bool controlGranted) { - ALOGV("controlStatusChanged %p control %d callback %p mUserData %p", this, controlGranted, mCbf, mUserData); + ALOGV("controlStatusChanged %p control %d callback %p mUserData %p", this, controlGranted, mCbf, + mUserData); if (controlGranted) { if (mStatus == ALREADY_EXISTS) { mStatus = NO_ERROR; diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 8ea6306..40ff1bf 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -36,7 +36,7 @@ namespace android { // static status_t AudioRecord::getMinFrameCount( - int* frameCount, + size_t* frameCount, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask) @@ -47,14 +47,14 @@ status_t AudioRecord::getMinFrameCount( *frameCount = 0; size_t size = 0; - if (AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size) - != NO_ERROR) { - ALOGE("AudioSystem could not query the input buffer size."); + status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size); + if (status != NO_ERROR) { + ALOGE("AudioSystem could not query the input buffer size; status %d", status); return NO_INIT; } if (size == 0) { - ALOGE("Unsupported configuration: sampleRate %d, format %d, channelMask %#x", + ALOGE("Unsupported configuration: sampleRate %u, format %d, channelMask %#x", sampleRate, format, channelMask); return BAD_VALUE; } @@ -63,7 +63,7 @@ status_t AudioRecord::getMinFrameCount( size <<= 1; if (audio_is_linear_pcm(format)) { - int channelCount = popcount(channelMask); + uint32_t channelCount = popcount(channelMask); size /= channelCount * audio_bytes_per_sample(format); } @@ -75,7 +75,8 @@ status_t AudioRecord::getMinFrameCount( AudioRecord::AudioRecord() : mStatus(NO_INIT), mSessionId(0), - mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT) + mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), + mProxy(NULL) { } @@ -90,10 +91,12 @@ AudioRecord::AudioRecord( int notificationFrames, int sessionId) : mStatus(NO_INIT), mSessionId(0), - mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT) + mPreviousPriority(ANDROID_PRIORITY_NORMAL), + mPreviousSchedulingGroup(SP_DEFAULT), + mProxy(NULL) { mStatus = set(inputSource, sampleRate, format, channelMask, - frameCount, cbf, user, notificationFrames, sessionId); + frameCount, cbf, user, notificationFrames, false /*threadCanCallJava*/, sessionId); } AudioRecord::~AudioRecord() @@ -112,6 +115,7 @@ AudioRecord::~AudioRecord() IPCThreadState::self()->flushCommands(); AudioSystem::releaseAudioSessionId(mSessionId); } + delete mProxy; } status_t AudioRecord::set( @@ -119,15 +123,22 @@ status_t AudioRecord::set( uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - int frameCount, + int frameCountInt, callback_t cbf, void* user, int notificationFrames, bool threadCanCallJava, int sessionId) { + // FIXME "int" here is legacy and will be replaced by size_t later + if (frameCountInt < 0) { + ALOGE("Invalid frame count %d", frameCountInt); + return BAD_VALUE; + } + size_t frameCount = frameCountInt; - ALOGV("set(): sampleRate %d, channelMask %#x, frameCount %d",sampleRate, channelMask, frameCount); + ALOGV("set(): sampleRate %u, channelMask %#x, frameCount %u", sampleRate, channelMask, + frameCount); AutoMutex lock(mLock); @@ -142,6 +153,8 @@ status_t AudioRecord::set( if (sampleRate == 0) { sampleRate = DEFAULT_SAMPLE_RATE; } + mSampleRate = sampleRate; + // these below should probably come from the audioFlinger too... if (format == AUDIO_FORMAT_DEFAULT) { format = AUDIO_FORMAT_PCM_16_BIT; @@ -151,12 +164,20 @@ status_t AudioRecord::set( ALOGE("Invalid format"); return BAD_VALUE; } + mFormat = format; if (!audio_is_input_channel(channelMask)) { return BAD_VALUE; } + mChannelMask = channelMask; + uint32_t channelCount = popcount(channelMask); + mChannelCount = channelCount; - int channelCount = popcount(channelMask); + if (audio_is_linear_pcm(format)) { + mFrameSize = channelCount * audio_bytes_per_sample(format); + } else { + mFrameSize = sizeof(uint8_t); + } if (sessionId == 0 ) { mSessionId = AudioSystem::newAudioSessionId(); @@ -176,7 +197,7 @@ status_t AudioRecord::set( } // validate framecount - int minFrameCount = 0; + size_t minFrameCount = 0; status_t status = getMinFrameCount(&minFrameCount, sampleRate, format, channelMask); if (status != NO_ERROR) { return status; @@ -194,8 +215,7 @@ status_t AudioRecord::set( } // create the IAudioRecord - status = openRecord_l(sampleRate, format, channelMask, - frameCount, input); + status = openRecord_l(sampleRate, format, frameCount, input); if (status != NO_ERROR) { return status; } @@ -207,11 +227,9 @@ status_t AudioRecord::set( mStatus = NO_ERROR; - mFormat = format; // Update buffer size in case it has been limited by AudioFlinger during track creation - mFrameCount = mCblk->frameCount; - mChannelCount = (uint8_t)channelCount; - mChannelMask = channelMask; + mFrameCount = mCblk->frameCount_; + mActive = false; mCbf = cbf; mNotificationFrames = notificationFrames; @@ -247,25 +265,16 @@ audio_format_t AudioRecord::format() const return mFormat; } -int AudioRecord::channelCount() const +uint32_t AudioRecord::channelCount() const { return mChannelCount; } -uint32_t AudioRecord::frameCount() const +size_t AudioRecord::frameCount() const { return mFrameCount; } -size_t AudioRecord::frameSize() const -{ - if (audio_is_linear_pcm(mFormat)) { - return channelCount()*audio_bytes_per_sample(mFormat); - } else { - return sizeof(uint8_t); - } -} - audio_source_t AudioRecord::inputSource() const { return mInputSource; @@ -291,17 +300,19 @@ status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession) mActive = true; cblk->lock.lock(); - if (!(cblk->flags & CBLK_INVALID_MSK)) { + if (!(cblk->flags & CBLK_INVALID)) { cblk->lock.unlock(); ALOGV("mAudioRecord->start()"); ret = mAudioRecord->start(event, triggerSession); cblk->lock.lock(); if (ret == DEAD_OBJECT) { - android_atomic_or(CBLK_INVALID_ON, &cblk->flags); + android_atomic_or(CBLK_INVALID, &cblk->flags); } } - if (cblk->flags & CBLK_INVALID_MSK) { - ret = restoreRecord_l(cblk); + if (cblk->flags & CBLK_INVALID) { + audio_track_cblk_t* temp = cblk; + ret = restoreRecord_l(temp); + cblk = temp; } cblk->lock.unlock(); if (ret == NO_ERROR) { @@ -355,7 +366,7 @@ bool AudioRecord::stopped() const uint32_t AudioRecord::getSampleRate() const { - return mCblk->sampleRate; + return mSampleRate; } status_t AudioRecord::setMarkerPosition(uint32_t marker) @@ -425,13 +436,13 @@ unsigned int AudioRecord::getInputFramesLost() const status_t AudioRecord::openRecord_l( uint32_t sampleRate, audio_format_t format, - audio_channel_mask_t channelMask, - int frameCount, + size_t frameCount, audio_io_handle_t input) { status_t status; const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); if (audioFlinger == 0) { + ALOGE("Could not get audioflinger"); return NO_INIT; } @@ -439,9 +450,9 @@ status_t AudioRecord::openRecord_l( // FIXME see similar logic at AudioTrack int originalSessionId = mSessionId; - sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input, + sp<IAudioRecord> record = audioFlinger->openRecord(input, sampleRate, format, - channelMask, + mChannelMask, frameCount, IAudioFlinger::TRACK_DEFAULT, tid, @@ -454,25 +465,32 @@ status_t AudioRecord::openRecord_l( ALOGE("AudioFlinger could not create record track, status: %d", status); return status; } - sp<IMemory> cblk = record->getCblk(); - if (cblk == 0) { + sp<IMemory> iMem = record->getCblk(); + if (iMem == 0) { ALOGE("Could not get control block"); return NO_INIT; } mAudioRecord.clear(); mAudioRecord = record; mCblkMemory.clear(); - mCblkMemory = cblk; - mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); - mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); - android_atomic_and(~CBLK_DIRECTION_MSK, &mCblk->flags); - mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; - mCblk->waitTimeMs = 0; + mCblkMemory = iMem; + audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMem->pointer()); + mCblk = cblk; + mBuffers = (char*)cblk + sizeof(audio_track_cblk_t); + cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; + cblk->waitTimeMs = 0; + + // update proxy + delete mProxy; + mProxy = new AudioRecordClientProxy(cblk, mBuffers, frameCount, mFrameSize); + return NO_ERROR; } status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) { + ALOG_ASSERT(mStatus == NO_ERROR && mProxy != NULL); + AutoMutex lock(mLock); bool active; status_t result = NO_ERROR; @@ -483,7 +501,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) audioBuffer->frameCount = 0; audioBuffer->size = 0; - uint32_t framesReady = cblk->framesReady(); + size_t framesReady = mProxy->framesReady(); if (framesReady == 0) { cblk->lock.lock(); @@ -498,17 +516,22 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) cblk->lock.unlock(); return WOULD_BLOCK; } - if (!(cblk->flags & CBLK_INVALID_MSK)) { + if (!(cblk->flags & CBLK_INVALID)) { mLock.unlock(); + // this condition is in shared memory, so if IAudioRecord and control block + // are replaced due to mediaserver death or IAudioRecord invalidation then + // cv won't be signalled, but fortunately the timeout will limit the wait result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); cblk->lock.unlock(); mLock.lock(); if (!mActive) { return status_t(STOPPED); } + // IAudioRecord may have been re-created while mLock was unlocked + cblk = mCblk; cblk->lock.lock(); } - if (cblk->flags & CBLK_INVALID_MSK) { + if (cblk->flags & CBLK_INVALID) { goto create_new_record; } if (CC_UNLIKELY(result != NO_ERROR)) { @@ -521,9 +544,11 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0); cblk->lock.lock(); if (result == DEAD_OBJECT) { - android_atomic_or(CBLK_INVALID_ON, &cblk->flags); + android_atomic_or(CBLK_INVALID, &cblk->flags); create_new_record: - result = AudioRecord::restoreRecord_l(cblk); + audio_track_cblk_t* temp = cblk; + result = AudioRecord::restoreRecord_l(temp); + cblk = temp; } if (result != NO_ERROR) { ALOGW("obtainBuffer create Track error %d", result); @@ -539,7 +564,7 @@ create_new_record: } // read the server count again start_loop_here: - framesReady = cblk->framesReady(); + framesReady = mProxy->framesReady(); } cblk->lock.unlock(); } @@ -553,26 +578,25 @@ create_new_record: } uint32_t u = cblk->user; - uint32_t bufferEnd = cblk->userBase + cblk->frameCount; + uint32_t bufferEnd = cblk->userBase + mFrameCount; if (framesReq > bufferEnd - u) { framesReq = bufferEnd - u; } - audioBuffer->flags = 0; - audioBuffer->channelCount= mChannelCount; - audioBuffer->format = mFormat; audioBuffer->frameCount = framesReq; - audioBuffer->size = framesReq*cblk->frameSize; - audioBuffer->raw = (int8_t*)cblk->buffer(u); + audioBuffer->size = framesReq * mFrameSize; + audioBuffer->raw = mProxy->buffer(u); active = mActive; return active ? status_t(NO_ERROR) : status_t(STOPPED); } void AudioRecord::releaseBuffer(Buffer* audioBuffer) { + ALOG_ASSERT(mStatus == NO_ERROR && mProxy != NULL); + AutoMutex lock(mLock); - mCblk->stepUser(audioBuffer->frameCount); + (void) mProxy->stepUser(audioBuffer->frameCount); } audio_io_handle_t AudioRecord::getInput() const @@ -585,7 +609,7 @@ audio_io_handle_t AudioRecord::getInput() const audio_io_handle_t AudioRecord::getInput_l() { mInput = AudioSystem::getInput(mInputSource, - mCblk->sampleRate, + mSampleRate, mFormat, mChannelMask, mSessionId); @@ -631,10 +655,13 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize) status_t err = obtainBuffer(&audioBuffer, ((2 * MAX_RUN_TIMEOUT_MS) / WAIT_PERIOD_MS)); if (err < 0) { // out of buffers, return #bytes written - if (err == status_t(NO_MORE_BUFFERS)) + if (err == status_t(NO_MORE_BUFFERS)) { break; - if (err == status_t(TIMED_OUT)) - err = 0; + } + if (err == status_t(TIMED_OUT)) { + // return partial transfer count + return read; + } return ssize_t(err); } @@ -701,7 +728,8 @@ bool AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread) status_t err = obtainBuffer(&audioBuffer, 1); if (err < NO_ERROR) { if (err != TIMED_OUT) { - ALOGE_IF(err != status_t(NO_MORE_BUFFERS), "Error obtaining an audio buffer, giving up."); + ALOGE_IF(err != status_t(NO_MORE_BUFFERS), + "Error obtaining an audio buffer, giving up."); return false; } break; @@ -733,11 +761,11 @@ bool AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread) // Manage overrun callback - if (active && (cblk->framesAvailable() == 0)) { + if (active && (mProxy->framesAvailable() == 0)) { // The value of active is stale, but we are almost sure to be active here because // otherwise we would have exited when obtainBuffer returned STOPPED earlier. ALOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); - if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) { + if (!(android_atomic_or(CBLK_UNDERRUN, &cblk->flags) & CBLK_UNDERRUN)) { mCbf(EVENT_OVERRUN, mUserData, NULL); } } @@ -753,57 +781,40 @@ bool AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread) // must be called with mLock and cblk.lock held. Callers must also hold strong references on // the IAudioRecord and IMemory in case they are recreated here. // If the IAudioRecord is successfully restored, the cblk pointer is updated -status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk) +status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& refCblk) { status_t result; - if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) { - ALOGW("dead IAudioRecord, creating a new one"); - // signal old cblk condition so that other threads waiting for available buffers stop - // waiting now - cblk->cv.broadcast(); - cblk->lock.unlock(); + audio_track_cblk_t* cblk = refCblk; + audio_track_cblk_t* newCblk = cblk; + ALOGW("dead IAudioRecord, creating a new one"); - // if the new IAudioRecord is created, openRecord_l() will modify the - // following member variables: mAudioRecord, mCblkMemory and mCblk. - // It will also delete the strong references on previous IAudioRecord and IMemory - result = openRecord_l(cblk->sampleRate, mFormat, mChannelMask, - mFrameCount, getInput_l()); - if (result == NO_ERROR) { - // callback thread or sync event hasn't changed - result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0); - } - if (result != NO_ERROR) { - mActive = false; - } + // signal old cblk condition so that other threads waiting for available buffers stop + // waiting now + cblk->cv.broadcast(); + cblk->lock.unlock(); - // signal old cblk condition for other threads waiting for restore completion - android_atomic_or(CBLK_RESTORED_ON, &cblk->flags); - cblk->cv.broadcast(); - } else { - if (!(cblk->flags & CBLK_RESTORED_MSK)) { - ALOGW("dead IAudioRecord, waiting for a new one to be created"); - mLock.unlock(); - result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS)); - cblk->lock.unlock(); - mLock.lock(); - } else { - ALOGW("dead IAudioRecord, already restored"); - result = NO_ERROR; - cblk->lock.unlock(); - } - if (result != NO_ERROR || !mActive) { - result = status_t(STOPPED); - } + // if the new IAudioRecord is created, openRecord_l() will modify the + // following member variables: mAudioRecord, mCblkMemory and mCblk. + // It will also delete the strong references on previous IAudioRecord and IMemory + result = openRecord_l(mSampleRate, mFormat, mFrameCount, getInput_l()); + if (result == NO_ERROR) { + newCblk = mCblk; + // callback thread or sync event hasn't changed + result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0); } + if (result != NO_ERROR) { + mActive = false; + } + ALOGV("restoreRecord_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x", - result, mActive, mCblk, cblk, mCblk->flags, cblk->flags); + result, mActive, newCblk, cblk, newCblk->flags, cblk->flags); if (result == NO_ERROR) { // from now on we switch to the newly created cblk - cblk = mCblk; + refCblk = newCblk; } - cblk->lock.lock(); + newCblk->lock.lock(); ALOGW_IF(result != NO_ERROR, "restoreRecord_l() error %d", result); diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 207f96f..693df60 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -205,12 +205,7 @@ int AudioSystem::logToLinear(float volume) return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0; } -// DEPRECATED -status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType) { - return getOutputSamplingRate(samplingRate, (audio_stream_type_t)streamType); -} - -status_t AudioSystem::getOutputSamplingRate(int* samplingRate, audio_stream_type_t streamType) +status_t AudioSystem::getOutputSamplingRate(uint32_t* samplingRate, audio_stream_type_t streamType) { audio_io_handle_t output; @@ -228,7 +223,7 @@ status_t AudioSystem::getOutputSamplingRate(int* samplingRate, audio_stream_type status_t AudioSystem::getSamplingRate(audio_io_handle_t output, audio_stream_type_t streamType, - int* samplingRate) + uint32_t* samplingRate) { OutputDescriptor *outputDesc; @@ -246,17 +241,13 @@ status_t AudioSystem::getSamplingRate(audio_io_handle_t output, gLock.unlock(); } - ALOGV("getSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, *samplingRate); + ALOGV("getSamplingRate() streamType %d, output %d, sampling rate %u", streamType, output, + *samplingRate); return NO_ERROR; } -// DEPRECATED -status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType) { - return getOutputFrameCount(frameCount, (audio_stream_type_t)streamType); -} - -status_t AudioSystem::getOutputFrameCount(int* frameCount, audio_stream_type_t streamType) +status_t AudioSystem::getOutputFrameCount(size_t* frameCount, audio_stream_type_t streamType) { audio_io_handle_t output; @@ -274,7 +265,7 @@ status_t AudioSystem::getOutputFrameCount(int* frameCount, audio_stream_type_t s status_t AudioSystem::getFrameCount(audio_io_handle_t output, audio_stream_type_t streamType, - int* frameCount) + size_t* frameCount) { OutputDescriptor *outputDesc; @@ -290,7 +281,8 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output, gLock.unlock(); } - ALOGV("getFrameCount() streamType %d, output %d, frameCount %d", streamType, output, *frameCount); + ALOGV("getFrameCount() streamType %d, output %d, frameCount %d", streamType, output, + *frameCount); return NO_ERROR; } @@ -369,7 +361,8 @@ status_t AudioSystem::setVoiceVolume(float value) return af->setVoiceVolume(value); } -status_t AudioSystem::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, audio_stream_type_t stream) +status_t AudioSystem::getRenderPosition(size_t *halFrames, size_t *dspFrames, + audio_stream_type_t stream) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; @@ -381,7 +374,7 @@ status_t AudioSystem::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames return af->getRenderPosition(halFrames, dspFrames, getOutput(stream)); } -unsigned int AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) { +size_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); unsigned int result = 0; if (af == 0) return result; @@ -449,8 +442,10 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle OutputDescriptor *outputDesc = new OutputDescriptor(*desc); gOutputs.add(ioHandle, outputDesc); - ALOGV("ioConfigChanged() new output samplingRate %d, format %d channels %#x frameCount %d latency %d", - outputDesc->samplingRate, outputDesc->format, outputDesc->channels, outputDesc->frameCount, outputDesc->latency); + ALOGV("ioConfigChanged() new output samplingRate %u, format %d channels %#x frameCount %u " + "latency %d", + outputDesc->samplingRate, outputDesc->format, outputDesc->channels, + outputDesc->frameCount, outputDesc->latency); } break; case OUTPUT_CLOSED: { if (gOutputs.indexOfKey(ioHandle) < 0) { @@ -471,7 +466,8 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle if (param2 == NULL) break; desc = (const OutputDescriptor *)param2; - ALOGV("ioConfigChanged() new config for output %d samplingRate %d, format %d channels %#x frameCount %d latency %d", + ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %d channels %#x " + "frameCount %d latency %d", ioHandle, desc->samplingRate, desc->format, desc->channels, desc->frameCount, desc->latency); OutputDescriptor *outputDesc = gOutputs.valueAt(index); @@ -510,7 +506,7 @@ sp<IAudioPolicyService> AudioSystem::gAudioPolicyService; sp<AudioSystem::AudioPolicyServiceClient> AudioSystem::gAudioPolicyServiceClient; -// establish binder interface to AudioFlinger service +// establish binder interface to AudioPolicy service const sp<IAudioPolicyService>& AudioSystem::get_audio_policy_service() { gLock.lock(); @@ -735,6 +731,16 @@ status_t AudioSystem::isStreamActive(audio_stream_type_t stream, bool* state, ui return NO_ERROR; } +status_t AudioSystem::isStreamActiveRemotely(audio_stream_type_t stream, bool* state, + uint32_t inPastMs) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + if (state == NULL) return BAD_VALUE; + *state = aps->isStreamActiveRemotely(stream, inPastMs); + return NO_ERROR; +} + status_t AudioSystem::isSourceActive(audio_source_t stream, bool* state) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); @@ -744,14 +750,14 @@ status_t AudioSystem::isSourceActive(audio_source_t stream, bool* state) return NO_ERROR; } -int32_t AudioSystem::getPrimaryOutputSamplingRate() +uint32_t AudioSystem::getPrimaryOutputSamplingRate() { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return 0; return af->getPrimaryOutputSamplingRate(); } -int32_t AudioSystem::getPrimaryOutputFrameCount() +size_t AudioSystem::getPrimaryOutputFrameCount() { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return 0; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 3278dbe..7eeb4f8 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -50,11 +50,13 @@ namespace android { // static status_t AudioTrack::getMinFrameCount( - int* frameCount, + size_t* frameCount, audio_stream_type_t streamType, uint32_t sampleRate) { - if (frameCount == NULL) return BAD_VALUE; + if (frameCount == NULL) { + return BAD_VALUE; + } // default to 0 in case of error *frameCount = 0; @@ -65,11 +67,11 @@ status_t AudioTrack::getMinFrameCount( // audio_format_t format // audio_channel_mask_t channelMask // audio_output_flags_t flags - int afSampleRate; + uint32_t afSampleRate; if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { return NO_INIT; } - int afFrameCount; + size_t afFrameCount; if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { return NO_INIT; } @@ -95,7 +97,8 @@ AudioTrack::AudioTrack() : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), - mPreviousSchedulingGroup(SP_DEFAULT) + mPreviousSchedulingGroup(SP_DEFAULT), + mProxy(NULL) { } @@ -113,35 +116,14 @@ AudioTrack::AudioTrack( : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), - mPreviousSchedulingGroup(SP_DEFAULT) + mPreviousSchedulingGroup(SP_DEFAULT), + mProxy(NULL) { mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId); } -// DEPRECATED -AudioTrack::AudioTrack( - int streamType, - uint32_t sampleRate, - int format, - int channelMask, - int frameCount, - uint32_t flags, - callback_t cbf, - void* user, - int notificationFrames, - int sessionId) - : mStatus(NO_INIT), - mIsTimed(false), - mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT) -{ - mStatus = set((audio_stream_type_t)streamType, sampleRate, (audio_format_t)format, - (audio_channel_mask_t) channelMask, - frameCount, (audio_output_flags_t)flags, cbf, user, notificationFrames, - 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId); -} - AudioTrack::AudioTrack( audio_stream_type_t streamType, uint32_t sampleRate, @@ -156,8 +138,14 @@ AudioTrack::AudioTrack( : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), - mPreviousSchedulingGroup(SP_DEFAULT) + mPreviousSchedulingGroup(SP_DEFAULT), + mProxy(NULL) { + if (sharedBuffer == 0) { + ALOGE("sharedBuffer must be non-0"); + mStatus = BAD_VALUE; + return; + } mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, sharedBuffer, false /*threadCanCallJava*/, sessionId); @@ -181,6 +169,7 @@ AudioTrack::~AudioTrack() IPCThreadState::self()->flushCommands(); AudioSystem::releaseAudioSessionId(mSessionId); } + delete mProxy; } status_t AudioTrack::set( @@ -188,7 +177,7 @@ status_t AudioTrack::set( uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - int frameCount, + int frameCountInt, audio_output_flags_t flags, callback_t cbf, void* user, @@ -197,10 +186,17 @@ status_t AudioTrack::set( bool threadCanCallJava, int sessionId) { + // FIXME "int" here is legacy and will be replaced by size_t later + if (frameCountInt < 0) { + ALOGE("Invalid frame count %d", frameCountInt); + return BAD_VALUE; + } + size_t frameCount = frameCountInt; - ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); + ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), + sharedBuffer->size()); - ALOGV("set() streamType %d frameCount %d flags %04x", streamType, frameCount, flags); + ALOGV("set() streamType %d frameCount %u flags %04x", streamType, frameCount, flags); AutoMutex lock(mLock); if (mAudioTrack != 0) { @@ -214,12 +210,13 @@ status_t AudioTrack::set( } if (sampleRate == 0) { - int afSampleRate; + uint32_t afSampleRate; if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { return NO_INIT; } sampleRate = afSampleRate; } + mSampleRate = sampleRate; // these below should probably come from the audioFlinger too... if (format == AUDIO_FORMAT_DEFAULT) { @@ -256,7 +253,17 @@ status_t AudioTrack::set( ALOGE("Invalid channel mask %#x", channelMask); return BAD_VALUE; } + mChannelMask = channelMask; uint32_t channelCount = popcount(channelMask); + mChannelCount = channelCount; + + if (audio_is_linear_pcm(format)) { + mFrameSize = channelCount * audio_bytes_per_sample(format); + mFrameSizeAF = channelCount * sizeof(int16_t); + } else { + mFrameSize = sizeof(uint8_t); + mFrameSizeAF = sizeof(uint8_t); + } audio_io_handle_t output = AudioSystem::getOutput( streamType, @@ -272,6 +279,7 @@ status_t AudioTrack::set( mVolume[RIGHT] = 1.0f; mSendLevel = 0.0f; mFrameCount = frameCount; + mReqFrameCount = frameCount; mNotificationFramesReq = notificationFrames; mSessionId = sessionId; mAuxEffectId = 0; @@ -287,7 +295,6 @@ status_t AudioTrack::set( status_t status = createTrack_l(streamType, sampleRate, format, - channelMask, frameCount, flags, sharedBuffer, @@ -305,10 +312,8 @@ status_t AudioTrack::set( mStreamType = streamType; mFormat = format; - mChannelMask = channelMask; - mChannelCount = channelCount; + mSharedBuffer = sharedBuffer; - mMuted = false; mActive = false; mUserData = user; mLoopCount = 0; @@ -318,56 +323,9 @@ status_t AudioTrack::set( mUpdatePeriod = 0; mFlushed = false; AudioSystem::acquireAudioSessionId(mSessionId); - mRestoreStatus = NO_ERROR; return NO_ERROR; } -status_t AudioTrack::initCheck() const -{ - return mStatus; -} - -// ------------------------------------------------------------------------- - -uint32_t AudioTrack::latency() const -{ - return mLatency; -} - -audio_stream_type_t AudioTrack::streamType() const -{ - return mStreamType; -} - -audio_format_t AudioTrack::format() const -{ - return mFormat; -} - -int AudioTrack::channelCount() const -{ - return mChannelCount; -} - -uint32_t AudioTrack::frameCount() const -{ - return mCblk->frameCount; -} - -size_t AudioTrack::frameSize() const -{ - if (audio_is_linear_pcm(mFormat)) { - return channelCount()*audio_bytes_per_sample(mFormat); - } else { - return sizeof(uint8_t); - } -} - -sp<IMemory>& AudioTrack::sharedBuffer() -{ - return mSharedBuffer; -} - // ------------------------------------------------------------------------- void AudioTrack::start() @@ -390,7 +348,7 @@ void AudioTrack::start() cblk->lock.lock(); cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; cblk->waitTimeMs = 0; - android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); + android_atomic_and(~CBLK_DISABLED, &cblk->flags); if (t != 0) { t->resume(); } else { @@ -399,19 +357,21 @@ void AudioTrack::start() androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); } - ALOGV("start %p before lock cblk %p", this, mCblk); + ALOGV("start %p before lock cblk %p", this, cblk); status_t status = NO_ERROR; - if (!(cblk->flags & CBLK_INVALID_MSK)) { + if (!(cblk->flags & CBLK_INVALID)) { cblk->lock.unlock(); ALOGV("mAudioTrack->start()"); status = mAudioTrack->start(); cblk->lock.lock(); if (status == DEAD_OBJECT) { - android_atomic_or(CBLK_INVALID_ON, &cblk->flags); + android_atomic_or(CBLK_INVALID, &cblk->flags); } } - if (cblk->flags & CBLK_INVALID_MSK) { - status = restoreTrack_l(cblk, true); + if (cblk->flags & CBLK_INVALID) { + audio_track_cblk_t* temp = cblk; + status = restoreTrack_l(temp, true /*fromStart*/); + cblk = temp; } cblk->lock.unlock(); if (status != NO_ERROR) { @@ -447,6 +407,7 @@ void AudioTrack::stop() mMarkerReached = false; // Force flush if a shared buffer is used otherwise audioflinger // will not stop before end of buffer is reached. + // It may be needed to make sure that we stop playback, likely in case looping is on. if (mSharedBuffer != 0) { flush_l(); } @@ -469,26 +430,26 @@ bool AudioTrack::stopped() const void AudioTrack::flush() { AutoMutex lock(mLock); - flush_l(); + if (!mActive && mSharedBuffer == 0) { + flush_l(); + } } -// must be called with mLock held void AudioTrack::flush_l() { ALOGV("flush"); + ALOG_ASSERT(!mActive); // clear playback marker and periodic update counter mMarkerPosition = 0; mMarkerReached = false; mUpdatePeriod = 0; - if (!mActive) { - mFlushed = true; - mAudioTrack->flush(); - // Release AudioTrack callback thread in case it was waiting for new buffers - // in AudioTrack::obtainBuffer() - mCblk->cv.signal(); - } + mFlushed = true; + mAudioTrack->flush(); + // Release AudioTrack callback thread in case it was waiting for new buffers + // in AudioTrack::obtainBuffer() + mCblk->cv.signal(); } void AudioTrack::pause() @@ -502,19 +463,13 @@ void AudioTrack::pause() } } -void AudioTrack::mute(bool e) -{ - mAudioTrack->mute(e); - mMuted = e; -} - -bool AudioTrack::muted() const -{ - return mMuted; -} - status_t AudioTrack::setVolume(float left, float right) { + if (mStatus != NO_ERROR) { + return mStatus; + } + ALOG_ASSERT(mProxy != NULL); + if (left < 0.0f || left > 1.0f || right < 0.0f || right > 1.0f) { return BAD_VALUE; } @@ -523,32 +478,32 @@ status_t AudioTrack::setVolume(float left, float right) mVolume[LEFT] = left; mVolume[RIGHT] = right; - mCblk->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000)); + mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000)); return NO_ERROR; } -void AudioTrack::getVolume(float* left, float* right) const +status_t AudioTrack::setVolume(float volume) { - if (left != NULL) { - *left = mVolume[LEFT]; - } - if (right != NULL) { - *right = mVolume[RIGHT]; - } + return setVolume(volume, volume); } status_t AudioTrack::setAuxEffectSendLevel(float level) { ALOGV("setAuxEffectSendLevel(%f)", level); + + if (mStatus != NO_ERROR) { + return mStatus; + } + ALOG_ASSERT(mProxy != NULL); + if (level < 0.0f || level > 1.0f) { return BAD_VALUE; } AutoMutex lock(mLock); mSendLevel = level; - - mCblk->setSendLevel(level); + mProxy->setSendLevel(level); return NO_ERROR; } @@ -560,9 +515,9 @@ void AudioTrack::getAuxEffectSendLevel(float* level) const } } -status_t AudioTrack::setSampleRate(int rate) +status_t AudioTrack::setSampleRate(uint32_t rate) { - int afSamplingRate; + uint32_t afSamplingRate; if (mIsTimed) { return INVALID_OPERATION; @@ -572,21 +527,25 @@ status_t AudioTrack::setSampleRate(int rate) return NO_INIT; } // Resampler implementation limits input sampling rate to 2 x output sampling rate. - if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE; + if (rate == 0 || rate > afSamplingRate*2 ) { + return BAD_VALUE; + } AutoMutex lock(mLock); - mCblk->sampleRate = rate; + mSampleRate = rate; + mProxy->setSampleRate(rate); + return NO_ERROR; } uint32_t AudioTrack::getSampleRate() const { if (mIsTimed) { - return INVALID_OPERATION; + return 0; } AutoMutex lock(mLock); - return mCblk->sampleRate; + return mSampleRate; } status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount) @@ -598,6 +557,10 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount // must be called with mLock held status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount) { + if (mSharedBuffer == 0 || mIsTimed) { + return INVALID_OPERATION; + } + audio_track_cblk_t* cblk = mCblk; Mutex::Autolock _l(cblk->lock); @@ -610,20 +573,18 @@ status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCou return NO_ERROR; } - if (mIsTimed) { - return INVALID_OPERATION; - } - if (loopStart >= loopEnd || - loopEnd - loopStart > cblk->frameCount || + loopEnd - loopStart > mFrameCount || cblk->server > loopStart) { - ALOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, cblk->frameCount, cblk->user); + ALOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, " + "user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user); return BAD_VALUE; } - if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) { - ALOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d", - loopStart, loopEnd, cblk->frameCount); + if ((mSharedBuffer != 0) && (loopEnd > mFrameCount)) { + ALOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, " + "framecount %d", + loopStart, loopEnd, mFrameCount); return BAD_VALUE; } @@ -637,7 +598,9 @@ status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCou status_t AudioTrack::setMarkerPosition(uint32_t marker) { - if (mCbf == NULL) return INVALID_OPERATION; + if (mCbf == NULL) { + return INVALID_OPERATION; + } mMarkerPosition = marker; mMarkerReached = false; @@ -647,7 +610,9 @@ status_t AudioTrack::setMarkerPosition(uint32_t marker) status_t AudioTrack::getMarkerPosition(uint32_t *marker) const { - if (marker == NULL) return BAD_VALUE; + if (marker == NULL) { + return BAD_VALUE; + } *marker = mMarkerPosition; @@ -656,7 +621,9 @@ status_t AudioTrack::getMarkerPosition(uint32_t *marker) const status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod) { - if (mCbf == NULL) return INVALID_OPERATION; + if (mCbf == NULL) { + return INVALID_OPERATION; + } uint32_t curPosition; getPosition(&curPosition); @@ -668,7 +635,9 @@ status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod) status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const { - if (updatePeriod == NULL) return BAD_VALUE; + if (updatePeriod == NULL) { + return BAD_VALUE; + } *updatePeriod = mUpdatePeriod; @@ -677,25 +646,34 @@ status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const status_t AudioTrack::setPosition(uint32_t position) { - if (mIsTimed) return INVALID_OPERATION; + if (mSharedBuffer == 0 || mIsTimed) { + return INVALID_OPERATION; + } AutoMutex lock(mLock); - if (!stopped_l()) return INVALID_OPERATION; + if (!stopped_l()) { + return INVALID_OPERATION; + } - Mutex::Autolock _l(mCblk->lock); + audio_track_cblk_t* cblk = mCblk; + Mutex::Autolock _l(cblk->lock); - if (position > mCblk->user) return BAD_VALUE; + if (position > cblk->user) { + return BAD_VALUE; + } - mCblk->server = position; - android_atomic_or(CBLK_FORCEREADY_ON, &mCblk->flags); + cblk->server = position; + android_atomic_or(CBLK_FORCEREADY, &cblk->flags); return NO_ERROR; } status_t AudioTrack::getPosition(uint32_t *position) { - if (position == NULL) return BAD_VALUE; + if (position == NULL) { + return BAD_VALUE; + } AutoMutex lock(mLock); *position = mFlushed ? 0 : mCblk->server; @@ -704,13 +682,24 @@ status_t AudioTrack::getPosition(uint32_t *position) status_t AudioTrack::reload() { + if (mStatus != NO_ERROR) { + return mStatus; + } + ALOG_ASSERT(mProxy != NULL); + + if (mSharedBuffer == 0 || mIsTimed) { + return INVALID_OPERATION; + } + AutoMutex lock(mLock); - if (!stopped_l()) return INVALID_OPERATION; + if (!stopped_l()) { + return INVALID_OPERATION; + } flush_l(); - mCblk->stepUser(mCblk->frameCount); + (void) mProxy->stepUser(mFrameCount); return NO_ERROR; } @@ -725,12 +714,7 @@ audio_io_handle_t AudioTrack::getOutput() audio_io_handle_t AudioTrack::getOutput_l() { return AudioSystem::getOutput(mStreamType, - mCblk->sampleRate, mFormat, mChannelMask, mFlags); -} - -int AudioTrack::getSessionId() const -{ - return mSessionId; + mSampleRate, mFormat, mChannelMask, mFlags); } status_t AudioTrack::attachAuxEffect(int effectId) @@ -750,8 +734,7 @@ status_t AudioTrack::createTrack_l( audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, - audio_channel_mask_t channelMask, - int frameCount, + size_t frameCount, audio_output_flags_t flags, const sp<IMemory>& sharedBuffer, audio_io_handle_t output) @@ -791,7 +774,7 @@ status_t AudioTrack::createTrack_l( // Same comment as below about ignoring frameCount parameter for set() frameCount = sharedBuffer->size(); } else if (frameCount == 0) { - int afFrameCount; + size_t afFrameCount; if (AudioSystem::getFrameCount(output, streamType, &afFrameCount) != NO_ERROR) { return NO_INIT; } @@ -800,17 +783,16 @@ status_t AudioTrack::createTrack_l( } else if (sharedBuffer != 0) { - // Ensure that buffer alignment matches channelCount - int channelCount = popcount(channelMask); + // Ensure that buffer alignment matches channel count // 8-bit data in shared memory is not currently supported by AudioFlinger size_t alignment = /* format == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2; - if (channelCount > 1) { + if (mChannelCount > 1) { // More than 2 channels does not require stronger alignment than stereo alignment <<= 1; } - if (((uint32_t)sharedBuffer->pointer() & (alignment - 1)) != 0) { - ALOGE("Invalid buffer alignment: address %p, channelCount %d", - sharedBuffer->pointer(), channelCount); + if (((size_t)sharedBuffer->pointer() & (alignment - 1)) != 0) { + ALOGE("Invalid buffer alignment: address %p, channel count %u", + sharedBuffer->pointer(), mChannelCount); return BAD_VALUE; } @@ -818,16 +800,16 @@ status_t AudioTrack::createTrack_l( // there's no frameCount parameter. // But when initializing a shared buffer AudioTrack via set(), // there _is_ a frameCount parameter. We silently ignore it. - frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t); + frameCount = sharedBuffer->size()/mChannelCount/sizeof(int16_t); } else if (!(flags & AUDIO_OUTPUT_FLAG_FAST)) { // FIXME move these calculations and associated checks to server - int afSampleRate; + uint32_t afSampleRate; if (AudioSystem::getSamplingRate(output, streamType, &afSampleRate) != NO_ERROR) { return NO_INIT; } - int afFrameCount; + size_t afFrameCount; if (AudioSystem::getFrameCount(output, streamType, &afFrameCount) != NO_ERROR) { return NO_INIT; } @@ -836,8 +818,8 @@ status_t AudioTrack::createTrack_l( uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate); if (minBufCount < 2) minBufCount = 2; - int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate; - ALOGV("minFrameCount: %d, afFrameCount=%d, minBufCount=%d, sampleRate=%d, afSampleRate=%d" + size_t minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate; + ALOGV("minFrameCount: %u, afFrameCount=%d, minBufCount=%d, sampleRate=%u, afSampleRate=%u" ", afLatency=%d", minFrameCount, afFrameCount, minBufCount, sampleRate, afSampleRate, afLatency); @@ -849,7 +831,7 @@ status_t AudioTrack::createTrack_l( } // Make sure that application is notified with sufficient margin // before underrun - if (mNotificationFramesAct > (uint32_t)frameCount/2) { + if (mNotificationFramesAct > frameCount/2) { mNotificationFramesAct = frameCount/2; } if (frameCount < minFrameCount) { @@ -876,13 +858,14 @@ status_t AudioTrack::createTrack_l( } } - sp<IAudioTrack> track = audioFlinger->createTrack(getpid(), - streamType, + sp<IAudioTrack> track = audioFlinger->createTrack(streamType, sampleRate, - format, - channelMask, + // AudioFlinger only sees 16-bit PCM + format == AUDIO_FORMAT_PCM_8_BIT ? + AUDIO_FORMAT_PCM_16_BIT : format, + mChannelMask, frameCount, - trackFlags, + &trackFlags, sharedBuffer, output, tid, @@ -893,55 +876,76 @@ status_t AudioTrack::createTrack_l( ALOGE("AudioFlinger could not create track, status: %d", status); return status; } - sp<IMemory> cblk = track->getCblk(); - if (cblk == 0) { + sp<IMemory> iMem = track->getCblk(); + if (iMem == 0) { ALOGE("Could not get control block"); return NO_INIT; } mAudioTrack = track; - mCblkMemory = cblk; - mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); - // old has the previous value of mCblk->flags before the "or" operation - int32_t old = android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags); + mCblkMemory = iMem; + audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMem->pointer()); + mCblk = cblk; + size_t temp = cblk->frameCount_; + if (temp < frameCount || (frameCount == 0 && temp == 0)) { + // In current design, AudioTrack client checks and ensures frame count validity before + // passing it to AudioFlinger so AudioFlinger should not return a different value except + // for fast track as it uses a special method of assigning frame count. + ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp); + } + frameCount = temp; + mAwaitBoost = false; if (flags & AUDIO_OUTPUT_FLAG_FAST) { - if (old & CBLK_FAST) { - ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %u", mCblk->frameCount); + if (trackFlags & IAudioFlinger::TRACK_FAST) { + ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %u", frameCount); + mAwaitBoost = true; } else { - ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", mCblk->frameCount); + ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", frameCount); // once denied, do not request again if IAudioTrack is re-created flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST); mFlags = flags; } if (sharedBuffer == 0) { - mNotificationFramesAct = mCblk->frameCount/2; + mNotificationFramesAct = frameCount/2; } } if (sharedBuffer == 0) { - mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); + mBuffers = (char*)cblk + sizeof(audio_track_cblk_t); } else { - mCblk->buffers = sharedBuffer->pointer(); - // Force buffer full condition as data is already present in shared memory - mCblk->stepUser(mCblk->frameCount); + mBuffers = sharedBuffer->pointer(); } - mCblk->setVolumeLR((uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000)); - mCblk->setSendLevel(mSendLevel); mAudioTrack->attachAuxEffect(mAuxEffectId); - mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; - mCblk->waitTimeMs = 0; + cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; + cblk->waitTimeMs = 0; mRemainingFrames = mNotificationFramesAct; // FIXME don't believe this lie - mLatency = afLatency + (1000*mCblk->frameCount) / sampleRate; + mLatency = afLatency + (1000*frameCount) / sampleRate; + mFrameCount = frameCount; // If IAudioTrack is re-created, don't let the requested frameCount // decrease. This can confuse clients that cache frameCount(). - if (mCblk->frameCount > mFrameCount) { - mFrameCount = mCblk->frameCount; + if (frameCount > mReqFrameCount) { + mReqFrameCount = frameCount; + } + + // update proxy + delete mProxy; + mProxy = new AudioTrackClientProxy(cblk, mBuffers, frameCount, mFrameSizeAF); + mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | + uint16_t(mVolume[LEFT] * 0x1000)); + mProxy->setSendLevel(mSendLevel); + mProxy->setSampleRate(mSampleRate); + if (sharedBuffer != 0) { + // Force buffer full condition as data is already present in shared memory + mProxy->stepUser(frameCount); } + return NO_ERROR; } status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) { + ALOG_ASSERT(mStatus == NO_ERROR && mProxy != NULL); + AutoMutex lock(mLock); bool active; status_t result = NO_ERROR; @@ -952,10 +956,10 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) audioBuffer->frameCount = 0; audioBuffer->size = 0; - uint32_t framesAvail = cblk->framesAvailable(); + size_t framesAvail = mProxy->framesAvailable(); cblk->lock.lock(); - if (cblk->flags & CBLK_INVALID_MSK) { + if (cblk->flags & CBLK_INVALID) { goto create_new_track; } cblk->lock.unlock(); @@ -974,18 +978,23 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) cblk->lock.unlock(); return WOULD_BLOCK; } - if (!(cblk->flags & CBLK_INVALID_MSK)) { + if (!(cblk->flags & CBLK_INVALID)) { mLock.unlock(); + // this condition is in shared memory, so if IAudioTrack and control block + // are replaced due to mediaserver death or IAudioTrack invalidation then + // cv won't be signalled, but fortunately the timeout will limit the wait result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); cblk->lock.unlock(); mLock.lock(); if (!mActive) { return status_t(STOPPED); } + // IAudioTrack may have been re-created while mLock was unlocked + cblk = mCblk; cblk->lock.lock(); } - if (cblk->flags & CBLK_INVALID_MSK) { + if (cblk->flags & CBLK_INVALID) { goto create_new_track; } if (CC_UNLIKELY(result != NO_ERROR)) { @@ -994,16 +1003,18 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) // timing out when a loop has been set and we have already written upto loop end // is a normal condition: no need to wake AudioFlinger up. if (cblk->user < cblk->loopEnd) { - ALOGW( "obtainBuffer timed out (is the CPU pegged?) %p name=%#x" - "user=%08x, server=%08x", this, cblk->mName, cblk->user, cblk->server); + ALOGW("obtainBuffer timed out (is the CPU pegged?) %p name=%#x user=%08x, " + "server=%08x", this, cblk->mName, cblk->user, cblk->server); //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140) cblk->lock.unlock(); result = mAudioTrack->start(); cblk->lock.lock(); if (result == DEAD_OBJECT) { - android_atomic_or(CBLK_INVALID_ON, &cblk->flags); + android_atomic_or(CBLK_INVALID, &cblk->flags); create_new_track: - result = restoreTrack_l(cblk, false); + audio_track_cblk_t* temp = cblk; + result = restoreTrack_l(temp, false /*fromStart*/); + cblk = temp; } if (result != NO_ERROR) { ALOGW("obtainBuffer create Track error %d", result); @@ -1021,7 +1032,7 @@ create_new_track: } // read the server count again start_loop_here: - framesAvail = cblk->framesAvailable_l(); + framesAvail = mProxy->framesAvailable_l(); } cblk->lock.unlock(); } @@ -1033,35 +1044,31 @@ create_new_track: } uint32_t u = cblk->user; - uint32_t bufferEnd = cblk->userBase + cblk->frameCount; + uint32_t bufferEnd = cblk->userBase + mFrameCount; if (framesReq > bufferEnd - u) { framesReq = bufferEnd - u; } - audioBuffer->flags = mMuted ? Buffer::MUTE : 0; - audioBuffer->channelCount = mChannelCount; audioBuffer->frameCount = framesReq; - audioBuffer->size = framesReq * cblk->frameSize; - if (audio_is_linear_pcm(mFormat)) { - audioBuffer->format = AUDIO_FORMAT_PCM_16_BIT; - } else { - audioBuffer->format = mFormat; - } - audioBuffer->raw = (int8_t *)cblk->buffer(u); + audioBuffer->size = framesReq * mFrameSizeAF; + audioBuffer->raw = mProxy->buffer(u); active = mActive; return active ? status_t(NO_ERROR) : status_t(STOPPED); } void AudioTrack::releaseBuffer(Buffer* audioBuffer) { + ALOG_ASSERT(mStatus == NO_ERROR && mProxy != NULL); + AutoMutex lock(mLock); - mCblk->stepUser(audioBuffer->frameCount); + audio_track_cblk_t* cblk = mCblk; + (void) mProxy->stepUser(audioBuffer->frameCount); if (audioBuffer->frameCount > 0) { // restart track if it was disabled by audioflinger due to previous underrun - if (mActive && (mCblk->flags & CBLK_DISABLED_MSK)) { - android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags); - ALOGW("releaseBuffer() track %p name=%#x disabled, restarting", this, mCblk->mName); + if (mActive && (cblk->flags & CBLK_DISABLED)) { + android_atomic_and(~CBLK_DISABLED, &cblk->flags); + ALOGW("releaseBuffer() track %p name=%#x disabled, restarting", this, cblk->mName); mAudioTrack->start(); } } @@ -1072,8 +1079,9 @@ void AudioTrack::releaseBuffer(Buffer* audioBuffer) ssize_t AudioTrack::write(const void* buffer, size_t userSize) { - if (mSharedBuffer != 0) return INVALID_OPERATION; - if (mIsTimed) return INVALID_OPERATION; + if (mSharedBuffer != 0 || mIsTimed) { + return INVALID_OPERATION; + } if (ssize_t(userSize) < 0) { // Sanity-check: user is most-likely passing an error code, and it would @@ -1096,6 +1104,9 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) sp<IMemory> iMem = mCblkMemory; mLock.unlock(); + // since mLock is unlocked the IAudioTrack and shared memory may be re-created, + // so all cblk references might still refer to old shared memory, but that should be benign + ssize_t written = 0; const int8_t *src = (const int8_t *)buffer; Buffer audioBuffer; @@ -1107,8 +1118,9 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) status_t err = obtainBuffer(&audioBuffer, -1); if (err < 0) { // out of buffers, return #bytes written - if (err == status_t(NO_MORE_BUFFERS)) + if (err == status_t(NO_MORE_BUFFERS)) { break; + } return ssize_t(err); } @@ -1140,27 +1152,37 @@ TimedAudioTrack::TimedAudioTrack() { status_t TimedAudioTrack::allocateTimedBuffer(size_t size, sp<IMemory>* buffer) { + AutoMutex lock(mLock); status_t result = UNKNOWN_ERROR; + // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed + // while we are accessing the cblk + sp<IAudioTrack> audioTrack = mAudioTrack; + sp<IMemory> iMem = mCblkMemory; + // If the track is not invalid already, try to allocate a buffer. alloc // fails indicating that the server is dead, flag the track as invalid so // we can attempt to restore in just a bit. - if (!(mCblk->flags & CBLK_INVALID_MSK)) { + audio_track_cblk_t* cblk = mCblk; + if (!(cblk->flags & CBLK_INVALID)) { result = mAudioTrack->allocateTimedBuffer(size, buffer); if (result == DEAD_OBJECT) { - android_atomic_or(CBLK_INVALID_ON, &mCblk->flags); + android_atomic_or(CBLK_INVALID, &cblk->flags); } } // If the track is invalid at this point, attempt to restore it. and try the // allocation one more time. - if (mCblk->flags & CBLK_INVALID_MSK) { - mCblk->lock.lock(); - result = restoreTrack_l(mCblk, false); - mCblk->lock.unlock(); + if (cblk->flags & CBLK_INVALID) { + cblk->lock.lock(); + audio_track_cblk_t* temp = cblk; + result = restoreTrack_l(temp, false /*fromStart*/); + cblk = temp; + cblk->lock.unlock(); - if (result == OK) + if (result == OK) { result = mAudioTrack->allocateTimedBuffer(size, buffer); + } } return result; @@ -1172,10 +1194,11 @@ status_t TimedAudioTrack::queueTimedBuffer(const sp<IMemory>& buffer, status_t status = mAudioTrack->queueTimedBuffer(buffer, pts); { AutoMutex lock(mLock); + audio_track_cblk_t* cblk = mCblk; // restart track if it was disabled by audioflinger due to previous underrun if (buffer->size() != 0 && status == NO_ERROR && - mActive && (mCblk->flags & CBLK_DISABLED_MSK)) { - android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags); + mActive && (cblk->flags & CBLK_DISABLED)) { + android_atomic_and(~CBLK_DISABLED, &cblk->flags); ALOGW("queueTimedBuffer() track %p disabled, restarting", this); mAudioTrack->start(); } @@ -1198,6 +1221,25 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) size_t writtenSize; mLock.lock(); + if (mAwaitBoost) { + mAwaitBoost = false; + mLock.unlock(); + static const int32_t kMaxTries = 5; + int32_t tryCounter = kMaxTries; + uint32_t pollUs = 10000; + do { + int policy = sched_getscheduler(0); + if (policy == SCHED_FIFO || policy == SCHED_RR) { + break; + } + usleep(pollUs); + pollUs <<= 1; + } while (tryCounter-- > 0); + if (tryCounter < 0) { + ALOGE("did not receive expected priority boost on time"); + } + return true; + } // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed // while we are accessing the cblk sp<IAudioTrack> audioTrack = mAudioTrack; @@ -1206,15 +1248,20 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) bool active = mActive; mLock.unlock(); + // since mLock is unlocked the IAudioTrack and shared memory may be re-created, + // so all cblk references might still refer to old shared memory, but that should be benign + // Manage underrun callback - if (active && (cblk->framesAvailable() == cblk->frameCount)) { + if (active && (mProxy->framesAvailable() == mFrameCount)) { ALOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); - if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) { + if (!(android_atomic_or(CBLK_UNDERRUN, &cblk->flags) & CBLK_UNDERRUN)) { mCbf(EVENT_UNDERRUN, mUserData, 0); - if (cblk->server == cblk->frameCount) { + if (cblk->server == mFrameCount) { mCbf(EVENT_BUFFER_END, mUserData, 0); } - if (mSharedBuffer != 0) return false; + if (mSharedBuffer != 0) { + return false; + } } } @@ -1265,12 +1312,15 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) status_t err = obtainBuffer(&audioBuffer, waitCount); if (err < NO_ERROR) { if (err != TIMED_OUT) { - ALOGE_IF(err != status_t(NO_MORE_BUFFERS), "Error obtaining an audio buffer, giving up."); + ALOGE_IF(err != status_t(NO_MORE_BUFFERS), + "Error obtaining an audio buffer, giving up."); return false; } break; } - if (err == status_t(STOPPED)) return false; + if (err == status_t(STOPPED)) { + return false; + } // Divide buffer size by 2 to take into account the expansion // due to 8 to 16 bit conversion: the callback must fill only half @@ -1293,7 +1343,9 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) break; } - if (writtenSize > reqSize) writtenSize = reqSize; + if (writtenSize > reqSize) { + writtenSize = reqSize; + } if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { // 8 to 16 bit conversion, note that source and destination are the same address @@ -1302,10 +1354,10 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) } audioBuffer.size = writtenSize; - // NOTE: mCblk->frameSize is not equal to AudioTrack::frameSize() for - // 8 bit PCM data: in this case, mCblk->frameSize is based on a sample size of + // NOTE: cblk->frameSize is not equal to AudioTrack::frameSize() for + // 8 bit PCM data: in this case, cblk->frameSize is based on a sample size of // 16 bit. - audioBuffer.frameCount = writtenSize/mCblk->frameSize; + audioBuffer.frameCount = writtenSize / mFrameSizeAF; frames -= audioBuffer.frameCount; @@ -1321,112 +1373,93 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) return true; } -// must be called with mLock and cblk.lock held. Callers must also hold strong references on +// must be called with mLock and refCblk.lock held. Callers must also hold strong references on // the IAudioTrack and IMemory in case they are recreated here. -// If the IAudioTrack is successfully restored, the cblk pointer is updated -status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) +// If the IAudioTrack is successfully restored, the refCblk pointer is updated +// FIXME Don't depend on caller to hold strong references. +status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& refCblk, bool fromStart) { status_t result; - if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) { - ALOGW("dead IAudioTrack, creating a new one from %s TID %d", - fromStart ? "start()" : "obtainBuffer()", gettid()); + audio_track_cblk_t* cblk = refCblk; + audio_track_cblk_t* newCblk = cblk; + ALOGW("dead IAudioTrack, creating a new one from %s", + fromStart ? "start()" : "obtainBuffer()"); - // signal old cblk condition so that other threads waiting for available buffers stop - // waiting now - cblk->cv.broadcast(); - cblk->lock.unlock(); + // signal old cblk condition so that other threads waiting for available buffers stop + // waiting now + cblk->cv.broadcast(); + cblk->lock.unlock(); - // refresh the audio configuration cache in this process to make sure we get new - // output parameters in getOutput_l() and createTrack_l() - AudioSystem::clearAudioConfigCache(); - - // if the new IAudioTrack is created, createTrack_l() will modify the - // following member variables: mAudioTrack, mCblkMemory and mCblk. - // It will also delete the strong references on previous IAudioTrack and IMemory - result = createTrack_l(mStreamType, - cblk->sampleRate, - mFormat, - mChannelMask, - mFrameCount, - mFlags, - mSharedBuffer, - getOutput_l()); - - if (result == NO_ERROR) { - uint32_t user = cblk->user; - uint32_t server = cblk->server; - // restore write index and set other indexes to reflect empty buffer status - mCblk->user = user; - mCblk->server = user; - mCblk->userBase = user; - mCblk->serverBase = 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; - // Make sure that a client relying on callback events indicating underrun or - // the actual amount of audio frames played (e.g SoundPool) receives them. - if (mSharedBuffer == 0) { - uint32_t frames = 0; - if (user > server) { - frames = ((user - server) > mCblk->frameCount) ? - mCblk->frameCount : (user - server); - memset(mCblk->buffers, 0, frames * mCblk->frameSize); - } - // restart playback even if buffer is not completely filled. - android_atomic_or(CBLK_FORCEREADY_ON, &mCblk->flags); - // stepUser() clears CBLK_UNDERRUN_ON flag enabling underrun callbacks to - // the client - mCblk->stepUser(frames); + // refresh the audio configuration cache in this process to make sure we get new + // output parameters in getOutput_l() and createTrack_l() + AudioSystem::clearAudioConfigCache(); + + // if the new IAudioTrack is created, createTrack_l() will modify the + // following member variables: mAudioTrack, mCblkMemory and mCblk. + // It will also delete the strong references on previous IAudioTrack and IMemory + result = createTrack_l(mStreamType, + mSampleRate, + mFormat, + mReqFrameCount, // so that frame count never goes down + mFlags, + mSharedBuffer, + getOutput_l()); + + if (result == NO_ERROR) { + uint32_t user = cblk->user; + uint32_t server = cblk->server; + // restore write index and set other indexes to reflect empty buffer status + newCblk = mCblk; + newCblk->user = user; + newCblk->server = user; + newCblk->userBase = user; + newCblk->serverBase = 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); + size_t frames = 0; + if (!fromStart) { + newCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; + // Make sure that a client relying on callback events indicating underrun or + // the actual amount of audio frames played (e.g SoundPool) receives them. + if (mSharedBuffer == 0) { + if (user > server) { + frames = ((user - server) > mFrameCount) ? + mFrameCount : (user - server); + memset(mBuffers, 0, frames * mFrameSizeAF); } - } - if (mSharedBuffer != 0) { - mCblk->stepUser(mCblk->frameCount); - } - if (mActive) { - result = mAudioTrack->start(); - ALOGW_IF(result != NO_ERROR, "restoreTrack_l() start() failed status %d", result); - } - if (fromStart && result == NO_ERROR) { - mNewPosition = mCblk->server + mUpdatePeriod; + // restart playback even if buffer is not completely filled. + android_atomic_or(CBLK_FORCEREADY, &newCblk->flags); } } - if (result != NO_ERROR) { - android_atomic_and(~CBLK_RESTORING_ON, &cblk->flags); - ALOGW_IF(result != NO_ERROR, "restoreTrack_l() failed status %d", result); + if (mSharedBuffer != 0) { + frames = mFrameCount; } - mRestoreStatus = result; - // signal old cblk condition for other threads waiting for restore completion - android_atomic_or(CBLK_RESTORED_ON, &cblk->flags); - cblk->cv.broadcast(); - } else { - if (!(cblk->flags & CBLK_RESTORED_MSK)) { - ALOGW("dead IAudioTrack, waiting for a new one TID %d", gettid()); - mLock.unlock(); - result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS)); - if (result == NO_ERROR) { - result = mRestoreStatus; - } - cblk->lock.unlock(); - mLock.lock(); - } else { - ALOGW("dead IAudioTrack, already restored TID %d", gettid()); - result = mRestoreStatus; - cblk->lock.unlock(); + if (frames > 0) { + // stepUser() clears CBLK_UNDERRUN flag enabling underrun callbacks to + // the client + mProxy->stepUser(frames); + } + if (mActive) { + result = mAudioTrack->start(); + ALOGW_IF(result != NO_ERROR, "restoreTrack_l() start() failed status %d", result); + } + if (fromStart && result == NO_ERROR) { + mNewPosition = newCblk->server + mUpdatePeriod; } } + ALOGW_IF(result != NO_ERROR, "restoreTrack_l() failed status %d", result); ALOGV("restoreTrack_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x", - result, mActive, mCblk, cblk, mCblk->flags, cblk->flags); + result, mActive, newCblk, cblk, newCblk->flags, cblk->flags); if (result == NO_ERROR) { // from now on we switch to the newly created cblk - cblk = mCblk; + refCblk = newCblk; } - cblk->lock.lock(); + newCblk->lock.lock(); - ALOGW_IF(result != NO_ERROR, "restoreTrack_l() error %d TID %d", result, gettid()); + ALOGW_IF(result != NO_ERROR, "restoreTrack_l() error %d", result); return result; } @@ -1439,11 +1472,13 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args) const String8 result; result.append(" AudioTrack::dump\n"); - snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", mStreamType, mVolume[0], mVolume[1]); + snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", mStreamType, + mVolume[0], mVolume[1]); result.append(buffer); - snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, (mCblk == 0) ? 0 : mCblk->frameCount); + snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, + mChannelCount, mFrameCount); result.append(buffer); - snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d)\n", (mCblk == 0) ? 0 : mCblk->sampleRate, mStatus, mMuted); + snprintf(buffer, 255, " sample rate(%u), status(%d)\n", mSampleRate, mStatus); result.append(buffer); snprintf(buffer, 255, " active(%d), latency (%d)\n", mActive, mLatency); result.append(buffer); @@ -1500,182 +1535,4 @@ void AudioTrack::AudioTrackThread::resume() } } -// ========================================================================= - - -audio_track_cblk_t::audio_track_cblk_t() - : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0), - userBase(0), serverBase(0), buffers(NULL), frameCount(0), - loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), mVolumeLR(0x10001000), - mSendLevel(0), flags(0) -{ -} - -uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) -{ - ALOGV("stepuser %08x %08x %d", user, server, frameCount); - - uint32_t u = user; - u += frameCount; - // Ensure that user is never ahead of server for AudioRecord - if (flags & CBLK_DIRECTION_MSK) { - // If stepServer() has been called once, switch to normal obtainBuffer() timeout period - if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) { - bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; - } - } else if (u > server) { - ALOGW("stepUser occurred after track reset"); - u = server; - } - - uint32_t fc = this->frameCount; - if (u >= fc) { - // common case, user didn't just wrap - if (u - fc >= userBase ) { - userBase += fc; - } - } else if (u >= userBase + fc) { - // user just wrapped - userBase += fc; - } - - user = u; - - // Clear flow control error condition as new data has been written/read to/from buffer. - if (flags & CBLK_UNDERRUN_MSK) { - android_atomic_and(~CBLK_UNDERRUN_MSK, &flags); - } - - return u; -} - -bool audio_track_cblk_t::stepServer(uint32_t frameCount) -{ - ALOGV("stepserver %08x %08x %d", user, server, frameCount); - - if (!tryLock()) { - ALOGW("stepServer() could not lock cblk"); - return false; - } - - uint32_t s = server; - bool flushed = (s == user); - - s += frameCount; - if (flags & CBLK_DIRECTION_MSK) { - // Mark that we have read the first buffer so that next time stepUser() is called - // we switch to normal obtainBuffer() timeout period - if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) { - bufferTimeoutMs = MAX_STARTUP_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 - // we have s > u - if (flushed) { - ALOGW("stepServer occurred after track reset"); - s = user; - } - } - - if (s >= loopEnd) { - ALOGW_IF(s > loopEnd, "stepServer: s %u > loopEnd %u", s, loopEnd); - s = loopStart; - if (--loopCount == 0) { - loopEnd = UINT_MAX; - loopStart = UINT_MAX; - } - } - - uint32_t fc = this->frameCount; - if (s >= fc) { - // common case, server didn't just wrap - if (s - fc >= serverBase ) { - serverBase += fc; - } - } else if (s >= serverBase + fc) { - // server just wrapped - serverBase += fc; - } - - server = s; - - if (!(flags & CBLK_INVALID_MSK)) { - cv.signal(); - } - lock.unlock(); - return true; -} - -void* audio_track_cblk_t::buffer(uint32_t offset) const -{ - return (int8_t *)buffers + (offset - userBase) * frameSize; -} - -uint32_t audio_track_cblk_t::framesAvailable() -{ - Mutex::Autolock _l(lock); - return framesAvailable_l(); -} - -uint32_t audio_track_cblk_t::framesAvailable_l() -{ - uint32_t u = user; - uint32_t s = server; - - if (flags & CBLK_DIRECTION_MSK) { - uint32_t limit = (s < loopStart) ? s : loopStart; - return limit + frameCount - u; - } else { - return frameCount + u - s; - } -} - -uint32_t audio_track_cblk_t::framesReady() -{ - uint32_t u = user; - uint32_t s = server; - - if (flags & CBLK_DIRECTION_MSK) { - if (u < loopEnd) { - return u - s; - } else { - // do not block on mutex shared with client on AudioFlinger side - if (!tryLock()) { - ALOGW("framesReady() could not lock cblk"); - return 0; - } - uint32_t frames = UINT_MAX; - if (loopCount >= 0) { - 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 diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp new file mode 100644 index 0000000..13d47c9 --- /dev/null +++ b/media/libmedia/AudioTrackShared.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AudioTrackShared" +//#define LOG_NDEBUG 0 + +#include <private/media/AudioTrackShared.h> +#include <utils/Log.h> + +namespace android { + +audio_track_cblk_t::audio_track_cblk_t() + : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0), + userBase(0), serverBase(0), frameCount_(0), + loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), mVolumeLR(0x10001000), + mSampleRate(0), mSendLevel(0), flags(0) +{ +} + +uint32_t audio_track_cblk_t::stepUser(size_t stepCount, size_t frameCount, bool isOut) +{ + ALOGV("stepuser %08x %08x %d", user, server, stepCount); + + uint32_t u = user; + u += stepCount; + // Ensure that user is never ahead of server for AudioRecord + if (isOut) { + // If stepServer() has been called once, switch to normal obtainBuffer() timeout period + if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) { + bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; + } + } else if (u > server) { + ALOGW("stepUser occurred after track reset"); + u = server; + } + + if (u >= frameCount) { + // common case, user didn't just wrap + if (u - frameCount >= userBase ) { + userBase += frameCount; + } + } else if (u >= userBase + frameCount) { + // user just wrapped + userBase += frameCount; + } + + user = u; + + // Clear flow control error condition as new data has been written/read to/from buffer. + if (flags & CBLK_UNDERRUN) { + android_atomic_and(~CBLK_UNDERRUN, &flags); + } + + return u; +} + +bool audio_track_cblk_t::stepServer(size_t stepCount, size_t frameCount, bool isOut) +{ + ALOGV("stepserver %08x %08x %d", user, server, stepCount); + + if (!tryLock()) { + ALOGW("stepServer() could not lock cblk"); + return false; + } + + uint32_t s = server; + bool flushed = (s == user); + + s += stepCount; + if (isOut) { + // Mark that we have read the first buffer so that next time stepUser() is called + // we switch to normal obtainBuffer() timeout period + if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) { + bufferTimeoutMs = MAX_STARTUP_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 + // we have s > u + if (flushed) { + ALOGW("stepServer occurred after track reset"); + s = user; + } + } + + if (s >= loopEnd) { + ALOGW_IF(s > loopEnd, "stepServer: s %u > loopEnd %u", s, loopEnd); + s = loopStart; + if (--loopCount == 0) { + loopEnd = UINT_MAX; + loopStart = UINT_MAX; + } + } + + if (s >= frameCount) { + // common case, server didn't just wrap + if (s - frameCount >= serverBase ) { + serverBase += frameCount; + } + } else if (s >= serverBase + frameCount) { + // server just wrapped + serverBase += frameCount; + } + + server = s; + + if (!(flags & CBLK_INVALID)) { + cv.signal(); + } + lock.unlock(); + return true; +} + +void* audio_track_cblk_t::buffer(void *buffers, size_t frameSize, uint32_t offset) const +{ + return (int8_t *)buffers + (offset - userBase) * frameSize; +} + +uint32_t audio_track_cblk_t::framesAvailable(size_t frameCount, bool isOut) +{ + Mutex::Autolock _l(lock); + return framesAvailable_l(frameCount, isOut); +} + +uint32_t audio_track_cblk_t::framesAvailable_l(size_t frameCount, bool isOut) +{ + uint32_t u = user; + uint32_t s = server; + + if (isOut) { + uint32_t limit = (s < loopStart) ? s : loopStart; + return limit + frameCount - u; + } else { + return frameCount + u - s; + } +} + +uint32_t audio_track_cblk_t::framesReady(bool isOut) +{ + uint32_t u = user; + uint32_t s = server; + + if (isOut) { + if (u < loopEnd) { + return u - s; + } else { + // do not block on mutex shared with client on AudioFlinger side + if (!tryLock()) { + ALOGW("framesReady() could not lock cblk"); + return 0; + } + uint32_t frames = UINT_MAX; + if (loopCount >= 0) { + 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 diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index ce8ffc4..2f18680 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -32,7 +32,7 @@ enum { CREATE_TRACK = IBinder::FIRST_CALL_TRANSACTION, OPEN_RECORD, SAMPLE_RATE, - CHANNEL_COUNT, // obsolete + RESERVED, // obsolete, was CHANNEL_COUNT FORMAT, FRAME_COUNT, LATENCY, @@ -84,13 +84,12 @@ public: } virtual sp<IAudioTrack> createTrack( - pid_t pid, audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - int frameCount, - track_flags_t flags, + size_t frameCount, + track_flags_t *flags, const sp<IMemory>& sharedBuffer, audio_io_handle_t output, pid_t tid, @@ -100,13 +99,13 @@ public: Parcel data, reply; sp<IAudioTrack> track; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - data.writeInt32(pid); data.writeInt32((int32_t) streamType); data.writeInt32(sampleRate); data.writeInt32(format); data.writeInt32(channelMask); data.writeInt32(frameCount); - data.writeInt32((int32_t) flags); + track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT; + data.writeInt32(lFlags); data.writeStrongBinder(sharedBuffer->asBinder()); data.writeInt32((int32_t) output); data.writeInt32((int32_t) tid); @@ -119,6 +118,10 @@ public: if (lStatus != NO_ERROR) { ALOGE("createTrack error: %s", strerror(-lStatus)); } else { + lFlags = reply.readInt32(); + if (flags != NULL) { + *flags = lFlags; + } lSessionId = reply.readInt32(); if (sessionId != NULL) { *sessionId = lSessionId; @@ -133,12 +136,11 @@ public: } virtual sp<IAudioRecord> openRecord( - pid_t pid, audio_io_handle_t input, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - int frameCount, + size_t frameCount, track_flags_t flags, pid_t tid, int *sessionId, @@ -147,7 +149,6 @@ public: Parcel data, reply; sp<IAudioRecord> record; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - data.writeInt32(pid); data.writeInt32((int32_t) input); data.writeInt32(sampleRate); data.writeInt32(format); @@ -186,17 +187,6 @@ public: return reply.readInt32(); } -#if 0 - virtual int channelCount(audio_io_handle_t output) const - { - Parcel data, reply; - data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - data.writeInt32((int32_t) output); - remote()->transact(CHANNEL_COUNT, data, &reply); - return reply.readInt32(); - } -#endif - virtual audio_format_t format(audio_io_handle_t output) const { Parcel data, reply; @@ -501,7 +491,7 @@ public: return reply.readInt32(); } - virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, + virtual status_t getRenderPosition(size_t *halFrames, size_t *dspFrames, audio_io_handle_t output) const { Parcel data, reply; @@ -522,7 +512,7 @@ public: return status; } - virtual unsigned int getInputFramesLost(audio_io_handle_t ioHandle) const + virtual size_t getInputFramesLost(audio_io_handle_t ioHandle) const { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); @@ -618,7 +608,7 @@ public: return NO_ERROR; } - virtual sp<IEffect> createEffect(pid_t pid, + virtual sp<IEffect> createEffect( effect_descriptor_t *pDesc, const sp<IEffectClient>& client, int32_t priority, @@ -639,7 +629,6 @@ public: } data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - data.writeInt32(pid); data.write(pDesc, sizeof(effect_descriptor_t)); data.writeStrongBinder(client->asBinder()); data.writeInt32(priority); @@ -690,7 +679,7 @@ public: return (audio_module_handle_t) reply.readInt32(); } - virtual int32_t getPrimaryOutputSamplingRate() + virtual uint32_t getPrimaryOutputSamplingRate() { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); @@ -698,7 +687,7 @@ public: return reply.readInt32(); } - virtual int32_t getPrimaryOutputFrameCount() + virtual size_t getPrimaryOutputFrameCount() { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); @@ -718,21 +707,21 @@ status_t BnAudioFlinger::onTransact( switch (code) { case CREATE_TRACK: { CHECK_INTERFACE(IAudioFlinger, data, reply); - pid_t pid = data.readInt32(); int streamType = data.readInt32(); uint32_t sampleRate = data.readInt32(); audio_format_t format = (audio_format_t) data.readInt32(); audio_channel_mask_t channelMask = data.readInt32(); - size_t bufferCount = data.readInt32(); + size_t frameCount = data.readInt32(); track_flags_t flags = (track_flags_t) data.readInt32(); sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder()); audio_io_handle_t output = (audio_io_handle_t) data.readInt32(); pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); status_t status; - sp<IAudioTrack> track = createTrack(pid, + sp<IAudioTrack> track = createTrack( (audio_stream_type_t) streamType, sampleRate, format, - channelMask, bufferCount, flags, buffer, output, tid, &sessionId, &status); + channelMask, frameCount, &flags, buffer, output, tid, &sessionId, &status); + reply->writeInt32(flags); reply->writeInt32(sessionId); reply->writeInt32(status); reply->writeStrongBinder(track->asBinder()); @@ -740,18 +729,17 @@ status_t BnAudioFlinger::onTransact( } break; case OPEN_RECORD: { CHECK_INTERFACE(IAudioFlinger, data, reply); - pid_t pid = data.readInt32(); audio_io_handle_t input = (audio_io_handle_t) data.readInt32(); uint32_t sampleRate = data.readInt32(); audio_format_t format = (audio_format_t) data.readInt32(); audio_channel_mask_t channelMask = data.readInt32(); - size_t bufferCount = data.readInt32(); + size_t frameCount = data.readInt32(); track_flags_t flags = (track_flags_t) data.readInt32(); pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); status_t status; - sp<IAudioRecord> record = openRecord(pid, input, - sampleRate, format, channelMask, bufferCount, flags, tid, &sessionId, &status); + sp<IAudioRecord> record = openRecord(input, + sampleRate, format, channelMask, frameCount, flags, tid, &sessionId, &status); reply->writeInt32(sessionId); reply->writeInt32(status); reply->writeStrongBinder(record->asBinder()); @@ -762,13 +750,6 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32( sampleRate((audio_io_handle_t) data.readInt32()) ); return NO_ERROR; } break; -#if 0 - case CHANNEL_COUNT: { - CHECK_INTERFACE(IAudioFlinger, data, reply); - reply->writeInt32( channelCount((audio_io_handle_t) data.readInt32()) ); - return NO_ERROR; - } break; -#endif case FORMAT: { CHECK_INTERFACE(IAudioFlinger, data, reply); reply->writeInt32( format((audio_io_handle_t) data.readInt32()) ); @@ -865,7 +846,8 @@ status_t BnAudioFlinger::onTransact( case REGISTER_CLIENT: { CHECK_INTERFACE(IAudioFlinger, data, reply); - sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient>(data.readStrongBinder()); + sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient>( + data.readStrongBinder()); registerClient(client); return NO_ERROR; } break; @@ -965,8 +947,8 @@ status_t BnAudioFlinger::onTransact( case GET_RENDER_POSITION: { CHECK_INTERFACE(IAudioFlinger, data, reply); audio_io_handle_t output = (audio_io_handle_t) data.readInt32(); - uint32_t halFrames; - uint32_t dspFrames; + size_t halFrames; + size_t dspFrames; status_t status = getRenderPosition(&halFrames, &dspFrames, output); reply->writeInt32(status); if (status == NO_ERROR) { @@ -1032,7 +1014,6 @@ status_t BnAudioFlinger::onTransact( } case CREATE_EFFECT: { CHECK_INTERFACE(IAudioFlinger, data, reply); - pid_t pid = data.readInt32(); effect_descriptor_t desc; data.read(&desc, sizeof(effect_descriptor_t)); sp<IEffectClient> client = interface_cast<IEffectClient>(data.readStrongBinder()); @@ -1043,7 +1024,8 @@ status_t BnAudioFlinger::onTransact( int id; int enabled; - sp<IEffect> effect = createEffect(pid, &desc, client, priority, output, sessionId, &status, &id, &enabled); + sp<IEffect> effect = createEffect(&desc, client, priority, output, sessionId, + &status, &id, &enabled); reply->writeInt32(status); reply->writeInt32(id); reply->writeInt32(enabled); diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp index 4178b29..2d1e0f8 100644 --- a/media/libmedia/IAudioFlingerClient.cpp +++ b/media/libmedia/IAudioFlingerClient.cpp @@ -50,7 +50,8 @@ public: ALOGV("ioConfigChanged stream %d", stream); data.writeInt32(stream); } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) { - const AudioSystem::OutputDescriptor *desc = (const AudioSystem::OutputDescriptor *)param2; + const AudioSystem::OutputDescriptor *desc = + (const AudioSystem::OutputDescriptor *)param2; data.writeInt32(desc->samplingRate); data.writeInt32(desc->format); data.writeInt32(desc->channels); diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 401437c..386c351 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -55,7 +55,8 @@ enum { IS_SOURCE_ACTIVE, GET_DEVICES_FOR_STREAM, QUERY_DEFAULT_PRE_PROCESSING, - SET_EFFECT_ENABLED + SET_EFFECT_ENABLED, + IS_STREAM_ACTIVE_REMOTELY }; class BpAudioPolicyService : public BpInterface<IAudioPolicyService> @@ -330,6 +331,16 @@ public: return reply.readInt32(); } + virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32((int32_t) stream); + data.writeInt32(inPastMs); + remote()->transact(IS_STREAM_ACTIVE_REMOTELY, data, &reply); + return reply.readInt32(); + } + virtual bool isSourceActive(audio_source_t source) const { Parcel data, reply; @@ -399,13 +410,15 @@ status_t BnAudioPolicyService::onTransact( case SET_PHONE_STATE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - reply->writeInt32(static_cast <uint32_t>(setPhoneState((audio_mode_t) data.readInt32()))); + reply->writeInt32(static_cast <uint32_t>(setPhoneState( + (audio_mode_t) data.readInt32()))); return NO_ERROR; } break; case SET_FORCE_USE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - audio_policy_force_use_t usage = static_cast <audio_policy_force_use_t>(data.readInt32()); + audio_policy_force_use_t usage = static_cast <audio_policy_force_use_t>( + data.readInt32()); audio_policy_forced_cfg_t config = static_cast <audio_policy_forced_cfg_t>(data.readInt32()); reply->writeInt32(static_cast <uint32_t>(setForceUse(usage, config))); @@ -414,7 +427,8 @@ status_t BnAudioPolicyService::onTransact( case GET_FORCE_USE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - audio_policy_force_use_t usage = static_cast <audio_policy_force_use_t>(data.readInt32()); + audio_policy_force_use_t usage = static_cast <audio_policy_force_use_t>( + data.readInt32()); reply->writeInt32(static_cast <uint32_t>(getForceUse(usage))); return NO_ERROR; } break; @@ -602,6 +616,14 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } break; + case IS_STREAM_ACTIVE_REMOTELY: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + audio_stream_type_t stream = (audio_stream_type_t) data.readInt32(); + uint32_t inPastMs = (uint32_t)data.readInt32(); + reply->writeInt32( isStreamActiveRemotely((audio_stream_type_t) stream, inPastMs) ); + return NO_ERROR; + } break; + case IS_SOURCE_ACTIVE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_source_t source = (audio_source_t) data.readInt32(); diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp index 867d1a5..e92f8aa 100644 --- a/media/libmedia/IAudioTrack.cpp +++ b/media/libmedia/IAudioTrack.cpp @@ -33,7 +33,7 @@ enum { START, STOP, FLUSH, - MUTE, + RESERVED, // was MUTE PAUSE, ATTACH_AUX_EFFECT, ALLOCATE_TIMED_BUFFER, @@ -88,14 +88,6 @@ public: remote()->transact(FLUSH, data, &reply); } - virtual void mute(bool e) - { - Parcel data, reply; - data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); - data.writeInt32(e); - remote()->transact(MUTE, data, &reply); - } - virtual void pause() { Parcel data, reply; @@ -192,11 +184,6 @@ status_t BnAudioTrack::onTransact( flush(); return NO_ERROR; } break; - case MUTE: { - CHECK_INTERFACE(IAudioTrack, data, reply); - mute( data.readInt32() ); - return NO_ERROR; - } break; case PAUSE: { CHECK_INTERFACE(IAudioTrack, data, reply); pause(); diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp index 2defc2d..98b183a 100644 --- a/media/libmedia/ICrypto.cpp +++ b/media/libmedia/ICrypto.cpp @@ -48,7 +48,7 @@ struct BpCrypto : public BpInterface<ICrypto> { return reply.readInt32(); } - virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const { + virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) { Parcel data, reply; data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); data.write(uuid, 16); diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp new file mode 100644 index 0000000..902aeb2 --- /dev/null +++ b/media/libmedia/IDrm.cpp @@ -0,0 +1,739 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "IDrm" +#include <utils/Log.h> + +#include <binder/Parcel.h> +#include <media/IDrm.h> +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/AString.h> + +namespace android { + +enum { + INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION, + IS_CRYPTO_SUPPORTED, + CREATE_PLUGIN, + DESTROY_PLUGIN, + OPEN_SESSION, + CLOSE_SESSION, + GET_KEY_REQUEST, + PROVIDE_KEY_RESPONSE, + REMOVE_KEYS, + RESTORE_KEYS, + QUERY_KEY_STATUS, + GET_PROVISION_REQUEST, + PROVIDE_PROVISION_RESPONSE, + GET_SECURE_STOPS, + RELEASE_SECURE_STOPS, + GET_PROPERTY_STRING, + GET_PROPERTY_BYTE_ARRAY, + SET_PROPERTY_STRING, + SET_PROPERTY_BYTE_ARRAY, + SET_CIPHER_ALGORITHM, + SET_MAC_ALGORITHM, + ENCRYPT, + DECRYPT, + SIGN, + VERIFY, + SET_LISTENER +}; + +struct BpDrm : public BpInterface<IDrm> { + BpDrm(const sp<IBinder> &impl) + : BpInterface<IDrm>(impl) { + } + + virtual status_t initCheck() const { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + remote()->transact(INIT_CHECK, data, &reply); + + return reply.readInt32(); + } + + virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + data.write(uuid, 16); + remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply); + + return reply.readInt32() != 0; + } + + virtual status_t createPlugin(const uint8_t uuid[16]) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + data.write(uuid, 16); + + remote()->transact(CREATE_PLUGIN, data, &reply); + + return reply.readInt32(); + } + + virtual status_t destroyPlugin() { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + remote()->transact(DESTROY_PLUGIN, data, &reply); + + return reply.readInt32(); + } + + virtual status_t openSession(Vector<uint8_t> &sessionId) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + remote()->transact(OPEN_SESSION, data, &reply); + readVector(reply, sessionId); + + return reply.readInt32(); + } + + virtual status_t closeSession(Vector<uint8_t> const &sessionId) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + remote()->transact(CLOSE_SESSION, data, &reply); + + return reply.readInt32(); + } + + virtual status_t + getKeyRequest(Vector<uint8_t> const &sessionId, + Vector<uint8_t> const &initData, + String8 const &mimeType, DrmPlugin::KeyType keyType, + KeyedVector<String8, String8> const &optionalParameters, + Vector<uint8_t> &request, String8 &defaultUrl) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + writeVector(data, initData); + data.writeString8(mimeType); + data.writeInt32((uint32_t)keyType); + + data.writeInt32(optionalParameters.size()); + for (size_t i = 0; i < optionalParameters.size(); ++i) { + data.writeString8(optionalParameters.keyAt(i)); + data.writeString8(optionalParameters.valueAt(i)); + } + remote()->transact(GET_KEY_REQUEST, data, &reply); + + readVector(reply, request); + defaultUrl = reply.readString8(); + + return reply.readInt32(); + } + + virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId, + Vector<uint8_t> const &response, + Vector<uint8_t> &keySetId) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + writeVector(data, sessionId); + writeVector(data, response); + remote()->transact(PROVIDE_KEY_RESPONSE, data, &reply); + readVector(reply, keySetId); + + return reply.readInt32(); + } + + virtual status_t removeKeys(Vector<uint8_t> const &keySetId) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, keySetId); + remote()->transact(REMOVE_KEYS, data, &reply); + + return reply.readInt32(); + } + + virtual status_t restoreKeys(Vector<uint8_t> const &sessionId, + Vector<uint8_t> const &keySetId) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + writeVector(data, keySetId); + remote()->transact(RESTORE_KEYS, data, &reply); + + return reply.readInt32(); + } + + virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId, + KeyedVector<String8, String8> &infoMap) const { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + remote()->transact(QUERY_KEY_STATUS, data, &reply); + + infoMap.clear(); + size_t count = reply.readInt32(); + for (size_t i = 0; i < count; i++) { + String8 key = reply.readString8(); + String8 value = reply.readString8(); + infoMap.add(key, value); + } + return reply.readInt32(); + } + + virtual status_t getProvisionRequest(Vector<uint8_t> &request, + String8 &defaultUrl) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + remote()->transact(GET_PROVISION_REQUEST, data, &reply); + + readVector(reply, request); + defaultUrl = reply.readString8(); + + return reply.readInt32(); + } + + virtual status_t provideProvisionResponse(Vector<uint8_t> const &response) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, response); + remote()->transact(PROVIDE_PROVISION_RESPONSE, data, &reply); + + return reply.readInt32(); + } + + virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + remote()->transact(GET_SECURE_STOPS, data, &reply); + + secureStops.clear(); + uint32_t count = reply.readInt32(); + for (size_t i = 0; i < count; i++) { + Vector<uint8_t> secureStop; + readVector(reply, secureStop); + secureStops.push_back(secureStop); + } + return reply.readInt32(); + } + + virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, ssRelease); + remote()->transact(RELEASE_SECURE_STOPS, data, &reply); + + return reply.readInt32(); + } + + virtual status_t getPropertyString(String8 const &name, String8 &value) const { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + data.writeString8(name); + remote()->transact(GET_PROPERTY_STRING, data, &reply); + + value = reply.readString8(); + return reply.readInt32(); + } + + virtual status_t getPropertyByteArray(String8 const &name, Vector<uint8_t> &value) const { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + data.writeString8(name); + remote()->transact(GET_PROPERTY_BYTE_ARRAY, data, &reply); + + readVector(reply, value); + return reply.readInt32(); + } + + virtual status_t setPropertyString(String8 const &name, String8 const &value) const { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + data.writeString8(name); + data.writeString8(value); + remote()->transact(SET_PROPERTY_STRING, data, &reply); + + return reply.readInt32(); + } + + virtual status_t setPropertyByteArray(String8 const &name, + Vector<uint8_t> const &value) const { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + data.writeString8(name); + writeVector(data, value); + remote()->transact(SET_PROPERTY_BYTE_ARRAY, data, &reply); + + return reply.readInt32(); + } + + + virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId, + String8 const &algorithm) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + data.writeString8(algorithm); + remote()->transact(SET_CIPHER_ALGORITHM, data, &reply); + return reply.readInt32(); + } + + virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId, + String8 const &algorithm) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + data.writeString8(algorithm); + remote()->transact(SET_MAC_ALGORITHM, data, &reply); + return reply.readInt32(); + } + + virtual status_t encrypt(Vector<uint8_t> const &sessionId, + Vector<uint8_t> const &keyId, + Vector<uint8_t> const &input, + Vector<uint8_t> const &iv, + Vector<uint8_t> &output) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + writeVector(data, keyId); + writeVector(data, input); + writeVector(data, iv); + + remote()->transact(ENCRYPT, data, &reply); + readVector(reply, output); + + return reply.readInt32(); + } + + virtual status_t decrypt(Vector<uint8_t> const &sessionId, + Vector<uint8_t> const &keyId, + Vector<uint8_t> const &input, + Vector<uint8_t> const &iv, + Vector<uint8_t> &output) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + writeVector(data, keyId); + writeVector(data, input); + writeVector(data, iv); + + remote()->transact(DECRYPT, data, &reply); + readVector(reply, output); + + return reply.readInt32(); + } + + virtual status_t sign(Vector<uint8_t> const &sessionId, + Vector<uint8_t> const &keyId, + Vector<uint8_t> const &message, + Vector<uint8_t> &signature) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + writeVector(data, keyId); + writeVector(data, message); + + remote()->transact(SIGN, data, &reply); + readVector(reply, signature); + + return reply.readInt32(); + } + + virtual status_t verify(Vector<uint8_t> const &sessionId, + Vector<uint8_t> const &keyId, + Vector<uint8_t> const &message, + Vector<uint8_t> const &signature, + bool &match) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + writeVector(data, keyId); + writeVector(data, message); + writeVector(data, signature); + + remote()->transact(VERIFY, data, &reply); + match = (bool)reply.readInt32(); + return reply.readInt32(); + } + + virtual status_t setListener(const sp<IDrmClient>& listener) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + data.writeStrongBinder(listener->asBinder()); + remote()->transact(SET_LISTENER, data, &reply); + return reply.readInt32(); + } + +private: + void readVector(Parcel &reply, Vector<uint8_t> &vector) const { + uint32_t size = reply.readInt32(); + vector.insertAt((size_t)0, size); + reply.read(vector.editArray(), size); + } + + void writeVector(Parcel &data, Vector<uint8_t> const &vector) const { + data.writeInt32(vector.size()); + data.write(vector.array(), vector.size()); + } + + DISALLOW_EVIL_CONSTRUCTORS(BpDrm); +}; + +IMPLEMENT_META_INTERFACE(Drm, "android.drm.IDrm"); + +//////////////////////////////////////////////////////////////////////////////// + +void BnDrm::readVector(const Parcel &data, Vector<uint8_t> &vector) const { + uint32_t size = data.readInt32(); + vector.insertAt((size_t)0, size); + data.read(vector.editArray(), size); +} + +void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const { + reply->writeInt32(vector.size()); + reply->write(vector.array(), vector.size()); +} + +status_t BnDrm::onTransact( + uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { + switch (code) { + case INIT_CHECK: + { + CHECK_INTERFACE(IDrm, data, reply); + reply->writeInt32(initCheck()); + return OK; + } + + case IS_CRYPTO_SUPPORTED: + { + CHECK_INTERFACE(IDrm, data, reply); + uint8_t uuid[16]; + data.read(uuid, sizeof(uuid)); + reply->writeInt32(isCryptoSchemeSupported(uuid)); + return OK; + } + + case CREATE_PLUGIN: + { + CHECK_INTERFACE(IDrm, data, reply); + uint8_t uuid[16]; + data.read(uuid, sizeof(uuid)); + reply->writeInt32(createPlugin(uuid)); + return OK; + } + + case DESTROY_PLUGIN: + { + CHECK_INTERFACE(IDrm, data, reply); + reply->writeInt32(destroyPlugin()); + return OK; + } + + case OPEN_SESSION: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId; + status_t result = openSession(sessionId); + writeVector(reply, sessionId); + reply->writeInt32(result); + return OK; + } + + case CLOSE_SESSION: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId; + readVector(data, sessionId); + reply->writeInt32(closeSession(sessionId)); + return OK; + } + + case GET_KEY_REQUEST: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId, initData; + + readVector(data, sessionId); + readVector(data, initData); + String8 mimeType = data.readString8(); + DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)data.readInt32(); + + KeyedVector<String8, String8> optionalParameters; + uint32_t count = data.readInt32(); + for (size_t i = 0; i < count; ++i) { + String8 key, value; + key = data.readString8(); + value = data.readString8(); + optionalParameters.add(key, value); + } + + Vector<uint8_t> request; + String8 defaultUrl; + + status_t result = getKeyRequest(sessionId, initData, + mimeType, keyType, + optionalParameters, + request, defaultUrl); + writeVector(reply, request); + reply->writeString8(defaultUrl); + reply->writeInt32(result); + return OK; + } + + case PROVIDE_KEY_RESPONSE: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId, response, keySetId; + readVector(data, sessionId); + readVector(data, response); + uint32_t result = provideKeyResponse(sessionId, response, keySetId); + writeVector(reply, keySetId); + reply->writeInt32(result); + return OK; + } + + case REMOVE_KEYS: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> keySetId; + readVector(data, keySetId); + reply->writeInt32(removeKeys(keySetId)); + return OK; + } + + case RESTORE_KEYS: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId, keySetId; + readVector(data, sessionId); + readVector(data, keySetId); + reply->writeInt32(restoreKeys(sessionId, keySetId)); + return OK; + } + + case QUERY_KEY_STATUS: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId; + readVector(data, sessionId); + KeyedVector<String8, String8> infoMap; + status_t result = queryKeyStatus(sessionId, infoMap); + size_t count = infoMap.size(); + reply->writeInt32(count); + for (size_t i = 0; i < count; ++i) { + reply->writeString8(infoMap.keyAt(i)); + reply->writeString8(infoMap.valueAt(i)); + } + reply->writeInt32(result); + return OK; + } + + case GET_PROVISION_REQUEST: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> request; + String8 defaultUrl; + status_t result = getProvisionRequest(request, defaultUrl); + writeVector(reply, request); + reply->writeString8(defaultUrl); + reply->writeInt32(result); + return OK; + } + + case PROVIDE_PROVISION_RESPONSE: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> response; + readVector(data, response); + reply->writeInt32(provideProvisionResponse(response)); + return OK; + } + + case GET_SECURE_STOPS: + { + CHECK_INTERFACE(IDrm, data, reply); + List<Vector<uint8_t> > secureStops; + status_t result = getSecureStops(secureStops); + size_t count = secureStops.size(); + reply->writeInt32(count); + List<Vector<uint8_t> >::iterator iter = secureStops.begin(); + while(iter != secureStops.end()) { + size_t size = iter->size(); + reply->writeInt32(size); + reply->write(iter->array(), iter->size()); + iter++; + } + reply->writeInt32(result); + return OK; + } + + case RELEASE_SECURE_STOPS: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> ssRelease; + readVector(data, ssRelease); + reply->writeInt32(releaseSecureStops(ssRelease)); + return OK; + } + + case GET_PROPERTY_STRING: + { + CHECK_INTERFACE(IDrm, data, reply); + String8 name = data.readString8(); + String8 value; + status_t result = getPropertyString(name, value); + reply->writeString8(value); + reply->writeInt32(result); + return OK; + } + + case GET_PROPERTY_BYTE_ARRAY: + { + CHECK_INTERFACE(IDrm, data, reply); + String8 name = data.readString8(); + Vector<uint8_t> value; + status_t result = getPropertyByteArray(name, value); + writeVector(reply, value); + reply->writeInt32(result); + return OK; + } + + case SET_PROPERTY_STRING: + { + CHECK_INTERFACE(IDrm, data, reply); + String8 name = data.readString8(); + String8 value = data.readString8(); + reply->writeInt32(setPropertyString(name, value)); + return OK; + } + + case SET_PROPERTY_BYTE_ARRAY: + { + CHECK_INTERFACE(IDrm, data, reply); + String8 name = data.readString8(); + Vector<uint8_t> value; + readVector(data, value); + reply->writeInt32(setPropertyByteArray(name, value)); + return OK; + } + + case SET_CIPHER_ALGORITHM: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId; + readVector(data, sessionId); + String8 algorithm = data.readString8(); + reply->writeInt32(setCipherAlgorithm(sessionId, algorithm)); + return OK; + } + + case SET_MAC_ALGORITHM: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId; + readVector(data, sessionId); + String8 algorithm = data.readString8(); + reply->writeInt32(setMacAlgorithm(sessionId, algorithm)); + return OK; + } + + case ENCRYPT: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId, keyId, input, iv, output; + readVector(data, sessionId); + readVector(data, keyId); + readVector(data, input); + readVector(data, iv); + uint32_t result = encrypt(sessionId, keyId, input, iv, output); + writeVector(reply, output); + reply->writeInt32(result); + return OK; + } + + case DECRYPT: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId, keyId, input, iv, output; + readVector(data, sessionId); + readVector(data, keyId); + readVector(data, input); + readVector(data, iv); + uint32_t result = decrypt(sessionId, keyId, input, iv, output); + writeVector(reply, output); + reply->writeInt32(result); + return OK; + } + + case SIGN: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId, keyId, message, signature; + readVector(data, sessionId); + readVector(data, keyId); + readVector(data, message); + uint32_t result = sign(sessionId, keyId, message, signature); + writeVector(reply, signature); + reply->writeInt32(result); + return OK; + } + + case VERIFY: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId, keyId, message, signature; + readVector(data, sessionId); + readVector(data, keyId); + readVector(data, message); + readVector(data, signature); + bool match; + uint32_t result = verify(sessionId, keyId, message, signature, match); + reply->writeInt32(match); + reply->writeInt32(result); + return OK; + } + + case SET_LISTENER: { + CHECK_INTERFACE(IDrm, data, reply); + sp<IDrmClient> listener = + interface_cast<IDrmClient>(data.readStrongBinder()); + reply->writeInt32(setListener(listener)); + return NO_ERROR; + } break; + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +} // namespace android + diff --git a/media/libmedia/IDrmClient.cpp b/media/libmedia/IDrmClient.cpp new file mode 100644 index 0000000..f50715e --- /dev/null +++ b/media/libmedia/IDrmClient.cpp @@ -0,0 +1,81 @@ +/* +** +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "IDrmClient" +#include <utils/Log.h> + +#include <utils/RefBase.h> +#include <binder/IInterface.h> +#include <binder/Parcel.h> + +#include <media/IMediaPlayerClient.h> +#include <media/IDrmClient.h> + +namespace android { + +enum { + NOTIFY = IBinder::FIRST_CALL_TRANSACTION, +}; + +class BpDrmClient: public BpInterface<IDrmClient> +{ +public: + BpDrmClient(const sp<IBinder>& impl) + : BpInterface<IDrmClient>(impl) + { + } + + virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) + { + Parcel data, reply; + data.writeInterfaceToken(IDrmClient::getInterfaceDescriptor()); + data.writeInt32((int)eventType); + data.writeInt32(extra); + if (obj && obj->dataSize() > 0) { + data.appendFrom(const_cast<Parcel *>(obj), 0, obj->dataSize()); + } + remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(DrmClient, "android.media.IDrmClient"); + +// ---------------------------------------------------------------------- + +status_t BnDrmClient::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch (code) { + case NOTIFY: { + CHECK_INTERFACE(IDrmClient, data, reply); + int eventType = data.readInt32(); + int extra = data.readInt32(); + Parcel obj; + if (data.dataAvail() > 0) { + obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail()); + } + + notify((DrmPlugin::EventType)eventType, extra, &obj); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android diff --git a/media/libmedia/IHDCP.cpp b/media/libmedia/IHDCP.cpp index 493f5a4..f13addc 100644 --- a/media/libmedia/IHDCP.cpp +++ b/media/libmedia/IHDCP.cpp @@ -31,6 +31,7 @@ enum { HDCP_INIT_ASYNC, HDCP_SHUTDOWN_ASYNC, HDCP_ENCRYPT, + HDCP_DECRYPT, }; struct BpHDCPObserver : public BpInterface<IHDCPObserver> { @@ -106,6 +107,29 @@ struct BpHDCP : public BpInterface<IHDCP> { return err; } + + virtual status_t decrypt( + const void *inData, size_t size, + uint32_t streamCTR, uint64_t inputCTR, + void *outData) { + Parcel data, reply; + data.writeInterfaceToken(IHDCP::getInterfaceDescriptor()); + data.writeInt32(size); + data.write(inData, size); + data.writeInt32(streamCTR); + data.writeInt64(inputCTR); + remote()->transact(HDCP_DECRYPT, data, &reply); + + status_t err = reply.readInt32(); + + if (err != OK) { + return err; + } + + reply.read(outData, size); + + return err; + } }; IMPLEMENT_META_INTERFACE(HDCP, "android.hardware.IHDCP"); @@ -198,6 +222,31 @@ status_t BnHDCP::onTransact( return OK; } + case HDCP_DECRYPT: + { + size_t size = data.readInt32(); + + void *inData = malloc(2 * size); + void *outData = (uint8_t *)inData + size; + + data.read(inData, size); + + uint32_t streamCTR = data.readInt32(); + uint64_t inputCTR = data.readInt64(); + status_t err = decrypt(inData, size, streamCTR, inputCTR, outData); + + reply->writeInt32(err); + + if (err == OK) { + reply->write(outData, size); + } + + free(inData); + inData = outData = NULL; + + return OK; + } + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IMediaLogService.cpp b/media/libmedia/IMediaLogService.cpp new file mode 100644 index 0000000..33239a7 --- /dev/null +++ b/media/libmedia/IMediaLogService.cpp @@ -0,0 +1,94 @@ +/* +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "IMediaLogService" +//#define LOG_NDEBUG 0 + +#include <utils/Log.h> +#include <stdint.h> +#include <sys/types.h> +#include <binder/Parcel.h> +#include <media/IMediaLogService.h> + +namespace android { + +enum { + REGISTER_WRITER = IBinder::FIRST_CALL_TRANSACTION, + UNREGISTER_WRITER, +}; + +class BpMediaLogService : public BpInterface<IMediaLogService> +{ +public: + BpMediaLogService(const sp<IBinder>& impl) + : BpInterface<IMediaLogService>(impl) + { + } + + virtual void registerWriter(const sp<IMemory>& shared, size_t size, const char *name) { + Parcel data, reply; + data.writeInterfaceToken(IMediaLogService::getInterfaceDescriptor()); + data.writeStrongBinder(shared->asBinder()); + data.writeInt32((int32_t) size); + data.writeCString(name); + status_t status = remote()->transact(REGISTER_WRITER, data, &reply); + // FIXME ignores status + } + + virtual void unregisterWriter(const sp<IMemory>& shared) { + Parcel data, reply; + data.writeInterfaceToken(IMediaLogService::getInterfaceDescriptor()); + data.writeStrongBinder(shared->asBinder()); + status_t status = remote()->transact(UNREGISTER_WRITER, data, &reply); + // FIXME ignores status + } + +}; + +IMPLEMENT_META_INTERFACE(MediaLogService, "android.media.IMediaLogService"); + +// ---------------------------------------------------------------------- + +status_t BnMediaLogService::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch (code) { + + case REGISTER_WRITER: { + CHECK_INTERFACE(IMediaLogService, data, reply); + sp<IMemory> shared = interface_cast<IMemory>(data.readStrongBinder()); + size_t size = (size_t) data.readInt32(); + const char *name = data.readCString(); + registerWriter(shared, size, name); + return NO_ERROR; + } + + case UNREGISTER_WRITER: { + CHECK_INTERFACE(IMediaLogService, data, reply); + sp<IMemory> shared = interface_cast<IMemory>(data.readStrongBinder()); + unregisterWriter(shared); + return NO_ERROR; + } + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index cb07766..e79bcd2 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -24,7 +24,7 @@ #include <media/IMediaPlayer.h> #include <media/IStreamSource.h> -#include <gui/ISurfaceTexture.h> +#include <gui/IGraphicBufferProducer.h> #include <utils/String8.h> namespace android { @@ -113,12 +113,12 @@ public: return reply.readInt32(); } - // pass the buffered ISurfaceTexture to the media player service - status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture) + // pass the buffered IGraphicBufferProducer to the media player service + status_t setVideoSurfaceTexture(const sp<IGraphicBufferProducer>& bufferProducer) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); - sp<IBinder> b(surfaceTexture->asBinder()); + sp<IBinder> b(bufferProducer->asBinder()); data.writeStrongBinder(b); remote()->transact(SET_VIDEO_SURFACETEXTURE, data, &reply); return reply.readInt32(); @@ -383,9 +383,9 @@ status_t BnMediaPlayer::onTransact( } case SET_VIDEO_SURFACETEXTURE: { CHECK_INTERFACE(IMediaPlayer, data, reply); - sp<ISurfaceTexture> surfaceTexture = - interface_cast<ISurfaceTexture>(data.readStrongBinder()); - reply->writeInt32(setVideoSurfaceTexture(surfaceTexture)); + sp<IGraphicBufferProducer> bufferProducer = + interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); + reply->writeInt32(setVideoSurfaceTexture(bufferProducer)); return NO_ERROR; } break; case PREPARE_ASYNC: { diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index c0a0260..74f574d 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -21,6 +21,7 @@ #include <binder/Parcel.h> #include <binder/IMemory.h> #include <media/ICrypto.h> +#include <media/IDrm.h> #include <media/IHDCP.h> #include <media/IMediaPlayerService.h> #include <media/IMediaRecorder.h> @@ -42,10 +43,12 @@ enum { CREATE_METADATA_RETRIEVER, GET_OMX, MAKE_CRYPTO, + MAKE_DRM, MAKE_HDCP, ADD_BATTERY_DATA, PULL_BATTERY_DATA, LISTEN_FOR_REMOTE_DISPLAY, + UPDATE_PROXY_CONFIG, }; class BpMediaPlayerService: public BpInterface<IMediaPlayerService> @@ -56,20 +59,18 @@ public: { } - virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) + virtual sp<IMediaMetadataRetriever> createMetadataRetriever() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); - data.writeInt32(pid); remote()->transact(CREATE_METADATA_RETRIEVER, data, &reply); return interface_cast<IMediaMetadataRetriever>(reply.readStrongBinder()); } virtual sp<IMediaPlayer> create( - pid_t pid, const sp<IMediaPlayerClient>& client, int audioSessionId) { + const sp<IMediaPlayerClient>& client, int audioSessionId) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); - data.writeInt32(pid); data.writeStrongBinder(client->asBinder()); data.writeInt32(audioSessionId); @@ -77,11 +78,10 @@ public: return interface_cast<IMediaPlayer>(reply.readStrongBinder()); } - virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid) + virtual sp<IMediaRecorder> createMediaRecorder() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); - data.writeInt32(pid); remote()->transact(CREATE_MEDIA_RECORDER, data, &reply); return interface_cast<IMediaRecorder>(reply.readStrongBinder()); } @@ -126,9 +126,17 @@ public: return interface_cast<ICrypto>(reply.readStrongBinder()); } - virtual sp<IHDCP> makeHDCP() { + virtual sp<IDrm> makeDrm() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + remote()->transact(MAKE_DRM, data, &reply); + return interface_cast<IDrm>(reply.readStrongBinder()); + } + + virtual sp<IHDCP> makeHDCP(bool createEncryptionModule) { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + data.writeInt32(createEncryptionModule); remote()->transact(MAKE_HDCP, data, &reply); return interface_cast<IHDCP>(reply.readStrongBinder()); } @@ -156,6 +164,25 @@ public: remote()->transact(LISTEN_FOR_REMOTE_DISPLAY, data, &reply); return interface_cast<IRemoteDisplay>(reply.readStrongBinder()); } + + virtual status_t updateProxyConfig( + const char *host, int32_t port, const char *exclusionList) { + Parcel data, reply; + + data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + if (host == NULL) { + data.writeInt32(0); + } else { + data.writeInt32(1); + data.writeCString(host); + data.writeInt32(port); + data.writeCString(exclusionList); + } + + remote()->transact(UPDATE_PROXY_CONFIG, data, &reply); + + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService"); @@ -168,11 +195,10 @@ status_t BnMediaPlayerService::onTransact( switch (code) { case CREATE: { CHECK_INTERFACE(IMediaPlayerService, data, reply); - pid_t pid = data.readInt32(); sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder()); int audioSessionId = data.readInt32(); - sp<IMediaPlayer> player = create(pid, client, audioSessionId); + sp<IMediaPlayer> player = create(client, audioSessionId); reply->writeStrongBinder(player->asBinder()); return NO_ERROR; } break; @@ -206,15 +232,13 @@ status_t BnMediaPlayerService::onTransact( } break; case CREATE_MEDIA_RECORDER: { CHECK_INTERFACE(IMediaPlayerService, data, reply); - pid_t pid = data.readInt32(); - sp<IMediaRecorder> recorder = createMediaRecorder(pid); + sp<IMediaRecorder> recorder = createMediaRecorder(); reply->writeStrongBinder(recorder->asBinder()); return NO_ERROR; } break; case CREATE_METADATA_RETRIEVER: { CHECK_INTERFACE(IMediaPlayerService, data, reply); - pid_t pid = data.readInt32(); - sp<IMediaMetadataRetriever> retriever = createMetadataRetriever(pid); + sp<IMediaMetadataRetriever> retriever = createMetadataRetriever(); reply->writeStrongBinder(retriever->asBinder()); return NO_ERROR; } break; @@ -230,9 +254,16 @@ status_t BnMediaPlayerService::onTransact( reply->writeStrongBinder(crypto->asBinder()); return NO_ERROR; } break; + case MAKE_DRM: { + CHECK_INTERFACE(IMediaPlayerService, data, reply); + sp<IDrm> drm = makeDrm(); + reply->writeStrongBinder(drm->asBinder()); + return NO_ERROR; + } break; case MAKE_HDCP: { CHECK_INTERFACE(IMediaPlayerService, data, reply); - sp<IHDCP> hdcp = makeHDCP(); + bool createEncryptionModule = data.readInt32(); + sp<IHDCP> hdcp = makeHDCP(createEncryptionModule); reply->writeStrongBinder(hdcp->asBinder()); return NO_ERROR; } break; @@ -256,6 +287,24 @@ status_t BnMediaPlayerService::onTransact( reply->writeStrongBinder(display->asBinder()); return NO_ERROR; } break; + case UPDATE_PROXY_CONFIG: + { + CHECK_INTERFACE(IMediaPlayerService, data, reply); + + const char *host = NULL; + int32_t port = 0; + const char *exclusionList = NULL; + + if (data.readInt32()) { + host = data.readCString(); + port = data.readInt32(); + exclusionList = data.readCString(); + } + + reply->writeInt32(updateProxyConfig(host, port, exclusionList)); + + return OK; + } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp index a710fd7..8e58162 100644 --- a/media/libmedia/IMediaRecorder.cpp +++ b/media/libmedia/IMediaRecorder.cpp @@ -23,7 +23,7 @@ #include <media/IMediaRecorderClient.h> #include <media/IMediaRecorder.h> #include <gui/Surface.h> -#include <gui/ISurfaceTexture.h> +#include <gui/IGraphicBufferProducer.h> #include <unistd.h> @@ -51,7 +51,8 @@ enum { SET_PARAMETERS, SET_PREVIEW_SURFACE, SET_CAMERA, - SET_LISTENER + SET_LISTENER, + SET_CLIENT_NAME }; class BpMediaRecorder: public BpInterface<IMediaRecorder> @@ -73,7 +74,7 @@ public: return reply.readInt32(); } - sp<ISurfaceTexture> querySurfaceMediaSource() + sp<IGraphicBufferProducer> querySurfaceMediaSource() { ALOGV("Query SurfaceMediaSource"); Parcel data, reply; @@ -83,15 +84,15 @@ public: if (returnedNull) { return NULL; } - return interface_cast<ISurfaceTexture>(reply.readStrongBinder()); + return interface_cast<IGraphicBufferProducer>(reply.readStrongBinder()); } - status_t setPreviewSurface(const sp<Surface>& surface) + status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface) { ALOGV("setPreviewSurface(%p)", surface.get()); Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); - Surface::writeToParcel(surface, &data); + data.writeStrongBinder(surface->asBinder()); remote()->transact(SET_PREVIEW_SURFACE, data, &reply); return reply.readInt32(); } @@ -217,6 +218,16 @@ public: return reply.readInt32(); } + status_t setClientName(const String16& clientName) + { + ALOGV("setClientName(%s)", String8(clientName).string()); + Parcel data, reply; + data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); + data.writeString16(clientName); + remote()->transact(SET_CLIENT_NAME, data, &reply); + return reply.readInt32(); + } + status_t prepare() { ALOGV("prepare"); @@ -423,10 +434,16 @@ status_t BnMediaRecorder::onTransact( reply->writeInt32(setListener(listener)); return NO_ERROR; } break; + case SET_CLIENT_NAME: { + ALOGV("SET_CLIENT_NAME"); + CHECK_INTERFACE(IMediaRecorder, data, reply); + reply->writeInt32(setClientName(data.readString16())); + return NO_ERROR; + } case SET_PREVIEW_SURFACE: { ALOGV("SET_PREVIEW_SURFACE"); CHECK_INTERFACE(IMediaRecorder, data, reply); - sp<Surface> surface = Surface::readFromParcel(data); + sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); reply->writeInt32(setPreviewSurface(surface)); return NO_ERROR; } break; @@ -444,7 +461,7 @@ status_t BnMediaRecorder::onTransact( CHECK_INTERFACE(IMediaRecorder, data, reply); // call the mediaserver side to create // a surfacemediasource - sp<ISurfaceTexture> surfaceMediaSource = querySurfaceMediaSource(); + sp<IGraphicBufferProducer> surfaceMediaSource = querySurfaceMediaSource(); // The mediaserver might have failed to create a source int returnedNull= (surfaceMediaSource == NULL) ? 1 : 0 ; reply->writeInt32(returnedNull); diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index 48e427a..d6cd43a 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -40,6 +40,8 @@ enum { ENABLE_GRAPHIC_BUFFERS, USE_BUFFER, USE_GRAPHIC_BUFFER, + CREATE_INPUT_SURFACE, + SIGNAL_END_OF_INPUT_STREAM, STORE_META_DATA_IN_BUFFERS, ALLOC_BUFFER, ALLOC_BUFFER_WITH_BACKUP, @@ -280,6 +282,45 @@ public: return err; } + virtual status_t createInputSurface( + node_id node, OMX_U32 port_index, + sp<IGraphicBufferProducer> *bufferProducer) { + Parcel data, reply; + status_t err; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(port_index); + err = remote()->transact(CREATE_INPUT_SURFACE, data, &reply); + if (err != OK) { + ALOGW("binder transaction failed: %d", err); + return err; + } + + err = reply.readInt32(); + if (err != OK) { + return err; + } + + *bufferProducer = IGraphicBufferProducer::asInterface( + reply.readStrongBinder()); + + return err; + } + + virtual status_t signalEndOfInputStream(node_id node) { + Parcel data, reply; + status_t err; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + err = remote()->transact(SIGNAL_END_OF_INPUT_STREAM, data, &reply); + if (err != OK) { + ALOGW("binder transaction failed: %d", err); + return err; + } + + return reply.readInt32(); + } + virtual status_t storeMetaDataInBuffers( node_id node, OMX_U32 port_index, OMX_BOOL enable) { Parcel data, reply; @@ -404,7 +445,7 @@ IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX"); //////////////////////////////////////////////////////////////////////////////// -#define CHECK_INTERFACE(interface, data, reply) \ +#define CHECK_OMX_INTERFACE(interface, data, reply) \ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ ALOGW("Call incorrectly routed to " #interface); \ return PERMISSION_DENIED; \ @@ -415,7 +456,7 @@ status_t BnOMX::onTransact( switch (code) { case LIVES_LOCALLY: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void *)data.readIntPtr(); pid_t pid = (pid_t)data.readInt32(); reply->writeInt32(livesLocally(node, pid)); @@ -425,7 +466,7 @@ status_t BnOMX::onTransact( case LIST_NODES: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); List<ComponentInfo> list; listNodes(&list); @@ -448,7 +489,7 @@ status_t BnOMX::onTransact( case ALLOCATE_NODE: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); const char *name = data.readCString(); @@ -468,7 +509,7 @@ status_t BnOMX::onTransact( case FREE_NODE: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); @@ -479,7 +520,7 @@ status_t BnOMX::onTransact( case SEND_COMMAND: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); @@ -497,7 +538,7 @@ status_t BnOMX::onTransact( case GET_CONFIG: case SET_CONFIG: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32()); @@ -539,7 +580,7 @@ status_t BnOMX::onTransact( case GET_STATE: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); OMX_STATETYPE state = OMX_StateInvalid; @@ -553,7 +594,7 @@ status_t BnOMX::onTransact( case ENABLE_GRAPHIC_BUFFERS: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); OMX_U32 port_index = data.readInt32(); @@ -567,7 +608,7 @@ status_t BnOMX::onTransact( case GET_GRAPHIC_BUFFER_USAGE: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); OMX_U32 port_index = data.readInt32(); @@ -582,7 +623,7 @@ status_t BnOMX::onTransact( case USE_BUFFER: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); OMX_U32 port_index = data.readInt32(); @@ -602,7 +643,7 @@ status_t BnOMX::onTransact( case USE_GRAPHIC_BUFFER: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); OMX_U32 port_index = data.readInt32(); @@ -621,9 +662,41 @@ status_t BnOMX::onTransact( return NO_ERROR; } + case CREATE_INPUT_SURFACE: + { + CHECK_OMX_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + OMX_U32 port_index = data.readInt32(); + + sp<IGraphicBufferProducer> bufferProducer; + status_t err = createInputSurface(node, port_index, + &bufferProducer); + + reply->writeInt32(err); + + if (err == OK) { + reply->writeStrongBinder(bufferProducer->asBinder()); + } + + return NO_ERROR; + } + + case SIGNAL_END_OF_INPUT_STREAM: + { + CHECK_OMX_INTERFACE(IOMX, data, reply); + + node_id node = (void*)data.readIntPtr(); + + status_t err = signalEndOfInputStream(node); + reply->writeInt32(err); + + return NO_ERROR; + } + case STORE_META_DATA_IN_BUFFERS: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); OMX_U32 port_index = data.readInt32(); @@ -637,7 +710,7 @@ status_t BnOMX::onTransact( case ALLOC_BUFFER: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); OMX_U32 port_index = data.readInt32(); @@ -659,7 +732,7 @@ status_t BnOMX::onTransact( case ALLOC_BUFFER_WITH_BACKUP: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); OMX_U32 port_index = data.readInt32(); @@ -681,7 +754,7 @@ status_t BnOMX::onTransact( case FREE_BUFFER: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); OMX_U32 port_index = data.readInt32(); @@ -693,7 +766,7 @@ status_t BnOMX::onTransact( case FILL_BUFFER: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); buffer_id buffer = (void*)data.readIntPtr(); @@ -704,7 +777,7 @@ status_t BnOMX::onTransact( case EMPTY_BUFFER: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); buffer_id buffer = (void*)data.readIntPtr(); @@ -723,7 +796,7 @@ status_t BnOMX::onTransact( case GET_EXTENSION_INDEX: { - CHECK_INTERFACE(IOMX, data, reply); + CHECK_OMX_INTERFACE(IOMX, data, reply); node_id node = (void*)data.readIntPtr(); const char *parameter_name = data.readCString(); @@ -769,7 +842,7 @@ status_t BnOMXObserver::onTransact( switch (code) { case OBSERVER_ON_MSG: { - CHECK_INTERFACE(IOMXObserver, data, reply); + CHECK_OMX_INTERFACE(IOMXObserver, data, reply); omx_message msg; data.read(&msg, sizeof(msg)); diff --git a/media/libmedia/IRemoteDisplayClient.cpp b/media/libmedia/IRemoteDisplayClient.cpp index 4a1b570..5c494b3 100644 --- a/media/libmedia/IRemoteDisplayClient.cpp +++ b/media/libmedia/IRemoteDisplayClient.cpp @@ -18,7 +18,7 @@ #include <sys/types.h> #include <media/IRemoteDisplayClient.h> -#include <gui/ISurfaceTexture.h> +#include <gui/IGraphicBufferProducer.h> #include <utils/String8.h> namespace android { @@ -37,12 +37,12 @@ public: { } - void onDisplayConnected(const sp<ISurfaceTexture>& surfaceTexture, + void onDisplayConnected(const sp<IGraphicBufferProducer>& bufferProducer, uint32_t width, uint32_t height, uint32_t flags) { Parcel data, reply; data.writeInterfaceToken(IRemoteDisplayClient::getInterfaceDescriptor()); - data.writeStrongBinder(surfaceTexture->asBinder()); + data.writeStrongBinder(bufferProducer->asBinder()); data.writeInt32(width); data.writeInt32(height); data.writeInt32(flags); @@ -75,8 +75,8 @@ status_t BnRemoteDisplayClient::onTransact( switch (code) { case ON_DISPLAY_CONNECTED: { CHECK_INTERFACE(IRemoteDisplayClient, data, reply); - sp<ISurfaceTexture> surfaceTexture( - interface_cast<ISurfaceTexture>(data.readStrongBinder())); + sp<IGraphicBufferProducer> surfaceTexture( + interface_cast<IGraphicBufferProducer>(data.readStrongBinder())); uint32_t width = data.readInt32(); uint32_t height = data.readInt32(); uint32_t flags = data.readInt32(); diff --git a/media/libmedia/SingleStateQueue.cpp b/media/libmedia/SingleStateQueue.cpp new file mode 100644 index 0000000..3503baa --- /dev/null +++ b/media/libmedia/SingleStateQueue.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <new> +#include <cutils/atomic.h> +#include <cutils/atomic-inline.h> // for android_memory_barrier() +#include <media/SingleStateQueue.h> + +namespace android { + +template<typename T> SingleStateQueue<T>::Mutator::Mutator(Shared *shared) + : mSequence(0), mShared((Shared *) shared) +{ + // exactly one of Mutator and Observer must initialize, currently it is Observer + //shared->init(); +} + +template<typename T> int32_t SingleStateQueue<T>::Mutator::push(const T& value) +{ + Shared *shared = mShared; + int32_t sequence = mSequence; + sequence++; + android_atomic_acquire_store(sequence, &shared->mSequence); + shared->mValue = value; + sequence++; + android_atomic_release_store(sequence, &shared->mSequence); + mSequence = sequence; + // consider signalling a futex here, if we know that observer is waiting + return sequence; +} + +template<typename T> bool SingleStateQueue<T>::Mutator::ack() +{ + return mShared->mAck - mSequence == 0; +} + +template<typename T> bool SingleStateQueue<T>::Mutator::ack(int32_t sequence) +{ + // this relies on 2's complement rollover to detect an ancient sequence number + return mShared->mAck - sequence >= 0; +} + +template<typename T> SingleStateQueue<T>::Observer::Observer(Shared *shared) + : mSequence(0), mSeed(1), mShared((Shared *) shared) +{ + // exactly one of Mutator and Observer must initialize, currently it is Observer + shared->init(); +} + +template<typename T> bool SingleStateQueue<T>::Observer::poll(T& value) +{ + Shared *shared = mShared; + int32_t before = shared->mSequence; + if (before == mSequence) { + return false; + } + for (int tries = 0; ; ) { + const int MAX_TRIES = 5; + if (before & 1) { + if (++tries >= MAX_TRIES) { + return false; + } + before = shared->mSequence; + } else { + android_memory_barrier(); + T temp = shared->mValue; + int32_t after = android_atomic_release_load(&shared->mSequence); + if (after == before) { + value = temp; + shared->mAck = before; + mSequence = before; + return true; + } + if (++tries >= MAX_TRIES) { + return false; + } + before = after; + } + } +} + +#if 0 +template<typename T> SingleStateQueue<T>::SingleStateQueue(void /*Shared*/ *shared) +{ + ((Shared *) shared)->init(); +} +#endif + +} // namespace android + +// hack for gcc +#ifdef SINGLE_STATE_QUEUE_INSTANTIATIONS +#include SINGLE_STATE_QUEUE_INSTANTIATIONS +#endif diff --git a/media/libmedia/SingleStateQueueInstantiations.cpp b/media/libmedia/SingleStateQueueInstantiations.cpp new file mode 100644 index 0000000..2afebe9 --- /dev/null +++ b/media/libmedia/SingleStateQueueInstantiations.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <media/SingleStateQueue.h> +#include <private/media/StaticAudioTrackState.h> + +// FIXME hack for gcc + +namespace android { + +template class SingleStateQueue<StaticAudioTrackState>; // typedef StaticAudioTrackSingleStateQueue + +} diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp index abc8899..ee70ef7 100644 --- a/media/libmedia/SoundPool.cpp +++ b/media/libmedia/SoundPool.cpp @@ -489,7 +489,7 @@ Sample::~Sample() ::close(mFd); } mData.clear(); - delete mUrl; + free(mUrl); } status_t Sample::doLoad() @@ -568,8 +568,8 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV } // initialize track - int afFrameCount; - int afSampleRate; + size_t afFrameCount; + uint32_t afSampleRate; audio_stream_type_t streamType = mSoundPool->streamType(); if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { afFrameCount = kDefaultFrameCount; diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp index 253602d..f55b697 100644 --- a/media/libmedia/ToneGenerator.cpp +++ b/media/libmedia/ToneGenerator.cpp @@ -803,6 +803,7 @@ ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool ALOGV("ToneGenerator constructor: streamType=%d, volume=%f", streamType, volume); mState = TONE_IDLE; + mpAudioTrack = NULL; if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) { ALOGE("Unable to marshal AudioFlinger"); @@ -811,7 +812,6 @@ ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool mThreadCanCallJava = threadCanCallJava; mStreamType = streamType; mVolume = volume; - mpAudioTrack = NULL; mpToneDesc = NULL; mpNewToneDesc = NULL; // Generate tone by chunks of 20 ms to keep cadencing precision @@ -885,6 +885,11 @@ bool ToneGenerator::startTone(tone_type toneType, int durationMs) { if ((toneType < 0) || (toneType >= NUM_TONES)) return lResult; + toneType = getToneForRegion(toneType); + if (toneType == TONE_CDMA_SIGNAL_OFF) { + return true; + } + if (mState == TONE_IDLE) { ALOGV("startTone: try to re-init AudioTrack"); if (!initAudioTrack()) { @@ -897,7 +902,6 @@ bool ToneGenerator::startTone(tone_type toneType, int durationMs) { mLock.lock(); // Get descriptor for requested tone - toneType = getToneForRegion(toneType); mpNewToneDesc = &sToneDescriptors[toneType]; mDurationMs = durationMs; @@ -918,6 +922,9 @@ bool ToneGenerator::startTone(tone_type toneType, int durationMs) { ALOGV("Immediate start, time %d", (unsigned int)(systemTime()/1000000)); lResult = true; mState = TONE_STARTING; + if (clock_gettime(CLOCK_MONOTONIC, &mStartTime) != 0) { + mStartTime.tv_sec = 0; + } mLock.unlock(); mpAudioTrack->start(); mLock.lock(); @@ -936,6 +943,7 @@ bool ToneGenerator::startTone(tone_type toneType, int durationMs) { } else { ALOGV("Delayed start"); mState = TONE_RESTARTING; + mStartTime.tv_sec = 0; lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3)); if (lStatus == NO_ERROR) { if (mState != TONE_IDLE) { @@ -972,21 +980,50 @@ void ToneGenerator::stopTone() { ALOGV("stopTone"); mLock.lock(); - if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) { - mState = TONE_STOPPING; + if (mState != TONE_IDLE && mState != TONE_INIT) { + if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) { + struct timespec stopTime; + // If the start time is valid, make sure that the number of audio samples produced + // corresponds at least to the time between the start and stop commands. + // This is needed in case of cold start of the output stream. + if ((mStartTime.tv_sec != 0) && (clock_gettime(CLOCK_MONOTONIC, &stopTime) == 0)) { + time_t sec = stopTime.tv_sec - mStartTime.tv_sec; + long nsec = stopTime.tv_nsec - mStartTime.tv_nsec; + long durationMs; + if (nsec < 0) { + --sec; + nsec += 1000000000; + } + + if ((sec + 1) > ((long)(INT_MAX / mSamplingRate))) { + mMaxSmp = sec * mSamplingRate; + } else { + // mSamplingRate is always > 1000 + sec = sec * 1000 + nsec / 1000000; // duration in milliseconds + mMaxSmp = (unsigned int)(((int64_t)sec * mSamplingRate) / 1000); + } + ALOGV("stopTone() forcing mMaxSmp to %d, total for far %d", mMaxSmp, mTotalSmp); + } else { + mState = TONE_STOPPING; + } + } ALOGV("waiting cond"); status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3)); if (lStatus == NO_ERROR) { + // If the tone was restarted exit now before calling clearWaveGens(); + if (mState != TONE_INIT) { + mLock.unlock(); + return; + } ALOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000)); } else { ALOGE("--- Stop timed out"); mState = TONE_IDLE; mpAudioTrack->stop(); } + clearWaveGens(); } - clearWaveGens(); - mLock.unlock(); } @@ -1036,7 +1073,7 @@ bool ToneGenerator::initAudioTrack() { goto initAudioTrack_exit; } - mpAudioTrack->setVolume(mVolume, mVolume); + mpAudioTrack->setVolume(mVolume); mState = TONE_INIT; @@ -1254,6 +1291,9 @@ audioCallback_EndLoop: ALOGV("Cbk restarting track"); if (lpToneGen->prepareWave()) { lpToneGen->mState = TONE_STARTING; + if (clock_gettime(CLOCK_MONOTONIC, &lpToneGen->mStartTime) != 0) { + lpToneGen->mStartTime.tv_sec = 0; + } // must reload lpToneDesc as prepareWave() may change mpToneDesc lpToneDesc = lpToneGen->mpToneDesc; } else { @@ -1295,7 +1335,7 @@ audioCallback_EndLoop: } if (lSignal) - lpToneGen->mWaitCbkCond.signal(); + lpToneGen->mWaitCbkCond.broadcast(); lpToneGen->mLock.unlock(); } } diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp index 8196e10..5b4071b 100644 --- a/media/libmedia/Visualizer.cpp +++ b/media/libmedia/Visualizer.cpp @@ -88,7 +88,8 @@ status_t Visualizer::setEnabled(bool enabled) return status; } -status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate) +status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, + uint32_t rate) { if (rate > CAPTURE_RATE_MAX) { return BAD_VALUE; @@ -334,7 +335,8 @@ void Visualizer::controlStatusChanged(bool controlGranted) { //------------------------------------------------------------------------- -Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava) +Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, + bool bCanCallJava) : Thread(bCanCallJava), mReceiver(receiver) { mSleepTimeUs = 1000000000 / captureRate; diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp index b0241aa..110b94c 100644 --- a/media/libmedia/mediametadataretriever.cpp +++ b/media/libmedia/mediametadataretriever.cpp @@ -64,7 +64,7 @@ MediaMetadataRetriever::MediaMetadataRetriever() ALOGE("failed to obtain MediaMetadataRetrieverService"); return; } - sp<IMediaMetadataRetriever> retriever(service->createMetadataRetriever(getpid())); + sp<IMediaMetadataRetriever> retriever(service->createMetadataRetriever()); if (retriever == 0) { ALOGE("failed to create IMediaMetadataRetriever object from server"); } diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 4ab98e3..963b04f 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -27,7 +27,7 @@ #include <binder/IServiceManager.h> #include <binder/IPCThreadState.h> -#include <gui/SurfaceTextureClient.h> +#include <gui/Surface.h> #include <media/mediaplayer.h> #include <media/AudioSystem.h> @@ -143,7 +143,7 @@ status_t MediaPlayer::setDataSource( if (url != NULL) { const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != 0) { - sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId)); + sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(url, headers))) { player.clear(); @@ -160,7 +160,7 @@ status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length) status_t err = UNKNOWN_ERROR; const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != 0) { - sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId)); + sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(fd, offset, length))) { player.clear(); @@ -176,7 +176,7 @@ status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source) status_t err = UNKNOWN_ERROR; const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != 0) { - sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId)); + sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(source))) { player.clear(); @@ -221,12 +221,12 @@ status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *m } status_t MediaPlayer::setVideoSurfaceTexture( - const sp<ISurfaceTexture>& surfaceTexture) + const sp<IGraphicBufferProducer>& bufferProducer) { ALOGV("setVideoSurfaceTexture"); Mutex::Autolock _l(mLock); if (mPlayer == 0) return NO_INIT; - return mPlayer->setVideoSurfaceTexture(surfaceTexture); + return mPlayer->setVideoSurfaceTexture(bufferProducer); } // must call with lock held @@ -398,6 +398,13 @@ status_t MediaPlayer::getDuration_l(int *msec) if (mPlayer != 0 && isValidState) { int durationMs; status_t ret = mPlayer->getDuration(&durationMs); + + if (ret != OK) { + // Do not enter error state just because no duration was available. + durationMs = -1; + ret = OK; + } + if (msec) { *msec = durationMs; } @@ -568,8 +575,8 @@ status_t MediaPlayer::setAudioSessionId(int sessionId) return BAD_VALUE; } if (sessionId != mAudioSessionId) { - AudioSystem::releaseAudioSessionId(mAudioSessionId); AudioSystem::acquireAudioSessionId(sessionId); + AudioSystem::releaseAudioSessionId(mAudioSessionId); mAudioSessionId = sessionId; } return NO_ERROR; @@ -807,4 +814,15 @@ status_t MediaPlayer::setNextMediaPlayer(const sp<MediaPlayer>& next) { return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer); } +status_t MediaPlayer::updateProxyConfig( + const char *host, int32_t port, const char *exclusionList) { + const sp<IMediaPlayerService>& service = getMediaPlayerService(); + + if (service != NULL) { + return service->updateProxyConfig(host, port, exclusionList); + } + + return INVALID_OPERATION; +} + }; // namespace android diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp index 9541015..3710e46 100644 --- a/media/libmedia/mediarecorder.cpp +++ b/media/libmedia/mediarecorder.cpp @@ -24,7 +24,7 @@ #include <media/IMediaPlayerService.h> #include <media/IMediaRecorder.h> #include <media/mediaplayer.h> // for MEDIA_ERROR_SERVER_DIED -#include <gui/ISurfaceTexture.h> +#include <gui/IGraphicBufferProducer.h> namespace android { @@ -49,7 +49,7 @@ status_t MediaRecorder::setCamera(const sp<ICamera>& camera, const sp<ICameraRec return ret; } -status_t MediaRecorder::setPreviewSurface(const sp<Surface>& surface) +status_t MediaRecorder::setPreviewSurface(const sp<IGraphicBufferProducer>& surface) { ALOGV("setPreviewSurface(%p)", surface.get()); if (mMediaRecorder == NULL) { @@ -348,9 +348,9 @@ status_t MediaRecorder::setVideoSize(int width, int height) } // Query a SurfaceMediaSurface through the Mediaserver, over the -// binder interface. This is used by the Filter Framework (MeidaEncoder) -// to get an <ISurfaceTexture> object to hook up to ANativeWindow. -sp<ISurfaceTexture> MediaRecorder:: +// binder interface. This is used by the Filter Framework (MediaEncoder) +// to get an <IGraphicBufferProducer> object to hook up to ANativeWindow. +sp<IGraphicBufferProducer> MediaRecorder:: querySurfaceMediaSourceFromMediaServer() { Mutex::Autolock _l(mLock); @@ -620,7 +620,7 @@ MediaRecorder::MediaRecorder() : mSurfaceMediaSource(NULL) const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != NULL) { - mMediaRecorder = service->createMediaRecorder(getpid()); + mMediaRecorder = service->createMediaRecorder(); } if (mMediaRecorder != NULL) { mCurrentState = MEDIA_RECORDER_IDLE; @@ -656,6 +656,27 @@ status_t MediaRecorder::setListener(const sp<MediaRecorderListener>& listener) return NO_ERROR; } +status_t MediaRecorder::setClientName(const String16& clientName) +{ + ALOGV("setClientName"); + if (mMediaRecorder == NULL) { + ALOGE("media recorder is not initialized yet"); + return INVALID_OPERATION; + } + bool isInvalidState = (mCurrentState & + (MEDIA_RECORDER_PREPARED | + MEDIA_RECORDER_RECORDING | + MEDIA_RECORDER_ERROR)); + if (isInvalidState) { + ALOGE("setClientName is called in an invalid state: %d", mCurrentState); + return INVALID_OPERATION; + } + + mMediaRecorder->setClientName(clientName); + + return NO_ERROR; +} + void MediaRecorder::notify(int msg, int ext1, int ext2) { ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2); |