diff options
Diffstat (limited to 'media/libmedia')
-rw-r--r-- | media/libmedia/Android.mk | 3 | ||||
-rw-r--r-- | media/libmedia/AudioPolicy.cpp | 115 | ||||
-rw-r--r-- | media/libmedia/AudioRecord.cpp | 31 | ||||
-rw-r--r-- | media/libmedia/AudioSystem.cpp | 310 | ||||
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 240 | ||||
-rw-r--r-- | media/libmedia/AudioTrackShared.cpp | 99 | ||||
-rw-r--r-- | media/libmedia/IAudioPolicyService.cpp | 225 | ||||
-rw-r--r-- | media/libmedia/ICrypto.cpp | 22 | ||||
-rw-r--r-- | media/libmedia/IDrm.cpp | 43 | ||||
-rw-r--r-- | media/libmedia/Visualizer.cpp | 19 |
10 files changed, 684 insertions, 423 deletions
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index e012116..a2e0909 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -59,7 +59,8 @@ LOCAL_SRC_FILES:= \ MemoryLeakTrackUtil.cpp \ SoundPool.cpp \ SoundPoolThread.cpp \ - StringArray.cpp + StringArray.cpp \ + AudioPolicy.cpp LOCAL_SRC_FILES += ../libnbaio/roundup.c diff --git a/media/libmedia/AudioPolicy.cpp b/media/libmedia/AudioPolicy.cpp new file mode 100644 index 0000000..d2d0971 --- /dev/null +++ b/media/libmedia/AudioPolicy.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AudioPolicy" +//#define LOG_NDEBUG 0 +#include <utils/Log.h> +#include <media/AudioPolicy.h> + +namespace android { + +// +// AttributeMatchCriterion implementation +// +AttributeMatchCriterion::AttributeMatchCriterion(audio_usage_t usage, + audio_source_t source, + uint32_t rule) +: mRule(rule) +{ + if (mRule == RULE_MATCH_ATTRIBUTE_USAGE || + mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) { + mAttr.mUsage = usage; + } else { + mAttr.mSource = source; + } +} + +status_t AttributeMatchCriterion::readFromParcel(Parcel *parcel) +{ + mRule = parcel->readInt32(); + if (mRule == RULE_MATCH_ATTRIBUTE_USAGE || + mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) { + mAttr.mUsage = (audio_usage_t)parcel->readInt32(); + } else { + mAttr.mSource = (audio_source_t)parcel->readInt32(); + } + return NO_ERROR; +} + +status_t AttributeMatchCriterion::writeToParcel(Parcel *parcel) const +{ + parcel->writeInt32(mRule); + parcel->writeInt32(mAttr.mUsage); + return NO_ERROR; +} + +// +// AudioMix implementation +// + +status_t AudioMix::readFromParcel(Parcel *parcel) +{ + mMixType = parcel->readInt32(); + mFormat.sample_rate = (uint32_t)parcel->readInt32(); + mFormat.channel_mask = (audio_channel_mask_t)parcel->readInt32(); + mFormat.format = (audio_format_t)parcel->readInt32(); + mRouteFlags = parcel->readInt32(); + mRegistrationId = parcel->readString8(); + size_t size = (size_t)parcel->readInt32(); + if (size > MAX_CRITERIA_PER_MIX) { + size = MAX_CRITERIA_PER_MIX; + } + for (size_t i = 0; i < size; i++) { + AttributeMatchCriterion criterion; + if (criterion.readFromParcel(parcel) == NO_ERROR) { + mCriteria.add(criterion); + } + } + return NO_ERROR; +} + +status_t AudioMix::writeToParcel(Parcel *parcel) const +{ + parcel->writeInt32(mMixType); + parcel->writeInt32(mFormat.sample_rate); + parcel->writeInt32(mFormat.channel_mask); + parcel->writeInt32(mFormat.format); + parcel->writeInt32(mRouteFlags); + parcel->writeString8(mRegistrationId); + size_t size = mCriteria.size(); + if (size > MAX_CRITERIA_PER_MIX) { + size = MAX_CRITERIA_PER_MIX; + } + size_t sizePosition = parcel->dataPosition(); + parcel->writeInt32(size); + size_t finalSize = size; + for (size_t i = 0; i < size; i++) { + size_t position = parcel->dataPosition(); + if (mCriteria[i].writeToParcel(parcel) != NO_ERROR) { + parcel->setDataPosition(position); + finalSize--; + } + } + if (size != finalSize) { + size_t position = parcel->dataPosition(); + parcel->setDataPosition(sizePosition); + parcel->writeInt32(finalSize); + parcel->setDataPosition(position); + } + return NO_ERROR; +} + +}; // namespace android diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 9e7ba88..ca3832d 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -82,14 +82,16 @@ AudioRecord::AudioRecord( uint32_t notificationFrames, int sessionId, transfer_type transferType, - audio_input_flags_t flags) + audio_input_flags_t flags, + const audio_attributes_t* pAttributes) : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mProxy(NULL) { mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user, - notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags); + notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags, + pAttributes); } AudioRecord::~AudioRecord() @@ -126,7 +128,8 @@ status_t AudioRecord::set( bool threadCanCallJava, int sessionId, transfer_type transferType, - audio_input_flags_t flags) + audio_input_flags_t flags, + const audio_attributes_t* pAttributes) { ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, " "notificationFrames %u, sessionId %d, transferType %d, flags %#x", @@ -164,11 +167,15 @@ status_t AudioRecord::set( return INVALID_OPERATION; } - // handle default values first. - if (inputSource == AUDIO_SOURCE_DEFAULT) { - inputSource = AUDIO_SOURCE_MIC; + if (pAttributes == NULL) { + memset(&mAttributes, 0, sizeof(audio_attributes_t)); + mAttributes.source = inputSource; + } else { + // stream type shouldn't be looked at, this track has audio attributes + memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t)); + ALOGV("Building AudioRecord with attributes: source=%d flags=0x%x tags=[%s]", + mAttributes.source, mAttributes.flags, mAttributes.tags); } - mInputSource = inputSource; if (sampleRate == 0) { ALOGE("Invalid sample rate %u", sampleRate); @@ -444,12 +451,14 @@ status_t AudioRecord::openRecord_l(size_t epoch) } } - audio_io_handle_t input = AudioSystem::getInput(mInputSource, mSampleRate, mFormat, - mChannelMask, mSessionId, mFlags); - if (input == AUDIO_IO_HANDLE_NONE) { + audio_io_handle_t input; + status = AudioSystem::getInputForAttr(&mAttributes, &input, (audio_session_t)mSessionId, + mSampleRate, mFormat, mChannelMask, mFlags); + + if (status != NO_ERROR) { ALOGE("Could not get audio input for record source %d, sample rate %u, format %#x, " "channel mask %#x, session %d, flags %#x", - mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId, mFlags); + mAttributes.source, mSampleRate, mFormat, mChannelMask, mSessionId, mFlags); return BAD_VALUE; } { diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index dda3657..9cae21c 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -32,6 +32,9 @@ namespace android { // client singleton for AudioFlinger binder interface Mutex AudioSystem::gLock; +Mutex AudioSystem::gLockCache; +Mutex AudioSystem::gLockAPS; +Mutex AudioSystem::gLockAPC; sp<IAudioFlinger> AudioSystem::gAudioFlinger; sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; @@ -48,33 +51,40 @@ size_t AudioSystem::gInBuffSize = 0; // zero indicates cache is invalid sp<AudioSystem::AudioPortCallback> AudioSystem::gAudioPortCallback; // establish binder interface to AudioFlinger service -const sp<IAudioFlinger>& AudioSystem::get_audio_flinger() -{ - Mutex::Autolock _l(gLock); - if (gAudioFlinger == 0) { - sp<IServiceManager> sm = defaultServiceManager(); - sp<IBinder> binder; - do { - binder = sm->getService(String16("media.audio_flinger")); - if (binder != 0) - break; - ALOGW("AudioFlinger not published, waiting..."); - usleep(500000); // 0.5 s - } while (true); - if (gAudioFlingerClient == NULL) { - gAudioFlingerClient = new AudioFlingerClient(); - } else { - if (gAudioErrorCallback) { - gAudioErrorCallback(NO_ERROR); +const sp<IAudioFlinger> AudioSystem::get_audio_flinger() +{ + sp<IAudioFlinger> af; + sp<AudioFlingerClient> afc; + { + Mutex::Autolock _l(gLock); + if (gAudioFlinger == 0) { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder; + do { + binder = sm->getService(String16("media.audio_flinger")); + if (binder != 0) + break; + ALOGW("AudioFlinger not published, waiting..."); + usleep(500000); // 0.5 s + } while (true); + if (gAudioFlingerClient == NULL) { + gAudioFlingerClient = new AudioFlingerClient(); + } else { + if (gAudioErrorCallback) { + gAudioErrorCallback(NO_ERROR); + } } + binder->linkToDeath(gAudioFlingerClient); + gAudioFlinger = interface_cast<IAudioFlinger>(binder); + LOG_ALWAYS_FATAL_IF(gAudioFlinger == 0); + afc = gAudioFlingerClient; } - binder->linkToDeath(gAudioFlingerClient); - gAudioFlinger = interface_cast<IAudioFlinger>(binder); - gAudioFlinger->registerClient(gAudioFlingerClient); + af = gAudioFlinger; } - ALOGE_IF(gAudioFlinger==0, "no AudioFlinger!?"); - - return gAudioFlinger; + if (afc != 0) { + af->registerClient(afc); + } + return af; } /* static */ status_t AudioSystem::checkAudioFlinger() @@ -245,36 +255,23 @@ status_t AudioSystem::getOutputSamplingRate(uint32_t* samplingRate, audio_stream return getSamplingRate(output, samplingRate); } -status_t AudioSystem::getOutputSamplingRateForAttr(uint32_t* samplingRate, - const audio_attributes_t *attr) -{ - if (attr == NULL) { - return BAD_VALUE; - } - audio_io_handle_t output = getOutputForAttr(attr); - if (output == 0) { - return PERMISSION_DENIED; - } - return getSamplingRate(output, samplingRate); -} - status_t AudioSystem::getSamplingRate(audio_io_handle_t output, uint32_t* samplingRate) { - OutputDescriptor *outputDesc; + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; - gLock.lock(); - outputDesc = AudioSystem::gOutputs.valueFor(output); + Mutex::Autolock _l(gLockCache); + + OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output); if (outputDesc == NULL) { ALOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output); - gLock.unlock(); - const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); - if (af == 0) return PERMISSION_DENIED; + gLockCache.unlock(); *samplingRate = af->sampleRate(output); + gLockCache.lock(); } else { ALOGV("getOutputSamplingRate() reading from output desc"); *samplingRate = outputDesc->samplingRate; - gLock.unlock(); } if (*samplingRate == 0) { ALOGE("AudioSystem::getSamplingRate failed for output %d", output); @@ -305,18 +302,18 @@ status_t AudioSystem::getOutputFrameCount(size_t* frameCount, audio_stream_type_ status_t AudioSystem::getFrameCount(audio_io_handle_t output, size_t* frameCount) { - OutputDescriptor *outputDesc; + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + + Mutex::Autolock _l(gLockCache); - gLock.lock(); - outputDesc = AudioSystem::gOutputs.valueFor(output); + OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output); if (outputDesc == NULL) { - gLock.unlock(); - const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); - if (af == 0) return PERMISSION_DENIED; + gLockCache.unlock(); *frameCount = af->frameCount(output); + gLockCache.lock(); } else { *frameCount = outputDesc->frameCount; - gLock.unlock(); } if (*frameCount == 0) { ALOGE("AudioSystem::getFrameCount failed for output %d", output); @@ -347,18 +344,18 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t st status_t AudioSystem::getLatency(audio_io_handle_t output, uint32_t* latency) { - OutputDescriptor *outputDesc; + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; - gLock.lock(); - outputDesc = AudioSystem::gOutputs.valueFor(output); + Mutex::Autolock _l(gLockCache); + + OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output); if (outputDesc == NULL) { - gLock.unlock(); - const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); - if (af == 0) return PERMISSION_DENIED; + gLockCache.unlock(); *latency = af->latency(output); + gLockCache.lock(); } else { *latency = outputDesc->latency; - gLock.unlock(); } ALOGV("getLatency() output %d, latency %d", output, *latency); @@ -369,24 +366,24 @@ status_t AudioSystem::getLatency(audio_io_handle_t output, status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t* buffSize) { - gLock.lock(); + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) { + return PERMISSION_DENIED; + } + Mutex::Autolock _l(gLockCache); // Do we have a stale gInBufferSize or are we requesting the input buffer size for new values size_t inBuffSize = gInBuffSize; if ((inBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat) || (channelMask != gPrevInChannelMask)) { - gLock.unlock(); - const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); - if (af == 0) { - return PERMISSION_DENIED; - } + gLockCache.unlock(); inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask); + gLockCache.lock(); if (inBuffSize == 0) { ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %x", sampleRate, format, channelMask); return BAD_VALUE; } // A benign race is possible here: we could overwrite a fresher cache entry - gLock.lock(); // save the request params gPrevInSamplingRate = sampleRate; gPrevInFormat = format; @@ -394,7 +391,6 @@ status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t for gInBuffSize = inBuffSize; } - gLock.unlock(); *buffSize = inBuffSize; return NO_ERROR; @@ -461,14 +457,21 @@ audio_hw_sync_t AudioSystem::getAudioHwSyncForSession(audio_session_t sessionId) void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused) { - Mutex::Autolock _l(AudioSystem::gLock); + audio_error_callback cb = NULL; + { + Mutex::Autolock _l(AudioSystem::gLock); + AudioSystem::gAudioFlinger.clear(); + cb = gAudioErrorCallback; + } - AudioSystem::gAudioFlinger.clear(); - // clear output handles and stream to output map caches - AudioSystem::gOutputs.clear(); + { + // clear output handles and stream to output map caches + Mutex::Autolock _l(gLockCache); + AudioSystem::gOutputs.clear(); + } - if (gAudioErrorCallback) { - gAudioErrorCallback(DEAD_OBJECT); + if (cb) { + cb(DEAD_OBJECT); } ALOGW("AudioFlinger server died!"); } @@ -481,7 +484,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle if (ioHandle == AUDIO_IO_HANDLE_NONE) return; - Mutex::Autolock _l(AudioSystem::gLock); + Mutex::Autolock _l(AudioSystem::gLockCache); switch (event) { case STREAM_CONFIG_CHANGED: @@ -543,55 +546,44 @@ void AudioSystem::setErrorCallback(audio_error_callback cb) gAudioErrorCallback = cb; } - -bool AudioSystem::routedToA2dpOutput(audio_stream_type_t streamType) -{ - switch (streamType) { - case AUDIO_STREAM_MUSIC: - case AUDIO_STREAM_VOICE_CALL: - case AUDIO_STREAM_BLUETOOTH_SCO: - case AUDIO_STREAM_SYSTEM: - return true; - default: - return false; - } -} - - // client singleton for AudioPolicyService binder interface +// protected by gLockAPS sp<IAudioPolicyService> AudioSystem::gAudioPolicyService; sp<AudioSystem::AudioPolicyServiceClient> AudioSystem::gAudioPolicyServiceClient; // establish binder interface to AudioPolicy service -const sp<IAudioPolicyService>& AudioSystem::get_audio_policy_service() -{ - gLock.lock(); - if (gAudioPolicyService == 0) { - sp<IServiceManager> sm = defaultServiceManager(); - sp<IBinder> binder; - do { - binder = sm->getService(String16("media.audio_policy")); - if (binder != 0) - break; - ALOGW("AudioPolicyService not published, waiting..."); - usleep(500000); // 0.5 s - } while (true); - if (gAudioPolicyServiceClient == NULL) { - gAudioPolicyServiceClient = new AudioPolicyServiceClient(); +const sp<IAudioPolicyService> AudioSystem::get_audio_policy_service() +{ + sp<IAudioPolicyService> ap; + sp<AudioPolicyServiceClient> apc; + { + Mutex::Autolock _l(gLockAPS); + if (gAudioPolicyService == 0) { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder; + do { + binder = sm->getService(String16("media.audio_policy")); + if (binder != 0) + break; + ALOGW("AudioPolicyService not published, waiting..."); + usleep(500000); // 0.5 s + } while (true); + if (gAudioPolicyServiceClient == NULL) { + gAudioPolicyServiceClient = new AudioPolicyServiceClient(); + } + binder->linkToDeath(gAudioPolicyServiceClient); + gAudioPolicyService = interface_cast<IAudioPolicyService>(binder); + LOG_ALWAYS_FATAL_IF(gAudioPolicyService == 0); + apc = gAudioPolicyServiceClient; } - binder->linkToDeath(gAudioPolicyServiceClient); - gAudioPolicyService = interface_cast<IAudioPolicyService>(binder); - gLock.unlock(); - // Registering the client takes the AudioPolicyService lock. - // Don't hold the AudioSystem lock at the same time. - gAudioPolicyService->registerClient(gAudioPolicyServiceClient); - } else { - // There exists a benign race condition where gAudioPolicyService - // is set, but gAudioPolicyServiceClient is not yet registered. - gLock.unlock(); + ap = gAudioPolicyService; + } + if (apc != 0) { + ap->registerClient(apc); } - return gAudioPolicyService; + + return ap; } // --------------------------------------------------------------------------- @@ -657,22 +649,26 @@ audio_io_handle_t AudioSystem::getOutput(audio_stream_type_t stream, return aps->getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo); } -audio_io_handle_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_output_flags_t flags, - const audio_offload_info_t *offloadInfo) +status_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *output, + audio_session_t session, + audio_stream_type_t *stream, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo) { - if (attr == NULL) return 0; const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); - if (aps == 0) return 0; - return aps->getOutputForAttr(attr, samplingRate, format, channelMask, flags, offloadInfo); + if (aps == 0) return NO_INIT; + return aps->getOutputForAttr(attr, output, session, stream, + samplingRate, format, channelMask, + flags, offloadInfo); } status_t AudioSystem::startOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; @@ -681,30 +677,33 @@ status_t AudioSystem::startOutput(audio_io_handle_t output, status_t AudioSystem::stopOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; return aps->stopOutput(output, stream, session); } -void AudioSystem::releaseOutput(audio_io_handle_t output) +void AudioSystem::releaseOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return; - aps->releaseOutput(output); + aps->releaseOutput(output, stream, session); } -audio_io_handle_t AudioSystem::getInput(audio_source_t inputSource, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - int sessionId, - audio_input_flags_t flags) +status_t AudioSystem::getInputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *input, + audio_session_t session, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_input_flags_t flags) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); - if (aps == 0) return 0; - return aps->getInput(inputSource, samplingRate, format, channelMask, sessionId, flags); + if (aps == 0) return NO_INIT; + return aps->getInputForAttr(attr, input, session, samplingRate, format, channelMask, flags); } status_t AudioSystem::startInput(audio_io_handle_t input, @@ -856,9 +855,21 @@ status_t AudioSystem::setLowRamDevice(bool isLowRamDevice) void AudioSystem::clearAudioConfigCache() { - Mutex::Autolock _l(gLock); + // called by restoreTrack_l(), which needs new IAudioFlinger and IAudioPolicyService instances ALOGV("clearAudioConfigCache()"); - gOutputs.clear(); + { + Mutex::Autolock _l(gLockCache); + gOutputs.clear(); + } + { + Mutex::Autolock _l(gLock); + gAudioFlinger.clear(); + } + { + Mutex::Autolock _l(gLockAPS); + gAudioPolicyService.clear(); + } + // Do not clear gAudioPortCallback } bool AudioSystem::isOffloadSupported(const audio_offload_info_t& info) @@ -920,7 +931,7 @@ status_t AudioSystem::setAudioPortConfig(const struct audio_port_config *config) void AudioSystem::setAudioPortCallback(sp<AudioPortCallback> callBack) { - Mutex::Autolock _l(gLock); + Mutex::Autolock _l(gLockAPC); gAudioPortCallback = callBack; } @@ -947,23 +958,34 @@ audio_mode_t AudioSystem::getPhoneState() return aps->getPhoneState(); } +status_t AudioSystem::registerPolicyMixes(Vector<AudioMix> mixes, bool registration) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->registerPolicyMixes(mixes, registration); +} // --------------------------------------------------------------------------- void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused) { - Mutex::Autolock _l(gLock); - if (gAudioPortCallback != 0) { - gAudioPortCallback->onServiceDied(); + { + Mutex::Autolock _l(gLockAPC); + if (gAudioPortCallback != 0) { + gAudioPortCallback->onServiceDied(); + } + } + { + Mutex::Autolock _l(gLockAPS); + AudioSystem::gAudioPolicyService.clear(); } - AudioSystem::gAudioPolicyService.clear(); ALOGW("AudioPolicyService server died!"); } void AudioSystem::AudioPolicyServiceClient::onAudioPortListUpdate() { - Mutex::Autolock _l(gLock); + Mutex::Autolock _l(gLockAPC); if (gAudioPortCallback != 0) { gAudioPortCallback->onAudioPortListUpdate(); } @@ -971,7 +993,7 @@ void AudioSystem::AudioPolicyServiceClient::onAudioPortListUpdate() void AudioSystem::AudioPolicyServiceClient::onAudioPatchListUpdate() { - Mutex::Autolock _l(gLock); + Mutex::Autolock _l(gLockAPC); if (gAudioPortCallback != 0) { gAudioPortCallback->onAudioPatchListUpdate(); } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 0a89fbb..389aacc 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -28,6 +28,7 @@ #include <utils/Log.h> #include <private/media/AudioTrackShared.h> #include <media/IAudioFlinger.h> +#include <media/AudioPolicyHelper.h> #include <media/AudioResamplerPublic.h> #define WAIT_PERIOD_MS 10 @@ -281,38 +282,21 @@ status_t AudioTrack::set( if (streamType == AUDIO_STREAM_DEFAULT) { streamType = AUDIO_STREAM_MUSIC; } - if (pAttributes == NULL) { - if (uint32_t(streamType) >= AUDIO_STREAM_CNT) { + if (uint32_t(streamType) >= AUDIO_STREAM_PUBLIC_CNT) { ALOGE("Invalid stream type %d", streamType); return BAD_VALUE; } - setAttributesFromStreamType(streamType); mStreamType = streamType; + } else { - if (!isValidAttributes(pAttributes)) { - ALOGE("Invalid attributes: usage=%d content=%d flags=0x%x tags=[%s]", - pAttributes->usage, pAttributes->content_type, pAttributes->flags, - pAttributes->tags); - } // stream type shouldn't be looked at, this track has audio attributes memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t)); - setStreamTypeFromAttributes(mAttributes); ALOGV("Building AudioTrack with attributes: usage=%d content=%d flags=0x%x tags=[%s]", mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags); + mStreamType = AUDIO_STREAM_DEFAULT; } - status_t status; - if (sampleRate == 0) { - status = AudioSystem::getOutputSamplingRateForAttr(&sampleRate, &mAttributes); - if (status != NO_ERROR) { - ALOGE("Could not get output sample rate for stream type %d; status %d", - mStreamType, status); - return status; - } - } - mSampleRate = sampleRate; - // these below should probably come from the audioFlinger too... if (format == AUDIO_FORMAT_DEFAULT) { format = AUDIO_FORMAT_PCM_16_BIT; @@ -350,9 +334,10 @@ status_t AudioTrack::set( // FIXME why can't we allow direct AND fast? ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST); } - // only allow deep buffering for music stream type - if (mStreamType != AUDIO_STREAM_MUSIC) { - flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER); + + // force direct flag if HW A/V sync requested + if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) { + flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT); } if (flags & AUDIO_OUTPUT_FLAG_DIRECT) { @@ -371,6 +356,12 @@ status_t AudioTrack::set( // so no need to check for specific PCM formats here } + // sampling rate must be specified for direct outputs + if (sampleRate == 0 && (flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) { + return BAD_VALUE; + } + mSampleRate = sampleRate; + // Make copy of input parameter offloadInfo so that in the future: // (a) createTrack_l doesn't need it as an input parameter // (b) we can support re-creation of offloaded tracks @@ -388,7 +379,11 @@ status_t AudioTrack::set( mReqFrameCount = frameCount; mNotificationFramesReq = notificationFrames; mNotificationFramesAct = 0; - mSessionId = sessionId; + if (sessionId == AUDIO_SESSION_ALLOCATE) { + mSessionId = AudioSystem::newAudioUniqueId(); + } else { + mSessionId = sessionId; + } int callingpid = IPCThreadState::self()->getCallingPid(); int mypid = getpid(); if (uid == -1 || (callingpid != mypid)) { @@ -411,7 +406,7 @@ status_t AudioTrack::set( } // create the IAudioTrack - status = createTrack_l(); + status_t status = createTrack_l(); if (status != NO_ERROR) { if (mAudioTrackThread != 0) { @@ -678,15 +673,18 @@ status_t AudioTrack::setSampleRate(uint32_t rate) return INVALID_OPERATION; } + AutoMutex lock(mLock); + if (mOutput == AUDIO_IO_HANDLE_NONE) { + return NO_INIT; + } uint32_t afSamplingRate; - if (AudioSystem::getOutputSamplingRateForAttr(&afSamplingRate, &mAttributes) != NO_ERROR) { + if (AudioSystem::getSamplingRate(mOutput, &afSamplingRate) != NO_ERROR) { return NO_INIT; } if (rate == 0 || rate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) { return BAD_VALUE; } - AutoMutex lock(mLock); mSampleRate = rate; mProxy->setSampleRate(rate); @@ -742,8 +740,7 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount void AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount) { - // FIXME If setting a loop also sets position to start of loop, then - // this is correct. Otherwise it should be removed. + // Setting the loop will reset next notification update period (like setPosition). mNewPosition = updateAndGetPosition_l() + mUpdatePeriod; mLoopPeriod = loopCount != 0 ? loopEnd - loopStart : 0; mStaticProxy->setLoop(loopStart, loopEnd, loopCount); @@ -859,6 +856,10 @@ status_t AudioTrack::getPosition(uint32_t *position) // due to hardware latency. We leave this behavior for now. *position = dspFrames; } else { + if (mCblk->mFlags & CBLK_INVALID) { + restoreTrack_l("getPosition"); + } + // IAudioTrack::stop() isn't synchronous; we don't know when presentation completes *position = (mState == STATE_STOPPED || mState == STATE_FLUSHED) ? 0 : updateAndGetPosition_l(); @@ -915,24 +916,38 @@ status_t AudioTrack::attachAuxEffect(int effectId) return status; } +audio_stream_type_t AudioTrack::streamType() const +{ + if (mStreamType == AUDIO_STREAM_DEFAULT) { + return audio_attributes_to_stream_type(&mAttributes); + } + return mStreamType; +} + // ------------------------------------------------------------------------- // must be called with mLock held status_t AudioTrack::createTrack_l() { - status_t status; const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); if (audioFlinger == 0) { ALOGE("Could not get audioflinger"); return NO_INIT; } - audio_io_handle_t output = AudioSystem::getOutputForAttr(&mAttributes, mSampleRate, mFormat, - mChannelMask, mFlags, mOffloadInfo); - if (output == AUDIO_IO_HANDLE_NONE) { + audio_io_handle_t output; + audio_stream_type_t streamType = mStreamType; + audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL; + status_t status = AudioSystem::getOutputForAttr(attr, &output, + (audio_session_t)mSessionId, &streamType, + mSampleRate, mFormat, mChannelMask, + mFlags, mOffloadInfo); + + + if (status != NO_ERROR || output == AUDIO_IO_HANDLE_NONE) { ALOGE("Could not get audio output for stream type %d, usage %d, sample rate %u, format %#x," " channel mask %#x, flags %#x", - mStreamType, mAttributes.usage, mSampleRate, mFormat, mChannelMask, mFlags); + streamType, mAttributes.usage, mSampleRate, mFormat, mChannelMask, mFlags); return BAD_VALUE; } { @@ -961,7 +976,9 @@ status_t AudioTrack::createTrack_l() ALOGE("getSamplingRate(output=%d) status %d", output, status); goto release; } - + if (mSampleRate == 0) { + mSampleRate = afSampleRate; + } // Client decides whether the track is TIMED (see below), but can only express a preference // for FAST. Server will perform additional tests. if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !(( @@ -1084,7 +1101,7 @@ status_t AudioTrack::createTrack_l() size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also - sp<IAudioTrack> track = audioFlinger->createTrack(mStreamType, + sp<IAudioTrack> track = audioFlinger->createTrack(streamType, mSampleRate, // AudioFlinger only sees 16-bit PCM mFormat == AUDIO_FORMAT_PCM_8_BIT && @@ -1218,7 +1235,11 @@ status_t AudioTrack::createTrack_l() mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF); mProxy = mStaticProxy; } - mProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY); + + mProxy->setVolumeLR(gain_minifloat_pack( + gain_from_float(mVolume[AUDIO_INTERLEAVE_LEFT]), + gain_from_float(mVolume[AUDIO_INTERLEAVE_RIGHT]))); + mProxy->setSendLevel(mSendLevel); mProxy->setSampleRate(mSampleRate); mProxy->setMinimum(mNotificationFramesAct); @@ -1230,7 +1251,7 @@ status_t AudioTrack::createTrack_l() } release: - AudioSystem::releaseOutput(output); + AudioSystem::releaseOutput(output, streamType, (audio_session_t)mSessionId); if (status == NO_ERROR) { status = NO_INIT; } @@ -1826,7 +1847,7 @@ status_t AudioTrack::restoreTrack_l(const char *from) status_t result; // refresh the audio configuration cache in this process to make sure we get new - // output parameters in createTrack_l() + // output parameters and new IAudioFlinger in createTrack_l() AudioSystem::clearAudioConfigCache(); if (isOffloadedOrDirect_l()) { @@ -1934,6 +1955,10 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) break; } + if (mCblk->mFlags & CBLK_INVALID) { + restoreTrack_l("getTimestamp"); + } + // The presented frame count must always lag behind the consumed frame count. // To avoid a race, read the presented frames first. This ensures that presented <= consumed. status_t status = mAudioTrack->getTimestamp(timestamp); @@ -2064,143 +2089,6 @@ uint32_t AudioTrack::getUnderrunFrames() const return mProxy->getUnderrunFrames(); } -void AudioTrack::setAttributesFromStreamType(audio_stream_type_t streamType) { - mAttributes.flags = 0x0; - - switch(streamType) { - case AUDIO_STREAM_DEFAULT: - case AUDIO_STREAM_MUSIC: - mAttributes.content_type = AUDIO_CONTENT_TYPE_MUSIC; - mAttributes.usage = AUDIO_USAGE_MEDIA; - break; - case AUDIO_STREAM_VOICE_CALL: - mAttributes.content_type = AUDIO_CONTENT_TYPE_SPEECH; - mAttributes.usage = AUDIO_USAGE_VOICE_COMMUNICATION; - break; - case AUDIO_STREAM_ENFORCED_AUDIBLE: - mAttributes.flags |= AUDIO_FLAG_AUDIBILITY_ENFORCED; - // intended fall through, attributes in common with STREAM_SYSTEM - case AUDIO_STREAM_SYSTEM: - mAttributes.content_type = AUDIO_CONTENT_TYPE_SONIFICATION; - mAttributes.usage = AUDIO_USAGE_ASSISTANCE_SONIFICATION; - break; - case AUDIO_STREAM_RING: - mAttributes.content_type = AUDIO_CONTENT_TYPE_SONIFICATION; - mAttributes.usage = AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE; - break; - case AUDIO_STREAM_ALARM: - mAttributes.content_type = AUDIO_CONTENT_TYPE_SONIFICATION; - mAttributes.usage = AUDIO_USAGE_ALARM; - break; - case AUDIO_STREAM_NOTIFICATION: - mAttributes.content_type = AUDIO_CONTENT_TYPE_SONIFICATION; - mAttributes.usage = AUDIO_USAGE_NOTIFICATION; - break; - case AUDIO_STREAM_BLUETOOTH_SCO: - mAttributes.content_type = AUDIO_CONTENT_TYPE_SPEECH; - mAttributes.usage = AUDIO_USAGE_VOICE_COMMUNICATION; - mAttributes.flags |= AUDIO_FLAG_SCO; - break; - case AUDIO_STREAM_DTMF: - mAttributes.content_type = AUDIO_CONTENT_TYPE_SONIFICATION; - mAttributes.usage = AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING; - break; - case AUDIO_STREAM_TTS: - mAttributes.content_type = AUDIO_CONTENT_TYPE_SPEECH; - mAttributes.usage = AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY; - break; - default: - ALOGE("invalid stream type %d when converting to attributes", streamType); - } -} - -void AudioTrack::setStreamTypeFromAttributes(audio_attributes_t& aa) { - // flags to stream type mapping - if ((aa.flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) { - mStreamType = AUDIO_STREAM_ENFORCED_AUDIBLE; - return; - } - if ((aa.flags & AUDIO_FLAG_SCO) == AUDIO_FLAG_SCO) { - mStreamType = AUDIO_STREAM_BLUETOOTH_SCO; - return; - } - - // usage to stream type mapping - switch (aa.usage) { - case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY: - // TODO once AudioPolicyManager fully supports audio_attributes_t, - // remove stream change based on phone state - if (AudioSystem::getPhoneState() == AUDIO_MODE_RINGTONE) { - mStreamType = AUDIO_STREAM_RING; - break; - } - /// FALL THROUGH - case AUDIO_USAGE_MEDIA: - case AUDIO_USAGE_GAME: - case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: - mStreamType = AUDIO_STREAM_MUSIC; - return; - case AUDIO_USAGE_ASSISTANCE_SONIFICATION: - mStreamType = AUDIO_STREAM_SYSTEM; - return; - case AUDIO_USAGE_VOICE_COMMUNICATION: - mStreamType = AUDIO_STREAM_VOICE_CALL; - return; - - case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING: - mStreamType = AUDIO_STREAM_DTMF; - return; - - case AUDIO_USAGE_ALARM: - mStreamType = AUDIO_STREAM_ALARM; - return; - case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE: - mStreamType = AUDIO_STREAM_RING; - return; - - case AUDIO_USAGE_NOTIFICATION: - case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST: - case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT: - case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED: - case AUDIO_USAGE_NOTIFICATION_EVENT: - mStreamType = AUDIO_STREAM_NOTIFICATION; - return; - - case AUDIO_USAGE_UNKNOWN: - default: - mStreamType = AUDIO_STREAM_MUSIC; - } -} - -bool AudioTrack::isValidAttributes(const audio_attributes_t *paa) { - // has flags that map to a strategy? - if ((paa->flags & (AUDIO_FLAG_AUDIBILITY_ENFORCED | AUDIO_FLAG_SCO)) != 0) { - return true; - } - - // has known usage? - switch (paa->usage) { - case AUDIO_USAGE_UNKNOWN: - case AUDIO_USAGE_MEDIA: - case AUDIO_USAGE_VOICE_COMMUNICATION: - case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING: - case AUDIO_USAGE_ALARM: - case AUDIO_USAGE_NOTIFICATION: - case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE: - case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST: - case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT: - case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED: - case AUDIO_USAGE_NOTIFICATION_EVENT: - case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY: - case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: - case AUDIO_USAGE_ASSISTANCE_SONIFICATION: - case AUDIO_USAGE_GAME: - break; - default: - return false; - } - return true; -} // ========================================================================= void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who __unused) diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index eec025e..ff24475 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -25,6 +25,12 @@ namespace android { +// used to clamp a value to size_t. TODO: move to another file. +template <typename T> +size_t clampToSize(T x) { + return x > SIZE_MAX ? SIZE_MAX : x < 0 ? 0 : (size_t) x; +} + audio_track_cblk_t::audio_track_cblk_t() : mServer(0), mFutex(0), mMinimum(0), mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0) @@ -301,6 +307,7 @@ void ClientProxy::binderDied() { audio_track_cblk_t* cblk = mCblk; if (!(android_atomic_or(CBLK_INVALID, &cblk->mFlags) & CBLK_INVALID)) { + android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex); // it seems that a FUTEX_WAKE_PRIVATE will not wake a FUTEX_WAIT, even within same process (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1); @@ -311,6 +318,7 @@ void ClientProxy::interrupt() { audio_track_cblk_t* cblk = mCblk; if (!(android_atomic_or(CBLK_INTERRUPT, &cblk->mFlags) & CBLK_INTERRUPT)) { + android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex); (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1); } @@ -348,7 +356,13 @@ size_t ClientProxy::getFramesFilled() { void AudioTrackClientProxy::flush() { - mCblk->u.mStreaming.mFlush++; + // This works for mFrameCountP2 <= 2^30 + size_t increment = mFrameCountP2 << 1; + size_t mask = increment - 1; + audio_track_cblk_t* cblk = mCblk; + int32_t newFlush = (cblk->u.mStreaming.mRear & mask) | + ((cblk->u.mStreaming.mFlush & ~mask) + increment); + android_atomic_release_store(newFlush, &cblk->u.mStreaming.mFlush); } bool AudioTrackClientProxy::clearStreamEndDone() { @@ -491,7 +505,11 @@ void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int newState.mLoopStart = (uint32_t) loopStart; newState.mLoopEnd = (uint32_t) loopEnd; newState.mLoopCount = loopCount; - mBufferPosition = loopStart; + size_t bufferPosition; + if (loopCount == 0 || (bufferPosition = getBufferPosition()) >= loopEnd) { + bufferPosition = loopStart; + } + mBufferPosition = bufferPosition; // snapshot buffer position until loop is acknowledged. (void) mMutator.push(newState); } @@ -536,17 +554,27 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush) rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear); front = cblk->u.mStreaming.mFront; if (flush != mFlush) { - mFlush = flush; // effectively obtain then release whatever is in the buffer - android_atomic_release_store(rear, &cblk->u.mStreaming.mFront); - if (front != rear) { + size_t mask = (mFrameCountP2 << 1) - 1; + int32_t newFront = (front & ~mask) | (flush & mask); + ssize_t filled = rear - newFront; + // Rather than shutting down on a corrupt flush, just treat it as a full flush + if (!(0 <= filled && (size_t) filled <= mFrameCount)) { + ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, filled %d=%#x", + mFlush, flush, front, rear, mask, newFront, filled, filled); + newFront = rear; + } + mFlush = flush; + android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront); + // There is no danger from a false positive, so err on the side of caution + if (true /*front != newFront*/) { int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex); if (!(old & CBLK_FUTEX_WAKE)) { (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1); } } - front = rear; + front = newFront; } } else { front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront); @@ -668,6 +696,7 @@ size_t AudioTrackServerProxy::framesReady() int32_t flush = cblk->u.mStreaming.mFlush; if (flush != mFlush) { + // FIXME should return an accurate value, but over-estimate is better than under-estimate return mFrameCount; } // the acquire might not be necessary since not doing a subsequent read @@ -711,7 +740,8 @@ StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cbl size_t frameCount, size_t frameSize) : AudioTrackServerProxy(cblk, buffers, frameCount, frameSize), mObserver(&cblk->u.mStatic.mSingleStateQueue), mPosition(0), - mEnd(frameCount), mFramesReadyIsCalledByMultipleThreads(false) + mFramesReadySafe(frameCount), mFramesReady(frameCount), + mFramesReadyIsCalledByMultipleThreads(false) { mState.mLoopStart = 0; mState.mLoopEnd = 0; @@ -725,20 +755,11 @@ void StaticAudioTrackServerProxy::framesReadyIsCalledByMultipleThreads() size_t StaticAudioTrackServerProxy::framesReady() { - // FIXME - // This is racy if called by normal mixer thread, - // as we're reading 2 independent variables without a lock. - // Can't call mObserver.poll(), as we might be called from wrong thread. - // If looping is enabled, should return a higher number (since includes non-contiguous). - size_t position = mPosition; + // Can't call pollPosition() from multiple threads. if (!mFramesReadyIsCalledByMultipleThreads) { - ssize_t positionOrStatus = pollPosition(); - if (positionOrStatus >= 0) { - position = (size_t) positionOrStatus; - } + (void) pollPosition(); } - size_t end = mEnd; - return position < end ? end - position : 0; + return mFramesReadySafe; } ssize_t StaticAudioTrackServerProxy::pollPosition() @@ -755,25 +776,37 @@ ssize_t StaticAudioTrackServerProxy::pollPosition() } // ignore loopEnd mPosition = position = loopStart; - mEnd = mFrameCount; + mFramesReady = mFrameCount - mPosition; mState.mLoopCount = 0; valid = true; - } else { + } else if (state.mLoopCount >= -1) { if (loopStart < loopEnd && loopEnd <= mFrameCount && loopEnd - loopStart >= MIN_LOOP) { - if (!(loopStart <= position && position < loopEnd)) { + // If the current position is greater than the end of the loop + // we "wrap" to the loop start. This might cause an audible pop. + if (position >= loopEnd) { mPosition = position = loopStart; } - mEnd = loopEnd; + if (state.mLoopCount == -1) { + mFramesReady = INT64_MAX; + } else { + // mFramesReady is 64 bits to handle the effective number of frames + // that the static audio track contains, including loops. + // TODO: Later consider fixing overflow, but does not seem needed now + // as will not overflow if loopStart and loopEnd are Java "ints". + mFramesReady = int64_t(state.mLoopCount) * (loopEnd - loopStart) + + mFrameCount - mPosition; + } mState = state; valid = true; } } - if (!valid) { + if (!valid || mPosition > mFrameCount) { ALOGE("%s client pushed an invalid state, shutting down", __func__); mIsShutdown = true; return (ssize_t) NO_INIT; } + mFramesReadySafe = clampToSize(mFramesReady); // This may overflow, but client is not supposed to rely on it mCblk->u.mStatic.mBufferPosition = (uint32_t) position; } @@ -798,9 +831,10 @@ status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush return (status_t) positionOrStatus; } size_t position = (size_t) positionOrStatus; + size_t end = mState.mLoopCount != 0 ? mState.mLoopEnd : mFrameCount; size_t avail; - if (position < mEnd) { - avail = mEnd - position; + if (position < end) { + avail = end - position; size_t wanted = buffer->mFrameCount; if (avail < wanted) { buffer->mFrameCount = avail; @@ -813,7 +847,10 @@ status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush buffer->mFrameCount = 0; buffer->mRaw = NULL; } - buffer->mNonContig = 0; // FIXME should be > 0 for looping + // As mFramesReady is the total remaining frames in the static audio track, + // it is always larger or equal to avail. + LOG_ALWAYS_FATAL_IF(mFramesReady < avail); + buffer->mNonContig = mFramesReady == INT64_MAX ? SIZE_MAX : clampToSize(mFramesReady - avail); mUnreleased = avail; return NO_ERROR; } @@ -821,6 +858,7 @@ status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer) { size_t stepCount = buffer->mFrameCount; + LOG_ALWAYS_FATAL_IF(!(stepCount <= mFramesReady)); LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased)); if (stepCount == 0) { // prevent accidental re-use of buffer @@ -837,11 +875,10 @@ void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer) ALOGW("%s newPosition %zu outside [%zu, %zu]", __func__, newPosition, position, mFrameCount); newPosition = mFrameCount; } else if (mState.mLoopCount != 0 && newPosition == mState.mLoopEnd) { + newPosition = mState.mLoopStart; if (mState.mLoopCount == -1 || --mState.mLoopCount != 0) { - newPosition = mState.mLoopStart; setFlags = CBLK_LOOP_CYCLE; } else { - mEnd = mFrameCount; // this is what allows playback to continue after the loop setFlags = CBLK_LOOP_FINAL; } } @@ -849,6 +886,10 @@ void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer) setFlags |= CBLK_BUFFER_END; } mPosition = newPosition; + if (mFramesReady != INT64_MAX) { + mFramesReady -= stepCount; + } + mFramesReadySafe = clampToSize(mFramesReady); cblk->mServer += stepCount; // This may overflow, but client is not supposed to rely on it diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index fc4a787..12efa8a 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -41,7 +41,7 @@ enum { START_OUTPUT, STOP_OUTPUT, RELEASE_OUTPUT, - GET_INPUT, + GET_INPUT_FOR_ATTR, START_INPUT, STOP_INPUT, RELEASE_INPUT, @@ -69,7 +69,8 @@ enum { GET_OUTPUT_FOR_ATTR, ACQUIRE_SOUNDTRIGGER_SESSION, RELEASE_SOUNDTRIGGER_SESSION, - GET_PHONE_STATE + GET_PHONE_STATE, + REGISTER_POLICY_MIXES, }; #define MAX_ITEMS_PER_LIST 1024 @@ -162,21 +163,45 @@ public: return static_cast <audio_io_handle_t> (reply.readInt32()); } - virtual audio_io_handle_t getOutputForAttr( - const audio_attributes_t *attr, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_output_flags_t flags, - const audio_offload_info_t *offloadInfo) + virtual status_t getOutputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *output, + audio_session_t session, + audio_stream_type_t *stream, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); if (attr == NULL) { - ALOGE("Writing NULL audio attributes - shouldn't happen"); - return (audio_io_handle_t) 0; + if (stream == NULL) { + ALOGE("getOutputForAttr(): NULL audio attributes and stream type"); + return BAD_VALUE; + } + if (*stream == AUDIO_STREAM_DEFAULT) { + ALOGE("getOutputForAttr unspecified stream type"); + return BAD_VALUE; + } + } + if (output == NULL) { + ALOGE("getOutputForAttr NULL output - shouldn't happen"); + return BAD_VALUE; + } + if (attr == NULL) { + data.writeInt32(0); + } else { + data.writeInt32(1); + data.write(attr, sizeof(audio_attributes_t)); + } + data.writeInt32(session); + if (stream == NULL) { + data.writeInt32(0); + } else { + data.writeInt32(1); + data.writeInt32(*stream); } - data.write(attr, sizeof(audio_attributes_t)); data.writeInt32(samplingRate); data.writeInt32(static_cast <uint32_t>(format)); data.writeInt32(channelMask); @@ -188,62 +213,93 @@ public: data.writeInt32(1); data.write(offloadInfo, sizeof(audio_offload_info_t)); } - remote()->transact(GET_OUTPUT_FOR_ATTR, data, &reply); - return static_cast <audio_io_handle_t> (reply.readInt32()); + status_t status = remote()->transact(GET_OUTPUT_FOR_ATTR, data, &reply); + if (status != NO_ERROR) { + return status; + } + status = (status_t)reply.readInt32(); + if (status != NO_ERROR) { + return status; + } + *output = (audio_io_handle_t)reply.readInt32(); + if (stream != NULL) { + *stream = (audio_stream_type_t)reply.readInt32(); + } + return status; } virtual status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(output); data.writeInt32((int32_t) stream); - data.writeInt32(session); + data.writeInt32((int32_t)session); remote()->transact(START_OUTPUT, data, &reply); return static_cast <status_t> (reply.readInt32()); } virtual status_t stopOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(output); data.writeInt32((int32_t) stream); - data.writeInt32(session); + data.writeInt32((int32_t)session); remote()->transact(STOP_OUTPUT, data, &reply); return static_cast <status_t> (reply.readInt32()); } - virtual void releaseOutput(audio_io_handle_t output) + virtual void releaseOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(output); + data.writeInt32((int32_t)stream); + data.writeInt32((int32_t)session); remote()->transact(RELEASE_OUTPUT, data, &reply); } - virtual audio_io_handle_t getInput( - audio_source_t inputSource, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - int audioSession, - audio_input_flags_t flags) + virtual status_t getInputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *input, + audio_session_t session, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_input_flags_t flags) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); - data.writeInt32((int32_t) inputSource); + if (attr == NULL) { + ALOGE("getInputForAttr NULL attr - shouldn't happen"); + return BAD_VALUE; + } + if (input == NULL) { + ALOGE("getInputForAttr NULL input - shouldn't happen"); + return BAD_VALUE; + } + data.write(attr, sizeof(audio_attributes_t)); + data.writeInt32(session); data.writeInt32(samplingRate); data.writeInt32(static_cast <uint32_t>(format)); data.writeInt32(channelMask); - data.writeInt32(audioSession); data.writeInt32(flags); - remote()->transact(GET_INPUT, data, &reply); - return static_cast <audio_io_handle_t> (reply.readInt32()); + status_t status = remote()->transact(GET_INPUT_FOR_ATTR, data, &reply); + if (status != NO_ERROR) { + return status; + } + status = reply.readInt32(); + if (status != NO_ERROR) { + return status; + } + *input = (audio_io_handle_t)reply.readInt32(); + return NO_ERROR; } virtual status_t startInput(audio_io_handle_t input, @@ -622,6 +678,38 @@ public: } return (audio_mode_t)reply.readInt32(); } + + virtual status_t registerPolicyMixes(Vector<AudioMix> mixes, bool registration) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(registration ? 1 : 0); + size_t size = mixes.size(); + if (size > MAX_MIXES_PER_POLICY) { + size = MAX_MIXES_PER_POLICY; + } + size_t sizePosition = data.dataPosition(); + data.writeInt32(size); + size_t finalSize = size; + for (size_t i = 0; i < size; i++) { + size_t position = data.dataPosition(); + if (mixes[i].writeToParcel(&data) != NO_ERROR) { + data.setDataPosition(position); + finalSize--; + } + } + if (size != finalSize) { + size_t position = data.dataPosition(); + data.setDataPosition(sizePosition); + data.writeInt32(finalSize); + data.setDataPosition(position); + } + status_t status = remote()->transact(REGISTER_POLICY_MIXES, data, &reply); + if (status == NO_ERROR) { + status = (status_t)reply.readInt32(); + } + return status; + } }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -707,8 +795,17 @@ status_t BnAudioPolicyService::onTransact( case GET_OUTPUT_FOR_ATTR: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - audio_attributes_t *attr = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); - data.read(attr, sizeof(audio_attributes_t)); + audio_attributes_t attr; + bool hasAttributes = data.readInt32() != 0; + if (hasAttributes) { + data.read(&attr, sizeof(audio_attributes_t)); + } + audio_session_t session = (audio_session_t)data.readInt32(); + audio_stream_type_t stream = AUDIO_STREAM_DEFAULT; + bool hasStream = data.readInt32() != 0; + if (hasStream) { + stream = (audio_stream_type_t)data.readInt32(); + } uint32_t samplingRate = data.readInt32(); audio_format_t format = (audio_format_t) data.readInt32(); audio_channel_mask_t channelMask = data.readInt32(); @@ -719,13 +816,14 @@ status_t BnAudioPolicyService::onTransact( if (hasOffloadInfo) { data.read(&offloadInfo, sizeof(audio_offload_info_t)); } - audio_io_handle_t output = getOutputForAttr(attr, - samplingRate, - format, - channelMask, - flags, - hasOffloadInfo ? &offloadInfo : NULL); - reply->writeInt32(static_cast <int>(output)); + audio_io_handle_t output; + status_t status = getOutputForAttr(hasAttributes ? &attr : NULL, + &output, session, &stream, + samplingRate, format, channelMask, + flags, hasOffloadInfo ? &offloadInfo : NULL); + reply->writeInt32(status); + reply->writeInt32(output); + reply->writeInt32(stream); return NO_ERROR; } break; @@ -734,7 +832,7 @@ status_t BnAudioPolicyService::onTransact( audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32()); audio_stream_type_t stream = static_cast <audio_stream_type_t>(data.readInt32()); - int session = data.readInt32(); + audio_session_t session = (audio_session_t)data.readInt32(); reply->writeInt32(static_cast <uint32_t>(startOutput(output, stream, session))); @@ -746,7 +844,7 @@ status_t BnAudioPolicyService::onTransact( audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32()); audio_stream_type_t stream = static_cast <audio_stream_type_t>(data.readInt32()); - int session = data.readInt32(); + audio_session_t session = (audio_session_t)data.readInt32(); reply->writeInt32(static_cast <uint32_t>(stopOutput(output, stream, session))); @@ -756,25 +854,29 @@ status_t BnAudioPolicyService::onTransact( case RELEASE_OUTPUT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32()); - releaseOutput(output); + audio_stream_type_t stream = (audio_stream_type_t)data.readInt32(); + audio_session_t session = (audio_session_t)data.readInt32(); + releaseOutput(output, stream, session); return NO_ERROR; } break; - case GET_INPUT: { + case GET_INPUT_FOR_ATTR: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - audio_source_t inputSource = (audio_source_t) data.readInt32(); + audio_attributes_t attr; + data.read(&attr, sizeof(audio_attributes_t)); + audio_session_t session = (audio_session_t)data.readInt32(); uint32_t samplingRate = data.readInt32(); audio_format_t format = (audio_format_t) data.readInt32(); audio_channel_mask_t channelMask = data.readInt32(); - int audioSession = data.readInt32(); audio_input_flags_t flags = (audio_input_flags_t) data.readInt32(); - audio_io_handle_t input = getInput(inputSource, - samplingRate, - format, - channelMask, - audioSession, - flags); - reply->writeInt32(static_cast <int>(input)); + audio_io_handle_t input; + status_t status = getInputForAttr(&attr, &input, session, + samplingRate, format, channelMask, + flags); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->writeInt32(input); + } return NO_ERROR; } break; @@ -1096,6 +1198,25 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } break; + case REGISTER_POLICY_MIXES: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + bool registration = data.readInt32() == 1; + Vector<AudioMix> mixes; + size_t size = (size_t)data.readInt32(); + if (size > MAX_MIXES_PER_POLICY) { + size = MAX_MIXES_PER_POLICY; + } + for (size_t i = 0; i < size; i++) { + AudioMix mix; + if (mix.readFromParcel((Parcel*)&data) == NO_ERROR) { + mixes.add(mix); + } + } + status_t status = registerPolicyMixes(mixes, registration); + reply->writeInt32(status); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp index 7bd120e..f7d8bc6 100644 --- a/media/libmedia/ICrypto.cpp +++ b/media/libmedia/ICrypto.cpp @@ -33,6 +33,7 @@ enum { DESTROY_PLUGIN, REQUIRES_SECURE_COMPONENT, DECRYPT, + NOTIFY_RESOLUTION, }; struct BpCrypto : public BpInterface<ICrypto> { @@ -149,6 +150,15 @@ struct BpCrypto : public BpInterface<ICrypto> { return result; } + virtual void notifyResolution( + uint32_t width, uint32_t height) { + Parcel data, reply; + data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); + data.writeInt32(width); + data.writeInt32(height); + remote()->transact(NOTIFY_RESOLUTION, data, &reply); + } + private: DISALLOW_EVIL_CONSTRUCTORS(BpCrypto); }; @@ -290,10 +300,20 @@ status_t BnCrypto::onTransact( return OK; } + case NOTIFY_RESOLUTION: + { + CHECK_INTERFACE(ICrypto, data, reply); + + int32_t width = data.readInt32(); + int32_t height = data.readInt32(); + notifyResolution(width, height); + + return OK; + } + default: return BBinder::onTransact(code, data, reply, flags); } } } // namespace android - diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp index 1904839..7e74de9 100644 --- a/media/libmedia/IDrm.cpp +++ b/media/libmedia/IDrm.cpp @@ -54,7 +54,9 @@ enum { SIGN_RSA, VERIFY, SET_LISTENER, - UNPROVISION_DEVICE + UNPROVISION_DEVICE, + GET_SECURE_STOP, + RELEASE_ALL_SECURE_STOPS }; struct BpDrm : public BpInterface<IDrm> { @@ -255,6 +257,17 @@ struct BpDrm : public BpInterface<IDrm> { return reply.readInt32(); } + virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, ssid); + remote()->transact(GET_SECURE_STOP, data, &reply); + + readVector(reply, secureStop); + return reply.readInt32(); + } + virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); @@ -265,6 +278,15 @@ struct BpDrm : public BpInterface<IDrm> { return reply.readInt32(); } + virtual status_t releaseAllSecureStops() { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + remote()->transact(RELEASE_ALL_SECURE_STOPS, data, &reply); + + return reply.readInt32(); + } + virtual status_t getPropertyString(String8 const &name, String8 &value) const { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); @@ -655,6 +677,17 @@ status_t BnDrm::onTransact( return OK; } + case GET_SECURE_STOP: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> ssid, secureStop; + readVector(data, ssid); + status_t result = getSecureStop(ssid, secureStop); + writeVector(reply, secureStop); + reply->writeInt32(result); + return OK; + } + case RELEASE_SECURE_STOPS: { CHECK_INTERFACE(IDrm, data, reply); @@ -664,6 +697,13 @@ status_t BnDrm::onTransact( return OK; } + case RELEASE_ALL_SECURE_STOPS: + { + CHECK_INTERFACE(IDrm, data, reply); + reply->writeInt32(releaseAllSecureStops()); + return OK; + } + case GET_PROPERTY_STRING: { CHECK_INTERFACE(IDrm, data, reply); @@ -809,4 +849,3 @@ status_t BnDrm::onTransact( } } // namespace android - diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp index c146b8d..f91e3e4 100644 --- a/media/libmedia/Visualizer.cpp +++ b/media/libmedia/Visualizer.cpp @@ -52,6 +52,13 @@ Visualizer::Visualizer (int32_t priority, Visualizer::~Visualizer() { + ALOGV("Visualizer::~Visualizer()"); + if (mCaptureThread != NULL) { + mCaptureThread->requestExitAndWait(); + mCaptureThread.clear(); + } + mCaptureCallBack = NULL; + mCaptureFlags = 0; } status_t Visualizer::setEnabled(bool enabled) @@ -102,20 +109,18 @@ status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t return INVALID_OPERATION; } - sp<CaptureThread> t = mCaptureThread; - if (t != 0) { - t->mLock.lock(); + if (mCaptureThread != 0) { + mCaptureLock.unlock(); + mCaptureThread->requestExitAndWait(); + mCaptureLock.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)); } |