diff options
Diffstat (limited to 'services')
25 files changed, 638 insertions, 307 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/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h index 4fa472e..58c65fa 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -218,6 +218,11 @@ public: virtual status_t registerPolicyMixes(Vector<AudioMix> mixes) = 0; virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes) = 0; + + virtual status_t startAudioSource(const struct audio_port_config *source, + const audio_attributes_t *attributes, + audio_io_handle_t *handle) = 0; + virtual status_t stopAudioSource(audio_io_handle_t handle) = 0; }; diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h index 1c2c27e..82e2c43 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h @@ -75,10 +75,8 @@ public: audio_format_t pickFormat() const; static const audio_format_t sPcmFormatCompareTable[]; - static int compareFormatsGoodToBad( - const audio_format_t *format1, const audio_format_t *format2) { - // compareFormats sorts from bad to good, we reverse it here - return compareFormats(*format2, *format1); + static int compareFormats(const audio_format_t *format1, const audio_format_t *format2) { + return compareFormats(*format1, *format2); } static int compareFormats(audio_format_t format1, audio_format_t format2); 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..64f883a 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp @@ -146,7 +146,7 @@ void AudioPort::importAudioPort(const sp<AudioPort> port) { break; } } - if (!hasFormat) { // never import a channel mask twice + if (!hasFormat) { // never import a format twice mFormats.add(format); } } @@ -216,7 +216,12 @@ void AudioPort::loadFormats(char *name) } str = strtok(NULL, "|"); } - mFormats.sort(compareFormatsGoodToBad); + // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry. + // TODO: compareFormats could be a lambda to convert between pointer-to-format to format: + // [](const audio_format_t *format1, const audio_format_t *format2) { + // return compareFormats(*format1, *format2); + // } + mFormats.sort(compareFormats); } void AudioPort::loadInChannels(char *name) @@ -235,8 +240,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 +452,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 @@ -495,11 +563,13 @@ status_t AudioPort::checkCompatibleFormat(audio_format_t format, audio_format_t mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK && audio_is_linear_pcm(format); - for (size_t i = 0; i < mFormats.size(); ++i) { + // iterate from best format to worst format (reverse order) + for (ssize_t i = mFormats.size() - 1; i >= 0 ; --i) { if (mFormats[i] == format || - (checkInexact && audio_is_linear_pcm(mFormats[i]))) { - // for inexact checks we take the first linear pcm format since - // mFormats is sorted from best PCM format to worst PCM format. + (checkInexact + && mFormats[i] != AUDIO_FORMAT_DEFAULT + && audio_is_linear_pcm(mFormats[i]))) { + // for inexact checks we take the first linear pcm format due to sorting. if (updatedFormat != NULL) { *updatedFormat = mFormats[i]; } @@ -726,10 +796,15 @@ void AudioPort::dump(int fd, int spaces) const const char *formatStr = ConfigParsingUtils::enumToString(sFormatNameToEnumTable, ARRAY_SIZE(sFormatNameToEnumTable), mFormats[i]); - if (i == 0 && strcmp(formatStr, "") == 0) { + const bool isEmptyStr = formatStr[0] == 0; + if (i == 0 && isEmptyStr) { snprintf(buffer, SIZE, "Dynamic"); } else { - snprintf(buffer, SIZE, "%s", formatStr); + if (isEmptyStr) { + snprintf(buffer, SIZE, "%#x", mFormats[i]); + } else { + snprintf(buffer, SIZE, "%s", formatStr); + } } result.append(buffer); result.append(i == (mFormats.size() - 1) ? "" : ", "); 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 266eeda..ba3fcaf 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*/); @@ -2475,6 +2477,18 @@ status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session return mSoundTriggerSessions.acquireSession(*session, *ioHandle); } +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 __unused) +{ + return INVALID_OPERATION; +} + // ---------------------------------------------------------------------------- // AudioPolicyManager // ---------------------------------------------------------------------------- @@ -4512,18 +4526,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 fe6b986..521f6c4 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -220,6 +220,11 @@ public: virtual status_t registerPolicyMixes(Vector<AudioMix> mixes); virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes); + virtual status_t startAudioSource(const struct audio_port_config *source, + const audio_attributes_t *attributes, + audio_io_handle_t *handle); + virtual status_t stopAudioSource(audio_io_handle_t handle); + // Audio policy configuration file parsing (audio_policy.conf) // TODO candidates to be moved to ConfigParsingUtils void defaultAudioPolicyConfig(void); @@ -239,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; @@ -247,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>> @@ -263,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); }; @@ -505,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 9510727..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; } @@ -661,4 +652,26 @@ status_t AudioPolicyService::registerPolicyMixes(Vector<AudioMix> mixes, bool re } } +status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source, + const audio_attributes_t *attributes, + audio_io_handle_t *handle) +{ + Mutex::Autolock _l(mLock); + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + + return mAudioPolicyManager->startAudioSource(source, attributes, handle); +} + +status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle) +{ + Mutex::Autolock _l(mLock); + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + + return mAudioPolicyManager->stopAudioSource(handle); +} + }; // namespace android diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp index e4ca5dc..f783437 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp @@ -604,4 +604,16 @@ status_t AudioPolicyService::registerPolicyMixes(Vector<AudioMix> mixes __unused return INVALID_OPERATION; } +status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source, + const audio_attributes_t *attributes, + audio_io_handle_t *handle) +{ + return INVALID_OPERATION; +} + +status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle) +{ + return INVALID_OPERATION; +} + }; // namespace android diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h index fbd8f0e..4e25d33 100644 --- a/services/audiopolicy/service/AudioPolicyService.h +++ b/services/audiopolicy/service/AudioPolicyService.h @@ -192,6 +192,11 @@ public: virtual status_t registerPolicyMixes(Vector<AudioMix> mixes, bool registration); + virtual status_t startAudioSource(const struct audio_port_config *source, + const audio_attributes_t *attributes, + audio_io_handle_t *handle); + virtual status_t stopAudioSource(audio_io_handle_t handle); + status_t doStopOutput(audio_io_handle_t output, audio_stream_type_t stream, audio_session_t session); diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 414d563..8c5c43a 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -140,76 +140,90 @@ void CameraService::onFirstRef() BnCameraService::onFirstRef(); camera_module_t *rawModule; - if (hw_get_module(CAMERA_HARDWARE_MODULE_ID, - (const hw_module_t **)&rawModule) < 0) { - ALOGE("Could not load camera HAL module"); + int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID, + (const hw_module_t **)&rawModule); + if (err < 0) { + ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err)); + logServiceError("Could not load camera HAL module", err); mNumberOfCameras = 0; + return; } - else { - mModule = new CameraModule(rawModule); - ALOGI("Loaded \"%s\" camera module", mModule->getModuleName()); - mNumberOfCameras = mModule->getNumberOfCameras(); - - mFlashlight = new CameraFlashlight(*mModule, *this); - status_t res = mFlashlight->findFlashUnits(); - if (res) { - // impossible because we haven't open any camera devices. - ALOGE("Failed to find flash units."); - } - for (int i = 0; i < mNumberOfCameras; i++) { - String8 cameraId = String8::format("%d", i); - - // Defaults to use for cost and conflicting devices - int cost = 100; - char** conflicting_devices = nullptr; - size_t conflicting_devices_length = 0; - - // If using post-2.4 module version, query the cost + conflicting devices from the HAL - if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) { - struct camera_info info; - status_t rc = mModule->getCameraInfo(i, &info); - if (rc == NO_ERROR) { - cost = info.resource_cost; - conflicting_devices = info.conflicting_devices; - conflicting_devices_length = info.conflicting_devices_length; - } else { - ALOGE("%s: Received error loading camera info for device %d, cost and" - " conflicting devices fields set to defaults for this device.", - __FUNCTION__, i); - } - } + mModule = new CameraModule(rawModule); + ALOGI("Loaded \"%s\" camera module", mModule->getModuleName()); + err = mModule->init(); + if (err != OK) { + ALOGE("Could not initialize camera HAL module: %d (%s)", err, + strerror(-err)); + logServiceError("Could not initialize camera HAL module", err); - std::set<String8> conflicting; - for (size_t i = 0; i < conflicting_devices_length; i++) { - conflicting.emplace(String8(conflicting_devices[i])); - } + mNumberOfCameras = 0; + delete mModule; + mModule = nullptr; + return; + } - // Initialize state for each camera device - { - Mutex::Autolock lock(mCameraStatesLock); - mCameraStates.emplace(cameraId, std::make_shared<CameraState>(cameraId, cost, - conflicting)); - } + mNumberOfCameras = mModule->getNumberOfCameras(); - if (mFlashlight->hasFlashUnit(cameraId)) { - mTorchStatusMap.add(cameraId, - ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF); + mFlashlight = new CameraFlashlight(*mModule, *this); + status_t res = mFlashlight->findFlashUnits(); + if (res) { + // impossible because we haven't open any camera devices. + ALOGE("Failed to find flash units."); + } + + for (int i = 0; i < mNumberOfCameras; i++) { + String8 cameraId = String8::format("%d", i); + + // Defaults to use for cost and conflicting devices + int cost = 100; + char** conflicting_devices = nullptr; + size_t conflicting_devices_length = 0; + + // If using post-2.4 module version, query the cost + conflicting devices from the HAL + if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) { + struct camera_info info; + status_t rc = mModule->getCameraInfo(i, &info); + if (rc == NO_ERROR) { + cost = info.resource_cost; + conflicting_devices = info.conflicting_devices; + conflicting_devices_length = info.conflicting_devices_length; + } else { + ALOGE("%s: Received error loading camera info for device %d, cost and" + " conflicting devices fields set to defaults for this device.", + __FUNCTION__, i); } } - if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_1) { - mModule->setCallbacks(this); + std::set<String8> conflicting; + for (size_t i = 0; i < conflicting_devices_length; i++) { + conflicting.emplace(String8(conflicting_devices[i])); } - VendorTagDescriptor::clearGlobalVendorTagDescriptor(); + // Initialize state for each camera device + { + Mutex::Autolock lock(mCameraStatesLock); + mCameraStates.emplace(cameraId, std::make_shared<CameraState>(cameraId, cost, + conflicting)); + } - if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_2) { - setUpVendorTags(); + if (mFlashlight->hasFlashUnit(cameraId)) { + mTorchStatusMap.add(cameraId, + ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF); } + } + + if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_1) { + mModule->setCallbacks(this); + } - CameraDeviceFactory::registerService(this); + VendorTagDescriptor::clearGlobalVendorTagDescriptor(); + + if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_2) { + setUpVendorTags(); } + + CameraDeviceFactory::registerService(this); } CameraService::~CameraService() { @@ -299,12 +313,11 @@ void CameraService::onTorchStatusChangedLocked(const String8& cameraId, ICameraServiceListener::TorchStatus status; status_t res = getTorchStatusLocked(cameraId, &status); if (res) { - ALOGE("%s: cannot get torch status of camera %s", cameraId.string()); + ALOGE("%s: cannot get torch status of camera %s: %s (%d)", + __FUNCTION__, cameraId.string(), strerror(-res), res); return; } if (status == newStatus) { - ALOGE("%s: Torch state transition to the same status 0x%x not allowed", - __FUNCTION__, (uint32_t)newStatus); return; } @@ -1139,14 +1152,14 @@ status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, // verify id is valid. auto state = getCameraState(id); if (state == nullptr) { - ALOGE("%s: camera id is invalid %s", id.string()); + ALOGE("%s: camera id is invalid %s", __FUNCTION__, id.string()); return -EINVAL; } ICameraServiceListener::Status cameraStatus = state->getStatus(); if (cameraStatus != ICameraServiceListener::STATUS_PRESENT && cameraStatus != ICameraServiceListener::STATUS_NOT_AVAILABLE) { - ALOGE("%s: camera id is invalid %s", id.string()); + ALOGE("%s: camera id is invalid %s", __FUNCTION__, id.string()); return -EINVAL; } @@ -1554,6 +1567,11 @@ void CameraService::logClientDied(int clientPid, const char* reason) { logEvent(String8::format("DIED client(s) with PID %d, reason: (%s)", clientPid, reason)); } +void CameraService::logServiceError(const char* msg, int errorCode) { + String8 curTime = getFormattedCurrentTime(); + logEvent(String8::format("SERVICE ERROR: %s : %d (%s)", msg, errorCode, strerror(errorCode))); +} + status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -1996,6 +2014,10 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { if (!mModule) { result = String8::format("No camera module available!\n"); write(fd, result.string(), result.size()); + + // Dump event log for error information + dumpEventLog(fd); + if (locked) mServiceLock.unlock(); return NO_ERROR; } @@ -2021,20 +2043,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { desc->dump(fd, /*verbosity*/2, /*indentation*/4); } - result = String8("Prior client events (most recent at top):\n"); - - { - Mutex::Autolock l(mLogLock); - for (const auto& msg : mEventLog) { - result.appendFormat("%s\n", msg.string()); - } - - if (mEventLog.size() == DEFAULT_EVENT_LOG_LENGTH) { - result.append("...\n"); - } - } - - write(fd, result.string(), result.size()); + dumpEventLog(fd); bool stateLocked = tryLock(mCameraStatesLock); if (!stateLocked) { @@ -2142,6 +2151,24 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { return NO_ERROR; } +void CameraService::dumpEventLog(int fd) { + String8 result = String8("\nPrior client events (most recent at top):\n"); + + Mutex::Autolock l(mLogLock); + for (const auto& msg : mEventLog) { + result.appendFormat(" %s\n", msg.string()); + } + + if (mEventLog.size() == DEFAULT_EVENT_LOG_LENGTH) { + result.append(" ...\n"); + } else if (mEventLog.size() == 0) { + result.append(" [no events yet]\n"); + } + result.append("\n"); + + write(fd, result.string(), result.size()); +} + void CameraService::handleTorchClientBinderDied(const wp<IBinder> &who) { Mutex::Autolock al(mTorchClientMapMutex); for (size_t i = 0; i < mTorchClientMap.size(); i++) { @@ -2204,16 +2231,20 @@ void CameraService::updateStatus(ICameraServiceListener::Status status, const St state->updateStatus(status, cameraId, rejectSourceStates, [this] (const String8& cameraId, ICameraServiceListener::Status status) { - // Update torch status - if (status == ICameraServiceListener::STATUS_NOT_PRESENT || - status == ICameraServiceListener::STATUS_NOT_AVAILABLE) { - // Update torch status to not available when the camera device becomes not present - // or not available. - onTorchStatusChanged(cameraId, ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE); - } else if (status == ICameraServiceListener::STATUS_PRESENT) { - // Update torch status to available when the camera device becomes present or - // available - onTorchStatusChanged(cameraId, ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF); + if (status != ICameraServiceListener::STATUS_ENUMERATING) { + // Update torch status if it has a flash unit. + Mutex::Autolock al(mTorchStatusMutex); + ICameraServiceListener::TorchStatus torchStatus; + if (getTorchStatusLocked(cameraId, &torchStatus) != + NAME_NOT_FOUND) { + ICameraServiceListener::TorchStatus newTorchStatus = + status == ICameraServiceListener::STATUS_PRESENT ? + ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF : + ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE; + if (torchStatus != newTorchStatus) { + onTorchStatusChangedLocked(cameraId, newTorchStatus); + } + } } Mutex::Autolock lock(mStatusListenerLock); diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 91c7d59..84e61c5 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -590,6 +590,16 @@ private: */ void logClientDied(int clientPid, const char* reason); + /** + * Add a event log message that a serious service-level error has occured + */ + void logServiceError(const char* msg, int errorCode); + + /** + * Dump the event log to an FD + */ + void dumpEventLog(int fd); + int mNumberOfCameras; // sounds diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp index b861d71..ac4d9a6 100644 --- a/services/camera/libcameraservice/common/CameraModule.cpp +++ b/services/camera/libcameraservice/common/CameraModule.cpp @@ -57,6 +57,14 @@ CameraModule::CameraModule(camera_module_t *module) { mCameraInfoMap.setCapacity(getNumberOfCameras()); } +int CameraModule::init() { + if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 && + mModule->init != NULL) { + return mModule->init(); + } + return OK; +} + int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { Mutex::Autolock lock(mCameraInfoLock); if (cameraId < 0) { @@ -98,7 +106,7 @@ int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { assert(index != NAME_NOT_FOUND); // return the cached camera info *info = mCameraInfoMap[index]; - return 0; + return OK; } int CameraModule::open(const char* id, struct hw_device_t** device) { @@ -166,4 +174,3 @@ void* CameraModule::getDso() { } }; // namespace android - diff --git a/services/camera/libcameraservice/common/CameraModule.h b/services/camera/libcameraservice/common/CameraModule.h index e285b21..c21092e 100644 --- a/services/camera/libcameraservice/common/CameraModule.h +++ b/services/camera/libcameraservice/common/CameraModule.h @@ -34,6 +34,10 @@ class CameraModule { public: CameraModule(camera_module_t *module); + // Must be called after construction + // Returns OK on success, NO_INIT on failure + int init(); + int getCameraInfo(int cameraId, struct camera_info *info); int getNumberOfCameras(void); int open(const char* id, struct hw_device_t** device); @@ -63,4 +67,3 @@ private: } // namespace android #endif - diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 3821da1..4c40bb6 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -109,11 +109,7 @@ camera3_stream* Camera3Stream::startConfiguration() { // oldUsage/oldMaxBuffers return this; case STATE_CONFIGURED: - if (stream_type == CAMERA3_STREAM_INPUT) { - ALOGE("%s: Cannot configure an input stream twice", - __FUNCTION__); - return NULL; - } else if (hasOutstandingBuffersLocked()) { + if (hasOutstandingBuffersLocked()) { ALOGE("%s: Cannot configure stream; has outstanding buffers", __FUNCTION__); return NULL; diff --git a/services/radio/RadioService.cpp b/services/radio/RadioService.cpp index a6c2bdf..cd0f5f3 100644 --- a/services/radio/RadioService.cpp +++ b/services/radio/RadioService.cpp @@ -146,7 +146,7 @@ status_t RadioService::attach(radio_handle_t handle, radio = module->addClient(client, config, withAudio); if (radio == 0) { - NO_INIT; + return NO_INIT; } return NO_ERROR; } @@ -500,13 +500,12 @@ sp<RadioService::ModuleClient> RadioService::Module::addClient(const sp<IRadioCl if (audio) { notifyDeviceConnection(true, ""); } + ALOGV("addClient() DONE moduleClient %p", moduleClient.get()); } else { + ALOGW("%s open_tuner failed with error %d", __FUNCTION__, ret); moduleClient.clear(); } - - ALOGV("addClient() DONE moduleClient %p", moduleClient.get()); - return moduleClient; } |