diff options
Diffstat (limited to 'media/libmedia')
| -rw-r--r-- | media/libmedia/Android.mk | 7 | ||||
| -rw-r--r-- | media/libmedia/AudioEffect.cpp | 462 | ||||
| -rw-r--r-- | media/libmedia/AudioRecord.cpp | 92 | ||||
| -rw-r--r-- | media/libmedia/AudioSystem.cpp | 50 | ||||
| -rw-r--r-- | media/libmedia/AudioTrack.cpp | 283 | ||||
| -rw-r--r-- | media/libmedia/IAudioFlinger.cpp | 281 | ||||
| -rw-r--r-- | media/libmedia/IAudioPolicyService.cpp | 148 | ||||
| -rw-r--r-- | media/libmedia/IAudioTrack.cpp | 24 | ||||
| -rw-r--r-- | media/libmedia/IEffect.cpp | 195 | ||||
| -rw-r--r-- | media/libmedia/IEffectClient.cpp | 145 | ||||
| -rw-r--r-- | media/libmedia/IMediaPlayer.cpp | 30 | ||||
| -rw-r--r-- | media/libmedia/IMediaPlayerService.cpp | 36 | ||||
| -rw-r--r-- | media/libmedia/IMediaRecorder.cpp | 8 | ||||
| -rw-r--r-- | media/libmedia/IMediaRecorderClient.cpp | 70 | ||||
| -rw-r--r-- | media/libmedia/IOMX.cpp | 2 | ||||
| -rw-r--r-- | media/libmedia/MediaProfiles.cpp | 81 | ||||
| -rw-r--r-- | media/libmedia/MediaScanner.cpp | 4 | ||||
| -rw-r--r-- | media/libmedia/Visualizer.cpp | 330 | ||||
| -rw-r--r-- | media/libmedia/mediaplayer.cpp | 109 |
19 files changed, 2112 insertions, 245 deletions
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 3adabcc..977e6be 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -12,6 +12,7 @@ LOCAL_SRC_FILES:= \ mediaplayer.cpp \ IMediaPlayerService.cpp \ IMediaPlayerClient.cpp \ + IMediaRecorderClient.cpp \ IMediaPlayer.cpp \ IMediaRecorder.cpp \ Metadata.cpp \ @@ -26,7 +27,11 @@ LOCAL_SRC_FILES:= \ MediaScannerClient.cpp \ autodetect.cpp \ IMediaDeathNotifier.cpp \ - MediaProfiles.cpp + MediaProfiles.cpp \ + IEffect.cpp \ + IEffectClient.cpp \ + AudioEffect.cpp \ + Visualizer.cpp LOCAL_SHARED_LIBRARIES := \ libui libcutils libutils libbinder libsonivox libicuuc libexpat libsurfaceflinger_client libcamera_client diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp new file mode 100644 index 0000000..3cdf48a --- /dev/null +++ b/media/libmedia/AudioEffect.cpp @@ -0,0 +1,462 @@ +/* +** +** Copyright 2010, 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 "AudioEffect" + +#include <stdint.h> +#include <sys/types.h> +#include <limits.h> + +#include <private/media/AudioEffectShared.h> +#include <media/AudioEffect.h> + +#include <utils/Log.h> +#include <cutils/atomic.h> +#include <binder/IPCThreadState.h> + + + +namespace android { + +// --------------------------------------------------------------------------- + +AudioEffect::AudioEffect() + : mStatus(NO_INIT) +{ +} + + +AudioEffect::AudioEffect(const effect_uuid_t *type, + const effect_uuid_t *uuid, + int32_t priority, + effect_callback_t cbf, + void* user, + int sessionId, + audio_io_handle_t output + ) + : mStatus(NO_INIT) +{ + mStatus = set(type, uuid, priority, cbf, user, sessionId, output); +} + +AudioEffect::AudioEffect(const char *typeStr, + const char *uuidStr, + int32_t priority, + effect_callback_t cbf, + void* user, + int sessionId, + audio_io_handle_t output + ) + : mStatus(NO_INIT) +{ + effect_uuid_t type; + effect_uuid_t *pType = NULL; + effect_uuid_t uuid; + effect_uuid_t *pUuid = NULL; + + LOGV("Constructor string\n - type: %s\n - uuid: %s", typeStr, uuidStr); + + if (typeStr != NULL) { + if (stringToGuid(typeStr, &type) == NO_ERROR) { + pType = &type; + } + } + + if (uuidStr != NULL) { + if (stringToGuid(uuidStr, &uuid) == NO_ERROR) { + pUuid = &uuid; + } + } + + mStatus = set(pType, pUuid, priority, cbf, user, sessionId, output); +} + +status_t AudioEffect::set(const effect_uuid_t *type, + const effect_uuid_t *uuid, + int32_t priority, + effect_callback_t cbf, + void* user, + int sessionId, + audio_io_handle_t output) +{ + sp<IEffect> iEffect; + sp<IMemory> cblk; + int enabled; + + LOGV("set %p mUserData: %p", this, user); + + if (mIEffect != 0) { + LOGW("Effect already in use"); + return INVALID_OPERATION; + } + + const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); + if (audioFlinger == 0) { + LOGE("set(): Could not get audioflinger"); + return NO_INIT; + } + + if (type == NULL && uuid == NULL) { + LOGW("Must specify at least type or uuid"); + return BAD_VALUE; + } + + mPriority = priority; + mCbf = cbf; + mUserData = user; + mSessionId = sessionId; + + memset(&mDescriptor, 0, sizeof(effect_descriptor_t)); + memcpy(&mDescriptor.type, EFFECT_UUID_NULL, sizeof(effect_uuid_t)); + memcpy(&mDescriptor.uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t)); + + if (type != NULL) { + memcpy(&mDescriptor.type, type, sizeof(effect_uuid_t)); + } + if (uuid != NULL) { + memcpy(&mDescriptor.uuid, uuid, sizeof(effect_uuid_t)); + } + + mIEffectClient = new EffectClient(this); + + iEffect = audioFlinger->createEffect(getpid(), (effect_descriptor_t *)&mDescriptor, + mIEffectClient, priority, output, mSessionId, &mStatus, &mId, &enabled); + + if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) { + LOGE("set(): AudioFlinger could not create effect, status: %d", mStatus); + return mStatus; + } + + mEnabled = (volatile int32_t)enabled; + + mIEffect = iEffect; + cblk = iEffect->getCblk(); + if (cblk == 0) { + mStatus = NO_INIT; + LOGE("Could not get control block"); + return mStatus; + } + + mIEffect = iEffect; + mCblkMemory = cblk; + mCblk = static_cast<effect_param_cblk_t*>(cblk->pointer()); + int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int); + mCblk->buffer = (uint8_t *)mCblk + bufOffset; + + iEffect->asBinder()->linkToDeath(mIEffectClient); + LOGV("set() %p OK effect: %s id: %d status %d enabled %d, ", this, mDescriptor.name, mId, mStatus, mEnabled); + + return mStatus; +} + + +AudioEffect::~AudioEffect() +{ + LOGV("Destructor %p", this); + + if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) { + setEnabled(false); + if (mIEffect != NULL) { + mIEffect->disconnect(); + mIEffect->asBinder()->unlinkToDeath(mIEffectClient); + } + IPCThreadState::self()->flushCommands(); + } + mIEffect.clear(); + mIEffectClient.clear(); + mCblkMemory.clear(); +} + + +status_t AudioEffect::initCheck() const +{ + return mStatus; +} + +// ------------------------------------------------------------------------- + +effect_descriptor_t AudioEffect::descriptor() const +{ + return mDescriptor; +} + +bool AudioEffect::getEnabled() const +{ + return (mEnabled != 0); +} + +status_t AudioEffect::setEnabled(bool enabled) +{ + if (mStatus != NO_ERROR) { + return INVALID_OPERATION; + } + + if (enabled) { + LOGV("enable %p", this); + if (android_atomic_or(1, &mEnabled) == 0) { + return mIEffect->enable(); + } + } else { + LOGV("disable %p", this); + if (android_atomic_and(~1, &mEnabled) == 1) { + return mIEffect->disable(); + } + } + return INVALID_OPERATION; +} + +status_t AudioEffect::command(uint32_t cmdCode, + uint32_t cmdSize, + void *cmdData, + uint32_t *replySize, + void *replyData) +{ + if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) { + return INVALID_OPERATION; + } + + return mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData); +} + + +status_t AudioEffect::setParameter(effect_param_t *param) +{ + if (mStatus != NO_ERROR) { + return INVALID_OPERATION; + } + + if (param == NULL || param->psize == 0 || param->vsize == 0) { + return BAD_VALUE; + } + + uint32_t size = sizeof(int); + uint32_t psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize; + + LOGV("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); +} + +status_t AudioEffect::setParameterDeferred(effect_param_t *param) +{ + if (mStatus != NO_ERROR) { + return INVALID_OPERATION; + } + + if (param == NULL || param->psize == 0 || param->vsize == 0) { + return BAD_VALUE; + } + + Mutex::Autolock _l(mCblk->lock); + + int psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize; + int size = ((sizeof(effect_param_t) + psize - 1) / sizeof(int) + 1) * sizeof(int); + + if (mCblk->clientIndex + size > EFFECT_PARAM_BUFFER_SIZE) { + return NO_MEMORY; + } + int *p = (int *)(mCblk->buffer + mCblk->clientIndex); + *p++ = size; + memcpy(p, param, sizeof(effect_param_t) + psize); + mCblk->clientIndex += size; + + return NO_ERROR; +} + +status_t AudioEffect::setParameterCommit() +{ + if (mStatus != NO_ERROR) { + return INVALID_OPERATION; + } + + Mutex::Autolock _l(mCblk->lock); + if (mCblk->clientIndex == 0) { + return INVALID_OPERATION; + } + uint32_t size = 0; + return mIEffect->command(EFFECT_CMD_SET_PARAM_COMMIT, 0, NULL, &size, NULL); +} + +status_t AudioEffect::getParameter(effect_param_t *param) +{ + if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) { + return INVALID_OPERATION; + } + + if (param == NULL || param->psize == 0 || param->vsize == 0) { + return BAD_VALUE; + } + + LOGV("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; + + return mIEffect->command(EFFECT_CMD_GET_PARAM, sizeof(effect_param_t) + param->psize, param, &psize, param); +} + + +// ------------------------------------------------------------------------- + +void AudioEffect::binderDied() +{ + LOGW("IEffect died"); + mStatus = NO_INIT; + if (mCbf) { + status_t status = DEAD_OBJECT; + mCbf(EVENT_ERROR, mUserData, &status); + } + mIEffect.clear(); +} + +// ------------------------------------------------------------------------- + +void AudioEffect::controlStatusChanged(bool controlGranted) +{ + LOGV("controlStatusChanged %p control %d callback %p mUserData %p", this, controlGranted, mCbf, mUserData); + if (controlGranted) { + if (mStatus == ALREADY_EXISTS) { + mStatus = NO_ERROR; + } + } else { + if (mStatus == NO_ERROR) { + mStatus = ALREADY_EXISTS; + } + } + if (mCbf) { + mCbf(EVENT_CONTROL_STATUS_CHANGED, mUserData, &controlGranted); + } +} + +void AudioEffect::enableStatusChanged(bool enabled) +{ + LOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf); + if (mStatus == ALREADY_EXISTS) { + mEnabled = enabled; + if (mCbf) { + mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled); + } + } +} + +void AudioEffect::commandExecuted(uint32_t cmdCode, + uint32_t cmdSize, + void *cmdData, + uint32_t replySize, + void *replyData) +{ + if (cmdData == NULL || replyData == NULL) { + return; + } + + if (mCbf && cmdCode == EFFECT_CMD_SET_PARAM) { + effect_param_t *cmd = (effect_param_t *)cmdData; + cmd->status = *(int32_t *)replyData; + mCbf(EVENT_PARAMETER_CHANGED, mUserData, cmd); + } +} + +// ------------------------------------------------------------------------- + +status_t AudioEffect::loadEffectLibrary(const char *libPath, int *handle) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->loadEffectLibrary(libPath, handle); +} + +status_t AudioEffect::unloadEffectLibrary(int handle) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->unloadEffectLibrary(handle); +} + +status_t AudioEffect::queryNumberEffects(uint32_t *numEffects) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->queryNumberEffects(numEffects); +} + +status_t AudioEffect::queryEffect(uint32_t index, effect_descriptor_t *descriptor) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->queryEffect(index, descriptor); +} + +status_t AudioEffect::getEffectDescriptor(effect_uuid_t *uuid, effect_descriptor_t *descriptor) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->getEffectDescriptor(uuid, descriptor); +} + +// ------------------------------------------------------------------------- + +status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid) +{ + if (str == NULL || guid == NULL) { + return BAD_VALUE; + } + + int tmp[10]; + + if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", + tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) { + return BAD_VALUE; + } + guid->timeLow = (uint32_t)tmp[0]; + guid->timeMid = (uint16_t)tmp[1]; + guid->timeHiAndVersion = (uint16_t)tmp[2]; + guid->clockSeq = (uint16_t)tmp[3]; + guid->node[0] = (uint8_t)tmp[4]; + guid->node[1] = (uint8_t)tmp[5]; + guid->node[2] = (uint8_t)tmp[6]; + guid->node[3] = (uint8_t)tmp[7]; + guid->node[4] = (uint8_t)tmp[8]; + guid->node[5] = (uint8_t)tmp[9]; + + return NO_ERROR; +} + +status_t AudioEffect::guidToString(const effect_uuid_t *guid, char *str, size_t maxLen) +{ + if (guid == NULL || str == NULL) { + return BAD_VALUE; + } + + snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", + guid->timeLow, + guid->timeMid, + guid->timeHiAndVersion, + guid->clockSeq, + guid->node[0], + guid->node[1], + guid->node[2], + guid->node[3], + guid->node[4], + guid->node[5]); + + return NO_ERROR; +} + + +}; // namespace android + diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index ad037d6..a6c515c 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -41,11 +41,43 @@ #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) namespace android { +// --------------------------------------------------------------------------- + +// static +status_t AudioRecord::getMinFrameCount( + int* frameCount, + uint32_t sampleRate, + int format, + int channelCount) +{ + size_t size = 0; + if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &size) + != NO_ERROR) { + LOGE("AudioSystem could not query the input buffer size."); + return NO_INIT; + } + + if (size == 0) { + LOGE("Unsupported configuration: sampleRate %d, format %d, channelCount %d", + sampleRate, format, channelCount); + return BAD_VALUE; + } + + // We double the size of input buffer for ping pong use of record buffer. + size <<= 1; + + if (AudioSystem::isLinearPCM(format)) { + size /= channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1); + } + + *frameCount = size; + return NO_ERROR; +} // --------------------------------------------------------------------------- AudioRecord::AudioRecord() - : mStatus(NO_INIT) + : mStatus(NO_INIT), mSessionId(0) { } @@ -58,11 +90,12 @@ AudioRecord::AudioRecord( uint32_t flags, callback_t cbf, void* user, - int notificationFrames) - : mStatus(NO_INIT) + int notificationFrames, + int sessionId) + : mStatus(NO_INIT), mSessionId(0) { mStatus = set(inputSource, sampleRate, format, channels, - frameCount, flags, cbf, user, notificationFrames); + frameCount, flags, cbf, user, notificationFrames, sessionId); } AudioRecord::~AudioRecord() @@ -91,7 +124,8 @@ status_t AudioRecord::set( callback_t cbf, void* user, int notificationFrames, - bool threadCanCallJava) + bool threadCanCallJava, + int sessionId) { LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount); @@ -119,6 +153,7 @@ status_t AudioRecord::set( if (!AudioSystem::isInputChannel(channels)) { return BAD_VALUE; } + int channelCount = AudioSystem::popCount(channels); audio_io_handle_t input = AudioSystem::getInput(inputSource, @@ -129,29 +164,11 @@ status_t AudioRecord::set( } // validate framecount - size_t inputBuffSizeInBytes = -1; - if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes) - != NO_ERROR) { - LOGE("AudioSystem could not query the input buffer size."); - return NO_INIT; - } - - if (inputBuffSizeInBytes == 0) { - LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d", - sampleRate, channelCount, format); - return BAD_VALUE; - } - - int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1); - if (AudioSystem::isLinearPCM(format)) { - frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? sizeof(int16_t) : sizeof(int8_t)); - } else { - frameSizeInBytes = sizeof(int8_t); + int minFrameCount = 0; + status_t status = getMinFrameCount(&minFrameCount, sampleRate, format, channelCount); + if (status != NO_ERROR) { + return status; } - - - // We use 2* size of input buffer for ping pong use of record buffer. - int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes; LOGV("AudioRecord::set() minFrameCount = %d", minFrameCount); if (frameCount == 0) { @@ -164,10 +181,11 @@ status_t AudioRecord::set( notificationFrames = frameCount/2; } - // create the IAudioRecord - status_t status = openRecord(sampleRate, format, channelCount, - frameCount, flags, input); + mSessionId = sessionId; + // create the IAudioRecord + status = openRecord(sampleRate, format, channelCount, + frameCount, flags, input); if (status != NO_ERROR) { return status; } @@ -414,6 +432,7 @@ status_t AudioRecord::openRecord( channelCount, frameCount, ((uint16_t)flags) << 16, + &mSessionId, &status); if (record == 0) { LOGE("AudioFlinger could not create record track, status: %d", status); @@ -430,7 +449,7 @@ status_t AudioRecord::openRecord( mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); - mCblk->out = 0; + mCblk->flags &= ~CBLK_DIRECTION_MSK; mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; mCblk->waitTimeMs = 0; return NO_ERROR; @@ -532,6 +551,11 @@ audio_io_handle_t AudioRecord::getInput() return mInput; } +int AudioRecord::getSessionId() +{ + return mSessionId; +} + // ------------------------------------------------------------------------- ssize_t AudioRecord::read(void* buffer, size_t userSize) @@ -644,10 +668,10 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread) // Manage overrun callback if (mActive && (mCblk->framesAvailable_l() == 0)) { - LOGV("Overrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag); - if (mCblk->flowControlFlag == 0) { + LOGV("Overrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags); + if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { mCbf(EVENT_OVERRUN, mUserData, 0); - mCblk->flowControlFlag = 1; + mCblk->flags |= CBLK_UNDERRUN_ON; } } diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 5e6ce42..7e3b743 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -364,6 +364,12 @@ unsigned int AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) { return result; } +int AudioSystem::newAudioSessionId() { + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return 0; + return af->newAudioSessionId(); +} + // --------------------------------------------------------------------------- void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) { @@ -584,18 +590,22 @@ audio_io_handle_t AudioSystem::getOutput(stream_type stream, return output; } -status_t AudioSystem::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioSystem::startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; - return aps->startOutput(output, stream); + return aps->startOutput(output, stream, session); } -status_t AudioSystem::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioSystem::stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; - return aps->stopOutput(output, stream); + return aps->stopOutput(output, stream, session); } void AudioSystem::releaseOutput(audio_io_handle_t output) @@ -660,6 +670,38 @@ status_t AudioSystem::getStreamVolumeIndex(stream_type stream, int *index) return aps->getStreamVolumeIndex(stream, index); } +uint32_t AudioSystem::getStrategyForStream(AudioSystem::stream_type stream) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return 0; + return aps->getStrategyForStream(stream); +} + +audio_io_handle_t AudioSystem::getOutputForEffect(effect_descriptor_t *desc) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->getOutputForEffect(desc); +} + +status_t AudioSystem::registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->registerEffect(desc, output, strategy, session, id); +} + +status_t AudioSystem::unregisterEffect(int id) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->unregisterEffect(id); +} + // --------------------------------------------------------------------------- void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) { diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index cd7bcd5..890786e 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -41,6 +41,35 @@ #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) namespace android { +// --------------------------------------------------------------------------- + +// static +status_t AudioTrack::getMinFrameCount( + int* frameCount, + int streamType, + uint32_t sampleRate) +{ + int afSampleRate; + if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { + return NO_INIT; + } + int afFrameCount; + if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { + return NO_INIT; + } + uint32_t afLatency; + if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) { + return NO_INIT; + } + + // Ensure that buffer depth covers at least audio hardware latency + uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate); + if (minBufCount < 2) minBufCount = 2; + + *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount : + afFrameCount * minBufCount * sampleRate / afSampleRate; + return NO_ERROR; +} // --------------------------------------------------------------------------- @@ -58,11 +87,13 @@ AudioTrack::AudioTrack( uint32_t flags, callback_t cbf, void* user, - int notificationFrames) + int notificationFrames, + int sessionId) : mStatus(NO_INIT) { mStatus = set(streamType, sampleRate, format, channels, - frameCount, flags, cbf, user, notificationFrames, 0); + frameCount, flags, cbf, user, notificationFrames, + 0, false, sessionId); } AudioTrack::AudioTrack( @@ -74,11 +105,13 @@ AudioTrack::AudioTrack( uint32_t flags, callback_t cbf, void* user, - int notificationFrames) + int notificationFrames, + int sessionId) : mStatus(NO_INIT) { mStatus = set(streamType, sampleRate, format, channels, - 0, flags, cbf, user, notificationFrames, sharedBuffer); + 0, flags, cbf, user, notificationFrames, + sharedBuffer, false, sessionId); } AudioTrack::~AudioTrack() @@ -110,7 +143,8 @@ status_t AudioTrack::set( void* user, int notificationFrames, const sp<IMemory>& sharedBuffer, - bool threadCanCallJava) + bool threadCanCallJava, + int sessionId) { LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); @@ -124,10 +158,6 @@ status_t AudioTrack::set( if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { return NO_INIT; } - int afFrameCount; - if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { - return NO_INIT; - } uint32_t afLatency; if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) { return NO_INIT; @@ -173,48 +203,17 @@ status_t AudioTrack::set( return BAD_VALUE; } - if (!AudioSystem::isLinearPCM(format)) { - if (sharedBuffer != 0) { - frameCount = sharedBuffer->size(); - } - } else { - // Ensure that buffer depth covers at least audio hardware latency - uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate); - if (minBufCount < 2) minBufCount = 2; - - int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate; - - if (sharedBuffer == 0) { - if (frameCount == 0) { - frameCount = minFrameCount; - } - if (notificationFrames == 0) { - notificationFrames = frameCount/2; - } - // Make sure that application is notified with sufficient margin - // before underrun - if (notificationFrames > frameCount/2) { - notificationFrames = frameCount/2; - } - if (frameCount < minFrameCount) { - LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount); - return BAD_VALUE; - } - } else { - // Ensure that buffer alignment matches channelcount - if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) { - LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount); - return BAD_VALUE; - } - frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t); - } - } - mVolume[LEFT] = 1.0f; mVolume[RIGHT] = 1.0f; + mSendLevel = 0; + mFrameCount = frameCount; + mNotificationFramesReq = notificationFrames; + mSessionId = sessionId; + mAuxEffectId = 0; + // create the IAudioTrack status_t status = createTrack(streamType, sampleRate, format, channelCount, - frameCount, flags, sharedBuffer, output); + frameCount, flags, sharedBuffer, output, true); if (status != NO_ERROR) { return status; @@ -238,10 +237,7 @@ status_t AudioTrack::set( mMuted = false; mActive = 0; mCbf = cbf; - mNotificationFrames = notificationFrames; - mRemainingFrames = notificationFrames; mUserData = user; - mLatency = afLatency + (1000*mFrameCount) / sampleRate; mLoopCount = 0; mMarkerPosition = 0; mMarkerReached = false; @@ -281,7 +277,7 @@ int AudioTrack::channelCount() const uint32_t AudioTrack::frameCount() const { - return mFrameCount; + return mCblk->frameCount; } int AudioTrack::frameSize() const @@ -303,6 +299,7 @@ sp<IMemory>& AudioTrack::sharedBuffer() void AudioTrack::start() { sp<AudioTrackThread> t = mAudioTrackThread; + status_t status; LOGV("start %p", this); if (t != 0) { @@ -325,11 +322,18 @@ void AudioTrack::start() setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT); } - status_t status = mAudioTrack->start(); + if (mCblk->flags & CBLK_INVALID_MSK) { + LOGW("start() track %p invalidated, creating a new one", this); + // no need to clear the invalid flag as this cblk will not be used anymore + // force new track creation + status = DEAD_OBJECT; + } else { + status = mAudioTrack->start(); + } if (status == DEAD_OBJECT) { LOGV("start() dead IAudioTrack: creating a new one"); status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount, - mFrameCount, mFlags, mSharedBuffer, getOutput()); + mFrameCount, mFlags, mSharedBuffer, getOutput(), false); if (status == NO_ERROR) { status = mAudioTrack->start(); if (status == NO_ERROR) { @@ -430,19 +434,50 @@ bool AudioTrack::muted() const return mMuted; } -void AudioTrack::setVolume(float left, float right) +status_t AudioTrack::setVolume(float left, float right) { + if (left > 1.0f || right > 1.0f) { + return BAD_VALUE; + } + mVolume[LEFT] = left; mVolume[RIGHT] = right; // write must be atomic - mCblk->volumeLR = (int32_t(int16_t(left * 0x1000)) << 16) | int16_t(right * 0x1000); + mCblk->volumeLR = (uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000); + + return NO_ERROR; } void AudioTrack::getVolume(float* left, float* right) { - *left = mVolume[LEFT]; - *right = mVolume[RIGHT]; + if (left != NULL) { + *left = mVolume[LEFT]; + } + if (right != NULL) { + *right = mVolume[RIGHT]; + } +} + +status_t AudioTrack::setAuxEffectSendLevel(float level) +{ + LOGV("setAuxEffectSendLevel(%f)", level); + if (level > 1.0f) { + return BAD_VALUE; + } + + mSendLevel = level; + + mCblk->sendLevel = uint16_t(level * 0x1000); + + return NO_ERROR; +} + +void AudioTrack::getAuxEffectSendLevel(float* level) +{ + if (level != NULL) { + *level = mSendLevel; + } } status_t AudioTrack::setSampleRate(int rate) @@ -479,14 +514,14 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount } if (loopStart >= loopEnd || - loopEnd - loopStart > mFrameCount) { - LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user); + loopEnd - loopStart > cblk->frameCount) { + LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, cblk->frameCount, cblk->user); return BAD_VALUE; } - if ((mSharedBuffer != 0) && (loopEnd > mFrameCount)) { + if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) { LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d", - loopStart, loopEnd, mFrameCount); + loopStart, loopEnd, cblk->frameCount); return BAD_VALUE; } @@ -566,7 +601,7 @@ status_t AudioTrack::setPosition(uint32_t position) if (position > mCblk->user) return BAD_VALUE; mCblk->server = position; - mCblk->forceReady = 1; + mCblk->flags |= CBLK_FORCEREADY_ON; return NO_ERROR; } @@ -586,7 +621,7 @@ status_t AudioTrack::reload() flush(); - mCblk->stepUser(mFrameCount); + mCblk->stepUser(mCblk->frameCount); return NO_ERROR; } @@ -597,6 +632,21 @@ audio_io_handle_t AudioTrack::getOutput() mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags); } +int AudioTrack::getSessionId() +{ + return mSessionId; +} + +status_t AudioTrack::attachAuxEffect(int effectId) +{ + LOGV("attachAuxEffect(%d)", effectId); + status_t status = mAudioTrack->attachAuxEffect(effectId); + if (status == NO_ERROR) { + mAuxEffectId = effectId; + } + return status; +} + // ------------------------------------------------------------------------- status_t AudioTrack::createTrack( @@ -607,7 +657,8 @@ status_t AudioTrack::createTrack( int frameCount, uint32_t flags, const sp<IMemory>& sharedBuffer, - audio_io_handle_t output) + audio_io_handle_t output, + bool enforceFrameCount) { status_t status; const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); @@ -616,6 +667,61 @@ status_t AudioTrack::createTrack( return NO_INIT; } + int afSampleRate; + if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { + return NO_INIT; + } + int afFrameCount; + if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { + return NO_INIT; + } + uint32_t afLatency; + if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) { + return NO_INIT; + } + + mNotificationFramesAct = mNotificationFramesReq; + if (!AudioSystem::isLinearPCM(format)) { + if (sharedBuffer != 0) { + frameCount = sharedBuffer->size(); + } + } else { + // Ensure that buffer depth covers at least audio hardware latency + uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate); + if (minBufCount < 2) minBufCount = 2; + + int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate; + + if (sharedBuffer == 0) { + if (frameCount == 0) { + frameCount = minFrameCount; + } + if (mNotificationFramesAct == 0) { + mNotificationFramesAct = frameCount/2; + } + // Make sure that application is notified with sufficient margin + // before underrun + if (mNotificationFramesAct > (uint32_t)frameCount/2) { + mNotificationFramesAct = frameCount/2; + } + if (frameCount < minFrameCount) { + if (enforceFrameCount) { + LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount); + return BAD_VALUE; + } else { + frameCount = minFrameCount; + } + } + } else { + // Ensure that buffer alignment matches channelcount + if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) { + LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount); + return BAD_VALUE; + } + frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t); + } + } + sp<IAudioTrack> track = audioFlinger->createTrack(getpid(), streamType, sampleRate, @@ -625,6 +731,7 @@ status_t AudioTrack::createTrack( ((uint16_t)flags) << 16, sharedBuffer, output, + &mSessionId, &status); if (track == 0) { @@ -641,20 +748,22 @@ status_t AudioTrack::createTrack( mCblkMemory.clear(); mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); - mCblk->out = 1; - // Update buffer size in case it has been limited by AudioFlinger during track creation - mFrameCount = mCblk->frameCount; + mCblk->flags |= CBLK_DIRECTION_OUT; if (sharedBuffer == 0) { mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); } else { mCblk->buffers = sharedBuffer->pointer(); // Force buffer full condition as data is already present in shared memory - mCblk->stepUser(mFrameCount); + mCblk->stepUser(mCblk->frameCount); } - mCblk->volumeLR = (int32_t(int16_t(mVolume[LEFT] * 0x1000)) << 16) | int16_t(mVolume[RIGHT] * 0x1000); + mCblk->volumeLR = (uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000); + mCblk->sendLevel = uint16_t(mSendLevel * 0x1000); + mAudioTrack->attachAuxEffect(mAuxEffectId); mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; mCblk->waitTimeMs = 0; + mRemainingFrames = mNotificationFramesAct; + mLatency = afLatency + (1000*mCblk->frameCount) / sampleRate; return NO_ERROR; } @@ -685,8 +794,15 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) cblk->lock.unlock(); return WOULD_BLOCK; } - - result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); + if (!(cblk->flags & CBLK_INVALID_MSK)) { + result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); + } + if (cblk->flags & CBLK_INVALID_MSK) { + LOGW("obtainBuffer() track %p invalidated, creating a new one", this); + // no need to clear the invalid flag as this cblk will not be used anymore + cblk->lock.unlock(); + goto create_new_track; + } if (__builtin_expect(result!=NO_ERROR, false)) { cblk->waitTimeMs += waitTimeMs; if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) { @@ -700,8 +816,9 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) result = mAudioTrack->start(); if (result == DEAD_OBJECT) { LOGW("obtainBuffer() dead IAudioTrack: creating a new one"); +create_new_track: result = createTrack(mStreamType, cblk->sampleRate, mFormat, mChannelCount, - mFrameCount, mFlags, mSharedBuffer, getOutput()); + mFrameCount, mFlags, mSharedBuffer, getOutput(), false); if (result == NO_ERROR) { cblk = mCblk; cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; @@ -826,13 +943,13 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) // Manage underrun callback if (mActive && (mCblk->framesReady() == 0)) { - LOGV("Underrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag); - if (mCblk->flowControlFlag == 0) { + LOGV("Underrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags); + if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { mCbf(EVENT_UNDERRUN, mUserData, 0); if (mCblk->server == mCblk->frameCount) { mCbf(EVENT_BUFFER_END, mUserData, 0); } - mCblk->flowControlFlag = 1; + mCblk->flags |= CBLK_UNDERRUN_ON; if (mSharedBuffer != 0) return false; } } @@ -932,7 +1049,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) while (frames); if (frames == 0) { - mRemainingFrames = mNotificationFrames; + mRemainingFrames = mNotificationFramesAct; } else { mRemainingFrames = frames; } @@ -949,7 +1066,7 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args) const result.append(" AudioTrack::dump\n"); 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, mFrameCount); + snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mCblk->frameCount); result.append(buffer); snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d)\n", (mCblk == 0) ? 0 : mCblk->sampleRate, mStatus, mMuted); result.append(buffer); @@ -986,7 +1103,7 @@ audio_track_cblk_t::audio_track_cblk_t() : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0), loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), - flowControlFlag(1), forceReady(0) + flags(0), sendLevel(0) { } @@ -996,7 +1113,7 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) u += frameCount; // Ensure that user is never ahead of server for AudioRecord - if (out) { + 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; @@ -1013,7 +1130,7 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) this->user = u; // Clear flow control error condition as new data has been written/read to/from buffer. - flowControlFlag = 0; + flags &= ~CBLK_UNDERRUN_MSK; return u; } @@ -1038,7 +1155,7 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount) uint32_t s = this->server; s += frameCount; - if (out) { + 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) { @@ -1089,7 +1206,7 @@ uint32_t audio_track_cblk_t::framesAvailable_l() uint32_t u = this->user; uint32_t s = this->server; - if (out) { + if (flags & CBLK_DIRECTION_MSK) { uint32_t limit = (s < loopStart) ? s : loopStart; return limit + frameCount - u; } else { @@ -1102,7 +1219,7 @@ uint32_t audio_track_cblk_t::framesReady() uint32_t u = this->user; uint32_t s = this->server; - if (out) { + if (flags & CBLK_DIRECTION_MSK) { if (u < loopEnd) { return u - s; } else { diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 47bcc12..3a89e25 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -62,7 +62,15 @@ enum { SET_STREAM_OUTPUT, SET_VOICE_VOLUME, GET_RENDER_POSITION, - GET_INPUT_FRAMES_LOST + GET_INPUT_FRAMES_LOST, + NEW_AUDIO_SESSION_ID, + LOAD_EFFECT_LIBRARY, + UNLOAD_EFFECT_LIBRARY, + QUERY_NUM_EFFECTS, + QUERY_EFFECT, + GET_EFFECT_DESCRIPTOR, + CREATE_EFFECT, + MOVE_EFFECTS }; class BpAudioFlinger : public BpInterface<IAudioFlinger> @@ -83,6 +91,7 @@ public: uint32_t flags, const sp<IMemory>& sharedBuffer, int output, + int *sessionId, status_t *status) { Parcel data, reply; @@ -97,10 +106,19 @@ public: data.writeInt32(flags); data.writeStrongBinder(sharedBuffer->asBinder()); data.writeInt32(output); + int lSessionId = 0; + if (sessionId != NULL) { + lSessionId = *sessionId; + } + data.writeInt32(lSessionId); status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply); if (lStatus != NO_ERROR) { LOGE("createTrack error: %s", strerror(-lStatus)); } else { + lSessionId = reply.readInt32(); + if (sessionId != NULL) { + *sessionId = lSessionId; + } lStatus = reply.readInt32(); track = interface_cast<IAudioTrack>(reply.readStrongBinder()); } @@ -118,6 +136,7 @@ public: int channelCount, int frameCount, uint32_t flags, + int *sessionId, status_t *status) { Parcel data, reply; @@ -130,10 +149,19 @@ public: data.writeInt32(channelCount); data.writeInt32(frameCount); data.writeInt32(flags); + int lSessionId = 0; + if (sessionId != NULL) { + lSessionId = *sessionId; + } + data.writeInt32(lSessionId); status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply); if (lStatus != NO_ERROR) { LOGE("openRecord error: %s", strerror(-lStatus)); } else { + lSessionId = reply.readInt32(); + if (sessionId != NULL) { + *sessionId = lSessionId; + } lStatus = reply.readInt32(); record = interface_cast<IAudioRecord>(reply.readStrongBinder()); } @@ -497,6 +525,169 @@ public: remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply); return reply.readInt32(); } + + virtual int newAudioSessionId() + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + status_t status = remote()->transact(NEW_AUDIO_SESSION_ID, data, &reply); + int id = 0; + if (status == NO_ERROR) { + id = reply.readInt32(); + } + return id; + } + + virtual status_t loadEffectLibrary(const char *libPath, int *handle) + { + if (libPath == NULL || handle == NULL) { + return BAD_VALUE; + } + *handle = 0; + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeCString(libPath); + status_t status = remote()->transact(LOAD_EFFECT_LIBRARY, data, &reply); + if (status == NO_ERROR) { + status = reply.readInt32(); + if (status == NO_ERROR) { + *handle = reply.readInt32(); + } + } + return status; + } + + virtual status_t unloadEffectLibrary(int handle) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(handle); + status_t status = remote()->transact(UNLOAD_EFFECT_LIBRARY, data, &reply); + if (status == NO_ERROR) { + status = reply.readInt32(); + } + return status; + } + + virtual status_t queryNumberEffects(uint32_t *numEffects) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + status_t status = remote()->transact(QUERY_NUM_EFFECTS, data, &reply); + if (status != NO_ERROR) { + return status; + } + status = reply.readInt32(); + if (status != NO_ERROR) { + return status; + } + if (numEffects) { + *numEffects = (uint32_t)reply.readInt32(); + } + return NO_ERROR; + } + + virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) + { + if (pDescriptor == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(index); + status_t status = remote()->transact(QUERY_EFFECT, data, &reply); + if (status != NO_ERROR) { + return status; + } + status = reply.readInt32(); + if (status != NO_ERROR) { + return status; + } + reply.read(pDescriptor, sizeof(effect_descriptor_t)); + return NO_ERROR; + } + + virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *pDescriptor) + { + if (pUuid == NULL || pDescriptor == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.write(pUuid, sizeof(effect_uuid_t)); + status_t status = remote()->transact(GET_EFFECT_DESCRIPTOR, data, &reply); + if (status != NO_ERROR) { + return status; + } + status = reply.readInt32(); + if (status != NO_ERROR) { + return status; + } + reply.read(pDescriptor, sizeof(effect_descriptor_t)); + return NO_ERROR; + } + + virtual sp<IEffect> createEffect(pid_t pid, + effect_descriptor_t *pDesc, + const sp<IEffectClient>& client, + int32_t priority, + int output, + int sessionId, + status_t *status, + int *id, + int *enabled) + { + Parcel data, reply; + sp<IEffect> effect; + + if (pDesc == NULL) { + return effect; + if (status) { + *status = BAD_VALUE; + } + } + + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(pid); + data.write(pDesc, sizeof(effect_descriptor_t)); + data.writeStrongBinder(client->asBinder()); + data.writeInt32(priority); + data.writeInt32(output); + data.writeInt32(sessionId); + + status_t lStatus = remote()->transact(CREATE_EFFECT, data, &reply); + if (lStatus != NO_ERROR) { + LOGE("createEffect error: %s", strerror(-lStatus)); + } else { + lStatus = reply.readInt32(); + int tmp = reply.readInt32(); + if (id) { + *id = tmp; + } + tmp = reply.readInt32(); + if (enabled) { + *enabled = tmp; + } + effect = interface_cast<IEffect>(reply.readStrongBinder()); + reply.read(pDesc, sizeof(effect_descriptor_t)); + } + if (status) { + *status = lStatus; + } + + return effect; + } + + virtual status_t moveEffects(int session, int srcOutput, int dstOutput) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(session); + data.writeInt32(srcOutput); + data.writeInt32(dstOutput); + remote()->transact(MOVE_EFFECTS, data, &reply); + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger"); @@ -518,10 +709,12 @@ status_t BnAudioFlinger::onTransact( uint32_t flags = data.readInt32(); sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder()); int output = data.readInt32(); + int sessionId = data.readInt32(); status_t status; sp<IAudioTrack> track = createTrack(pid, streamType, sampleRate, format, - channelCount, bufferCount, flags, buffer, output, &status); + channelCount, bufferCount, flags, buffer, output, &sessionId, &status); + reply->writeInt32(sessionId); reply->writeInt32(status); reply->writeStrongBinder(track->asBinder()); return NO_ERROR; @@ -535,9 +728,11 @@ status_t BnAudioFlinger::onTransact( int channelCount = data.readInt32(); size_t bufferCount = data.readInt32(); uint32_t flags = data.readInt32(); + int sessionId = data.readInt32(); status_t status; sp<IAudioRecord> record = openRecord(pid, input, - sampleRate, format, channelCount, bufferCount, flags, &status); + sampleRate, format, channelCount, bufferCount, flags, &sessionId, &status); + reply->writeInt32(sessionId); reply->writeInt32(status); reply->writeStrongBinder(record->asBinder()); return NO_ERROR; @@ -768,7 +963,87 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32(getInputFramesLost(ioHandle)); return NO_ERROR; } break; + case NEW_AUDIO_SESSION_ID: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32(newAudioSessionId()); + return NO_ERROR; + } break; + case LOAD_EFFECT_LIBRARY: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int handle; + status_t status = loadEffectLibrary(data.readCString(), &handle); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->writeInt32(handle); + } + return NO_ERROR; + } + case UNLOAD_EFFECT_LIBRARY: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32(unloadEffectLibrary(data.readInt32())); + return NO_ERROR; + } + case QUERY_NUM_EFFECTS: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + uint32_t numEffects; + status_t status = queryNumberEffects(&numEffects); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->writeInt32((int32_t)numEffects); + } + return NO_ERROR; + } + case QUERY_EFFECT: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + effect_descriptor_t desc; + status_t status = queryEffect(data.readInt32(), &desc); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->write(&desc, sizeof(effect_descriptor_t)); + } + return NO_ERROR; + } + case GET_EFFECT_DESCRIPTOR: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + effect_uuid_t uuid; + data.read(&uuid, sizeof(effect_uuid_t)); + effect_descriptor_t desc; + status_t status = getEffectDescriptor(&uuid, &desc); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->write(&desc, sizeof(effect_descriptor_t)); + } + return NO_ERROR; + } + 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()); + int32_t priority = data.readInt32(); + int output = data.readInt32(); + int sessionId = data.readInt32(); + status_t status; + int id; + int enabled; + sp<IEffect> effect = createEffect(pid, &desc, client, priority, output, sessionId, &status, &id, &enabled); + reply->writeInt32(status); + reply->writeInt32(id); + reply->writeInt32(enabled); + reply->writeStrongBinder(effect->asBinder()); + reply->write(&desc, sizeof(effect_descriptor_t)); + return NO_ERROR; + } break; + case MOVE_EFFECTS: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int session = data.readInt32(); + int srcOutput = data.readInt32(); + int dstOutput = data.readInt32(); + reply->writeInt32(moveEffects(session, srcOutput, dstOutput)); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 18dd173..950c213 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -44,7 +44,11 @@ enum { RELEASE_INPUT, INIT_STREAM_VOLUME, SET_STREAM_VOLUME, - GET_STREAM_VOLUME + GET_STREAM_VOLUME, + GET_STRATEGY_FOR_STREAM, + GET_OUTPUT_FOR_EFFECT, + REGISTER_EFFECT, + UNREGISTER_EFFECT }; class BpAudioPolicyService : public BpInterface<IAudioPolicyService> @@ -137,22 +141,28 @@ public: return static_cast <audio_io_handle_t> (reply.readInt32()); } - virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) + virtual status_t startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(output); data.writeInt32(stream); + data.writeInt32(session); remote()->transact(START_OUTPUT, data, &reply); return static_cast <status_t> (reply.readInt32()); } - virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) + virtual status_t stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(output); data.writeInt32(stream); + data.writeInt32(session); remote()->transact(STOP_OUTPUT, data, &reply); return static_cast <status_t> (reply.readInt32()); } @@ -242,6 +252,51 @@ public: if (index) *index = lIndex; return static_cast <status_t> (reply.readInt32()); } + + virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(static_cast <uint32_t>(stream)); + remote()->transact(GET_STRATEGY_FOR_STREAM, data, &reply); + return reply.readInt32(); + } + + virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(desc, sizeof(effect_descriptor_t)); + remote()->transact(GET_OUTPUT_FOR_EFFECT, data, &reply); + return static_cast <audio_io_handle_t> (reply.readInt32()); + } + + virtual status_t registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(desc, sizeof(effect_descriptor_t)); + data.writeInt32(output); + data.writeInt32(strategy); + data.writeInt32(session); + data.writeInt32(id); + remote()->transact(REGISTER_EFFECT, data, &reply); + return static_cast <status_t> (reply.readInt32()); + } + + virtual status_t unregisterEffect(int id) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(id); + remote()->transact(UNREGISTER_EFFECT, data, &reply); + return static_cast <status_t> (reply.readInt32()); + } + }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -255,18 +310,24 @@ status_t BnAudioPolicyService::onTransact( switch(code) { case SET_DEVICE_CONNECTION_STATE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32()); - AudioSystem::device_connection_state state = static_cast <AudioSystem::device_connection_state>(data.readInt32()); + AudioSystem::audio_devices device = + static_cast <AudioSystem::audio_devices>(data.readInt32()); + AudioSystem::device_connection_state state = + static_cast <AudioSystem::device_connection_state>(data.readInt32()); const char *device_address = data.readCString(); - reply->writeInt32(static_cast <uint32_t>(setDeviceConnectionState(device, state, device_address))); + reply->writeInt32(static_cast<uint32_t> (setDeviceConnectionState(device, + state, + device_address))); return NO_ERROR; } break; case GET_DEVICE_CONNECTION_STATE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32()); + AudioSystem::audio_devices device = + static_cast<AudioSystem::audio_devices> (data.readInt32()); const char *device_address = data.readCString(); - reply->writeInt32(static_cast <uint32_t>(getDeviceConnectionState(device, device_address))); + reply->writeInt32(static_cast<uint32_t> (getDeviceConnectionState(device, + device_address))); return NO_ERROR; } break; @@ -287,7 +348,8 @@ status_t BnAudioPolicyService::onTransact( case SET_FORCE_USE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); AudioSystem::force_use usage = static_cast <AudioSystem::force_use>(data.readInt32()); - AudioSystem::forced_config config = static_cast <AudioSystem::forced_config>(data.readInt32()); + AudioSystem::forced_config config = + static_cast <AudioSystem::forced_config>(data.readInt32()); reply->writeInt32(static_cast <uint32_t>(setForceUse(usage, config))); return NO_ERROR; } break; @@ -301,11 +363,13 @@ status_t BnAudioPolicyService::onTransact( case GET_OUTPUT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32()); + AudioSystem::stream_type stream = + static_cast <AudioSystem::stream_type>(data.readInt32()); uint32_t samplingRate = data.readInt32(); uint32_t format = data.readInt32(); uint32_t channels = data.readInt32(); - AudioSystem::output_flags flags = static_cast <AudioSystem::output_flags>(data.readInt32()); + AudioSystem::output_flags flags = + static_cast <AudioSystem::output_flags>(data.readInt32()); audio_io_handle_t output = getOutput(stream, samplingRate, @@ -320,7 +384,10 @@ status_t BnAudioPolicyService::onTransact( CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32()); uint32_t stream = data.readInt32(); - reply->writeInt32(static_cast <uint32_t>(startOutput(output, (AudioSystem::stream_type)stream))); + int session = data.readInt32(); + reply->writeInt32(static_cast <uint32_t>(startOutput(output, + (AudioSystem::stream_type)stream, + session))); return NO_ERROR; } break; @@ -328,7 +395,10 @@ status_t BnAudioPolicyService::onTransact( CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32()); uint32_t stream = data.readInt32(); - reply->writeInt32(static_cast <uint32_t>(stopOutput(output, (AudioSystem::stream_type)stream))); + int session = data.readInt32(); + reply->writeInt32(static_cast <uint32_t>(stopOutput(output, + (AudioSystem::stream_type)stream, + session))); return NO_ERROR; } break; @@ -345,7 +415,8 @@ status_t BnAudioPolicyService::onTransact( uint32_t samplingRate = data.readInt32(); uint32_t format = data.readInt32(); uint32_t channels = data.readInt32(); - AudioSystem::audio_in_acoustics acoustics = static_cast <AudioSystem::audio_in_acoustics>(data.readInt32()); + AudioSystem::audio_in_acoustics acoustics = + static_cast <AudioSystem::audio_in_acoustics>(data.readInt32()); audio_io_handle_t input = getInput(inputSource, samplingRate, format, @@ -378,7 +449,8 @@ status_t BnAudioPolicyService::onTransact( case INIT_STREAM_VOLUME: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32()); + AudioSystem::stream_type stream = + static_cast <AudioSystem::stream_type>(data.readInt32()); int indexMin = data.readInt32(); int indexMax = data.readInt32(); reply->writeInt32(static_cast <uint32_t>(initStreamVolume(stream, indexMin,indexMax))); @@ -387,7 +459,8 @@ status_t BnAudioPolicyService::onTransact( case SET_STREAM_VOLUME: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32()); + AudioSystem::stream_type stream = + static_cast <AudioSystem::stream_type>(data.readInt32()); int index = data.readInt32(); reply->writeInt32(static_cast <uint32_t>(setStreamVolumeIndex(stream, index))); return NO_ERROR; @@ -395,7 +468,8 @@ status_t BnAudioPolicyService::onTransact( case GET_STREAM_VOLUME: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32()); + AudioSystem::stream_type stream = + static_cast <AudioSystem::stream_type>(data.readInt32()); int index; status_t status = getStreamVolumeIndex(stream, &index); reply->writeInt32(index); @@ -403,6 +477,46 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } break; + case GET_STRATEGY_FOR_STREAM: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + AudioSystem::stream_type stream = + static_cast <AudioSystem::stream_type>(data.readInt32()); + reply->writeInt32(getStrategyForStream(stream)); + return NO_ERROR; + } break; + + case GET_OUTPUT_FOR_EFFECT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + effect_descriptor_t desc; + data.read(&desc, sizeof(effect_descriptor_t)); + audio_io_handle_t output = getOutputForEffect(&desc); + reply->writeInt32(static_cast <int>(output)); + return NO_ERROR; + } break; + + case REGISTER_EFFECT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + effect_descriptor_t desc; + data.read(&desc, sizeof(effect_descriptor_t)); + audio_io_handle_t output = data.readInt32(); + uint32_t strategy = data.readInt32(); + int session = data.readInt32(); + int id = data.readInt32(); + reply->writeInt32(static_cast <int32_t>(registerEffect(&desc, + output, + strategy, + session, + id))); + return NO_ERROR; + } break; + + case UNREGISTER_EFFECT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + int id = data.readInt32(); + reply->writeInt32(static_cast <int32_t>(unregisterEffect(id))); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp index 01ffd75..bc8ff34 100644 --- a/media/libmedia/IAudioTrack.cpp +++ b/media/libmedia/IAudioTrack.cpp @@ -34,7 +34,8 @@ enum { STOP, FLUSH, MUTE, - PAUSE + PAUSE, + ATTACH_AUX_EFFECT }; class BpAudioTrack : public BpInterface<IAudioTrack> @@ -97,7 +98,21 @@ public: cblk = interface_cast<IMemory>(reply.readStrongBinder()); } return cblk; - } + } + + virtual status_t attachAuxEffect(int effectId) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + data.writeInt32(effectId); + status_t status = remote()->transact(ATTACH_AUX_EFFECT, data, &reply); + if (status == NO_ERROR) { + status = reply.readInt32(); + } else { + LOGW("attachAuxEffect() error: %s", strerror(-status)); + } + return status; + } }; IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack"); @@ -138,6 +153,11 @@ status_t BnAudioTrack::onTransact( pause(); return NO_ERROR; } + case ATTACH_AUX_EFFECT: { + CHECK_INTERFACE(IAudioTrack, data, reply); + reply->writeInt32(attachAuxEffect(data.readInt32())); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp new file mode 100644 index 0000000..a945b97 --- /dev/null +++ b/media/libmedia/IEffect.cpp @@ -0,0 +1,195 @@ +/* +** +** Copyright 2010, 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 "IEffect" +#include <utils/Log.h> +#include <stdint.h> +#include <sys/types.h> +#include <binder/Parcel.h> +#include <media/IEffect.h> + +namespace android { + +enum { + ENABLE = IBinder::FIRST_CALL_TRANSACTION, + DISABLE, + COMMAND, + DISCONNECT, + GET_CBLK +}; + +class BpEffect: public BpInterface<IEffect> +{ +public: + BpEffect(const sp<IBinder>& impl) + : BpInterface<IEffect>(impl) + { + } + + status_t enable() + { + LOGV("enable"); + Parcel data, reply; + data.writeInterfaceToken(IEffect::getInterfaceDescriptor()); + remote()->transact(ENABLE, data, &reply); + return reply.readInt32(); + } + + status_t disable() + { + LOGV("disable"); + Parcel data, reply; + data.writeInterfaceToken(IEffect::getInterfaceDescriptor()); + remote()->transact(DISABLE, data, &reply); + return reply.readInt32(); + } + + status_t command(uint32_t cmdCode, + uint32_t cmdSize, + void *pCmdData, + uint32_t *pReplySize, + void *pReplyData) + { + LOGV("command"); + Parcel data, reply; + data.writeInterfaceToken(IEffect::getInterfaceDescriptor()); + data.writeInt32(cmdCode); + int size = cmdSize; + if (pCmdData == NULL) { + size = 0; + } + data.writeInt32(size); + if (size) { + data.write(pCmdData, size); + } + if (pReplySize == NULL) { + size = 0; + } else { + size = *pReplySize; + } + data.writeInt32(size); + remote()->transact(COMMAND, data, &reply); + status_t status = reply.readInt32(); + size = reply.readInt32(); + if (size != 0 && pReplyData != NULL && pReplySize != NULL) { + reply.read(pReplyData, size); + *pReplySize = size; + } + return status; + } + + void disconnect() + { + LOGV("disconnect"); + Parcel data, reply; + data.writeInterfaceToken(IEffect::getInterfaceDescriptor()); + remote()->transact(DISCONNECT, data, &reply); + return; + } + + virtual sp<IMemory> getCblk() const + { + Parcel data, reply; + sp<IMemory> cblk; + data.writeInterfaceToken(IEffect::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_CBLK, data, &reply); + if (status == NO_ERROR) { + cblk = interface_cast<IMemory>(reply.readStrongBinder()); + } + return cblk; + } + }; + +IMPLEMENT_META_INTERFACE(Effect, "android.media.IEffect"); + +// ---------------------------------------------------------------------- + +status_t BnEffect::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case ENABLE: { + LOGV("ENABLE"); + CHECK_INTERFACE(IEffect, data, reply); + reply->writeInt32(enable()); + return NO_ERROR; + } break; + + case DISABLE: { + LOGV("DISABLE"); + CHECK_INTERFACE(IEffect, data, reply); + reply->writeInt32(disable()); + return NO_ERROR; + } break; + + case COMMAND: { + LOGV("COMMAND"); + CHECK_INTERFACE(IEffect, data, reply); + uint32_t cmdCode = data.readInt32(); + uint32_t cmdSize = data.readInt32(); + char *cmd = NULL; + if (cmdSize) { + cmd = (char *)malloc(cmdSize); + data.read(cmd, cmdSize); + } + uint32_t replySize = data.readInt32(); + uint32_t replySz = replySize; + char *resp = NULL; + if (replySize) { + resp = (char *)malloc(replySize); + } + status_t status = command(cmdCode, cmdSize, cmd, &replySz, resp); + reply->writeInt32(status); + if (replySz < replySize) { + replySize = replySz; + } + reply->writeInt32(replySize); + if (replySize) { + reply->write(resp, replySize); + } + if (cmd) { + free(cmd); + } + if (resp) { + free(resp); + } + return NO_ERROR; + } break; + + case DISCONNECT: { + LOGV("DISCONNECT"); + CHECK_INTERFACE(IEffect, data, reply); + disconnect(); + return NO_ERROR; + } break; + + case GET_CBLK: { + CHECK_INTERFACE(IEffect, data, reply); + reply->writeStrongBinder(getCblk()->asBinder()); + return NO_ERROR; + } break; + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android + diff --git a/media/libmedia/IEffectClient.cpp b/media/libmedia/IEffectClient.cpp new file mode 100644 index 0000000..1fa9cbe --- /dev/null +++ b/media/libmedia/IEffectClient.cpp @@ -0,0 +1,145 @@ +/* +** +** Copyright 2010, 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 "IEffectClient" +#include <utils/Log.h> +#include <stdint.h> +#include <sys/types.h> +#include <media/IEffectClient.h> + +namespace android { + +enum { + CONTROL_STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION, + ENABLE_STATUS_CHANGED, + COMMAND_EXECUTED +}; + +class BpEffectClient: public BpInterface<IEffectClient> +{ +public: + BpEffectClient(const sp<IBinder>& impl) + : BpInterface<IEffectClient>(impl) + { + } + + void controlStatusChanged(bool controlGranted) + { + LOGV("controlStatusChanged"); + Parcel data, reply; + data.writeInterfaceToken(IEffectClient::getInterfaceDescriptor()); + data.writeInt32((uint32_t)controlGranted); + remote()->transact(CONTROL_STATUS_CHANGED, data, &reply, IBinder::FLAG_ONEWAY); + } + + void enableStatusChanged(bool enabled) + { + LOGV("enableStatusChanged"); + Parcel data, reply; + data.writeInterfaceToken(IEffectClient::getInterfaceDescriptor()); + data.writeInt32((uint32_t)enabled); + remote()->transact(ENABLE_STATUS_CHANGED, data, &reply, IBinder::FLAG_ONEWAY); + } + + void commandExecuted(uint32_t cmdCode, + uint32_t cmdSize, + void *pCmdData, + uint32_t replySize, + void *pReplyData) + { + LOGV("commandExecuted"); + Parcel data, reply; + data.writeInterfaceToken(IEffectClient::getInterfaceDescriptor()); + data.writeInt32(cmdCode); + int size = cmdSize; + if (pCmdData == NULL) { + size = 0; + } + data.writeInt32(size); + if (size) { + data.write(pCmdData, size); + } + size = replySize; + if (pReplyData == NULL) { + size = 0; + } + data.writeInt32(size); + if (size) { + data.write(pReplyData, size); + } + remote()->transact(COMMAND_EXECUTED, data, &reply, IBinder::FLAG_ONEWAY); + } + +}; + +IMPLEMENT_META_INTERFACE(EffectClient, "android.media.IEffectClient"); + +// ---------------------------------------------------------------------- + +status_t BnEffectClient::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case CONTROL_STATUS_CHANGED: { + LOGV("CONTROL_STATUS_CHANGED"); + CHECK_INTERFACE(IEffectClient, data, reply); + bool hasControl = (bool)data.readInt32(); + controlStatusChanged(hasControl); + return NO_ERROR; + } break; + case ENABLE_STATUS_CHANGED: { + LOGV("ENABLE_STATUS_CHANGED"); + CHECK_INTERFACE(IEffectClient, data, reply); + bool enabled = (bool)data.readInt32(); + enableStatusChanged(enabled); + return NO_ERROR; + } break; + case COMMAND_EXECUTED: { + LOGV("COMMAND_EXECUTED"); + CHECK_INTERFACE(IEffectClient, data, reply); + uint32_t cmdCode = data.readInt32(); + uint32_t cmdSize = data.readInt32(); + char *cmd = NULL; + if (cmdSize) { + cmd = (char *)malloc(cmdSize); + data.read(cmd, cmdSize); + } + uint32_t replySize = data.readInt32(); + char *resp = NULL; + if (replySize) { + resp = (char *)malloc(replySize); + data.read(resp, replySize); + } + commandExecuted(cmdCode, cmdSize, cmd, replySize, resp); + if (cmd) { + free(cmd); + } + if (resp) { + free(resp); + } + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android + diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index ed792b3..0f55b19d 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -45,6 +45,8 @@ enum { GET_METADATA, SUSPEND, RESUME, + SET_AUX_EFFECT_SEND_LEVEL, + ATTACH_AUX_EFFECT }; class BpMediaPlayer: public BpInterface<IMediaPlayer> @@ -221,6 +223,24 @@ public: return reply.readInt32(); } + + status_t setAuxEffectSendLevel(float level) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeFloat(level); + remote()->transact(SET_AUX_EFFECT_SEND_LEVEL, data, &reply); + return reply.readInt32(); + } + + status_t attachAuxEffect(int effectId) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeInt32(effectId); + remote()->transact(ATTACH_AUX_EFFECT, data, &reply); + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer"); @@ -339,6 +359,16 @@ status_t BnMediaPlayer::onTransact( reply->setDataPosition(0); return NO_ERROR; } break; + case SET_AUX_EFFECT_SEND_LEVEL: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(setAuxEffectSendLevel(data.readFloat())); + return NO_ERROR; + } break; + case ATTACH_AUX_EFFECT: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(attachAuxEffect(data.readInt32())); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index 71c5f86..4abfa75 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -35,8 +35,7 @@ enum { DECODE_FD, CREATE_MEDIA_RECORDER, CREATE_METADATA_RETRIEVER, - GET_OMX, - SNOOP + GET_OMX }; class BpMediaPlayerService: public BpInterface<IMediaPlayerService> @@ -58,7 +57,7 @@ public: virtual sp<IMediaPlayer> create( pid_t pid, const sp<IMediaPlayerClient>& client, - const char* url, const KeyedVector<String8, String8> *headers) { + const char* url, const KeyedVector<String8, String8> *headers, int audioSessionId) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); data.writeInt32(pid); @@ -75,8 +74,10 @@ public: data.writeString8(headers->valueAt(i)); } } + data.writeInt32(audioSessionId); remote()->transact(CREATE_URL, data, &reply); + return interface_cast<IMediaPlayer>(reply.readStrongBinder()); } @@ -89,7 +90,8 @@ public: return interface_cast<IMediaRecorder>(reply.readStrongBinder()); } - virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) + virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, + int64_t offset, int64_t length, int audioSessionId) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); @@ -98,8 +100,11 @@ public: data.writeFileDescriptor(fd); data.writeInt64(offset); data.writeInt64(length); + data.writeInt32(audioSessionId); + remote()->transact(CREATE_FD, data, &reply); - return interface_cast<IMediaPlayer>(reply.readStrongBinder()); + + return interface_cast<IMediaPlayer>(reply.readStrongBinder());; } virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) @@ -128,14 +133,6 @@ public: return interface_cast<IMemory>(reply.readStrongBinder()); } - virtual sp<IMemory> snoop() - { - Parcel data, reply; - data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); - remote()->transact(SNOOP, data, &reply); - return interface_cast<IMemory>(reply.readStrongBinder()); - } - virtual sp<IOMX> getOMX() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); @@ -166,9 +163,10 @@ status_t BnMediaPlayerService::onTransact( String8 value = data.readString8(); headers.add(key, value); } + int audioSessionId = data.readInt32(); sp<IMediaPlayer> player = create( - pid, client, url, numHeaders > 0 ? &headers : NULL); + pid, client, url, numHeaders > 0 ? &headers : NULL, audioSessionId); reply->writeStrongBinder(player->asBinder()); return NO_ERROR; @@ -180,7 +178,9 @@ status_t BnMediaPlayerService::onTransact( int fd = dup(data.readFileDescriptor()); int64_t offset = data.readInt64(); int64_t length = data.readInt64(); - sp<IMediaPlayer> player = create(pid, client, fd, offset, length); + int audioSessionId = data.readInt32(); + + sp<IMediaPlayer> player = create(pid, client, fd, offset, length, audioSessionId); reply->writeStrongBinder(player->asBinder()); return NO_ERROR; } break; @@ -212,12 +212,6 @@ status_t BnMediaPlayerService::onTransact( reply->writeStrongBinder(player->asBinder()); return NO_ERROR; } break; - case SNOOP: { - CHECK_INTERFACE(IMediaPlayerService, data, reply); - sp<IMemory> snooped_audio = snoop(); - reply->writeStrongBinder(snooped_audio->asBinder()); - return NO_ERROR; - } break; case CREATE_MEDIA_RECORDER: { CHECK_INTERFACE(IMediaPlayerService, data, reply); pid_t pid = data.readInt32(); diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp index 1de9f9b..4eb63e8 100644 --- a/media/libmedia/IMediaRecorder.cpp +++ b/media/libmedia/IMediaRecorder.cpp @@ -21,7 +21,7 @@ #include <binder/Parcel.h> #include <surfaceflinger/ISurface.h> #include <camera/ICamera.h> -#include <media/IMediaPlayerClient.h> +#include <media/IMediaRecorderClient.h> #include <media/IMediaRecorder.h> namespace android { @@ -189,7 +189,7 @@ public: return reply.readInt32(); } - status_t setListener(const sp<IMediaPlayerClient>& listener) + status_t setListener(const sp<IMediaRecorderClient>& listener) { LOGV("setListener(%p)", listener.get()); Parcel data, reply; @@ -399,8 +399,8 @@ status_t BnMediaRecorder::onTransact( case SET_LISTENER: { LOGV("SET_LISTENER"); CHECK_INTERFACE(IMediaRecorder, data, reply); - sp<IMediaPlayerClient> listener = - interface_cast<IMediaPlayerClient>(data.readStrongBinder()); + sp<IMediaRecorderClient> listener = + interface_cast<IMediaRecorderClient>(data.readStrongBinder()); reply->writeInt32(setListener(listener)); return NO_ERROR; } break; diff --git a/media/libmedia/IMediaRecorderClient.cpp b/media/libmedia/IMediaRecorderClient.cpp new file mode 100644 index 0000000..ff235c9 --- /dev/null +++ b/media/libmedia/IMediaRecorderClient.cpp @@ -0,0 +1,70 @@ +/* +** +** Copyright 2010, 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 <utils/RefBase.h> +#include <binder/IInterface.h> +#include <binder/Parcel.h> + +#include <media/IMediaRecorderClient.h> + +namespace android { + +enum { + NOTIFY = IBinder::FIRST_CALL_TRANSACTION, +}; + +class BpMediaRecorderClient: public BpInterface<IMediaRecorderClient> +{ +public: + BpMediaRecorderClient(const sp<IBinder>& impl) + : BpInterface<IMediaRecorderClient>(impl) + { + } + + virtual void notify(int msg, int ext1, int ext2) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaRecorderClient::getInterfaceDescriptor()); + data.writeInt32(msg); + data.writeInt32(ext1); + data.writeInt32(ext2); + remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(MediaRecorderClient, "android.media.IMediaRecorderClient"); + +// ---------------------------------------------------------------------- + +status_t BnMediaRecorderClient::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case NOTIFY: { + CHECK_INTERFACE(IMediaRecorderClient, data, reply); + int msg = data.readInt32(); + int ext1 = data.readInt32(); + int ext2 = data.readInt32(); + notify(msg, ext1, ext2); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index 01b6737..f3804b8 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -57,7 +57,7 @@ sp<IOMXRenderer> IOMX::createRendererFromJavaSurface( return NULL; } - jfieldID surfaceID = env->GetFieldID(surfaceClass, "mSurface", "I"); + jfieldID surfaceID = env->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I"); if (surfaceID == NULL) { LOGE("Can't find Surface.mSurface"); return NULL; diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp index 1263373..3869389 100644 --- a/media/libmedia/MediaProfiles.cpp +++ b/media/libmedia/MediaProfiles.cpp @@ -272,7 +272,7 @@ MediaProfiles::createEncoderOutputFileFormat(const char **atts) } /*static*/ MediaProfiles::CamcorderProfile* -MediaProfiles::createCamcorderProfile(const char **atts) +MediaProfiles::createCamcorderProfile(int cameraId, const char **atts) { CHECK(!strcmp("quality", atts[0]) && !strcmp("fileFormat", atts[2]) && @@ -287,16 +287,47 @@ MediaProfiles::createCamcorderProfile(const char **atts) CHECK(fileFormat != -1); MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile; + profile->mCameraId = cameraId; profile->mFileFormat = static_cast<output_format>(fileFormat); profile->mQuality = static_cast<camcorder_quality>(quality); profile->mDuration = atoi(atts[5]); return profile; } -/*static*/ int -MediaProfiles::getImageEncodingQualityLevel(const char** atts) +MediaProfiles::ImageEncodingQualityLevels* +MediaProfiles::findImageEncodingQualityLevels(int cameraId) const +{ + int n = mImageEncodingQualityLevels.size(); + for (int i = 0; i < n; i++) { + ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i]; + if (levels->mCameraId == cameraId) { + return levels; + } + } + return NULL; +} + +void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts) { CHECK(!strcmp("quality", atts[0])); + int quality = atoi(atts[1]); + LOGV("%s: cameraId=%d, quality=%d\n", __func__, cameraId, quality); + ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId); + + if (levels == NULL) { + levels = new ImageEncodingQualityLevels(); + levels->mCameraId = cameraId; + mImageEncodingQualityLevels.add(levels); + } + + levels->mLevels.add(quality); +} + +/*static*/ int +MediaProfiles::getCameraId(const char** atts) +{ + if (!atts[0]) return 0; // default cameraId = 0 + CHECK(!strcmp("cameraId", atts[0])); return atoi(atts[1]); } @@ -322,10 +353,13 @@ MediaProfiles::startElementHandler(void *userData, const char *name, const char profiles->mAudioDecoders.add(createAudioDecoderCap(atts)); } else if (strcmp("EncoderOutputFileFormat", name) == 0) { profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts)); + } else if (strcmp("CamcorderProfiles", name) == 0) { + profiles->mCurrentCameraId = getCameraId(atts); } else if (strcmp("EncoderProfile", name) == 0) { - profiles->mCamcorderProfiles.add(createCamcorderProfile(atts)); + profiles->mCamcorderProfiles.add( + createCamcorderProfile(profiles->mCurrentCameraId, atts)); } else if (strcmp("ImageEncoding", name) == 0) { - profiles->mImageEncodingQualityLevels.add(getImageEncodingQualityLevel(atts)); + profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts); } } @@ -383,7 +417,8 @@ MediaProfiles::createDefaultCamcorderHighProfile() new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20); AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1); - CamcorderProfile *profile = new CamcorderProfile; + CamcorderProfile *profile = new MediaProfiles::CamcorderProfile; + profile->mCameraId = 0; profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP; profile->mQuality = CAMCORDER_QUALITY_HIGH; profile->mDuration = 60; @@ -402,6 +437,7 @@ MediaProfiles::createDefaultCamcorderLowProfile() new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1); MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile; + profile->mCameraId = 0; profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP; profile->mQuality = CAMCORDER_QUALITY_LOW; profile->mDuration = 30; @@ -458,9 +494,12 @@ MediaProfiles::createDefaultAmrNBEncoderCap() /*static*/ void MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles) { - profiles->mImageEncodingQualityLevels.add(70); - profiles->mImageEncodingQualityLevels.add(80); - profiles->mImageEncodingQualityLevels.add(90); + ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels(); + levels->mCameraId = 0; + levels->mLevels.add(70); + levels->mLevels.add(80); + levels->mLevels.add(90); + profiles->mImageEncodingQualityLevels.add(levels); } /*static*/ MediaProfiles* @@ -629,19 +668,24 @@ Vector<audio_decoder> MediaProfiles::getAudioDecoders() const return decoders; // copy out } -int MediaProfiles::getCamcorderProfileParamByName(const char *name, camcorder_quality quality) const +int MediaProfiles::getCamcorderProfileParamByName(const char *name, + int cameraId, + camcorder_quality quality) const { - LOGV("getCamcorderProfileParamByName: %s for quality %d", name, quality); + LOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d", + name, cameraId, quality); int index = -1; for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) { - if (mCamcorderProfiles[i]->mQuality == quality) { + if (mCamcorderProfiles[i]->mCameraId == cameraId && + mCamcorderProfiles[i]->mQuality == quality) { index = i; break; } } if (index == -1) { - LOGE("The given camcorder profile quality %d is not found", quality); + LOGE("The given camcorder profile camera %d quality %d is not found", + cameraId, quality); return -1; } @@ -657,13 +701,18 @@ int MediaProfiles::getCamcorderProfileParamByName(const char *name, camcorder_qu if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels; if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate; - LOGE("The given camcorder profile param name %s is not found", name); + LOGE("The given camcorder profile param id %d name %s is not found", cameraId, name); return -1; } -Vector<int> MediaProfiles::getImageEncodingQualityLevels() const +Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const { - return mImageEncodingQualityLevels; // copy out + Vector<int> result; + ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId); + if (levels != NULL) { + result = levels->mLevels; // copy out + } + return result; } MediaProfiles::~MediaProfiles() diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp index 843a8fd..6f581d3 100644 --- a/media/libmedia/MediaScanner.cpp +++ b/media/libmedia/MediaScanner.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaScanner" +#include <utils/Log.h> + #include <media/mediascanner.h> #include <sys/stat.h> diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp new file mode 100644 index 0000000..32cdb49 --- /dev/null +++ b/media/libmedia/Visualizer.cpp @@ -0,0 +1,330 @@ +/* +** +** Copyright 2010, 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 "Visualizer" +#include <utils/Log.h> + +#include <stdint.h> +#include <sys/types.h> +#include <limits.h> + +#include <media/Visualizer.h> + +extern "C" { +#define FLOATING_POINT 1 +#include "fftwrap.h" +} + +namespace android { + +// --------------------------------------------------------------------------- + +Visualizer::Visualizer (int32_t priority, + effect_callback_t cbf, + void* user, + int sessionId) + : AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId), + mCaptureRate(CAPTURE_RATE_DEF), + mCaptureSize(CAPTURE_SIZE_DEF), + mSampleRate(44100000), + mCaptureCallBack(NULL), + mCaptureCbkUser(NULL) +{ + initCaptureSize(); + if (mCaptureSize != 0) { + mFftTable = spx_fft_init(mCaptureSize); + } else { + mFftTable = NULL; + } +} + +Visualizer::~Visualizer() +{ + if (mFftTable != NULL) { + spx_fft_destroy(mFftTable); + } +} + +status_t Visualizer::setEnabled(bool enabled) +{ + Mutex::Autolock _l(mLock); + + sp<CaptureThread> t = mCaptureThread; + if (t != 0) { + if (enabled) { + if (t->exitPending()) { + if (t->requestExitAndWait() == WOULD_BLOCK) { + LOGE("Visualizer::enable() called from thread"); + return INVALID_OPERATION; + } + } + } + t->mLock.lock(); + } + + status_t status = AudioEffect::setEnabled(enabled); + + if (status == NO_ERROR) { + if (t != 0) { + if (enabled) { + t->run("AudioTrackThread"); + } else { + t->requestExit(); + } + } + } + + if (t != 0) { + t->mLock.unlock(); + } + + return status; +} + +status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate) +{ + if (rate > CAPTURE_RATE_MAX) { + return BAD_VALUE; + } + Mutex::Autolock _l(mLock); + + if (mEnabled) { + return INVALID_OPERATION; + } + + sp<CaptureThread> t = mCaptureThread; + if (t != 0) { + t->mLock.lock(); + } + mCaptureThread.clear(); + mCaptureCallBack = cbk; + mCaptureCbkUser = user; + mCaptureFlags = flags; + mCaptureRate = rate; + + if (t != 0) { + t->mLock.unlock(); + } + + if (cbk != NULL) { + mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0)); + if (mCaptureThread == 0) { + LOGE("Could not create callback thread"); + return NO_INIT; + } + } + LOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x", + rate, mCaptureThread.get(), mCaptureFlags); + return NO_ERROR; +} + +status_t Visualizer::setCaptureSize(uint32_t size) +{ + if (size > VISUALIZER_CAPTURE_SIZE_MAX || + size < VISUALIZER_CAPTURE_SIZE_MIN || + AudioSystem::popCount(size) != 1) { + return BAD_VALUE; + } + + Mutex::Autolock _l(mLock); + if (mEnabled) { + return INVALID_OPERATION; + } + + uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2]; + effect_param_t *p = (effect_param_t *)buf32; + + p->psize = sizeof(uint32_t); + p->vsize = sizeof(uint32_t); + *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE; + *((int32_t *)p->data + 1)= size; + status_t status = setParameter(p); + + LOGV("setCaptureSize size %d status %d p->status %d", size, status, p->status); + + if (status == NO_ERROR) { + status = p->status; + } + if (status == NO_ERROR) { + mCaptureSize = size; + if (mFftTable != NULL) { + spx_fft_destroy(mFftTable); + } + mFftTable = spx_fft_init(mCaptureSize); + LOGV("setCaptureSize size %d mFftTable %p", mCaptureSize, mFftTable); + } + + return status; +} + +status_t Visualizer::getWaveForm(uint8_t *waveform) +{ + if (waveform == NULL) { + return BAD_VALUE; + } + if (mCaptureSize == 0) { + return NO_INIT; + } + + status_t status = NO_ERROR; + if (mEnabled) { + uint32_t replySize = mCaptureSize; + status_t status = command(VISU_CMD_CAPTURE, 0, NULL, &replySize, waveform); + if (replySize == 0) { + status = NOT_ENOUGH_DATA; + } + } else { + memset(waveform, 0x80, mCaptureSize); + } + return status; +} + +status_t Visualizer::getFft(uint8_t *fft) +{ + if (fft == NULL) { + return BAD_VALUE; + } + if (mCaptureSize == 0) { + return NO_INIT; + } + + status_t status = NO_ERROR; + if (mEnabled) { + uint8_t buf[mCaptureSize]; + status_t status = getWaveForm(buf); + if (status == NO_ERROR) { + status = doFft(fft, buf); + } + } else { + memset(fft, 0, mCaptureSize); + } + return status; +} + +status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform) +{ + if (mFftTable == NULL) { + return NO_INIT; + } + + float fsrc[mCaptureSize]; + for (uint32_t i = 0; i < mCaptureSize; i++) { + fsrc[i] = (int16_t)(waveform[i] ^ 0x80) << 8; + } + float fdst[mCaptureSize]; + spx_fft_float(mFftTable, fsrc, fdst); + for (uint32_t i = 0; i < mCaptureSize; i++) { + fft[i] = (uint8_t)((int32_t)fdst[i] >> 8); + } + return NO_ERROR; +} + +void Visualizer::periodicCapture() +{ + Mutex::Autolock _l(mLock); + LOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x", + this, mCaptureCallBack, mCaptureFlags); + if (mCaptureCallBack != NULL && + (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) && + mCaptureSize != 0) { + uint8_t waveform[mCaptureSize]; + status_t status = getWaveForm(waveform); + if (status != NO_ERROR) { + return; + } + uint8_t fft[mCaptureSize]; + if (mCaptureFlags & CAPTURE_FFT) { + status = doFft(fft, waveform); + } + if (status != NO_ERROR) { + return; + } + uint8_t *wavePtr = NULL; + uint8_t *fftPtr = NULL; + uint32_t waveSize = 0; + uint32_t fftSize = 0; + if (mCaptureFlags & CAPTURE_WAVEFORM) { + wavePtr = waveform; + waveSize = mCaptureSize; + } + if (mCaptureFlags & CAPTURE_FFT) { + fftPtr = fft; + fftSize = mCaptureSize; + } + mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate); + } +} + +uint32_t Visualizer::initCaptureSize() +{ + uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2]; + effect_param_t *p = (effect_param_t *)buf32; + + p->psize = sizeof(uint32_t); + p->vsize = sizeof(uint32_t); + *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE; + status_t status = getParameter(p); + + if (status == NO_ERROR) { + status = p->status; + } + + uint32_t size = 0; + if (status == NO_ERROR) { + size = *((int32_t *)p->data + 1); + } + mCaptureSize = size; + + LOGV("initCaptureSize size %d status %d", mCaptureSize, status); + + return size; +} + +//------------------------------------------------------------------------- + +Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava) + : Thread(bCanCallJava), mReceiver(receiver) +{ + mSleepTimeUs = 1000000000 / captureRate; + LOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs); +} + +bool Visualizer::CaptureThread::threadLoop() +{ + LOGV("CaptureThread %p enter", this); + while (!exitPending()) + { + usleep(mSleepTimeUs); + mReceiver.periodicCapture(); + } + LOGV("CaptureThread %p exiting", this); + return false; +} + +status_t Visualizer::CaptureThread::readyToRun() +{ + return NO_ERROR; +} + +void Visualizer::CaptureThread::onFirstRef() +{ +} + +}; // namespace android + diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index c6bbbcc..1c99ae5 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -55,6 +55,7 @@ MediaPlayer::MediaPlayer() mLeftVolume = mRightVolume = 1.0; mVideoWidth = mVideoHeight = 0; mLockThreadId = 0; + mAudioSessionId = AudioSystem::newAudioSessionId(); } MediaPlayer::~MediaPlayer() @@ -137,7 +138,7 @@ status_t MediaPlayer::setDataSource( const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != 0) { sp<IMediaPlayer> player( - service->create(getpid(), this, url, headers)); + service->create(getpid(), this, url, headers, mAudioSessionId)); err = setDataSource(player); } } @@ -150,7 +151,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, fd, offset, length)); + sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length, mAudioSessionId)); err = setDataSource(player); } return err; @@ -269,6 +270,7 @@ status_t MediaPlayer::start() MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) { mPlayer->setLooping(mLoop); mPlayer->setVolume(mLeftVolume, mRightVolume); + mPlayer->setAuxEffectSendLevel(mSendLevel); mCurrentState = MEDIA_PLAYER_STARTED; status_t ret = mPlayer->start(); if (ret != NO_ERROR) { @@ -501,6 +503,52 @@ status_t MediaPlayer::setVolume(float leftVolume, float rightVolume) return OK; } +status_t MediaPlayer::setAudioSessionId(int sessionId) +{ + LOGV("MediaPlayer::setAudioSessionId(%d)", sessionId); + Mutex::Autolock _l(mLock); + if (!(mCurrentState & MEDIA_PLAYER_IDLE)) { + LOGE("setAudioSessionId called in state %d", mCurrentState); + return INVALID_OPERATION; + } + if (sessionId < 0) { + return BAD_VALUE; + } + mAudioSessionId = sessionId; + return NO_ERROR; +} + +int MediaPlayer::getAudioSessionId() +{ + Mutex::Autolock _l(mLock); + return mAudioSessionId; +} + +status_t MediaPlayer::setAuxEffectSendLevel(float level) +{ + LOGV("MediaPlayer::setAuxEffectSendLevel(%f)", level); + Mutex::Autolock _l(mLock); + mSendLevel = level; + if (mPlayer != 0) { + return mPlayer->setAuxEffectSendLevel(level); + } + return OK; +} + +status_t MediaPlayer::attachAuxEffect(int effectId) +{ + LOGV("MediaPlayer::attachAuxEffect(%d)", effectId); + Mutex::Autolock _l(mLock); + if (mPlayer == 0 || + (mCurrentState & MEDIA_PLAYER_IDLE) || + (mCurrentState == MEDIA_PLAYER_STATE_ERROR )) { + LOGE("attachAuxEffect called in state %d", mCurrentState); + return INVALID_OPERATION; + } + + return mPlayer->attachAuxEffect(effectId); +} + void MediaPlayer::notify(int msg, int ext1, int ext2) { LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2); @@ -636,61 +684,4 @@ void MediaPlayer::died() } -extern "C" { -#define FLOATING_POINT 1 -#include "fftwrap.h" -} - -static void *ffttable = NULL; - -// peeks at the audio data and fills 'data' with the requested kind -// (currently kind=0 returns mono 16 bit PCM data, and kind=1 returns -// 256 point FFT data). Return value is number of samples returned, -// which may be 0. -/*static*/ int MediaPlayer::snoop(short* data, int len, int kind) { - - sp<IMemory> p; - const sp<IMediaPlayerService>& service = getMediaPlayerService(); - if (service != 0) { - // Take a peek at the waveform. The returned data consists of 16 bit mono PCM data. - p = service->snoop(); - - if (p == NULL) { - return 0; - } - - if (kind == 0) { // return waveform data - int plen = p->size(); - len *= 2; // number of shorts -> number of bytes - short *src = (short*) p->pointer(); - if (plen > len) { - plen = len; - } - memcpy(data, src, plen); - return plen / sizeof(short); // return number of samples - } else if (kind == 1) { - // TODO: use a more efficient FFT - // Right now this uses the speex library, which is compiled to do a float FFT - if (!ffttable) ffttable = spx_fft_init(512); - short *usrc = (short*) p->pointer(); - float fsrc[512]; - for (int i=0;i<512;i++) - fsrc[i] = usrc[i]; - float fdst[512]; - spx_fft_float(ffttable, fsrc, fdst); - if (len > 512) { - len = 512; - } - len /= 2; // only half the output data is valid - for (int i=0; i < len; i++) - data[i] = fdst[i]; - return len; - } - - } else { - LOGE("Unable to locate media service"); - } - return 0; -} - }; // namespace android |
