summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioFlinger.h12
-rw-r--r--services/audioflinger/AudioMixer.cpp51
-rw-r--r--services/audioflinger/AudioMixer.h6
-rw-r--r--services/audioflinger/BufferProviders.cpp105
-rw-r--r--services/audioflinger/BufferProviders.h21
-rw-r--r--services/audioflinger/FastCapture.cpp2
-rw-r--r--services/audioflinger/Threads.cpp239
-rw-r--r--services/audioflinger/Threads.h19
-rw-r--r--services/audioflinger/Tracks.cpp8
-rw-r--r--services/audiopolicy/AudioPolicyInterface.h5
-rw-r--r--services/audiopolicy/common/managerdefinitions/include/AudioPort.h6
-rw-r--r--services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h14
-rw-r--r--services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp113
-rw-r--r--services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp3
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.cpp34
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.h21
-rw-r--r--services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp31
-rw-r--r--services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp12
-rw-r--r--services/audiopolicy/service/AudioPolicyService.h5
-rw-r--r--services/camera/libcameraservice/CameraService.cpp199
-rw-r--r--services/camera/libcameraservice/CameraService.h10
-rw-r--r--services/camera/libcameraservice/common/CameraModule.cpp11
-rw-r--r--services/camera/libcameraservice/common/CameraModule.h5
-rw-r--r--services/camera/libcameraservice/device3/Camera3Stream.cpp6
-rw-r--r--services/radio/RadioService.cpp7
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;
}