diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 12 | ||||
-rw-r--r-- | services/audioflinger/AudioMixer.cpp | 51 | ||||
-rw-r--r-- | services/audioflinger/AudioMixer.h | 6 | ||||
-rw-r--r-- | services/audioflinger/BufferProviders.cpp | 105 | ||||
-rw-r--r-- | services/audioflinger/BufferProviders.h | 21 | ||||
-rw-r--r-- | services/audioflinger/FastCapture.cpp | 2 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 239 | ||||
-rw-r--r-- | services/audioflinger/Threads.h | 19 | ||||
-rw-r--r-- | services/audioflinger/Tracks.cpp | 8 | ||||
-rw-r--r-- | services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h | 14 | ||||
-rw-r--r-- | services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp | 85 | ||||
-rw-r--r-- | services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp | 3 | ||||
-rw-r--r-- | services/audiopolicy/managerdefault/AudioPolicyManager.cpp | 30 | ||||
-rw-r--r-- | services/audiopolicy/managerdefault/AudioPolicyManager.h | 16 | ||||
-rw-r--r-- | services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp | 9 |
15 files changed, 417 insertions, 203 deletions
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index c7d9161..e1ddcbc 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -73,18 +73,18 @@ class AudioMixer; class AudioBuffer; class AudioResampler; class FastMixer; +class PassthruBufferProvider; class ServerProxy; // ---------------------------------------------------------------------------- -// AudioFlinger has a hard-coded upper limit of 2 channels for capture and playback. -// There is support for > 2 channel tracks down-mixed to 2 channel output via a down-mix effect. -// Adding full support for > 2 channel capture or playback would require more than simply changing -// this #define. There is an independent hard-coded upper limit in AudioMixer; -// removing that AudioMixer limit would be necessary but insufficient to support > 2 channels. -// The macro FCC_2 highlights some (but not all) places where there is are 2-channel assumptions. +// The macro FCC_2 highlights some (but not all) places where there are are 2-channel assumptions. +// This is typically due to legacy implementation of stereo input or output. // Search also for "2", "left", "right", "[0]", "[1]", ">> 16", "<< 16", etc. #define FCC_2 2 // FCC_2 = Fixed Channel Count 2 +// The macro FCC_8 highlights places where there are 8-channel assumptions. +// This is typically due to audio mixer and resampler limitations. +#define FCC_8 8 // FCC_8 = Fixed Channel Count 8 static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3); diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index c2c791f..7040af4 100644 --- a/services/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp @@ -38,7 +38,6 @@ #include <audio_utils/format.h> #include <common_time/local_clock.h> #include <common_time/cc_helper.h> -#include <media/AudioResamplerPublic.h> #include "AudioMixerOps.h" #include "AudioMixer.h" @@ -223,8 +222,7 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, t->mMixerChannelMask = audio_channel_mask_from_representation_and_bits( AUDIO_CHANNEL_REPRESENTATION_POSITION, AUDIO_CHANNEL_OUT_STEREO); t->mMixerChannelCount = audio_channel_count_from_out_mask(t->mMixerChannelMask); - t->mSpeed = AUDIO_TIMESTRETCH_SPEED_NORMAL; - t->mPitch = AUDIO_TIMESTRETCH_PITCH_NORMAL; + t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT; // Check the downmixing (or upmixing) requirements. status_t status = t->prepareForDownmix(); if (status != OK) { @@ -319,7 +317,7 @@ status_t AudioMixer::track_t::prepareForDownmix() // discard the previous downmixer if there was one unprepareForDownmix(); - // Only remix (upmix or downmix) if the track and mixer/device channel masks + // MONO_HACK Only remix (upmix or downmix) if the track and mixer/device channel masks // are not the same and not handled internally, as mono -> stereo currently is. if (channelMask == mMixerChannelMask || (channelMask == AUDIO_CHANNEL_OUT_MONO @@ -668,19 +666,25 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) case TIMESTRETCH: switch (param) { case PLAYBACK_RATE: { - const float speed = reinterpret_cast<float*>(value)[0]; - const float pitch = reinterpret_cast<float*>(value)[1]; - ALOG_ASSERT(AUDIO_TIMESTRETCH_SPEED_MIN <= speed - && speed <= AUDIO_TIMESTRETCH_SPEED_MAX, - "bad speed %f", speed); - ALOG_ASSERT(AUDIO_TIMESTRETCH_PITCH_MIN <= pitch - && pitch <= AUDIO_TIMESTRETCH_PITCH_MAX, - "bad pitch %f", pitch); - if (track.setPlaybackRate(speed, pitch)) { - ALOGV("setParameter(TIMESTRETCH, PLAYBACK_RATE, %f %f", speed, pitch); + const AudioPlaybackRate *playbackRate = + reinterpret_cast<AudioPlaybackRate*>(value); + ALOG_ASSERT(AUDIO_TIMESTRETCH_SPEED_MIN <= playbackRate->mSpeed + && playbackRate->mSpeed <= AUDIO_TIMESTRETCH_SPEED_MAX, + "bad speed %f", playbackRate->mSpeed); + ALOG_ASSERT(AUDIO_TIMESTRETCH_PITCH_MIN <= playbackRate->mPitch + && playbackRate->mPitch <= AUDIO_TIMESTRETCH_PITCH_MAX, + "bad pitch %f", playbackRate->mPitch); + //TODO: use function from AudioResamplerPublic.h to test validity. + if (track.setPlaybackRate(*playbackRate)) { + ALOGV("setParameter(TIMESTRETCH, PLAYBACK_RATE, STRETCH_MODE, FALLBACK_MODE " + "%f %f %d %d", + playbackRate->mSpeed, + playbackRate->mPitch, + playbackRate->mStretchMode, + playbackRate->mFallbackMode); // invalidateState(1 << name); } - } break; + } break; default: LOG_ALWAYS_FATAL("setParameter timestretch: bad param %d", param); } @@ -730,24 +734,26 @@ bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSam return false; } -bool AudioMixer::track_t::setPlaybackRate(float speed, float pitch) +bool AudioMixer::track_t::setPlaybackRate(const AudioPlaybackRate &playbackRate) { - if (speed == mSpeed && pitch == mPitch) { + if ((mTimestretchBufferProvider == NULL && + fabs(playbackRate.mSpeed - mPlaybackRate.mSpeed) < AUDIO_TIMESTRETCH_SPEED_MIN_DELTA && + fabs(playbackRate.mPitch - mPlaybackRate.mPitch) < AUDIO_TIMESTRETCH_PITCH_MIN_DELTA) || + isAudioPlaybackRateEqual(playbackRate, mPlaybackRate)) { return false; } - mSpeed = speed; - mPitch = pitch; + mPlaybackRate = playbackRate; if (mTimestretchBufferProvider == NULL) { // TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer // but if none exists, it is the channel count (1 for mono). const int timestretchChannelCount = downmixerBufferProvider != NULL ? mMixerChannelCount : channelCount; mTimestretchBufferProvider = new TimestretchBufferProvider(timestretchChannelCount, - mMixerInFormat, sampleRate, speed, pitch); + mMixerInFormat, sampleRate, playbackRate); reconfigureBufferProviders(); } else { reinterpret_cast<TimestretchBufferProvider*>(mTimestretchBufferProvider) - ->setPlaybackRate(speed, pitch); + ->setPlaybackRate(playbackRate); } return true; } @@ -914,7 +920,8 @@ void AudioMixer::process__validate(state_t* state, int64_t pts) } else { if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){ t.hook = getTrackHook( - t.mMixerChannelCount == 2 // TODO: MONO_HACK. + (t.mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO // TODO: MONO_HACK + && t.channelMask == AUDIO_CHANNEL_OUT_MONO) ? TRACKTYPE_NORESAMPLEMONO : TRACKTYPE_NORESAMPLE, t.mMixerChannelCount, t.mMixerInFormat, t.mMixerFormat); diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h index e27a0d1..7165c6c 100644 --- a/services/audioflinger/AudioMixer.h +++ b/services/audioflinger/AudioMixer.h @@ -23,6 +23,7 @@ #include <hardware/audio_effect.h> #include <media/AudioBufferProvider.h> +#include <media/AudioResamplerPublic.h> #include <media/nbaio/NBLog.h> #include <system/audio.h> #include <utils/Compat.h> @@ -259,8 +260,7 @@ private: audio_channel_mask_t mMixerChannelMask; uint32_t mMixerChannelCount; - float mSpeed; - float mPitch; + AudioPlaybackRate mPlaybackRate; bool needsRamp() { return (volumeInc[0] | volumeInc[1] | auxInc) != 0; } bool setResampler(uint32_t trackSampleRate, uint32_t devSampleRate); @@ -274,7 +274,7 @@ private: void unprepareForDownmix(); status_t prepareForReformat(); void unprepareForReformat(); - bool setPlaybackRate(float speed, float pitch); + bool setPlaybackRate(const AudioPlaybackRate &playbackRate); void reconfigureBufferProviders(); }; diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp index dcae5e7..77bf4ac 100644 --- a/services/audioflinger/BufferProviders.cpp +++ b/services/audioflinger/BufferProviders.cpp @@ -361,25 +361,25 @@ void ReformatBufferProvider::copyFrames(void *dst, const void *src, size_t frame } TimestretchBufferProvider::TimestretchBufferProvider(int32_t channelCount, - audio_format_t format, uint32_t sampleRate, float speed, float pitch) : + audio_format_t format, uint32_t sampleRate, const AudioPlaybackRate &playbackRate) : mChannelCount(channelCount), mFormat(format), mSampleRate(sampleRate), mFrameSize(channelCount * audio_bytes_per_sample(format)), - mSpeed(speed), - mPitch(pitch), mLocalBufferFrameCount(0), mLocalBufferData(NULL), mRemaining(0), - mSonicStream(sonicCreateStream(sampleRate, mChannelCount)) + mSonicStream(sonicCreateStream(sampleRate, mChannelCount)), + mFallbackFailErrorShown(false) { - ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f)", - this, channelCount, format, sampleRate, speed, pitch); - mBuffer.frameCount = 0; - LOG_ALWAYS_FATAL_IF(mSonicStream == NULL, "TimestretchBufferProvider can't allocate Sonic stream"); - sonicSetSpeed(mSonicStream, speed); + + setPlaybackRate(playbackRate); + ALOGV("TimestretchBufferProvider(%p)(%u, %#x, %u %f %f %d %d)", + this, channelCount, format, sampleRate, playbackRate.mSpeed, + playbackRate.mPitch, playbackRate.mStretchMode, playbackRate.mFallbackMode); + mBuffer.frameCount = 0; } TimestretchBufferProvider::~TimestretchBufferProvider() @@ -423,8 +423,8 @@ status_t TimestretchBufferProvider::getNextBuffer( // need to fetch more data const size_t outputDesired = pBuffer->frameCount - mRemaining; - mBuffer.frameCount = mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL - ? outputDesired : outputDesired * mSpeed + 1; + mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL + ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1; status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts); @@ -491,13 +491,13 @@ void TimestretchBufferProvider::reset() mRemaining = 0; } -status_t TimestretchBufferProvider::setPlaybackRate(float speed, float pitch) +status_t TimestretchBufferProvider::setPlaybackRate(const AudioPlaybackRate &playbackRate) { - mSpeed = speed; - mPitch = pitch; - - sonicSetSpeed(mSonicStream, speed); + mPlaybackRate = playbackRate; + mFallbackFailErrorShown = false; + sonicSetSpeed(mSonicStream, mPlaybackRate.mSpeed); //TODO: pitch is ignored for now + //TODO: optimize: if parameters are the same, don't do any extra computation. return OK; } @@ -508,33 +508,68 @@ void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames // Note dstFrames is the required number of frames. // Ensure consumption from src is as expected. - const size_t targetSrc = *dstFrames * mSpeed; + //TODO: add logic to track "very accurate" consumption related to speed, original sampling + //rate, actual frames processed. + const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed; if (*srcFrames < targetSrc) { // limit dst frames to that possible - *dstFrames = *srcFrames / mSpeed; + *dstFrames = *srcFrames / mPlaybackRate.mSpeed; } else if (*srcFrames > targetSrc + 1) { *srcFrames = targetSrc + 1; } - switch (mFormat) { - case AUDIO_FORMAT_PCM_FLOAT: - if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) { - ALOGE("sonicWriteFloatToStream cannot realloc"); - *srcFrames = 0; // cannot consume all of srcBuffer + if (mPlaybackRate.mSpeed< TIMESTRETCH_SONIC_SPEED_MIN || + mPlaybackRate.mSpeed > TIMESTRETCH_SONIC_SPEED_MAX ) { + //fallback mode + if (*dstFrames > 0) { + switch(mPlaybackRate.mFallbackMode) { + case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT: + if (*dstFrames <= *srcFrames) { + size_t copySize = mFrameSize * *dstFrames; + memcpy(dstBuffer, srcBuffer, copySize); + } else { + // cyclically repeat the source. + for (size_t count = 0; count < *dstFrames; count += *srcFrames) { + size_t remaining = min(*srcFrames, *dstFrames - count); + memcpy((uint8_t*)dstBuffer + mFrameSize * count, + srcBuffer, mFrameSize * remaining); + } + } + break; + case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT: + case AUDIO_TIMESTRETCH_FALLBACK_MUTE: + memset(dstBuffer,0, mFrameSize * *dstFrames); + break; + case AUDIO_TIMESTRETCH_FALLBACK_FAIL: + default: + if(!mFallbackFailErrorShown) { + ALOGE("invalid parameters in TimestretchBufferProvider fallbackMode:%d", + mPlaybackRate.mFallbackMode); + mFallbackFailErrorShown = true; + } + break; + } } - *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames); - break; - case AUDIO_FORMAT_PCM_16_BIT: - if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) { - ALOGE("sonicWriteShortToStream cannot realloc"); - *srcFrames = 0; // cannot consume all of srcBuffer + } else { + switch (mFormat) { + case AUDIO_FORMAT_PCM_FLOAT: + if (sonicWriteFloatToStream(mSonicStream, (float*)srcBuffer, *srcFrames) != 1) { + ALOGE("sonicWriteFloatToStream cannot realloc"); + *srcFrames = 0; // cannot consume all of srcBuffer + } + *dstFrames = sonicReadFloatFromStream(mSonicStream, (float*)dstBuffer, *dstFrames); + break; + case AUDIO_FORMAT_PCM_16_BIT: + if (sonicWriteShortToStream(mSonicStream, (short*)srcBuffer, *srcFrames) != 1) { + ALOGE("sonicWriteShortToStream cannot realloc"); + *srcFrames = 0; // cannot consume all of srcBuffer + } + *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames); + break; + default: + // could also be caught on construction + LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat); } - *dstFrames = sonicReadShortFromStream(mSonicStream, (short*)dstBuffer, *dstFrames); - break; - default: - // could also be caught on construction - LOG_ALWAYS_FATAL("invalid format %#x for TimestretchBufferProvider", mFormat); } } - // ---------------------------------------------------------------------------- } // namespace android diff --git a/services/audioflinger/BufferProviders.h b/services/audioflinger/BufferProviders.h index 42030c0..4970b6c 100644 --- a/services/audioflinger/BufferProviders.h +++ b/services/audioflinger/BufferProviders.h @@ -151,7 +151,8 @@ protected: class TimestretchBufferProvider : public PassthruBufferProvider { public: TimestretchBufferProvider(int32_t channelCount, - audio_format_t format, uint32_t sampleRate, float speed, float pitch); + audio_format_t format, uint32_t sampleRate, + const AudioPlaybackRate &playbackRate); virtual ~TimestretchBufferProvider(); // Overrides AudioBufferProvider methods @@ -161,7 +162,7 @@ public: // Overrides PassthruBufferProvider virtual void reset(); - virtual status_t setPlaybackRate(float speed, float pitch); + virtual status_t setPlaybackRate(const AudioPlaybackRate &playbackRate); // processes frames // dstBuffer is where to place the data @@ -176,15 +177,17 @@ protected: const audio_format_t mFormat; const uint32_t mSampleRate; // const for now (TODO change this) const size_t mFrameSize; - float mSpeed; - float mPitch; + AudioPlaybackRate mPlaybackRate; private: - AudioBufferProvider::Buffer mBuffer; - size_t mLocalBufferFrameCount; - void *mLocalBufferData; - size_t mRemaining; - sonicStream mSonicStream; + AudioBufferProvider::Buffer mBuffer; // for upstream request + size_t mLocalBufferFrameCount; // size of local buffer + void *mLocalBufferData; // internally allocated buffer for data returned + // to caller + size_t mRemaining; // remaining data in local buffer + sonicStream mSonicStream; // handle to sonic timestretch object + //FIXME: this dependency should be abstracted out + bool mFallbackFailErrorShown; // log fallback error only once }; // ---------------------------------------------------------------------------- diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp index 9e7e8a4..79ac12b 100644 --- a/services/audioflinger/FastCapture.cpp +++ b/services/audioflinger/FastCapture.cpp @@ -105,7 +105,7 @@ void FastCapture::onStateChange() mFormat = mInputSource->format(); mSampleRate = Format_sampleRate(mFormat); unsigned channelCount = Format_channelCount(mFormat); - ALOG_ASSERT(channelCount == 1 || channelCount == 2); + ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_8); } dumpState->mSampleRate = mSampleRate; eitherChanged = true; diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index b30fd20..4039564 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -56,6 +56,7 @@ #include "AudioFlinger.h" #include "AudioMixer.h" +#include "BufferProviders.h" #include "FastMixer.h" #include "FastCapture.h" #include "ServiceUtilities.h" @@ -94,6 +95,10 @@ static inline T min(const T& a, const T& b) return a < b ? a : b; } +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +#endif + namespace android { // retry counts for buffer fill timeout @@ -3599,11 +3604,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac // during last round size_t desiredFrames; const uint32_t sampleRate = track->mAudioTrackServerProxy->getSampleRate(); - float speed, pitch; - track->mAudioTrackServerProxy->getPlaybackRate(&speed, &pitch); + AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate(); desiredFrames = sourceFramesNeededWithTimestretch( - sampleRate, mNormalFrameCount, mSampleRate, speed); + sampleRate, mNormalFrameCount, mSampleRate, playbackRate.mSpeed); // TODO: ONLY USED FOR LEGACY RESAMPLERS, remove when they are removed. // add frames already consumed but not yet released by the resampler // because mAudioTrackServerProxy->framesReady() will include these frames @@ -3772,15 +3776,12 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac AudioMixer::SAMPLE_RATE, (void *)(uintptr_t)reqSampleRate); - // set the playback rate as an float array {speed, pitch} - float playbackRate[2]; - track->mAudioTrackServerProxy->getPlaybackRate( - &playbackRate[0] /*speed*/, &playbackRate[1] /*pitch*/); + AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate(); mAudioMixer->setParameter( name, AudioMixer::TIMESTRETCH, AudioMixer::PLAYBACK_RATE, - playbackRate); + &playbackRate); /* * Select the appropriate output buffer for the track. @@ -5328,7 +5329,7 @@ AudioFlinger::RecordThread::~RecordThread() } mAudioFlinger->unregisterWriter(mFastCaptureNBLogWriter); mAudioFlinger->unregisterWriter(mNBLogWriter); - delete[] mRsmpInBuffer; + free(mRsmpInBuffer); } void AudioFlinger::RecordThread::onFirstRef() @@ -5561,7 +5562,7 @@ reacquire_wakelock: // If an NBAIO source is present, use it to read the normal capture's data if (mPipeSource != 0) { size_t framesToRead = mBufferSize / mFrameSize; - framesRead = mPipeSource->read(&mRsmpInBuffer[rear * mChannelCount], + framesRead = mPipeSource->read((uint8_t*)mRsmpInBuffer + rear * mFrameSize, framesToRead, AudioBufferProvider::kInvalidPTS); if (framesRead == 0) { // since pipe is non-blocking, simulate blocking input @@ -5570,7 +5571,7 @@ reacquire_wakelock: // otherwise use the HAL / AudioStreamIn directly } else { ssize_t bytesRead = mInput->stream->read(mInput->stream, - &mRsmpInBuffer[rear * mChannelCount], mBufferSize); + (uint8_t*)mRsmpInBuffer + rear * mFrameSize, mBufferSize); if (bytesRead < 0) { framesRead = bytesRead; } else { @@ -5590,13 +5591,13 @@ reacquire_wakelock: ALOG_ASSERT(framesRead > 0); if (mTeeSink != 0) { - (void) mTeeSink->write(&mRsmpInBuffer[rear * mChannelCount], framesRead); + (void) mTeeSink->write((uint8_t*)mRsmpInBuffer + rear * mFrameSize, framesRead); } // If destination is non-contiguous, we now correct for reading past end of buffer. { size_t part1 = mRsmpInFramesP2 - rear; if ((size_t) framesRead > part1) { - memcpy(mRsmpInBuffer, &mRsmpInBuffer[mRsmpInFramesP2 * mChannelCount], + memcpy(mRsmpInBuffer, (uint8_t*)mRsmpInBuffer + mRsmpInFramesP2 * mFrameSize, (framesRead - part1) * mFrameSize); } } @@ -6214,7 +6215,7 @@ status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer( return NOT_ENOUGH_DATA; } - buffer->raw = recordThread->mRsmpInBuffer + front * recordThread->mChannelCount; + buffer->raw = (uint8_t*)recordThread->mRsmpInBuffer + front * recordThread->mFrameSize; buffer->frameCount = part1; mRsmpInUnrel = part1; return NO_ERROR; @@ -6250,7 +6251,11 @@ AudioFlinger::RecordThread::RecordBufferConverter::RecordBufferConverter( // mDstChannelCount // mDstFrameSize mBuf(NULL), mBufFrames(0), mBufFrameSize(0), - mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0) + mResampler(NULL), + mIsLegacyDownmix(false), + mIsLegacyUpmix(false), + mRequiresFloat(false), + mInputConverterProvider(NULL) { (void)updateParameters(srcChannelMask, srcFormat, srcSampleRate, dstChannelMask, dstFormat, dstSampleRate); @@ -6259,13 +6264,18 @@ AudioFlinger::RecordThread::RecordBufferConverter::RecordBufferConverter( AudioFlinger::RecordThread::RecordBufferConverter::~RecordBufferConverter() { free(mBuf); delete mResampler; - free(mRsmpOutBuffer); + delete mInputConverterProvider; } size_t AudioFlinger::RecordThread::RecordBufferConverter::convert(void *dst, AudioBufferProvider *provider, size_t frames) { - if (mSrcSampleRate == mDstSampleRate) { + if (mInputConverterProvider != NULL) { + mInputConverterProvider->setBufferProvider(provider); + provider = mInputConverterProvider; + } + + if (mResampler == NULL) { ALOGVV("NO RESAMPLING sampleRate:%u mSrcFormat:%#x mDstFormat:%#x", mSrcSampleRate, mSrcFormat, mDstFormat); @@ -6277,8 +6287,8 @@ size_t AudioFlinger::RecordThread::RecordBufferConverter::convert(void *dst, frames -= i; // cannot fill request. break; } - // convert to destination buffer - convert(dst, buffer.raw, buffer.frameCount); + // format convert to destination buffer + convertNoResampler(dst, buffer.raw, buffer.frameCount); dst = (int8_t*)dst + buffer.frameCount * mDstFrameSize; i -= buffer.frameCount; @@ -6288,20 +6298,17 @@ size_t AudioFlinger::RecordThread::RecordBufferConverter::convert(void *dst, ALOGVV("RESAMPLING mSrcSampleRate:%u mDstSampleRate:%u mSrcFormat:%#x mDstFormat:%#x", mSrcSampleRate, mDstSampleRate, mSrcFormat, mDstFormat); - // reallocate mRsmpOutBuffer as needed; we will grow but never shrink - if (mRsmpOutFrameCount < frames) { - // FIXME why does each track need it's own mRsmpOutBuffer? can't they share? - free(mRsmpOutBuffer); - // resampler always outputs stereo (FOR NOW) - (void)posix_memalign(&mRsmpOutBuffer, 32, frames * FCC_2 * sizeof(int32_t) /*Q4.27*/); - mRsmpOutFrameCount = frames; - } + // reallocate buffer if needed + if (mBufFrameSize != 0 && mBufFrames < frames) { + free(mBuf); + mBufFrames = frames; + (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize); + } // resampler accumulates, but we only have one source track - memset(mRsmpOutBuffer, 0, frames * FCC_2 * sizeof(int32_t)); - frames = mResampler->resample((int32_t*)mRsmpOutBuffer, frames, provider); - - // convert to destination buffer - convert(dst, mRsmpOutBuffer, frames); + memset(mBuf, 0, frames * mBufFrameSize); + frames = mResampler->resample((int32_t*)mBuf, frames, provider); + // format convert to destination buffer + convertResampler(dst, mBuf, frames); } return frames; } @@ -6345,74 +6352,132 @@ status_t AudioFlinger::RecordThread::RecordBufferConverter::updateParameters( mDstChannelCount = audio_channel_count_from_in_mask(dstChannelMask); mDstFrameSize = mDstChannelCount * audio_bytes_per_sample(mDstFormat); - // do we need a format buffer? - if (mSrcFormat != mDstFormat && mDstChannelCount != mSrcChannelCount) { + // do we need to resample? + delete mResampler; + mResampler = NULL; + if (mSrcSampleRate != mDstSampleRate) { + mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_FLOAT, + mSrcChannelCount, mDstSampleRate); + mResampler->setSampleRate(mSrcSampleRate); + mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT); + } + + // are we running legacy channel conversion modes? + mIsLegacyDownmix = (mSrcChannelMask == AUDIO_CHANNEL_IN_STEREO + || mSrcChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK) + && mDstChannelMask == AUDIO_CHANNEL_IN_MONO; + mIsLegacyUpmix = mSrcChannelMask == AUDIO_CHANNEL_IN_MONO + && (mDstChannelMask == AUDIO_CHANNEL_IN_STEREO + || mDstChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK); + + // do we need to process in float? + mRequiresFloat = mResampler != NULL || mIsLegacyDownmix || mIsLegacyUpmix; + + // do we need a staging buffer to convert for destination (we can still optimize this)? + // we use mBufFrameSize > 0 to indicate both frame size as well as buffer necessity + if (mResampler != NULL) { + mBufFrameSize = max(mSrcChannelCount, FCC_2) + * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT); + } else if ((mIsLegacyUpmix || mIsLegacyDownmix) && mDstFormat != AUDIO_FORMAT_PCM_FLOAT) { + mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT); + } else if (mSrcChannelMask != mDstChannelMask && mDstFormat != mSrcFormat) { mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(mSrcFormat); } else { mBufFrameSize = 0; } mBufFrames = 0; // force the buffer to be resized. - // do we need to resample? - if (mSrcSampleRate != mDstSampleRate) { - if (mResampler != NULL) { - delete mResampler; - } - mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_16_BIT, - mSrcChannelCount, mDstSampleRate); // may seem confusing... - mResampler->setSampleRate(mSrcSampleRate); - mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT); + // do we need an input converter buffer provider to give us float? + delete mInputConverterProvider; + mInputConverterProvider = NULL; + if (mRequiresFloat && mSrcFormat != AUDIO_FORMAT_PCM_FLOAT) { + mInputConverterProvider = new ReformatBufferProvider( + audio_channel_count_from_in_mask(mSrcChannelMask), + mSrcFormat, + AUDIO_FORMAT_PCM_FLOAT, + 256 /* provider buffer frame count */); + } + + // do we need a remixer to do channel mask conversion + if (!mIsLegacyDownmix && !mIsLegacyUpmix && mSrcChannelMask != mDstChannelMask) { + (void) memcpy_by_index_array_initialization_from_channel_mask( + mIdxAry, ARRAY_SIZE(mIdxAry), mDstChannelMask, mSrcChannelMask); } return NO_ERROR; } -void AudioFlinger::RecordThread::RecordBufferConverter::convert( - void *dst, /*const*/ void *src, size_t frames) +void AudioFlinger::RecordThread::RecordBufferConverter::convertNoResampler( + void *dst, const void *src, size_t frames) { - // check if a memcpy will do - if (mResampler == NULL - && mSrcChannelCount == mDstChannelCount - && mSrcFormat == mDstFormat) { - memcpy(dst, src, - frames * mDstChannelCount * audio_bytes_per_sample(mDstFormat)); - return; - } - // reallocate buffer if needed + // src is native type unless there is legacy upmix or downmix, whereupon it is float. if (mBufFrameSize != 0 && mBufFrames < frames) { free(mBuf); mBufFrames = frames; (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize); } - // do processing - if (mResampler != NULL) { - // src channel count is always >= 2. + // do we need to do legacy upmix and downmix? + if (mIsLegacyUpmix || mIsLegacyDownmix) { void *dstBuf = mBuf != NULL ? mBuf : dst; - // ditherAndClamp() works as long as all buffers returned by - // activeTrack->getNextBuffer() are 32 bit aligned which should be always true. - if (mDstChannelCount == 1) { - // the resampler always outputs stereo samples. - // FIXME: this rewrites back into src - ditherAndClamp((int32_t *)src, (const int32_t *)src, frames); - downmix_to_mono_i16_from_stereo_i16((int16_t *)dstBuf, - (const int16_t *)src, frames); - } else { - ditherAndClamp((int32_t *)dstBuf, (const int32_t *)src, frames); + if (mIsLegacyUpmix) { + upmix_to_stereo_float_from_mono_float((float *)dstBuf, + (const float *)src, frames); + } else /*mIsLegacyDownmix */ { + downmix_to_mono_float_from_stereo_float((float *)dstBuf, + (const float *)src, frames); } - } else if (mSrcChannelCount != mDstChannelCount) { + if (mBuf != NULL) { + memcpy_by_audio_format(dst, mDstFormat, mBuf, AUDIO_FORMAT_PCM_FLOAT, + frames * mDstChannelCount); + } + return; + } + // do we need to do channel mask conversion? + if (mSrcChannelMask != mDstChannelMask) { void *dstBuf = mBuf != NULL ? mBuf : dst; + memcpy_by_index_array(dstBuf, mDstChannelCount, + src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mSrcFormat), frames); + if (dstBuf == dst) { + return; // format is the same + } + } + // convert to destination buffer + const void *convertBuf = mBuf != NULL ? mBuf : src; + memcpy_by_audio_format(dst, mDstFormat, convertBuf, mSrcFormat, + frames * mDstChannelCount); +} + +void AudioFlinger::RecordThread::RecordBufferConverter::convertResampler( + void *dst, /*not-a-const*/ void *src, size_t frames) +{ + // src buffer format is ALWAYS float when entering this routine + if (mIsLegacyUpmix) { + ; // mono to stereo already handled by resampler + } else if (mIsLegacyDownmix + || (mSrcChannelMask == mDstChannelMask && mSrcChannelCount == 1)) { + // the resampler outputs stereo for mono input channel (a feature?) + // must convert to mono + downmix_to_mono_float_from_stereo_float((float *)src, + (const float *)src, frames); + } else if (mSrcChannelMask != mDstChannelMask) { + // convert to mono channel again for channel mask conversion (could be skipped + // with further optimization). if (mSrcChannelCount == 1) { - upmix_to_stereo_i16_from_mono_i16((int16_t *)dstBuf, (const int16_t *)src, - frames); - } else { - downmix_to_mono_i16_from_stereo_i16((int16_t *)dstBuf, - (const int16_t *)src, frames); + downmix_to_mono_float_from_stereo_float((float *)src, + (const float *)src, frames); } + // convert to destination format (in place, OK as float is larger than other types) + if (mDstFormat != AUDIO_FORMAT_PCM_FLOAT) { + memcpy_by_audio_format(src, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT, + frames * mSrcChannelCount); + } + // channel convert and save to dst + memcpy_by_index_array(dst, mDstChannelCount, + src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mDstFormat), frames); + return; } - if (mSrcFormat != mDstFormat) { - void *srcBuf = mBuf != NULL ? mBuf : src; - memcpy_by_audio_format(dst, mDstFormat, srcBuf, mSrcFormat, - frames * mDstChannelCount); - } + // convert to destination format and save to dst + memcpy_by_audio_format(dst, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT, + frames * mDstChannelCount); } bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair, @@ -6425,6 +6490,10 @@ bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValueP audio_format_t reqFormat = mFormat; uint32_t samplingRate = mSampleRate; audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(mChannelCount); + // possible that we are > 2 channels, use channel index mask + if (channelMask == AUDIO_CHANNEL_INVALID && mChannelCount <= FCC_8) { + audio_channel_mask_for_index_assignment_from_count(mChannelCount); + } AudioParameter param = AudioParameter(keyValuePair); int value; @@ -6445,7 +6514,8 @@ bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValueP } if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) { audio_channel_mask_t mask = (audio_channel_mask_t) value; - if (mask != AUDIO_CHANNEL_IN_MONO && mask != AUDIO_CHANNEL_IN_STEREO) { + if (!audio_is_input_channel(mask) || + audio_channel_count_from_in_mask(mask) > FCC_8) { status = BAD_VALUE; } else { channelMask = mask; @@ -6570,10 +6640,13 @@ void AudioFlinger::RecordThread::readInputParameters_l() mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common); mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common); mChannelCount = audio_channel_count_from_in_mask(mChannelMask); + if (mChannelCount > FCC_8) { + ALOGE("HAL channel count %d > %d", mChannelCount, FCC_8); + } mHALFormat = mInput->stream->common.get_format(&mInput->stream->common); mFormat = mHALFormat; - if (mFormat != AUDIO_FORMAT_PCM_16_BIT) { - ALOGE("HAL format %#x not supported; must be AUDIO_FORMAT_PCM_16_BIT", mFormat); + if (!audio_is_linear_pcm(mFormat)) { + ALOGE("HAL format %#x is not linear pcm", mFormat); } mFrameSize = audio_stream_in_frame_size(mInput->stream); mBufferSize = mInput->stream->common.get_buffer_size(&mInput->stream->common); @@ -6588,7 +6661,7 @@ void AudioFlinger::RecordThread::readInputParameters_l() // Note this is independent of the maximum downsampling ratio permitted for capture. mRsmpInFrames = mFrameCount * 7; mRsmpInFramesP2 = roundup(mRsmpInFrames); - delete[] mRsmpInBuffer; + free(mRsmpInBuffer); // TODO optimize audio capture buffer sizes ... // Here we calculate the size of the sliding buffer used as a source @@ -6598,7 +6671,7 @@ void AudioFlinger::RecordThread::readInputParameters_l() // The current value is higher than necessary. However it should not add to latency. // Over-allocate beyond mRsmpInFramesP2 to permit a HAL read past end of buffer - mRsmpInBuffer = new int16_t[(mRsmpInFramesP2 + mFrameCount - 1) * mChannelCount]; + (void)posix_memalign(&mRsmpInBuffer, 32, (mRsmpInFramesP2 + mFrameCount - 1) * mFrameSize); // AudioRecord mSampleRate and mChannelCount are constant due to AudioRecord API constraints. // But if thread's mSampleRate or mChannelCount changes, how will that affect active tracks? diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 27bc56b..b7c1ed1 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -1130,8 +1130,11 @@ public: } private: - // internal convert function for format and channel mask. - void convert(void *dst, /*const*/ void *src, size_t frames); + // format conversion when not using resampler + void convertNoResampler(void *dst, const void *src, size_t frames); + + // format conversion when using resampler; modifies src in-place + void convertResampler(void *dst, /*not-a-const*/ void *src, size_t frames); // user provided information audio_channel_mask_t mSrcChannelMask; @@ -1153,10 +1156,12 @@ public: // resampler info AudioResampler *mResampler; - // interleaved stereo pairs of fixed-point Q4.27 or float depending on resampler - void *mRsmpOutBuffer; - // current allocated frame count for the above, which may be larger than needed - size_t mRsmpOutFrameCount; + + bool mIsLegacyDownmix; // legacy stereo to mono conversion needed + bool mIsLegacyUpmix; // legacy mono to stereo conversion needed + bool mRequiresFloat; // data processing requires float (e.g. resampler) + PassthruBufferProvider *mInputConverterProvider; // converts input to float + int8_t mIdxAry[sizeof(uint32_t) * 8]; // used for channel mask conversion }; #include "RecordTracks.h" @@ -1267,7 +1272,7 @@ private: Condition mStartStopCond; // resampler converts input at HAL Hz to output at AudioRecord client Hz - int16_t *mRsmpInBuffer; // see new[] for details on the size + void *mRsmpInBuffer; // size_t mRsmpInFrames; // size of resampler input in frames size_t mRsmpInFramesP2;// size rounded up to a power-of-2 diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index da2d634..c6e9745 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -906,11 +906,9 @@ status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& times // FIXME Not accurate under dynamic changes of sample rate and speed. // Do not use track's mSampleRate as it is not current for mixer tracks. uint32_t sampleRate = mAudioTrackServerProxy->getSampleRate(); - float speed, pitch; - mAudioTrackServerProxy->getPlaybackRate(&speed, &pitch); - uint32_t unpresentedFrames = - ((double) playbackThread->mLatchQ.mUnpresentedFrames * sampleRate * speed) - / playbackThread->mSampleRate; + AudioPlaybackRate playbackRate = mAudioTrackServerProxy->getPlaybackRate(); + uint32_t unpresentedFrames = ((double) playbackThread->mLatchQ.mUnpresentedFrames * + sampleRate * playbackRate.mSpeed)/ playbackThread->mSampleRate; // FIXME Since we're using a raw pointer as the key, it is theoretically possible // for a brand new track to share the same address as a recently destroyed // track, and thus for us to get the frames released of the wrong track. diff --git a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h index f8c4d08..0b08430 100644 --- a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h +++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h @@ -38,7 +38,8 @@ struct StringToEnum { uint32_t value; }; -#define STRING_TO_ENUM(string) { #string, string } +// TODO: move to a separate file. Should be in sync with audio.h. +#define STRING_TO_ENUM(string) { #string, (uint32_t)string } // uint32_t cast removes warning #define NAME_TO_ENUM(name, value) { name, value } #ifndef ARRAY_SIZE #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) @@ -204,6 +205,17 @@ const StringToEnum sInChannelsNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK), }; +const StringToEnum sIndexChannelsNameToEnumTable[] = { + STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1), + STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2), + STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3), + STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4), + STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5), + STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6), + STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7), + STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8), +}; + const StringToEnum sGainModeNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_GAIN_MODE_JOINT), STRING_TO_ENUM(AUDIO_GAIN_MODE_CHANNELS), diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp index f3978ec..647550c 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp @@ -235,8 +235,14 @@ void AudioPort::loadInChannels(char *name) (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable, ARRAY_SIZE(sInChannelsNameToEnumTable), str); + if (channelMask == 0) { // if not found, check the channel index table + channelMask = (audio_channel_mask_t) + ConfigParsingUtils::stringToEnum(sIndexChannelsNameToEnumTable, + ARRAY_SIZE(sIndexChannelsNameToEnumTable), + str); + } if (channelMask != 0) { - ALOGV("loadInChannels() adding channelMask %04x", channelMask); + ALOGV("loadInChannels() adding channelMask %#x", channelMask); mChannelMasks.add(channelMask); } str = strtok(NULL, "|"); @@ -441,30 +447,87 @@ status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask, } const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK; + const bool isIndex = audio_channel_mask_get_representation(channelMask) + == AUDIO_CHANNEL_REPRESENTATION_INDEX; + int bestMatch = 0; for (size_t i = 0; i < mChannelMasks.size(); i ++) { - // FIXME Does not handle multi-channel automatic conversions yet audio_channel_mask_t supported = mChannelMasks[i]; if (supported == channelMask) { + // Exact matches always taken. if (updatedChannelMask != NULL) { *updatedChannelMask = channelMask; } return NO_ERROR; } - if (isRecordThread) { - // This uses hard-coded knowledge that AudioFlinger can silently down-mix and up-mix. - // FIXME Abstract this out to a table. - if (((supported == AUDIO_CHANNEL_IN_FRONT_BACK || supported == AUDIO_CHANNEL_IN_STEREO) - && channelMask == AUDIO_CHANNEL_IN_MONO) || - (supported == AUDIO_CHANNEL_IN_MONO && (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK - || channelMask == AUDIO_CHANNEL_IN_STEREO))) { + + // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support + if (isRecordThread && supported != AUDIO_CHANNEL_NONE) { + // Approximate (best) match: + // The match score measures how well the supported channel mask matches the + // desired mask, where increasing-is-better. + // + // TODO: Some tweaks may be needed. + // Should be a static function of the data processing library. + // + // In priority: + // match score = 1000 if legacy channel conversion equivalent (always prefer this) + // OR + // match score += 100 if the channel mask representations match + // match score += number of channels matched. + // + // If there are no matched channels, the mask may still be accepted + // but the playback or record will be silent. + const bool isSupportedIndex = (audio_channel_mask_get_representation(supported) + == AUDIO_CHANNEL_REPRESENTATION_INDEX); + int match; + if (isIndex && isSupportedIndex) { + // index equivalence + match = 100 + __builtin_popcount( + audio_channel_mask_get_bits(channelMask) + & audio_channel_mask_get_bits(supported)); + } else if (isIndex && !isSupportedIndex) { + const uint32_t equivalentBits = + (1 << audio_channel_count_from_in_mask(supported)) - 1 ; + match = __builtin_popcount( + audio_channel_mask_get_bits(channelMask) & equivalentBits); + } else if (!isIndex && isSupportedIndex) { + const uint32_t equivalentBits = + (1 << audio_channel_count_from_in_mask(channelMask)) - 1; + match = __builtin_popcount( + equivalentBits & audio_channel_mask_get_bits(supported)); + } else { + // positional equivalence + match = 100 + __builtin_popcount( + audio_channel_mask_get_bits(channelMask) + & audio_channel_mask_get_bits(supported)); + switch (supported) { + case AUDIO_CHANNEL_IN_FRONT_BACK: + case AUDIO_CHANNEL_IN_STEREO: + if (channelMask == AUDIO_CHANNEL_IN_MONO) { + match = 1000; + } + break; + case AUDIO_CHANNEL_IN_MONO: + if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK + || channelMask == AUDIO_CHANNEL_IN_STEREO) { + match = 1000; + } + break; + default: + break; + } + } + if (match > bestMatch) { + bestMatch = match; if (updatedChannelMask != NULL) { *updatedChannelMask = supported; + } else { + return NO_ERROR; // any match will do in this case. } - return NO_ERROR; } } } - return BAD_VALUE; + return bestMatch > 0 ? NO_ERROR : BAD_VALUE; } status_t AudioPort::checkExactFormat(audio_format_t format) const diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp index 9573583..0715eea 100644 --- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp @@ -52,6 +52,9 @@ bool DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const // - are of the same type (a device type cannot be AUDIO_DEVICE_NONE) // - have the same address or one device does not specify the address // - have the same channel mask or one device does not specify the channel mask + if (other == 0) { + return false; + } return (mDeviceType == other->mDeviceType) && (mAddress == "" || other->mAddress == "" || mAddress == other->mAddress) && (mChannelMask == 0 || other->mChannelMask == 0 || diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 3ea6a11..01f2b61 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -969,6 +969,8 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, audio_devices_t newDevice; if (outputDesc->mPolicyMix != NULL) { newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + } else if (mOutputRoutes.hasRouteChanged(session)) { + newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/); } else { newDevice = AUDIO_DEVICE_NONE; } @@ -1026,7 +1028,7 @@ status_t AudioPolicyManager::startSource(sp<AudioOutputDescriptor> outputDesc, // necessary for a correct control of hardware output routing by startOutput() and stopOutput() outputDesc->changeRefCount(stream, 1); - if (outputDesc->mRefCount[stream] == 1) { + if (outputDesc->mRefCount[stream] == 1 || device != AUDIO_DEVICE_NONE) { // starting an output being rerouted? if (device == AUDIO_DEVICE_NONE) { device = getNewOutputDevice(outputDesc, false /*fromCache*/); @@ -2462,14 +2464,14 @@ status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session return mSoundTriggerSessions.acquireSession(*session, *ioHandle); } -status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source, - const audio_attributes_t *attributes, - audio_io_handle_t *handle) +status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source __unused, + const audio_attributes_t *attributes __unused, + audio_io_handle_t *handle __unused) { return INVALID_OPERATION; } -status_t AudioPolicyManager::stopAudioSource(audio_io_handle_t handle) +status_t AudioPolicyManager::stopAudioSource(audio_io_handle_t handle __unused) { return INVALID_OPERATION; } @@ -4511,18 +4513,36 @@ bool AudioPolicyManager::SessionRouteMap::hasRoute(audio_session_t session) return indexOfKey(session) >= 0 && valueFor(session)->mDeviceDescriptor != 0; } +bool AudioPolicyManager::SessionRouteMap::hasRouteChanged(audio_session_t session) +{ + if (indexOfKey(session) >= 0) { + if (valueFor(session)->mChanged) { + valueFor(session)->mChanged = false; + return true; + } + } + return false; +} + void AudioPolicyManager::SessionRouteMap::addRoute(audio_session_t session, audio_stream_type_t streamType, sp<DeviceDescriptor> deviceDescriptor) { sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0; if (route != NULL) { + if ((route->mDeviceDescriptor == 0 && deviceDescriptor != 0) || + (!route->mDeviceDescriptor->equals(deviceDescriptor))) { + route->mChanged = true; + } route->mRefCount++; route->mDeviceDescriptor = deviceDescriptor; } else { route = new AudioPolicyManager::SessionRoute(session, streamType, deviceDescriptor); route->mRefCount++; add(session, route); + if (deviceDescriptor != 0) { + route->mChanged = true; + } } } diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index 146a7af..521f6c4 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -244,7 +244,10 @@ protected: mStreamType(streamType), mDeviceDescriptor(deviceDescriptor), mRefCount(0), - mActivityCount(0) {} + mActivityCount(0), + mChanged(false) {} + + void log(const char* prefix); audio_session_t mSession; audio_stream_type_t mStreamType; @@ -252,10 +255,9 @@ protected: sp<DeviceDescriptor> mDeviceDescriptor; // "reference" counting - int mRefCount; // +/- on references - int mActivityCount; // +/- on start/stop - - void log(const char* prefix); + int mRefCount; // +/- on references + int mActivityCount; // +/- on start/stop + bool mChanged; }; class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute>> @@ -268,7 +270,7 @@ protected: int incRouteActivity(audio_session_t session); int decRouteActivity(audio_session_t session); - + bool hasRouteChanged(audio_session_t session); // also clears the changed flag void log(const char* caption); }; @@ -510,6 +512,8 @@ protected: void updateCallRouting(audio_devices_t rxDevice, int delayMs = 0); + // if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force + // the re-evaluation of the output device. status_t startSource(sp<AudioOutputDescriptor> outputDesc, audio_stream_type_t stream, audio_devices_t device, diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 5f501a5..e764eda 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -546,9 +546,6 @@ status_t AudioPolicyService::listAudioPorts(audio_port_role_t role, unsigned int *generation) { Mutex::Autolock _l(mLock); - if(!modifyAudioRoutingAllowed()) { - return PERMISSION_DENIED; - } if (mAudioPolicyManager == NULL) { return NO_INIT; } @@ -559,9 +556,6 @@ status_t AudioPolicyService::listAudioPorts(audio_port_role_t role, status_t AudioPolicyService::getAudioPort(struct audio_port *port) { Mutex::Autolock _l(mLock); - if(!modifyAudioRoutingAllowed()) { - return PERMISSION_DENIED; - } if (mAudioPolicyManager == NULL) { return NO_INIT; } @@ -602,9 +596,6 @@ status_t AudioPolicyService::listAudioPatches(unsigned int *num_patches, unsigned int *generation) { Mutex::Autolock _l(mLock); - if(!modifyAudioRoutingAllowed()) { - return PERMISSION_DENIED; - } if (mAudioPolicyManager == NULL) { return NO_INIT; } |