summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/Android.mk1
-rw-r--r--services/audioflinger/AudioFlinger.cpp36
-rw-r--r--services/audioflinger/AudioFlinger.h27
-rw-r--r--services/audioflinger/AudioMixer.cpp202
-rw-r--r--services/audioflinger/AudioMixer.h58
-rw-r--r--services/audioflinger/AudioWatchdog.cpp2
-rw-r--r--services/audioflinger/FastMixer.cpp108
-rw-r--r--services/audioflinger/FastMixer.h12
-rw-r--r--services/audioflinger/FastMixerState.cpp2
-rw-r--r--services/audioflinger/FastMixerState.h1
-rw-r--r--services/audioflinger/FastThread.cpp7
-rw-r--r--services/audioflinger/PatchPanel.cpp409
-rw-r--r--services/audioflinger/PatchPanel.h60
-rw-r--r--services/audioflinger/StateQueue.cpp4
-rw-r--r--services/audioflinger/Threads.cpp255
-rw-r--r--services/audioflinger/Threads.h73
-rw-r--r--services/audioflinger/TrackBase.h9
-rw-r--r--services/audioflinger/Tracks.cpp29
-rw-r--r--services/audiopolicy/Android.mk36
-rw-r--r--services/audiopolicy/AudioPolicyClientImpl.cpp11
-rw-r--r--services/audiopolicy/AudioPolicyInterface.h9
-rw-r--r--services/audiopolicy/AudioPolicyInterfaceImpl.cpp38
-rw-r--r--services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp38
-rw-r--r--services/audiopolicy/AudioPolicyManager.cpp621
-rw-r--r--services/audiopolicy/AudioPolicyManager.h146
-rw-r--r--services/audiopolicy/AudioPolicyService.cpp69
-rw-r--r--services/audiopolicy/AudioPolicyService.h51
-rw-r--r--services/camera/libcameraservice/CameraService.cpp310
-rw-r--r--services/camera/libcameraservice/CameraService.h39
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.cpp19
-rw-r--r--services/camera/libcameraservice/api2/CameraDeviceClient.cpp12
-rw-r--r--services/camera/libcameraservice/api2/CameraDeviceClient.h4
-rw-r--r--services/camera/libcameraservice/utils/CameraTraces.cpp4
-rw-r--r--services/medialog/MediaLogService.cpp4
34 files changed, 2181 insertions, 525 deletions
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 8d0a705..f7b6f64 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -29,6 +29,7 @@ LOCAL_SRC_FILES:= \
Tracks.cpp \
Effects.cpp \
AudioMixer.cpp.arm \
+ PatchPanel.cpp
LOCAL_SRC_FILES += StateQueue.cpp
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 45e17f8..5b09d54 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -143,7 +143,7 @@ static int load_audio_interface(const char *if_name, audio_hw_device_t **dev)
if (rc) {
goto out;
}
- if ((*dev)->common.version != AUDIO_DEVICE_API_VERSION_CURRENT) {
+ if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
rc = BAD_VALUE;
goto out;
@@ -177,6 +177,7 @@ AudioFlinger::AudioFlinger()
if (doLog) {
mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters", MemoryHeapBase::READ_ONLY);
}
+
#ifdef TEE_SINK
(void) property_get("ro.debuggable", value, "0");
int debuggable = atoi(value);
@@ -218,6 +219,8 @@ void AudioFlinger::onFirstRef()
}
}
+ mPatchPanel = new PatchPanel(this);
+
mMode = AUDIO_MODE_NORMAL;
}
@@ -427,7 +430,7 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
if (mLogMemoryDealer != 0) {
sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
if (binder != 0) {
- fdprintf(fd, "\nmedia.log:\n");
+ dprintf(fd, "\nmedia.log:\n");
Vector<String16> args;
binder->dump(fd, args);
}
@@ -635,8 +638,12 @@ sp<IAudioTrack> AudioFlinger::createTrack(
if (lStatus != NO_ERROR) {
// remove local strong reference to Client before deleting the Track so that the
// Client destructor is called by the TrackBase destructor with mClientLock held
- Mutex::Autolock _cl(mClientLock);
- client.clear();
+ // Don't hold mClientLock when releasing the reference on the track as the
+ // destructor will acquire it.
+ {
+ Mutex::Autolock _cl(mClientLock);
+ client.clear();
+ }
track.clear();
goto Exit;
}
@@ -1173,7 +1180,7 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
}
// mClientLock should not be held here because ThreadBase::sendIoConfigEvent() will lock the
- // ThreadBase mutex and teh locknig order is ThreadBase::mLock then AudioFlinger::mClientLock.
+ // ThreadBase mutex and the locking order is ThreadBase::mLock then AudioFlinger::mClientLock.
if (clientAdded) {
// the config change is always sent from playback or record threads to avoid deadlock
// with AudioSystem::gLock
@@ -1419,8 +1426,12 @@ sp<IAudioRecord> AudioFlinger::openRecord(
if (lStatus != NO_ERROR) {
// remove local strong reference to Client before deleting the RecordTrack so that the
// Client destructor is called by the TrackBase destructor with mClientLock held
- Mutex::Autolock _cl(mClientLock);
- client.clear();
+ // Don't hold mClientLock when releasing the reference on the track as the
+ // destructor will acquire it.
+ {
+ Mutex::Autolock _cl(mClientLock);
+ client.clear();
+ }
recordTrack.clear();
goto Exit;
}
@@ -2380,6 +2391,11 @@ sp<IEffect> AudioFlinger::createEffect(
if (handle != 0 && id != NULL) {
*id = handle->id();
}
+ if (handle == 0) {
+ // remove local strong reference to Client with mClientLock held
+ Mutex::Autolock _cl(mClientLock);
+ client.clear();
+ }
}
Exit:
@@ -2590,7 +2606,7 @@ void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_hand
}
} else {
if (fd >= 0) {
- fdprintf(fd, "unable to rotate tees in %s: %s\n", teePath, strerror(errno));
+ dprintf(fd, "unable to rotate tees in %s: %s\n", teePath, strerror(errno));
}
}
char teeTime[16];
@@ -2644,11 +2660,11 @@ void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_hand
write(teeFd, &temp, sizeof(temp));
close(teeFd);
if (fd >= 0) {
- fdprintf(fd, "tee copied to %s\n", teePath);
+ dprintf(fd, "tee copied to %s\n", teePath);
}
} else {
if (fd >= 0) {
- fdprintf(fd, "unable to create tee %s: %s\n", teePath, strerror(errno));
+ dprintf(fd, "unable to create tee %s: %s\n", teePath, strerror(errno));
}
}
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d2ded9a..29dc6b2 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -223,6 +223,27 @@ public:
virtual status_t setLowRamDevice(bool isLowRamDevice);
+ /* List available audio ports and their attributes */
+ virtual status_t listAudioPorts(unsigned int *num_ports,
+ struct audio_port *ports);
+
+ /* Get attributes for a given audio port */
+ virtual status_t getAudioPort(struct audio_port *port);
+
+ /* Create an audio patch between several source and sink ports */
+ virtual status_t createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle);
+
+ /* Release an audio patch */
+ virtual status_t releaseAudioPatch(audio_patch_handle_t handle);
+
+ /* List existing audio patches */
+ virtual status_t listAudioPatches(unsigned int *num_patches,
+ struct audio_patch *patches);
+
+ /* Set audio port configuration */
+ virtual status_t setAudioPortConfig(const struct audio_port_config *config);
+
virtual status_t onTransact(
uint32_t code,
const Parcel& data,
@@ -397,6 +418,8 @@ private:
#include "Effects.h"
+#include "PatchPanel.h"
+
// server side of the client's IAudioTrack
class TrackHandle : public android::BnAudioTrack {
public:
@@ -504,6 +527,8 @@ private:
const char *moduleName() const { return mModuleName; }
audio_hw_device_t *hwDevice() const { return mHwDevice; }
+ uint32_t version() const { return mHwDevice->common.version; }
+
private:
const char * const mModuleName;
audio_hw_device_t * const mHwDevice;
@@ -664,6 +689,8 @@ private:
bool mIsLowRamDevice;
bool mIsDeviceTypeKnown;
nsecs_t mGlobalEffectEnableTime; // when a global effect was last enabled
+
+ sp<PatchPanel> mPatchPanel;
};
#undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 805eaa4..8d57451 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -34,6 +34,7 @@
#include <system/audio.h>
#include <audio_utils/primitives.h>
+#include <audio_utils/format.h>
#include <common_time/local_clock.h>
#include <common_time/cc_helper.h>
@@ -88,6 +89,103 @@ void AudioMixer::DownmixerBufferProvider::releaseBuffer(AudioBufferProvider::Buf
}
}
+template <typename T>
+T min(const T& a, const T& b)
+{
+ return a < b ? a : b;
+}
+
+AudioMixer::ReformatBufferProvider::ReformatBufferProvider(int32_t channels,
+ audio_format_t inputFormat, audio_format_t outputFormat) :
+ mTrackBufferProvider(NULL),
+ mChannels(channels),
+ mInputFormat(inputFormat),
+ mOutputFormat(outputFormat),
+ mInputFrameSize(channels * audio_bytes_per_sample(inputFormat)),
+ mOutputFrameSize(channels * audio_bytes_per_sample(outputFormat)),
+ mOutputData(NULL),
+ mOutputCount(0),
+ mConsumed(0)
+{
+ ALOGV("ReformatBufferProvider(%p)(%d, %#x, %#x)", this, channels, inputFormat, outputFormat);
+ if (requiresInternalBuffers()) {
+ mOutputCount = 256;
+ (void)posix_memalign(&mOutputData, 32, mOutputCount * mOutputFrameSize);
+ }
+ mBuffer.frameCount = 0;
+}
+
+AudioMixer::ReformatBufferProvider::~ReformatBufferProvider()
+{
+ ALOGV("~ReformatBufferProvider(%p)", this);
+ if (mBuffer.frameCount != 0) {
+ mTrackBufferProvider->releaseBuffer(&mBuffer);
+ }
+ free(mOutputData);
+}
+
+status_t AudioMixer::ReformatBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer,
+ int64_t pts) {
+ //ALOGV("ReformatBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
+ // this, pBuffer, pBuffer->frameCount, pts);
+ if (!requiresInternalBuffers()) {
+ status_t res = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
+ if (res == OK) {
+ memcpy_by_audio_format(pBuffer->raw, mOutputFormat, pBuffer->raw, mInputFormat,
+ pBuffer->frameCount * mChannels);
+ }
+ return res;
+ }
+ if (mBuffer.frameCount == 0) {
+ mBuffer.frameCount = pBuffer->frameCount;
+ status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
+ // TODO: Track down a bug in the upstream provider
+ // LOG_ALWAYS_FATAL_IF(res == OK && mBuffer.frameCount == 0,
+ // "ReformatBufferProvider::getNextBuffer():"
+ // " Invalid zero framecount returned from getNextBuffer()");
+ if (res != OK || mBuffer.frameCount == 0) {
+ pBuffer->raw = NULL;
+ pBuffer->frameCount = 0;
+ return res;
+ }
+ }
+ ALOG_ASSERT(mConsumed < mBuffer.frameCount);
+ size_t count = min(mOutputCount, mBuffer.frameCount - mConsumed);
+ count = min(count, pBuffer->frameCount);
+ pBuffer->raw = mOutputData;
+ pBuffer->frameCount = count;
+ //ALOGV("reformatting %d frames from %#x to %#x, %d chan",
+ // pBuffer->frameCount, mInputFormat, mOutputFormat, mChannels);
+ memcpy_by_audio_format(pBuffer->raw, mOutputFormat,
+ (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize, mInputFormat,
+ pBuffer->frameCount * mChannels);
+ return OK;
+}
+
+void AudioMixer::ReformatBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) {
+ //ALOGV("ReformatBufferProvider(%p)::releaseBuffer(%p(%zu))",
+ // this, pBuffer, pBuffer->frameCount);
+ if (!requiresInternalBuffers()) {
+ mTrackBufferProvider->releaseBuffer(pBuffer);
+ return;
+ }
+ // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
+ mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content
+ if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) {
+ mConsumed = 0;
+ mTrackBufferProvider->releaseBuffer(&mBuffer);
+ // ALOG_ASSERT(mBuffer.frameCount == 0);
+ }
+ pBuffer->raw = NULL;
+ pBuffer->frameCount = 0;
+}
+
+void AudioMixer::ReformatBufferProvider::reset() {
+ if (mBuffer.frameCount != 0) {
+ mTrackBufferProvider->releaseBuffer(&mBuffer);
+ }
+ mConsumed = 0;
+}
// ----------------------------------------------------------------------------
bool AudioMixer::sIsMultichannelCapable = false;
@@ -153,8 +251,13 @@ void AudioMixer::setLog(NBLog::Writer *log)
mState.mLog = log;
}
-int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId)
+int AudioMixer::getTrackName(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId)
{
+ if (!isValidPcmTrackFormat(format)) {
+ ALOGE("AudioMixer::getTrackName invalid format (%#x)", format);
+ return -1;
+ }
uint32_t names = (~mTrackNames) & mConfiguredNames;
if (names != 0) {
int n = __builtin_ctz(names);
@@ -176,7 +279,8 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId)
// t->frameCount
t->channelCount = audio_channel_count_from_out_mask(channelMask);
t->enabled = false;
- t->format = 16;
+ ALOGV_IF(channelMask != AUDIO_CHANNEL_OUT_STEREO,
+ "Non-stereo channel mask: %d\n", channelMask);
t->channelMask = channelMask;
t->sessionId = sessionId;
// setBufferProvider(name, AudioBufferProvider *) is required before enable(name)
@@ -191,9 +295,15 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId)
// setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name)
t->mainBuffer = NULL;
t->auxBuffer = NULL;
+ t->mInputBufferProvider = NULL;
+ t->mReformatBufferProvider = NULL;
t->downmixerBufferProvider = NULL;
t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
-
+ t->mFormat = format;
+ t->mMixerInFormat = AUDIO_FORMAT_PCM_16_BIT;
+ if (t->mFormat != t->mMixerInFormat) {
+ prepareTrackForReformat(t, n);
+ }
status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask);
if (status != OK) {
ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
@@ -237,9 +347,9 @@ void AudioMixer::unprepareTrackForDownmix(track_t* pTrack, int trackName __unuse
if (pTrack->downmixerBufferProvider != NULL) {
// this track had previously been configured with a downmixer, delete it
ALOGV(" deleting old downmixer");
- pTrack->bufferProvider = pTrack->downmixerBufferProvider->mTrackBufferProvider;
delete pTrack->downmixerBufferProvider;
pTrack->downmixerBufferProvider = NULL;
+ reconfigureBufferProviders(pTrack);
} else {
ALOGV(" nothing to do, no downmixer to delete");
}
@@ -333,21 +443,51 @@ status_t AudioMixer::prepareTrackForDownmix(track_t* pTrack, int trackName)
}// end of scope for local variables that are not used in goto label "noDownmixForActiveTrack"
// initialization successful:
- // - keep track of the real buffer provider in case it was set before
- pDbp->mTrackBufferProvider = pTrack->bufferProvider;
- // - we'll use the downmix effect integrated inside this
- // track's buffer provider, and we'll use it as the track's buffer provider
pTrack->downmixerBufferProvider = pDbp;
- pTrack->bufferProvider = pDbp;
-
+ reconfigureBufferProviders(pTrack);
return NO_ERROR;
noDownmixForActiveTrack:
delete pDbp;
pTrack->downmixerBufferProvider = NULL;
+ reconfigureBufferProviders(pTrack);
return NO_INIT;
}
+void AudioMixer::unprepareTrackForReformat(track_t* pTrack, int trackName __unused) {
+ ALOGV("AudioMixer::unprepareTrackForReformat(%d)", trackName);
+ if (pTrack->mReformatBufferProvider != NULL) {
+ delete pTrack->mReformatBufferProvider;
+ pTrack->mReformatBufferProvider = NULL;
+ reconfigureBufferProviders(pTrack);
+ }
+}
+
+status_t AudioMixer::prepareTrackForReformat(track_t* pTrack, int trackName)
+{
+ ALOGV("AudioMixer::prepareTrackForReformat(%d) with format %#x", trackName, pTrack->mFormat);
+ // discard the previous reformatter if there was one
+ unprepareTrackForReformat(pTrack, trackName);
+ pTrack->mReformatBufferProvider = new ReformatBufferProvider(
+ audio_channel_count_from_out_mask(pTrack->channelMask),
+ pTrack->mFormat, pTrack->mMixerInFormat);
+ reconfigureBufferProviders(pTrack);
+ return NO_ERROR;
+}
+
+void AudioMixer::reconfigureBufferProviders(track_t* pTrack)
+{
+ pTrack->bufferProvider = pTrack->mInputBufferProvider;
+ if (pTrack->mReformatBufferProvider) {
+ pTrack->mReformatBufferProvider->mTrackBufferProvider = pTrack->bufferProvider;
+ pTrack->bufferProvider = pTrack->mReformatBufferProvider;
+ }
+ if (pTrack->downmixerBufferProvider) {
+ pTrack->downmixerBufferProvider->mTrackBufferProvider = pTrack->bufferProvider;
+ pTrack->bufferProvider = pTrack->downmixerBufferProvider;
+ }
+}
+
void AudioMixer::deleteTrackName(int name)
{
ALOGV("AudioMixer::deleteTrackName(%d)", name);
@@ -364,6 +504,8 @@ void AudioMixer::deleteTrackName(int name)
track.resampler = NULL;
// delete the downmixer
unprepareTrackForDownmix(&mState.tracks[name], name);
+ // delete the reformatter
+ unprepareTrackForReformat(&mState.tracks[name], name);
mTrackNames &= ~(1<<name);
}
@@ -435,9 +577,20 @@ void AudioMixer::setParameter(int name, int target, int param, void *value)
invalidateState(1 << name);
}
break;
- case FORMAT:
- ALOG_ASSERT(valueInt == AUDIO_FORMAT_PCM_16_BIT);
- break;
+ case FORMAT: {
+ audio_format_t format = static_cast<audio_format_t>(valueInt);
+ if (track.mFormat != format) {
+ ALOG_ASSERT(audio_is_linear_pcm(format), "Invalid format %#x", format);
+ track.mFormat = format;
+ ALOGV("setParameter(TRACK, FORMAT, %#x)", format);
+ //if (track.mFormat != track.mMixerInFormat)
+ {
+ ALOGD("Reformatting!");
+ prepareTrackForReformat(&track, name);
+ }
+ invalidateState(1 << name);
+ }
+ } break;
// FIXME do we want to support setting the downmix type from AudioFlinger?
// for a specific track? or per mixer?
/* case DOWNMIX_TYPE:
@@ -550,8 +703,9 @@ bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
} else {
quality = AudioResampler::DEFAULT_QUALITY;
}
+ const int bits = mMixerInFormat == AUDIO_FORMAT_PCM_16_BIT ? 16 : /* FLOAT */ 32;
resampler = AudioResampler::create(
- format,
+ bits,
// the resampler sees the number of channels after the downmixer, if any
(int) (downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount),
devSampleRate, quality);
@@ -596,21 +750,13 @@ void AudioMixer::setBufferProvider(int name, AudioBufferProvider* bufferProvider
name -= TRACK0;
ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name);
- if (mState.tracks[name].downmixerBufferProvider != NULL) {
- // update required?
- if (mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider != bufferProvider) {
- ALOGV("AudioMixer::setBufferProvider(%p) for downmix", bufferProvider);
- // setting the buffer provider for a track that gets downmixed consists in:
- // 1/ setting the buffer provider to the "downmix / buffer provider" wrapper
- // so it's the one that gets called when the buffer provider is needed,
- mState.tracks[name].bufferProvider = mState.tracks[name].downmixerBufferProvider;
- // 2/ saving the buffer provider for the track so the wrapper can use it
- // when it downmixes.
- mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider = bufferProvider;
- }
- } else {
- mState.tracks[name].bufferProvider = bufferProvider;
+ if (mState.tracks[name].mReformatBufferProvider != NULL) {
+ mState.tracks[name].mReformatBufferProvider->reset();
+ } else if (mState.tracks[name].downmixerBufferProvider != NULL) {
}
+
+ mState.tracks[name].mInputBufferProvider = bufferProvider;
+ reconfigureBufferProviders(&mState.tracks[name]);
}
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 09e63a6..573ba96 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -104,7 +104,10 @@ public:
// For all APIs with "name": TRACK0 <= name < TRACK0 + MAX_NUM_TRACKS
// Allocate a track name. Returns new track name if successful, -1 on failure.
- int getTrackName(audio_channel_mask_t channelMask, int sessionId);
+ // The failure could be because of an invalid channelMask or format, or that
+ // the track capacity of the mixer is exceeded.
+ int getTrackName(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId);
// Free an allocated track by name
void deleteTrackName(int name);
@@ -122,6 +125,13 @@ public:
size_t getUnreleasedFrames(int name) const;
+ static inline bool isValidPcmTrackFormat(audio_format_t format) {
+ return format == AUDIO_FORMAT_PCM_16_BIT ||
+ format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
+ format == AUDIO_FORMAT_PCM_32_BIT ||
+ format == AUDIO_FORMAT_PCM_FLOAT;
+ }
+
private:
enum {
@@ -143,6 +153,7 @@ private:
struct state_t;
struct track_t;
class DownmixerBufferProvider;
+ class ReformatBufferProvider;
typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp,
int32_t* aux);
@@ -170,7 +181,7 @@ private:
uint16_t frameCount;
uint8_t channelCount; // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK)
- uint8_t format; // always 16
+ uint8_t unused_padding; // formerly format, was always 16
uint16_t enabled; // actually bool
audio_channel_mask_t channelMask;
@@ -193,14 +204,19 @@ private:
int32_t* auxBuffer;
// 16-byte boundary
-
+ AudioBufferProvider* mInputBufferProvider; // 4 bytes
+ ReformatBufferProvider* mReformatBufferProvider; // 4 bytes
DownmixerBufferProvider* downmixerBufferProvider; // 4 bytes
int32_t sessionId;
- audio_format_t mMixerFormat; // at this time: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+ // 16-byte boundary
+ audio_format_t mMixerFormat; // output mix format: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+ audio_format_t mFormat; // input track format
+ audio_format_t mMixerInFormat; // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+ // each track must be converted to this format.
- int32_t padding[1];
+ int32_t mUnused[1]; // alignment padding
// 16-byte boundary
@@ -239,6 +255,35 @@ private:
effect_config_t mDownmixConfig;
};
+ // AudioBufferProvider wrapper that reformats track to acceptable mixer input type
+ class ReformatBufferProvider : public AudioBufferProvider {
+ public:
+ ReformatBufferProvider(int32_t channels,
+ audio_format_t inputFormat, audio_format_t outputFormat);
+ virtual ~ReformatBufferProvider();
+
+ // overrides AudioBufferProvider methods
+ virtual status_t getNextBuffer(Buffer* buffer, int64_t pts);
+ virtual void releaseBuffer(Buffer* buffer);
+
+ void reset();
+ inline bool requiresInternalBuffers() {
+ return true; //mInputFrameSize < mOutputFrameSize;
+ }
+
+ AudioBufferProvider* mTrackBufferProvider;
+ int32_t mChannels;
+ audio_format_t mInputFormat;
+ audio_format_t mOutputFormat;
+ size_t mInputFrameSize;
+ size_t mOutputFrameSize;
+ // (only) required for reformatting to a larger size.
+ AudioBufferProvider::Buffer mBuffer;
+ void* mOutputData;
+ size_t mOutputCount;
+ size_t mConsumed;
+ };
+
// bitmask of allocated track names, where bit 0 corresponds to TRACK0 etc.
uint32_t mTrackNames;
@@ -266,6 +311,9 @@ private:
static status_t initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask);
static status_t prepareTrackForDownmix(track_t* pTrack, int trackNum);
static void unprepareTrackForDownmix(track_t* pTrack, int trackName);
+ static status_t prepareTrackForReformat(track_t* pTrack, int trackNum);
+ static void unprepareTrackForReformat(track_t* pTrack, int trackName);
+ static void reconfigureBufferProviders(track_t* pTrack);
static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp,
int32_t* aux);
diff --git a/services/audioflinger/AudioWatchdog.cpp b/services/audioflinger/AudioWatchdog.cpp
index 93d185e..877e776 100644
--- a/services/audioflinger/AudioWatchdog.cpp
+++ b/services/audioflinger/AudioWatchdog.cpp
@@ -34,7 +34,7 @@ void AudioWatchdogDump::dump(int fd)
} else {
strcpy(buf, "N/A\n");
}
- fdprintf(fd, "Watchdog: underruns=%u, logs=%u, most recent underrun log at %s",
+ dprintf(fd, "Watchdog: underruns=%u, logs=%u, most recent underrun log at %s",
mUnderruns, mLogs, buf);
}
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 1caed11..c840418 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -26,7 +26,6 @@
#define ATRACE_TAG ATRACE_TAG_AUDIO
#include "Configuration.h"
-#include <sys/atomics.h>
#include <time.h>
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -53,8 +52,8 @@ FastMixer::FastMixer() : FastThread(),
outputSink(NULL),
outputSinkGen(0),
mixer(NULL),
- mixBuffer(NULL),
- mixBufferState(UNDEFINED),
+ mMixerBuffer(NULL),
+ mMixerBufferState(UNDEFINED),
format(Format_Invalid),
sampleRate(0),
fastTracksGen(0),
@@ -109,7 +108,7 @@ void FastMixer::onIdle()
void FastMixer::onExit()
{
delete mixer;
- delete[] mixBuffer;
+ delete[] mMixerBuffer;
}
bool FastMixer::isSubClassCommand(FastThreadState::Command command)
@@ -155,14 +154,14 @@ void FastMixer::onStateChange()
// FIXME to avoid priority inversion, don't delete here
delete mixer;
mixer = NULL;
- delete[] mixBuffer;
- mixBuffer = NULL;
+ delete[] mMixerBuffer;
+ mMixerBuffer = NULL;
if (frameCount > 0 && sampleRate > 0) {
// FIXME new may block for unbounded time at internal mutex of the heap
// implementation; it would be better to have normal mixer allocate for us
// to avoid blocking here and to prevent possible priority inversion
mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
- mixBuffer = new short[frameCount * FCC_2];
+ mMixerBuffer = new short[frameCount * FCC_2];
periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00
underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75
overrunNs = (frameCount * 500000000LL) / sampleRate; // 0.50
@@ -175,7 +174,7 @@ void FastMixer::onStateChange()
forceNs = 0;
warmupNs = 0;
}
- mixBufferState = UNDEFINED;
+ mMixerBufferState = UNDEFINED;
#if !LOG_NDEBUG
for (unsigned i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
fastTrackNames[i] = -1;
@@ -193,7 +192,7 @@ void FastMixer::onStateChange()
const unsigned currentTrackMask = current->mTrackMask;
dumpState->mTrackMask = currentTrackMask;
if (current->mFastTracksGen != fastTracksGen) {
- ALOG_ASSERT(mixBuffer != NULL);
+ ALOG_ASSERT(mMixerBuffer != NULL);
int name;
// process removed tracks first to avoid running out of track names
@@ -224,13 +223,16 @@ void FastMixer::onStateChange()
AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1);
if (mixer != NULL) {
- name = mixer->getTrackName(fastTrack->mChannelMask, AUDIO_SESSION_OUTPUT_MIX);
+ name = mixer->getTrackName(fastTrack->mChannelMask,
+ fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX);
ALOG_ASSERT(name >= 0);
fastTrackNames[i] = name;
mixer->setBufferProvider(name, bufferProvider);
mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
- (void *) mixBuffer);
+ (void *) mMixerBuffer);
// newly allocated track names default to full scale volume
+ mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
+ (void *)(uintptr_t)fastTrack->mFormat);
mixer->enable(name);
}
generations[i] = fastTrack->mGeneration;
@@ -259,6 +261,8 @@ void FastMixer::onStateChange()
}
mixer->setParameter(name, AudioMixer::RESAMPLE,
AudioMixer::REMOVE, NULL);
+ mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
+ (void *)(uintptr_t)fastTrack->mFormat);
mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
(void *)(uintptr_t) fastTrack->mChannelMask);
// already enabled
@@ -281,7 +285,7 @@ void FastMixer::onWork()
const size_t frameCount = current->mFrameCount;
if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) {
- ALOG_ASSERT(mixBuffer != NULL);
+ ALOG_ASSERT(mMixerBuffer != NULL);
// for each track, update volume and check for underrun
unsigned currentTrackMask = current->mTrackMask;
while (currentTrackMask != 0) {
@@ -358,26 +362,26 @@ void FastMixer::onWork()
// process() is CPU-bound
mixer->process(pts);
- mixBufferState = MIXED;
- } else if (mixBufferState == MIXED) {
- mixBufferState = UNDEFINED;
+ mMixerBufferState = MIXED;
+ } else if (mMixerBufferState == MIXED) {
+ mMixerBufferState = UNDEFINED;
}
//bool didFullWrite = false; // dumpsys could display a count of partial writes
- if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) {
- if (mixBufferState == UNDEFINED) {
- memset(mixBuffer, 0, frameCount * FCC_2 * sizeof(short));
- mixBufferState = ZEROED;
+ if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mMixerBuffer != NULL)) {
+ if (mMixerBufferState == UNDEFINED) {
+ memset(mMixerBuffer, 0, frameCount * FCC_2 * sizeof(short));
+ mMixerBufferState = ZEROED;
}
// if non-NULL, then duplicate write() to this non-blocking sink
NBAIO_Sink* teeSink;
if ((teeSink = current->mTeeSink) != NULL) {
- (void) teeSink->write(mixBuffer, frameCount);
+ (void) teeSink->write(mMixerBuffer, frameCount);
}
// FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
// but this code should be modified to handle both non-blocking and blocking sinks
dumpState->mWriteSequence++;
ATRACE_BEGIN("write");
- ssize_t framesWritten = outputSink->write(mixBuffer, frameCount);
+ ssize_t framesWritten = outputSink->write(mMixerBuffer, frameCount);
ATRACE_END();
dumpState->mWriteSequence++;
if (framesWritten >= 0) {
@@ -461,7 +465,7 @@ static int compare_uint32_t(const void *pa, const void *pb)
void FastMixerDumpState::dump(int fd) const
{
if (mCommand == FastMixerState::INITIAL) {
- fdprintf(fd, " FastMixer not initialized\n");
+ dprintf(fd, " FastMixer not initialized\n");
return;
}
#define COMMAND_MAX 32
@@ -495,10 +499,10 @@ void FastMixerDumpState::dump(int fd) const
double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) +
(mMeasuredWarmupTs.tv_nsec / 1000000.0);
double mixPeriodSec = (double) mFrameCount / (double) mSampleRate;
- fdprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n"
- " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
- " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
- " mixPeriod=%.2f ms\n",
+ dprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n"
+ " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
+ " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
+ " mixPeriod=%.2f ms\n",
string, mWriteSequence, mFramesWritten,
mNumTracks, mWriteErrors, mUnderruns, mOverruns,
mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
@@ -550,26 +554,26 @@ void FastMixerDumpState::dump(int fd) const
#endif
}
if (n) {
- fdprintf(fd, " Simple moving statistics over last %.1f seconds:\n",
- wall.n() * mixPeriodSec);
- fdprintf(fd, " wall clock time in ms per mix cycle:\n"
- " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
- wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
- wall.stddev()*1e-6);
- fdprintf(fd, " raw CPU load in us per mix cycle:\n"
- " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
- loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
- loadNs.stddev()*1e-3);
+ dprintf(fd, " Simple moving statistics over last %.1f seconds:\n",
+ wall.n() * mixPeriodSec);
+ dprintf(fd, " wall clock time in ms per mix cycle:\n"
+ " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+ wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
+ wall.stddev()*1e-6);
+ dprintf(fd, " raw CPU load in us per mix cycle:\n"
+ " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
+ loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
+ loadNs.stddev()*1e-3);
} else {
- fdprintf(fd, " No FastMixer statistics available currently\n");
+ dprintf(fd, " No FastMixer statistics available currently\n");
}
#ifdef CPU_FREQUENCY_STATISTICS
- fdprintf(fd, " CPU clock frequency in MHz:\n"
- " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
- kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
- fdprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
- " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
- loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
+ dprintf(fd, " CPU clock frequency in MHz:\n"
+ " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
+ kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
+ dprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
+ " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
+ loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
#endif
if (tail != NULL) {
qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
@@ -580,12 +584,12 @@ void FastMixerDumpState::dump(int fd) const
left.sample(tail[i]);
right.sample(tail[n - (i + 1)]);
}
- fdprintf(fd, " Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n"
- " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
- " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
- left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
- right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
- right.stddev()*1e-6);
+ dprintf(fd, " Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n"
+ " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
+ " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+ left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
+ right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
+ right.stddev()*1e-6);
delete[] tail;
}
#endif
@@ -595,9 +599,9 @@ void FastMixerDumpState::dump(int fd) const
// Instead we always display all tracks, with an indication
// of whether we think the track is active.
uint32_t trackMask = mTrackMask;
- fdprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
+ dprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
FastMixerState::kMaxFastTracks, trackMask);
- fdprintf(fd, " Index Active Full Partial Empty Recent Ready\n");
+ dprintf(fd, " Index Active Full Partial Empty Recent Ready\n");
for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
bool isActive = trackMask & 1;
const FastTrackDump *ftDump = &mTracks[i];
@@ -617,7 +621,7 @@ void FastMixerDumpState::dump(int fd) const
mostRecent = "?";
break;
}
- fdprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
+ dprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
(underruns.mBitFields.mFull) & UNDERRUN_MASK,
(underruns.mBitFields.mPartial) & UNDERRUN_MASK,
(underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 981c1a7..db3e2c9 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -17,13 +17,11 @@
#ifndef ANDROID_AUDIO_FAST_MIXER_H
#define ANDROID_AUDIO_FAST_MIXER_H
+#include <linux/futex.h>
+#include <sys/syscall.h>
#include <utils/Debug.h>
-#if 1 // FIXME move to where used
-extern "C" {
-#include "../private/bionic_futex.h"
-}
-#endif
#include "FastThread.h"
+#include <utils/Thread.h>
#include "StateQueue.h"
#include "FastMixerState.h"
#include "FastMixerDumpState.h"
@@ -63,8 +61,8 @@ private:
NBAIO_Sink *outputSink;
int outputSinkGen;
AudioMixer* mixer;
- short *mixBuffer;
- enum {UNDEFINED, MIXED, ZEROED} mixBufferState;
+ short *mMixerBuffer;
+ enum {UNDEFINED, MIXED, ZEROED} mMixerBufferState;
NBAIO_Format format;
unsigned sampleRate;
int fastTracksGen;
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index 8e6d0d4..3aa8dad 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -20,7 +20,7 @@ namespace android {
FastTrack::FastTrack() :
mBufferProvider(NULL), mVolumeProvider(NULL),
- mChannelMask(AUDIO_CHANNEL_OUT_STEREO), mGeneration(0)
+ mChannelMask(AUDIO_CHANNEL_OUT_STEREO), mFormat(AUDIO_FORMAT_INVALID), mGeneration(0)
{
}
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index e388fb3..661c9ca 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -45,6 +45,7 @@ struct FastTrack {
ExtendedAudioBufferProvider* mBufferProvider; // must be NULL if inactive, or non-NULL if active
VolumeProvider* mVolumeProvider; // optional; if NULL then full-scale
audio_channel_mask_t mChannelMask; // AUDIO_CHANNEL_OUT_MONO or AUDIO_CHANNEL_OUT_STEREO
+ audio_format_t mFormat; // track format
int mGeneration; // increment when any field is assigned
};
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index 8a216b3..216dace 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -20,10 +20,9 @@
#define ATRACE_TAG ATRACE_TAG_AUDIO
#include "Configuration.h"
+#include <linux/futex.h>
+#include <sys/syscall.h>
#include <utils/Log.h>
-extern "C" {
-#include "../private/bionic_futex.h"
-}
#include <utils/Trace.h>
#include "FastThread.h"
@@ -157,7 +156,7 @@ bool FastThread::threadLoop()
ALOG_ASSERT(coldFutexAddr != NULL);
int32_t old = android_atomic_dec(coldFutexAddr);
if (old <= 0) {
- __futex_syscall4(coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, NULL);
+ syscall(__NR_futex, coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, NULL);
}
int policy = sched_getscheduler(0);
if (!(policy == SCHED_FIFO || policy == SCHED_RR)) {
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
new file mode 100644
index 0000000..eee74b3
--- /dev/null
+++ b/services/audioflinger/PatchPanel.cpp
@@ -0,0 +1,409 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+
+#define LOG_TAG "AudioFlinger::PatchPanel"
+//#define LOG_NDEBUG 0
+
+#include "Configuration.h"
+#include <utils/Log.h>
+#include <audio_utils/primitives.h>
+
+#include "AudioFlinger.h"
+#include "ServiceUtilities.h"
+#include <media/AudioParameter.h>
+
+// ----------------------------------------------------------------------------
+
+// Note: the following macro is used for extremely verbose logging message. In
+// order to run with ALOG_ASSERT turned on, we need to have LOG_NDEBUG set to
+// 0; but one side effect of this is to turn all LOGV's as well. Some messages
+// are so verbose that we want to suppress them even when we have ALOG_ASSERT
+// turned on. Do not uncomment the #def below unless you really know what you
+// are doing and want to see all of the extremely verbose messages.
+//#define VERY_VERY_VERBOSE_LOGGING
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+namespace android {
+
+/* List connected audio ports and their attributes */
+status_t AudioFlinger::listAudioPorts(unsigned int *num_ports,
+ struct audio_port *ports)
+{
+ Mutex::Autolock _l(mLock);
+ if (mPatchPanel != 0) {
+ return mPatchPanel->listAudioPorts(num_ports, ports);
+ }
+ return NO_INIT;
+}
+
+/* Get supported attributes for a given audio port */
+status_t AudioFlinger::getAudioPort(struct audio_port *port)
+{
+ Mutex::Autolock _l(mLock);
+ if (mPatchPanel != 0) {
+ return mPatchPanel->getAudioPort(port);
+ }
+ return NO_INIT;
+}
+
+
+/* Connect a patch between several source and sink ports */
+status_t AudioFlinger::createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle)
+{
+ Mutex::Autolock _l(mLock);
+ if (mPatchPanel != 0) {
+ return mPatchPanel->createAudioPatch(patch, handle);
+ }
+ return NO_INIT;
+}
+
+/* Disconnect a patch */
+status_t AudioFlinger::releaseAudioPatch(audio_patch_handle_t handle)
+{
+ Mutex::Autolock _l(mLock);
+ if (mPatchPanel != 0) {
+ return mPatchPanel->releaseAudioPatch(handle);
+ }
+ return NO_INIT;
+}
+
+
+/* List connected audio ports and they attributes */
+status_t AudioFlinger::listAudioPatches(unsigned int *num_patches,
+ struct audio_patch *patches)
+{
+ Mutex::Autolock _l(mLock);
+ if (mPatchPanel != 0) {
+ return mPatchPanel->listAudioPatches(num_patches, patches);
+ }
+ return NO_INIT;
+}
+
+/* Set audio port configuration */
+status_t AudioFlinger::setAudioPortConfig(const struct audio_port_config *config)
+{
+ Mutex::Autolock _l(mLock);
+ if (mPatchPanel != 0) {
+ return mPatchPanel->setAudioPortConfig(config);
+ }
+ return NO_INIT;
+}
+
+
+AudioFlinger::PatchPanel::PatchPanel(const sp<AudioFlinger>& audioFlinger)
+ : mAudioFlinger(audioFlinger)
+{
+}
+
+AudioFlinger::PatchPanel::~PatchPanel()
+{
+}
+
+/* List connected audio ports and their attributes */
+status_t AudioFlinger::PatchPanel::listAudioPorts(unsigned int *num_ports __unused,
+ struct audio_port *ports __unused)
+{
+ ALOGV("listAudioPorts");
+ return NO_ERROR;
+}
+
+/* Get supported attributes for a given audio port */
+status_t AudioFlinger::PatchPanel::getAudioPort(struct audio_port *port __unused)
+{
+ ALOGV("getAudioPort");
+ return NO_ERROR;
+}
+
+
+/* Connect a patch between several source and sink ports */
+status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle)
+{
+ ALOGV("createAudioPatch() num_sources %d num_sinks %d handle %d",
+ patch->num_sources, patch->num_sinks, *handle);
+ status_t status = NO_ERROR;
+
+ audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE;
+
+ sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
+ if (audioflinger == 0) {
+ return NO_INIT;
+ }
+ if (handle == NULL || patch == NULL) {
+ return BAD_VALUE;
+ }
+ // limit number of sources to 1 for now
+ if (patch->num_sources == 0 || patch->num_sources > 1 ||
+ patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
+ return BAD_VALUE;
+ }
+
+ for (size_t index = 0; *handle != 0 && index < mPatches.size(); index++) {
+ if (*handle == mPatches[index]->mHandle) {
+ ALOGV("createAudioPatch() removing patch handle %d", *handle);
+ halHandle = mPatches[index]->mHalHandle;
+ mPatches.removeAt(index);
+ break;
+ }
+ }
+
+ switch (patch->sources[0].type) {
+ case AUDIO_PORT_TYPE_DEVICE: {
+ // limit number of sinks to 1 for now
+ if (patch->num_sinks > 1) {
+ return BAD_VALUE;
+ }
+ audio_module_handle_t src_module = patch->sources[0].ext.device.hw_module;
+ ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module);
+ if (index < 0) {
+ ALOGW("createAudioPatch() bad src hw module %d", src_module);
+ return BAD_VALUE;
+ }
+ for (unsigned int i = 0; i < patch->num_sinks; i++) {
+ // limit to connections between devices and output streams
+ if (patch->sinks[i].type != AUDIO_PORT_TYPE_MIX) {
+ ALOGW("createAudioPatch() invalid sink type %d for device source",
+ patch->sinks[i].type);
+ return BAD_VALUE;
+ }
+ // limit to connections between sinks and sources on same HW module
+ if (patch->sinks[i].ext.mix.hw_module != src_module) {
+ ALOGW("createAudioPatch() cannot connect source on module %d to"
+ "sink on module %d", src_module, patch->sinks[i].ext.mix.hw_module);
+ return BAD_VALUE;
+ }
+ }
+
+ AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
+ if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
+ sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
+ patch->sinks[0].ext.mix.handle);
+ if (thread == 0) {
+ ALOGW("createAudioPatch() bad capture I/O handle %d",
+ patch->sinks[0].ext.mix.handle);
+ return BAD_VALUE;
+ }
+ status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+ } else {
+ audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
+ status = hwDevice->create_audio_patch(hwDevice,
+ patch->num_sources,
+ patch->sources,
+ patch->num_sinks,
+ patch->sinks,
+ &halHandle);
+ }
+ } else {
+ sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
+ patch->sinks[0].ext.mix.handle);
+ if (thread == 0) {
+ ALOGW("createAudioPatch() bad capture I/O handle %d",
+ patch->sinks[0].ext.mix.handle);
+ return BAD_VALUE;
+ }
+ AudioParameter param;
+ param.addInt(String8(AudioParameter::keyRouting),
+ (int)patch->sources[0].ext.device.type);
+ param.addInt(String8(AudioParameter::keyInputSource),
+ (int)patch->sinks[0].ext.mix.usecase.source);
+
+ ALOGW("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
+ param.toString().string());
+ status = thread->setParameters(param.toString());
+ }
+ } break;
+ case AUDIO_PORT_TYPE_MIX: {
+ audio_module_handle_t src_module = patch->sources[0].ext.mix.hw_module;
+ ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module);
+ if (index < 0) {
+ ALOGW("createAudioPatch() bad src hw module %d", src_module);
+ return BAD_VALUE;
+ }
+ // limit to connections between devices and output streams
+ for (unsigned int i = 0; i < patch->num_sinks; i++) {
+ if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
+ ALOGW("createAudioPatch() invalid sink type %d for bus source",
+ patch->sinks[i].type);
+ return BAD_VALUE;
+ }
+ // limit to connections between sinks and sources on same HW module
+ if (patch->sinks[i].ext.device.hw_module != src_module) {
+ return BAD_VALUE;
+ }
+ }
+ AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
+ sp<ThreadBase> thread =
+ audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
+ if (thread == 0) {
+ ALOGW("createAudioPatch() bad playback I/O handle %d",
+ patch->sources[0].ext.mix.handle);
+ return BAD_VALUE;
+ }
+ if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+ } else {
+ audio_devices_t type = AUDIO_DEVICE_NONE;
+ for (unsigned int i = 0; i < patch->num_sinks; i++) {
+ type |= patch->sinks[i].ext.device.type;
+ }
+ AudioParameter param;
+ param.addInt(String8(AudioParameter::keyRouting), (int)type);
+ status = thread->setParameters(param.toString());
+ }
+
+ } break;
+ default:
+ return BAD_VALUE;
+ }
+ ALOGV("createAudioPatch() status %d", status);
+ if (status == NO_ERROR) {
+ *handle = audioflinger->nextUniqueId();
+ Patch *newPatch = new Patch(patch);
+ newPatch->mHandle = *handle;
+ newPatch->mHalHandle = halHandle;
+ mPatches.add(newPatch);
+ ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle);
+ }
+ return status;
+}
+
+/* Disconnect a patch */
+status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle)
+{
+ ALOGV("releaseAudioPatch handle %d", handle);
+ status_t status = NO_ERROR;
+ size_t index;
+
+ sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
+ if (audioflinger == 0) {
+ return NO_INIT;
+ }
+
+ for (index = 0; index < mPatches.size(); index++) {
+ if (handle == mPatches[index]->mHandle) {
+ break;
+ }
+ }
+ if (index == mPatches.size()) {
+ return BAD_VALUE;
+ }
+
+ struct audio_patch *patch = &mPatches[index]->mAudioPatch;
+
+ switch (patch->sources[0].type) {
+ case AUDIO_PORT_TYPE_DEVICE: {
+ audio_module_handle_t src_module = patch->sources[0].ext.device.hw_module;
+ ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module);
+ if (index < 0) {
+ ALOGW("releaseAudioPatch() bad src hw module %d", src_module);
+ status = BAD_VALUE;
+ break;
+ }
+ AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
+ if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
+ sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
+ patch->sinks[0].ext.mix.handle);
+ if (thread == 0) {
+ ALOGW("createAudioPatch() bad capture I/O handle %d",
+ patch->sinks[0].ext.mix.handle);
+ status = BAD_VALUE;
+ break;
+ }
+ status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle);
+ } else {
+ audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
+ status = hwDevice->release_audio_patch(hwDevice, mPatches[index]->mHalHandle);
+ }
+ } else {
+ sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
+ patch->sinks[0].ext.mix.handle);
+ if (thread == 0) {
+ ALOGW("releaseAudioPatch() bad capture I/O handle %d",
+ patch->sinks[0].ext.mix.handle);
+ status = BAD_VALUE;
+ break;
+ }
+ AudioParameter param;
+ param.addInt(String8(AudioParameter::keyRouting), 0);
+ ALOGW("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
+ param.toString().string());
+ status = thread->setParameters(param.toString());
+ }
+ } break;
+ case AUDIO_PORT_TYPE_MIX: {
+ audio_module_handle_t src_module = patch->sources[0].ext.mix.hw_module;
+ ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module);
+ if (index < 0) {
+ ALOGW("releaseAudioPatch() bad src hw module %d", src_module);
+ status = BAD_VALUE;
+ break;
+ }
+ sp<ThreadBase> thread =
+ audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
+ if (thread == 0) {
+ ALOGW("releaseAudioPatch() bad playback I/O handle %d",
+ patch->sources[0].ext.mix.handle);
+ status = BAD_VALUE;
+ break;
+ }
+ AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
+ if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle);
+ } else {
+ AudioParameter param;
+ param.addInt(String8(AudioParameter::keyRouting), (int)0);
+ status = thread->setParameters(param.toString());
+ }
+ } break;
+ default:
+ status = BAD_VALUE;
+ break;
+ }
+
+ delete (mPatches[index]);
+ mPatches.removeAt(index);
+ return status;
+}
+
+
+/* List connected audio ports and they attributes */
+status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused,
+ struct audio_patch *patches __unused)
+{
+ ALOGV("listAudioPatches");
+ return NO_ERROR;
+}
+
+/* Set audio port configuration */
+status_t AudioFlinger::PatchPanel::setAudioPortConfig(
+ const struct audio_port_config *config __unused)
+{
+ ALOGV("setAudioPortConfig");
+ return NO_ERROR;
+}
+
+
+
+}; // namespace android
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
new file mode 100644
index 0000000..7f78621
--- /dev/null
+++ b/services/audioflinger/PatchPanel.h
@@ -0,0 +1,60 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef INCLUDING_FROM_AUDIOFLINGER_H
+ #error This header file should only be included from AudioFlinger.h
+#endif
+
+class PatchPanel : public RefBase {
+public:
+ PatchPanel(const sp<AudioFlinger>& audioFlinger);
+ virtual ~PatchPanel();
+
+ /* List connected audio ports and their attributes */
+ status_t listAudioPorts(unsigned int *num_ports,
+ struct audio_port *ports);
+
+ /* Get supported attributes for a given audio port */
+ status_t getAudioPort(struct audio_port *port);
+
+ /* Create a patch between several source and sink ports */
+ status_t createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle);
+
+ /* Release a patch */
+ status_t releaseAudioPatch(audio_patch_handle_t handle);
+
+ /* List connected audio devices and they attributes */
+ status_t listAudioPatches(unsigned int *num_patches,
+ struct audio_patch *patches);
+
+ /* Set audio port configuration */
+ status_t setAudioPortConfig(const struct audio_port_config *config);
+
+ class Patch {
+ public:
+ Patch(const struct audio_patch *patch) :
+ mAudioPatch(*patch), mHandle(0), mHalHandle(0) {}
+
+ struct audio_patch mAudioPatch;
+ audio_patch_handle_t mHandle;
+ audio_patch_handle_t mHalHandle;
+ };
+private:
+ const wp<AudioFlinger> mAudioFlinger;
+ SortedVector <Patch *> mPatches;
+};
diff --git a/services/audioflinger/StateQueue.cpp b/services/audioflinger/StateQueue.cpp
index 48399c0..7e01c9f 100644
--- a/services/audioflinger/StateQueue.cpp
+++ b/services/audioflinger/StateQueue.cpp
@@ -28,12 +28,12 @@ namespace android {
#ifdef STATE_QUEUE_DUMP
void StateQueueObserverDump::dump(int fd)
{
- fdprintf(fd, "State queue observer: stateChanges=%u\n", mStateChanges);
+ dprintf(fd, "State queue observer: stateChanges=%u\n", mStateChanges);
}
void StateQueueMutatorDump::dump(int fd)
{
- fdprintf(fd, "State queue mutator: pushDirty=%u pushAck=%u blockedSequence=%u\n",
+ dprintf(fd, "State queue mutator: pushDirty=%u pushAck=%u blockedSequence=%u\n",
mPushDirty, mPushAck, mBlockedSequence);
}
#endif
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index ce08ff1..576350e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -142,8 +142,17 @@ static const int kPriorityFastMixer = 3;
// FIXME It would be better for client to tell AudioFlinger the value of N,
// so AudioFlinger could allocate the right amount of memory.
// See the client's minBufCount and mNotificationFramesAct calculations for details.
+
+// This is the default value, if not specified by property.
static const int kFastTrackMultiplier = 2;
+// The minimum and maximum allowed values
+static const int kFastTrackMultiplierMin = 1;
+static const int kFastTrackMultiplierMax = 2;
+
+// The actual value to use, which can be specified per-device via property af.fast_track_multiplier.
+static int sFastTrackMultiplier = kFastTrackMultiplier;
+
// See Thread::readOnlyHeap().
// Initially this heap is used to allocate client buffers for "fast" AudioRecord.
// Eventually it will be the single buffer that FastCapture writes into via HAL read(),
@@ -152,6 +161,22 @@ static const size_t kRecordThreadReadOnlyHeapSize = 0x1000;
// ----------------------------------------------------------------------------
+static pthread_once_t sFastTrackMultiplierOnce = PTHREAD_ONCE_INIT;
+
+static void sFastTrackMultiplierInit()
+{
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("af.fast_track_multiplier", value, NULL) > 0) {
+ char *endptr;
+ unsigned long ul = strtoul(value, &endptr, 0);
+ if (*endptr == '\0' && kFastTrackMultiplierMin <= ul && ul <= kFastTrackMultiplierMax) {
+ sFastTrackMultiplier = (int) ul;
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
#ifdef ADD_BATTERY_DATA
// To collect the amplifier usage
static void addBatteryData(uint32_t params) {
@@ -401,6 +426,30 @@ status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8&
return sendConfigEvent_l(configEvent);
}
+status_t AudioFlinger::ThreadBase::sendCreateAudioPatchConfigEvent(
+ const struct audio_patch *patch,
+ audio_patch_handle_t *handle)
+{
+ Mutex::Autolock _l(mLock);
+ sp<ConfigEvent> configEvent = (ConfigEvent *)new CreateAudioPatchConfigEvent(*patch, *handle);
+ status_t status = sendConfigEvent_l(configEvent);
+ if (status == NO_ERROR) {
+ CreateAudioPatchConfigEventData *data =
+ (CreateAudioPatchConfigEventData *)configEvent->mData.get();
+ *handle = data->mHandle;
+ }
+ return status;
+}
+
+status_t AudioFlinger::ThreadBase::sendReleaseAudioPatchConfigEvent(
+ const audio_patch_handle_t handle)
+{
+ Mutex::Autolock _l(mLock);
+ sp<ConfigEvent> configEvent = (ConfigEvent *)new ReleaseAudioPatchConfigEvent(handle);
+ return sendConfigEvent_l(configEvent);
+}
+
+
// post condition: mConfigEvents.isEmpty()
void AudioFlinger::ThreadBase::processConfigEvents_l()
{
@@ -431,6 +480,16 @@ void AudioFlinger::ThreadBase::processConfigEvents_l()
configChanged = true;
}
} break;
+ case CFG_EVENT_CREATE_AUDIO_PATCH: {
+ CreateAudioPatchConfigEventData *data =
+ (CreateAudioPatchConfigEventData *)event->mData.get();
+ event->mStatus = createAudioPatch_l(&data->mPatch, &data->mHandle);
+ } break;
+ case CFG_EVENT_RELEASE_AUDIO_PATCH: {
+ ReleaseAudioPatchConfigEventData *data =
+ (ReleaseAudioPatchConfigEventData *)event->mData.get();
+ event->mStatus = releaseAudioPatch_l(data->mHandle);
+ } break;
default:
ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType);
break;
@@ -505,30 +564,30 @@ void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __u
bool locked = AudioFlinger::dumpTryLock(mLock);
if (!locked) {
- fdprintf(fd, "thread %p maybe dead locked\n", this);
+ dprintf(fd, "thread %p maybe dead locked\n", this);
}
- fdprintf(fd, " I/O handle: %d\n", mId);
- fdprintf(fd, " TID: %d\n", getTid());
- fdprintf(fd, " Standby: %s\n", mStandby ? "yes" : "no");
- fdprintf(fd, " Sample rate: %u\n", mSampleRate);
- fdprintf(fd, " HAL frame count: %zu\n", mFrameCount);
- fdprintf(fd, " HAL buffer size: %u bytes\n", mBufferSize);
- fdprintf(fd, " Channel Count: %u\n", mChannelCount);
- fdprintf(fd, " Channel Mask: 0x%08x (%s)\n", mChannelMask,
+ dprintf(fd, " I/O handle: %d\n", mId);
+ dprintf(fd, " TID: %d\n", getTid());
+ dprintf(fd, " Standby: %s\n", mStandby ? "yes" : "no");
+ dprintf(fd, " Sample rate: %u\n", mSampleRate);
+ dprintf(fd, " HAL frame count: %zu\n", mFrameCount);
+ dprintf(fd, " HAL buffer size: %u bytes\n", mBufferSize);
+ dprintf(fd, " Channel Count: %u\n", mChannelCount);
+ dprintf(fd, " Channel Mask: 0x%08x (%s)\n", mChannelMask,
channelMaskToString(mChannelMask, mType != RECORD).string());
- fdprintf(fd, " Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
- fdprintf(fd, " Frame size: %zu\n", mFrameSize);
- fdprintf(fd, " Pending config events:");
+ dprintf(fd, " Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
+ dprintf(fd, " Frame size: %zu\n", mFrameSize);
+ dprintf(fd, " Pending config events:");
size_t numConfig = mConfigEvents.size();
if (numConfig) {
for (size_t i = 0; i < numConfig; i++) {
mConfigEvents[i]->dump(buffer, SIZE);
- fdprintf(fd, "\n %s", buffer);
+ dprintf(fd, "\n %s", buffer);
}
- fdprintf(fd, "\n");
+ dprintf(fd, "\n");
} else {
- fdprintf(fd, " none\n");
+ dprintf(fd, " none\n");
}
if (locked) {
@@ -1191,15 +1250,15 @@ void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& ar
// These values are "raw"; they will wrap around. See prepareTracks_l() for a better way.
FastTrackUnderruns underruns = getFastTrackUnderruns(0);
- fdprintf(fd, " Normal mixer raw underrun counters: partial=%u empty=%u\n",
+ dprintf(fd, " Normal mixer raw underrun counters: partial=%u empty=%u\n",
underruns.mBitFields.mPartial, underruns.mBitFields.mEmpty);
size_t numtracks = mTracks.size();
size_t numactive = mActiveTracks.size();
- fdprintf(fd, " %d Tracks", numtracks);
+ dprintf(fd, " %d Tracks", numtracks);
size_t numactiveseen = 0;
if (numtracks) {
- fdprintf(fd, " of which %d are active\n", numactive);
+ dprintf(fd, " of which %d are active\n", numactive);
Track::appendDumpHeader(result);
for (size_t i = 0; i < numtracks; ++i) {
sp<Track> track = mTracks[i];
@@ -1231,22 +1290,21 @@ void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& ar
}
write(fd, result.string(), result.size());
-
}
void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
{
- fdprintf(fd, "\nOutput thread %p:\n", this);
- fdprintf(fd, " Normal frame count: %zu\n", mNormalFrameCount);
- fdprintf(fd, " Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
- fdprintf(fd, " Total writes: %d\n", mNumWrites);
- fdprintf(fd, " Delayed writes: %d\n", mNumDelayedWrites);
- fdprintf(fd, " Blocked in write: %s\n", mInWrite ? "yes" : "no");
- fdprintf(fd, " Suspend count: %d\n", mSuspended);
- fdprintf(fd, " Sink buffer : %p\n", mSinkBuffer);
- fdprintf(fd, " Mixer buffer: %p\n", mMixerBuffer);
- fdprintf(fd, " Effect buffer: %p\n", mEffectBuffer);
- fdprintf(fd, " Fast track availMask=%#x\n", mFastTrackAvailMask);
+ dprintf(fd, "\nOutput thread %p:\n", this);
+ dprintf(fd, " Normal frame count: %zu\n", mNormalFrameCount);
+ dprintf(fd, " Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
+ dprintf(fd, " Total writes: %d\n", mNumWrites);
+ dprintf(fd, " Delayed writes: %d\n", mNumDelayedWrites);
+ dprintf(fd, " Blocked in write: %s\n", mInWrite ? "yes" : "no");
+ dprintf(fd, " Suspend count: %d\n", mSuspended);
+ dprintf(fd, " Sink buffer : %p\n", mSinkBuffer);
+ dprintf(fd, " Mixer buffer: %p\n", mMixerBuffer);
+ dprintf(fd, " Effect buffer: %p\n", mEffectBuffer);
+ dprintf(fd, " Fast track availMask=%#x\n", mFastTrackAvailMask);
dumpBase(fd, args);
}
@@ -1322,7 +1380,12 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
) {
// if frameCount not specified, then it defaults to fast mixer (HAL) frame count
if (frameCount == 0) {
- frameCount = mFrameCount * kFastTrackMultiplier;
+ // read the fast track multiplier property the first time it is needed
+ int ok = pthread_once(&sFastTrackMultiplierOnce, sFastTrackMultiplierInit);
+ if (ok != 0) {
+ ALOGE("%s pthread_once failed: %d", __func__, ok);
+ }
+ frameCount = mFrameCount * sFastTrackMultiplier;
}
ALOGV("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d",
frameCount, mFrameCount);
@@ -2594,6 +2657,47 @@ status_t AudioFlinger::PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp)
}
return INVALID_OPERATION;
}
+
+status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_patch *patch,
+ audio_patch_handle_t *handle)
+{
+ status_t status = NO_ERROR;
+ if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ // store new device and send to effects
+ audio_devices_t type = AUDIO_DEVICE_NONE;
+ for (unsigned int i = 0; i < patch->num_sinks; i++) {
+ type |= patch->sinks[i].ext.device.type;
+ }
+ mOutDevice = type;
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ mEffectChains[i]->setDevice_l(mOutDevice);
+ }
+
+ audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice();
+ status = hwDevice->create_audio_patch(hwDevice,
+ patch->num_sources,
+ patch->sources,
+ patch->num_sinks,
+ patch->sinks,
+ handle);
+ } else {
+ ALOG_ASSERT(false, "createAudioPatch_l() called on a pre 3.0 HAL");
+ }
+ return status;
+}
+
+status_t AudioFlinger::PlaybackThread::releaseAudioPatch_l(const audio_patch_handle_t handle)
+{
+ status_t status = NO_ERROR;
+ if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice();
+ status = hwDevice->release_audio_patch(hwDevice, handle);
+ } else {
+ ALOG_ASSERT(false, "releaseAudioPatch_l() called on a pre 3.0 HAL");
+ }
+ return status;
+}
+
// ----------------------------------------------------------------------------
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
@@ -2683,6 +2787,8 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
// wrap the source side of the MonoPipe to make it an AudioBufferProvider
fastTrack->mBufferProvider = new SourceAudioBufferProvider(new MonoPipeReader(monoPipe));
fastTrack->mVolumeProvider = NULL;
+ fastTrack->mChannelMask = mChannelMask; // mPipeSink channel mask for audio to FastMixer
+ fastTrack->mFormat = mFormat; // mPipeSink format for audio to FastMixer
fastTrack->mGeneration++;
state->mFastTracksGen++;
state->mTrackMask = 1;
@@ -2752,7 +2858,7 @@ AudioFlinger::MixerThread::~MixerThread()
if (state->mCommand == FastMixerState::COLD_IDLE) {
int32_t old = android_atomic_inc(&mFastMixerFutex);
if (old == -1) {
- (void) __futex_syscall3(&mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1);
+ (void) syscall(__NR_futex, &mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1);
}
}
state->mCommand = FastMixerState::EXIT;
@@ -2809,7 +2915,7 @@ ssize_t AudioFlinger::MixerThread::threadLoop_write()
if (state->mCommand == FastMixerState::COLD_IDLE) {
int32_t old = android_atomic_inc(&mFastMixerFutex);
if (old == -1) {
- (void) __futex_syscall3(&mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1);
+ (void) syscall(__NR_futex, &mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1);
}
#ifdef AUDIO_WATCHDOG
if (mAudioWatchdog != 0) {
@@ -3135,6 +3241,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
fastTrack->mBufferProvider = eabp;
fastTrack->mVolumeProvider = vp;
fastTrack->mChannelMask = track->mChannelMask;
+ fastTrack->mFormat = track->mFormat;
fastTrack->mGeneration++;
state->mTrackMask |= 1 << j;
didModify = true;
@@ -3526,9 +3633,10 @@ track_is_ready: ;
}
// getTrackName_l() must be called with ThreadBase::mLock held
-int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask, int sessionId)
+int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId)
{
- return mAudioMixer->getTrackName(channelMask, sessionId);
+ return mAudioMixer->getTrackName(channelMask, format, sessionId);
}
// deleteTrackName_l() must be called with ThreadBase::mLock held
@@ -3641,7 +3749,8 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa
delete mAudioMixer;
mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
for (size_t i = 0; i < mTracks.size() ; i++) {
- int name = getTrackName_l(mTracks[i]->mChannelMask, mTracks[i]->mSessionId);
+ int name = getTrackName_l(mTracks[i]->mChannelMask,
+ mTracks[i]->mFormat, mTracks[i]->mSessionId);
if (name < 0) {
break;
}
@@ -3673,7 +3782,7 @@ void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& ar
PlaybackThread::dumpInternals(fd, args);
- fdprintf(fd, " AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
+ dprintf(fd, " AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
// Make a non-atomic copy of fast mixer dump state so it won't change underneath us
const FastMixerDumpState copy(mFastMixerDumpState);
@@ -3932,7 +4041,7 @@ void AudioFlinger::DirectOutputThread::threadLoop_sleepTime()
// getTrackName_l() must be called with ThreadBase::mLock held
int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused,
- int sessionId __unused)
+ audio_format_t format __unused, int sessionId __unused)
{
return 0;
}
@@ -5128,6 +5237,7 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe
// to be at least 2 x the record thread frame count and cover audio hardware latency.
// This is probably too conservative, but legacy application code may depend on it.
// If you change this calculation, also review the start threshold which is related.
+ // FIXME It's not clear how input latency actually matters. Perhaps this should be 0.
uint32_t latencyMs = 50; // FIXME mInput->stream->get_latency(mInput->stream);
size_t mNormalFrameCount = 2048; // FIXME
uint32_t minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate);
@@ -5360,12 +5470,12 @@ void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& args)
{
- fdprintf(fd, "\nInput thread %p:\n", this);
+ dprintf(fd, "\nInput thread %p:\n", this);
if (mActiveTracks.size() > 0) {
- fdprintf(fd, " Buffer size: %zu bytes\n", mBufferSize);
+ dprintf(fd, " Buffer size: %zu bytes\n", mBufferSize);
} else {
- fdprintf(fd, " No active record clients\n");
+ dprintf(fd, " No active record clients\n");
}
dumpBase(fd, args);
@@ -5380,9 +5490,9 @@ void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args
size_t numtracks = mTracks.size();
size_t numactive = mActiveTracks.size();
size_t numactiveseen = 0;
- fdprintf(fd, " %d Tracks", numtracks);
+ dprintf(fd, " %d Tracks", numtracks);
if (numtracks) {
- fdprintf(fd, " of which %d are active\n", numactive);
+ dprintf(fd, " of which %d are active\n", numactive);
RecordTrack::appendDumpHeader(result);
for (size_t i = 0; i < numtracks ; ++i) {
sp<RecordTrack> track = mTracks[i];
@@ -5396,7 +5506,7 @@ void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args
}
}
} else {
- fdprintf(fd, "\n");
+ dprintf(fd, "\n");
}
if (numactiveseen != numactive) {
@@ -5743,4 +5853,61 @@ size_t AudioFlinger::RecordThread::removeEffectChain_l(const sp<EffectChain>& ch
return 0;
}
+status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch *patch,
+ audio_patch_handle_t *handle)
+{
+ status_t status = NO_ERROR;
+ if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ // store new device and send to effects
+ mInDevice = patch->sources[0].ext.device.type;
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ mEffectChains[i]->setDevice_l(mInDevice);
+ }
+
+ // disable AEC and NS if the device is a BT SCO headset supporting those
+ // pre processings
+ if (mTracks.size() > 0) {
+ bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
+ mAudioFlinger->btNrecIsOff();
+ for (size_t i = 0; i < mTracks.size(); i++) {
+ sp<RecordTrack> track = mTracks[i];
+ setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
+ setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
+ }
+ }
+
+ // store new source and send to effects
+ if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) {
+ mAudioSource = patch->sinks[0].ext.mix.usecase.source;
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ mEffectChains[i]->setAudioSource_l(mAudioSource);
+ }
+ }
+
+ audio_hw_device_t *hwDevice = mInput->audioHwDev->hwDevice();
+ status = hwDevice->create_audio_patch(hwDevice,
+ patch->num_sources,
+ patch->sources,
+ patch->num_sinks,
+ patch->sinks,
+ handle);
+ } else {
+ ALOG_ASSERT(false, "createAudioPatch_l() called on a pre 3.0 HAL");
+ }
+ return status;
+}
+
+status_t AudioFlinger::RecordThread::releaseAudioPatch_l(const audio_patch_handle_t handle)
+{
+ status_t status = NO_ERROR;
+ if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ audio_hw_device_t *hwDevice = mInput->audioHwDev->hwDevice();
+ status = hwDevice->release_audio_patch(hwDevice, handle);
+ } else {
+ ALOG_ASSERT(false, "releaseAudioPatch_l() called on a pre 3.0 HAL");
+ }
+ return status;
+}
+
+
}; // namespace android
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index cc2b246..8c9943c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -48,6 +48,8 @@ public:
CFG_EVENT_IO,
CFG_EVENT_PRIO,
CFG_EVENT_SET_PARAMETER,
+ CFG_EVENT_CREATE_AUDIO_PATCH,
+ CFG_EVENT_RELEASE_AUDIO_PATCH,
};
class ConfigEventData: public RefBase {
@@ -161,6 +163,52 @@ public:
virtual ~SetParameterConfigEvent() {}
};
+ class CreateAudioPatchConfigEventData : public ConfigEventData {
+ public:
+ CreateAudioPatchConfigEventData(const struct audio_patch patch,
+ audio_patch_handle_t handle) :
+ mPatch(patch), mHandle(handle) {}
+
+ virtual void dump(char *buffer, size_t size) {
+ snprintf(buffer, size, "Patch handle: %u\n", mHandle);
+ }
+
+ const struct audio_patch mPatch;
+ audio_patch_handle_t mHandle;
+ };
+
+ class CreateAudioPatchConfigEvent : public ConfigEvent {
+ public:
+ CreateAudioPatchConfigEvent(const struct audio_patch patch,
+ audio_patch_handle_t handle) :
+ ConfigEvent(CFG_EVENT_CREATE_AUDIO_PATCH) {
+ mData = new CreateAudioPatchConfigEventData(patch, handle);
+ mWaitStatus = true;
+ }
+ virtual ~CreateAudioPatchConfigEvent() {}
+ };
+
+ class ReleaseAudioPatchConfigEventData : public ConfigEventData {
+ public:
+ ReleaseAudioPatchConfigEventData(const audio_patch_handle_t handle) :
+ mHandle(handle) {}
+
+ virtual void dump(char *buffer, size_t size) {
+ snprintf(buffer, size, "Patch handle: %u\n", mHandle);
+ }
+
+ audio_patch_handle_t mHandle;
+ };
+
+ class ReleaseAudioPatchConfigEvent : public ConfigEvent {
+ public:
+ ReleaseAudioPatchConfigEvent(const audio_patch_handle_t handle) :
+ ConfigEvent(CFG_EVENT_RELEASE_AUDIO_PATCH) {
+ mData = new ReleaseAudioPatchConfigEventData(handle);
+ mWaitStatus = true;
+ }
+ virtual ~ReleaseAudioPatchConfigEvent() {}
+ };
class PMDeathRecipient : public IBinder::DeathRecipient {
public:
@@ -209,8 +257,15 @@ public:
void sendIoConfigEvent_l(int event, int param = 0);
void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
status_t sendSetParameterConfigEvent_l(const String8& keyValuePair);
+ status_t sendCreateAudioPatchConfigEvent(const struct audio_patch *patch,
+ audio_patch_handle_t *handle);
+ status_t sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle);
void processConfigEvents_l();
virtual void cacheParameters_l() = 0;
+ virtual status_t createAudioPatch_l(const struct audio_patch *patch,
+ audio_patch_handle_t *handle) = 0;
+ virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle) = 0;
+
// see note at declaration of mStandby, mOutDevice and mInDevice
bool standby() const { return mStandby; }
@@ -301,6 +356,8 @@ public:
// If a thread does not have such a heap, this method returns 0.
virtual sp<MemoryDealer> readOnlyHeap() const { return 0; }
+ virtual sp<IMemory> pipeMemory() const { return 0; }
+
mutable Mutex mLock;
protected:
@@ -619,7 +676,8 @@ protected:
// Allocate a track name for a given channel mask.
// Returns name >= 0 if successful, -1 on failure.
- virtual int getTrackName_l(audio_channel_mask_t channelMask, int sessionId) = 0;
+ virtual int getTrackName_l(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId) = 0;
virtual void deleteTrackName_l(int name) = 0;
// Time to sleep between cycles when:
@@ -641,6 +699,10 @@ protected:
virtual uint32_t correctLatency_l(uint32_t latency) const;
+ virtual status_t createAudioPatch_l(const struct audio_patch *patch,
+ audio_patch_handle_t *handle);
+ virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle);
+
private:
friend class AudioFlinger; // for numerous
@@ -772,7 +834,8 @@ public:
protected:
virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
- virtual int getTrackName_l(audio_channel_mask_t channelMask, int sessionId);
+ virtual int getTrackName_l(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId);
virtual void deleteTrackName_l(int name);
virtual uint32_t idleSleepTimeUs() const;
virtual uint32_t suspendSleepTimeUs() const;
@@ -825,7 +888,8 @@ public:
status_t& status);
protected:
- virtual int getTrackName_l(audio_channel_mask_t channelMask, int sessionId);
+ virtual int getTrackName_l(audio_channel_mask_t channelMask,
+ audio_format_t format, int sessionId);
virtual void deleteTrackName_l(int name);
virtual uint32_t activeSleepTimeUs() const;
virtual uint32_t idleSleepTimeUs() const;
@@ -1030,6 +1094,9 @@ public:
virtual void cacheParameters_l() {}
virtual String8 getParameters(const String8& keys);
virtual void audioConfigChanged(int event, int param = 0);
+ virtual status_t createAudioPatch_l(const struct audio_patch *patch,
+ audio_patch_handle_t *handle);
+ virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle);
void readInputParameters_l();
virtual uint32_t getInputFramesLost();
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 5f13be3..4cba3fd 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -39,6 +39,13 @@ public:
STARTING_2, // for RecordTrack only
};
+ // where to allocate the data buffer
+ enum alloc_type {
+ ALLOC_CBLK, // allocate immediately after control block
+ ALLOC_READONLY, // allocate from a separate read-only heap per thread
+ ALLOC_PIPE, // do not allocate; use the pipe buffer
+ };
+
TrackBase(ThreadBase *thread,
const sp<Client>& client,
uint32_t sampleRate,
@@ -50,7 +57,7 @@ public:
int uid,
IAudioFlinger::track_flags_t flags,
bool isOut,
- bool useReadOnlyHeap = false);
+ alloc_type alloc = ALLOC_CBLK);
virtual ~TrackBase();
virtual status_t initCheck() const { return getCblk() != 0 ? NO_ERROR : NO_MEMORY; }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index de1782d..7ddc71c 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -21,6 +21,7 @@
#include "Configuration.h"
#include <math.h>
+#include <sys/syscall.h>
#include <utils/Log.h>
#include <private/media/AudioTrackShared.h>
@@ -72,7 +73,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
int clientUid,
IAudioFlinger::track_flags_t flags,
bool isOut,
- bool useReadOnlyHeap)
+ alloc_type alloc)
: RefBase(),
mThread(thread),
mClient(client),
@@ -116,7 +117,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
// ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
size_t size = sizeof(audio_track_cblk_t);
size_t bufferSize = (sharedBuffer == 0 ? roundup(frameCount) : frameCount) * mFrameSize;
- if (sharedBuffer == 0 && !useReadOnlyHeap) {
+ if (sharedBuffer == 0 && alloc == ALLOC_CBLK) {
size += bufferSize;
}
@@ -138,7 +139,8 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
// construct the shared structure in-place.
if (mCblk != NULL) {
new(mCblk) audio_track_cblk_t();
- if (useReadOnlyHeap) {
+ switch (alloc) {
+ case ALLOC_READONLY: {
const sp<MemoryDealer> roHeap(thread->readOnlyHeap());
if (roHeap == 0 ||
(mBufferMemory = roHeap->allocate(bufferSize)) == 0 ||
@@ -152,7 +154,17 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
return;
}
memset(mBuffer, 0, bufferSize);
- } else {
+ } break;
+ case ALLOC_PIPE:
+ mBufferMemory = thread->pipeMemory();
+ // mBuffer is the virtual address as seen from current process (mediaserver),
+ // and should normally be coming from mBufferMemory->pointer().
+ // However in this case the TrackBase does not reference the buffer directly.
+ // It should references the buffer via the pipe.
+ // Therefore, to detect incorrect usage of the buffer, we set mBuffer to NULL.
+ mBuffer = NULL;
+ break;
+ case ALLOC_CBLK:
// clear all buffers
if (sharedBuffer == 0) {
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
@@ -163,6 +175,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
mCblk->mFlags = CBLK_FORCEREADY; // FIXME hack, need to fix the track ready logic
#endif
}
+ break;
}
#ifdef TEE_SINK
@@ -384,7 +397,7 @@ AudioFlinger::PlaybackThread::Track::Track(
}
mServerProxy = mAudioTrackServerProxy;
- mName = thread->getTrackName_l(channelMask, sessionId);
+ mName = thread->getTrackName_l(channelMask, format, sessionId);
if (mName < 0) {
ALOGE("no more track names available");
return;
@@ -1008,7 +1021,7 @@ void AudioFlinger::PlaybackThread::Track::invalidate()
android_atomic_or(CBLK_INVALID, &cblk->mFlags);
android_atomic_release_store(0x40000000, &cblk->mFutex);
// client is not in server, so FUTEX_WAKE is needed instead of FUTEX_WAKE_PRIVATE
- (void) __futex_syscall3(&cblk->mFutex, FUTEX_WAKE, INT_MAX);
+ (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, INT_MAX);
mIsInvalid = true;
}
@@ -1841,7 +1854,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
: TrackBase(thread, client, sampleRate, format,
channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid,
flags, false /*isOut*/,
- (flags & IAudioFlinger::TRACK_FAST) != 0 /*useReadOnlyHeap*/),
+ (flags & IAudioFlinger::TRACK_FAST) != 0 ? ALLOC_READONLY : ALLOC_CBLK),
mOverflow(false), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0),
// See real initialization of mRsmpInFront at RecordThread::start()
mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL)
@@ -1937,7 +1950,7 @@ void AudioFlinger::RecordThread::RecordTrack::invalidate()
android_atomic_or(CBLK_INVALID, &cblk->mFlags);
android_atomic_release_store(0x40000000, &cblk->mFutex);
// client is not in server, so FUTEX_WAKE is needed instead of FUTEX_WAKE_PRIVATE
- (void) __futex_syscall3(&cblk->mFutex, FUTEX_WAKE, INT_MAX);
+ (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, INT_MAX);
}
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index f270bfc..a22ad9d 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -5,7 +5,6 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
AudioPolicyService.cpp
-USE_LEGACY_AUDIO_POLICY = 1
ifeq ($(USE_LEGACY_AUDIO_POLICY), 1)
LOCAL_SRC_FILES += \
AudioPolicyInterfaceImplLegacy.cpp \
@@ -15,8 +14,7 @@ LOCAL_SRC_FILES += \
else
LOCAL_SRC_FILES += \
AudioPolicyInterfaceImpl.cpp \
- AudioPolicyClientImpl.cpp \
- AudioPolicyManager.cpp
+ AudioPolicyClientImpl.cpp
endif
LOCAL_C_INCLUDES := \
@@ -31,14 +29,42 @@ LOCAL_SHARED_LIBRARIES := \
libbinder \
libmedia \
libhardware \
- libhardware_legacy
+ libhardware_legacy \
+
+ifneq ($(USE_LEGACY_AUDIO_POLICY), 1)
+LOCAL_SHARED_LIBRARIES += \
+ libaudiopolicymanager
+endif
LOCAL_STATIC_LIBRARIES := \
libmedia_helper \
libserviceutility
-LOCAL_MODULE:= libaudiopolicy
+LOCAL_MODULE:= libaudiopolicyservice
LOCAL_CFLAGS += -fvisibility=hidden
include $(BUILD_SHARED_LIBRARY)
+
+ifneq ($(USE_LEGACY_AUDIO_POLICY), 1)
+ifneq ($(USE_CUSTOM_AUDIO_POLICY), 1)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ AudioPolicyManager.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ liblog
+
+LOCAL_STATIC_LIBRARIES := \
+ libmedia_helper
+
+LOCAL_MODULE:= libaudiopolicymanager
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
+endif
diff --git a/services/audiopolicy/AudioPolicyClientImpl.cpp b/services/audiopolicy/AudioPolicyClientImpl.cpp
index 44c47c3..8225e36 100644
--- a/services/audiopolicy/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/AudioPolicyClientImpl.cpp
@@ -182,6 +182,17 @@ status_t AudioPolicyService::AudioPolicyClient::moveEffects(int session,
return af->moveEffects(session, src_output, dst_output);
}
+status_t AudioPolicyService::AudioPolicyClient::createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs)
+{
+ return mAudioPolicyService->clientCreateAudioPatch(patch, handle, delayMs);
+}
+status_t AudioPolicyService::AudioPolicyClient::releaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs)
+{
+ return mAudioPolicyService->clientReleaseAudioPatch(handle, delayMs);
+}
}; // namespace android
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 66260e3..bb2deb6 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -246,6 +246,15 @@ public:
audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput) = 0;
+ /* Create a patch between several source and sink ports */
+ virtual status_t createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs) = 0;
+
+ /* Release a patch */
+ virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs) = 0;
+
};
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
index c57c4fa..7cd253b 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
@@ -463,5 +463,43 @@ bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
return mAudioPolicyManager->isOffloadSupported(info);
}
+status_t AudioPolicyService::listAudioPorts(audio_port_role_t role __unused,
+ audio_port_type_t type __unused,
+ unsigned int *num_ports,
+ struct audio_port *ports __unused,
+ unsigned int *generation __unused)
+{
+ *num_ports = 0;
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::getAudioPort(struct audio_port *port __unused)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::createAudioPatch(const struct audio_patch *patch __unused,
+ audio_patch_handle_t *handle __unused)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::releaseAudioPatch(audio_patch_handle_t handle __unused)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::listAudioPatches(unsigned int *num_patches,
+ struct audio_patch *patches __unused,
+ unsigned int *generation __unused)
+{
+ *num_patches = 0;
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::setAudioPortConfig(const struct audio_port_config *config __unused)
+{
+ return INVALID_OPERATION;
+}
}; // namespace android
diff --git a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
index bb62ab3..0bf4982 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
@@ -485,5 +485,43 @@ bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
return mpAudioPolicy->is_offload_supported(mpAudioPolicy, &info);
}
+status_t AudioPolicyService::listAudioPorts(audio_port_role_t role __unused,
+ audio_port_type_t type __unused,
+ unsigned int *num_ports,
+ struct audio_port *ports __unused,
+ unsigned int *generation __unused)
+{
+ *num_ports = 0;
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::getAudioPort(struct audio_port *port __unused)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::createAudioPatch(const struct audio_patch *patch __unused,
+ audio_patch_handle_t *handle __unused)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::releaseAudioPatch(audio_patch_handle_t handle __unused)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::listAudioPatches(unsigned int *num_patches,
+ struct audio_patch *patches __unused,
+ unsigned int *generation __unused)
+{
+ *num_patches = 0;
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::setAudioPortConfig(const struct audio_port_config *config __unused)
+{
+ return INVALID_OPERATION;
+}
}; // namespace android
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 27dc335..db0f57d 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -268,7 +268,7 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
// also force a device 0 for the two outputs it is duplicated to which may override
// a valid device selection on those outputs.
setOutputDevice(mOutputs.keyAt(i),
- getNewDevice(mOutputs.keyAt(i), true /*fromCache*/),
+ getNewOutputDevice(mOutputs.keyAt(i), true /*fromCache*/),
!mOutputs.valueAt(i)->isDuplicated(),
0);
}
@@ -420,7 +420,7 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state)
}
// check for device and output changes triggered by new phone state
- newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
+ newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
checkA2dpSuspend();
checkOutputForAllStrategies();
updateDevicesAndOutputs();
@@ -545,7 +545,7 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage,
updateDevicesAndOutputs();
for (size_t i = 0; i < mOutputs.size(); i++) {
audio_io_handle_t output = mOutputs.keyAt(i);
- audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+ audio_devices_t newDevice = getNewOutputDevice(output, true /*fromCache*/);
setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
applyStreamVolumes(output, newDevice, 0, true);
@@ -554,16 +554,7 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage,
audio_io_handle_t activeInput = getActiveInput();
if (activeInput != 0) {
- AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
- audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
- if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
- ALOGV("setForceUse() changing device from %x to %x for input %d",
- inputDesc->mDevice, newDevice, activeInput);
- inputDesc->mDevice = newDevice;
- AudioParameter param = AudioParameter();
- param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
- mpClientInterface->setParameters(activeInput, param.toString());
- }
+ setInputDevice(activeInput, getNewInputDevice(activeInput));
}
}
@@ -580,7 +571,7 @@ void AudioPolicyManager::setSystemProperty(const char* property, const char* val
// Find a direct output profile compatible with the parameters passed, even if the input flags do
// not explicitly request a direct output
-AudioPolicyManager::IOProfile *AudioPolicyManager::getProfileForDirectOutput(
+sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getProfileForDirectOutput(
audio_devices_t device,
uint32_t samplingRate,
audio_format_t format,
@@ -592,7 +583,7 @@ AudioPolicyManager::IOProfile *AudioPolicyManager::getProfileForDirectOutput(
continue;
}
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
- IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+ sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
bool found = false;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
if (profile->isCompatibleProfile(device, samplingRate, format,
@@ -677,7 +668,7 @@ audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream,
// FIXME: We should check the audio session here but we do not have it in this context.
// This may prevent offloading in rare situations where effects are left active by apps
// in the background.
- IOProfile *profile = NULL;
+ sp<IOProfile> profile;
if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
!isNonOffloadableEffectEnabled()) {
profile = getProfileForDirectOutput(device,
@@ -687,7 +678,7 @@ audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream,
(audio_output_flags_t)flags);
}
- if (profile != NULL) {
+ if (profile != 0) {
AudioOutputDescriptor *outputDesc = NULL;
for (size_t i = 0; i < mOutputs.size(); i++) {
@@ -706,7 +697,7 @@ audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream,
}
// close direct output if currently open and configured with different parameters
if (outputDesc != NULL) {
- closeOutput(outputDesc->mId);
+ closeOutput(outputDesc->mIoHandle);
}
outputDesc = new AudioOutputDescriptor(profile);
outputDesc->mDevice = device;
@@ -838,7 +829,7 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
outputDesc->changeRefCount(stream, 1);
if (outputDesc->mRefCount[stream] == 1) {
- audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+ audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/);
routing_strategy strategy = getStrategy(stream);
bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
(strategy == STRATEGY_SONIFICATION_RESPECTFUL);
@@ -911,7 +902,7 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
// store time at which the stream was stopped - see isStreamActive()
if (outputDesc->mRefCount[stream] == 0) {
outputDesc->mStopTime[stream] = systemTime();
- audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+ audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/);
// delay the device switch by twice the latency because stopOutput() is executed when
// the track stop() command is received and at that time the audio track buffer can
// still contain data that needs to be drained. The latency only covers the audio HAL
@@ -929,7 +920,7 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
outputDesc->sharesHwModuleWith(desc) &&
(newDevice != desc->device())) {
setOutputDevice(curOutput,
- getNewDevice(curOutput, false /*fromCache*/),
+ getNewOutputDevice(curOutput, false /*fromCache*/),
true,
outputDesc->mLatency*2);
}
@@ -1019,11 +1010,11 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource,
break;
}
- IOProfile *profile = getInputProfile(device,
+ sp<IOProfile> profile = getInputProfile(device,
samplingRate,
format,
channelMask);
- if (profile == NULL) {
+ if (profile == 0) {
ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d, "
"channelMask %04x",
device, samplingRate, format, channelMask);
@@ -1096,10 +1087,7 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input)
}
}
- audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
- if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
- inputDesc->mDevice = newDevice;
- }
+ setInputDevice(input, getNewInputDevice(input), true /* force */);
// automatically enable the remote submix output when input is started
if (audio_is_remote_submix_device(inputDesc->mDevice)) {
@@ -1107,17 +1095,8 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input)
AUDIO_POLICY_DEVICE_STATE_AVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
}
- AudioParameter param = AudioParameter();
- param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
-
- int aliasSource = (inputDesc->mInputSource == AUDIO_SOURCE_HOTWORD) ?
- AUDIO_SOURCE_VOICE_RECOGNITION : inputDesc->mInputSource;
-
- param.addInt(String8(AudioParameter::keyInputSource), aliasSource);
ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource);
- mpClientInterface->setParameters(input, param.toString());
-
inputDesc->mRefCount = 1;
return NO_ERROR;
}
@@ -1142,9 +1121,7 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input)
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
}
- AudioParameter param = AudioParameter();
- param.addInt(String8(AudioParameter::keyRouting), 0);
- mpClientInterface->setParameters(input, param.toString());
+ resetInputDevice(input);
inputDesc->mRefCount = 0;
return NO_ERROR;
}
@@ -1609,13 +1586,13 @@ bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadI
// See if there is a profile to support this.
// AUDIO_DEVICE_NONE
- IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */,
+ sp<IOProfile> profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */,
offloadInfo.sample_rate,
offloadInfo.format,
offloadInfo.channel_mask,
AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
- ALOGV("isOffloadSupported() profile %sfound", profile != NULL ? "" : "NOT ");
- return (profile != NULL);
+ ALOGV("isOffloadSupported() profile %sfound", profile != 0 ? "" : "NOT ");
+ return (profile != 0);
}
// ----------------------------------------------------------------------------
@@ -1672,7 +1649,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
// This also validates mAvailableOutputDevices list
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
- const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j];
+ const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];
if (outProfile->mSupportedDevices.isEmpty()) {
ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName);
@@ -1684,7 +1661,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile);
- outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice->mType & profileTypes);
+ outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice->mDeviceType & profileTypes);
audio_io_handle_t output = mpClientInterface->openOutput(
outProfile->mModule->mHandle,
&outputDesc->mDevice,
@@ -1700,7 +1677,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
delete outputDesc;
} else {
for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) {
- audio_devices_t type = outProfile->mSupportedDevices[k]->mType;
+ audio_devices_t type = outProfile->mSupportedDevices[k]->mDeviceType;
ssize_t index =
mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
@@ -1723,7 +1700,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
// mAvailableInputDevices list
for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
{
- const IOProfile *inProfile = mHwModules[i]->mInputProfiles[j];
+ const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];
if (inProfile->mSupportedDevices.isEmpty()) {
ALOGW("Input profile contains no device on module %s", mHwModules[i]->mName);
@@ -1735,7 +1712,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
AudioInputDescriptor *inputDesc = new AudioInputDescriptor(inProfile);
inputDesc->mInputSource = AUDIO_SOURCE_MIC;
- inputDesc->mDevice = inProfile->mSupportedDevices[0]->mType;
+ inputDesc->mDevice = inProfile->mSupportedDevices[0]->mDeviceType;
audio_io_handle_t input = mpClientInterface->openInput(
inProfile->mModule->mHandle,
&inputDesc->mDevice,
@@ -1745,7 +1722,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
if (input != 0) {
for (size_t k = 0; k < inProfile->mSupportedDevices.size(); k++) {
- audio_devices_t type = inProfile->mSupportedDevices[k]->mType;
+ audio_devices_t type = inProfile->mSupportedDevices[k]->mDeviceType;
ssize_t index =
mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
@@ -1766,7 +1743,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
// make sure all attached devices have been allocated a unique ID
for (size_t i = 0; i < mAvailableOutputDevices.size();) {
if (mAvailableOutputDevices[i]->mId == 0) {
- ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mType);
+ ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mDeviceType);
mAvailableOutputDevices.remove(mAvailableOutputDevices[i]);
continue;
}
@@ -1774,7 +1751,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
}
for (size_t i = 0; i < mAvailableInputDevices.size();) {
if (mAvailableInputDevices[i]->mId == 0) {
- ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->mType);
+ ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->mDeviceType);
mAvailableInputDevices.remove(mAvailableInputDevices[i]);
continue;
}
@@ -1782,7 +1759,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
}
// make sure default device is reachable
if (mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
- ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->mType);
+ ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->mDeviceType);
}
ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
@@ -1991,16 +1968,18 @@ int AudioPolicyManager::testOutputIndex(audio_io_handle_t output)
// ---
-void AudioPolicyManager::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc)
+void AudioPolicyManager::addOutput(audio_io_handle_t output, AudioOutputDescriptor *outputDesc)
{
- outputDesc->mId = id;
- mOutputs.add(id, outputDesc);
+ outputDesc->mIoHandle = output;
+ outputDesc->mId = nextUniqueId();
+ mOutputs.add(output, outputDesc);
}
-void AudioPolicyManager::addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc)
+void AudioPolicyManager::addInput(audio_io_handle_t input, AudioInputDescriptor *inputDesc)
{
- inputDesc->mId = id;
- mInputs.add(id, inputDesc);
+ inputDesc->mIoHandle = input;
+ inputDesc->mId = nextUniqueId();
+ mInputs.add(input, inputDesc);
}
String8 AudioPolicyManager::addressToParameter(audio_devices_t device, const String8 address)
@@ -2028,7 +2007,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
}
}
// then look for output profiles that can be routed to this device
- SortedVector<IOProfile *> profiles;
+ SortedVector< sp<IOProfile> > profiles;
for (size_t i = 0; i < mHwModules.size(); i++)
{
if (mHwModules[i]->mHandle == 0) {
@@ -2051,7 +2030,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
// open outputs for matching profiles if needed. Direct outputs are also opened to
// query for dynamic parameters and will be closed later by setDeviceConnectionState()
for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
- IOProfile *profile = profiles[profile_index];
+ sp<IOProfile> profile = profiles[profile_index];
// nothing to do if one output is already opened for this profile
size_t j;
@@ -2097,7 +2076,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadSamplingRates(value + 1, profile);
+ profile->loadSamplingRates(value + 1);
}
}
if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
@@ -2107,7 +2086,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadFormats(value + 1, profile);
+ profile->loadFormats(value + 1);
}
}
if (profile->mChannelMasks[0] == 0) {
@@ -2117,7 +2096,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadOutChannels(value + 1, profile);
+ profile->loadOutChannels(value + 1);
}
}
if (((profile->mSamplingRates[0] == 0) &&
@@ -2212,7 +2191,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
}
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
- IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+ sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
if (profile->mSupportedDevices.types() & device) {
ALOGV("checkOutputsForDevice(): "
"clearing direct output profile %zu on module %zu", j, i);
@@ -2252,7 +2231,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device,
}
// then look for input profiles that can be routed to this device
- SortedVector<IOProfile *> profiles;
+ SortedVector< sp<IOProfile> > profiles;
for (size_t module_idx = 0; module_idx < mHwModules.size(); module_idx++)
{
if (mHwModules[module_idx]->mHandle == 0) {
@@ -2280,7 +2259,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device,
// query for dynamic parameters and will be closed later by setDeviceConnectionState()
for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
- IOProfile *profile = profiles[profile_index];
+ sp<IOProfile> profile = profiles[profile_index];
// nothing to do if one input is already opened for this profile
size_t input_index;
for (input_index = 0; input_index < mInputs.size(); input_index++) {
@@ -2318,7 +2297,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device,
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadSamplingRates(value + 1, profile);
+ profile->loadSamplingRates(value + 1);
}
}
if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
@@ -2327,7 +2306,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device,
ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadFormats(value + 1, profile);
+ profile->loadFormats(value + 1);
}
}
if (profile->mChannelMasks[0] == 0) {
@@ -2337,7 +2316,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device,
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
- loadInChannels(value + 1, profile);
+ profile->loadInChannels(value + 1);
}
}
if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
@@ -2387,7 +2366,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device,
for (size_t profile_index = 0;
profile_index < mHwModules[module_index]->mInputProfiles.size();
profile_index++) {
- IOProfile *profile = mHwModules[module_index]->mInputProfiles[profile_index];
+ sp<IOProfile> profile = mHwModules[module_index]->mInputProfiles[profile_index];
if (profile->mSupportedDevices.types() & device) {
ALOGV("checkInputsForDevice(): clearing direct input profile %d on module %d",
profile_index, module_index);
@@ -2606,7 +2585,7 @@ void AudioPolicyManager::checkA2dpSuspend()
}
}
-audio_devices_t AudioPolicyManager::getNewDevice(audio_io_handle_t output, bool fromCache)
+audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output, bool fromCache)
{
audio_devices_t device = AUDIO_DEVICE_NONE;
@@ -2639,7 +2618,16 @@ audio_devices_t AudioPolicyManager::getNewDevice(audio_io_handle_t output, bool
device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
}
- ALOGV("getNewDevice() selected device %x", device);
+ ALOGV("getNewOutputDevice() selected device %x", device);
+ return device;
+}
+
+audio_devices_t AudioPolicyManager::getNewInputDevice(audio_io_handle_t input)
+{
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+ audio_devices_t device = getDeviceForInputSource(inputDesc->mInputSource);
+
+ ALOGV("getNewInputDevice() selected device %x", device);
return device;
}
@@ -2785,7 +2773,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
}
device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_EARPIECE;
if (device) break;
- device = mDefaultOutputDevice->mType;
+ device = mDefaultOutputDevice->mDeviceType;
if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
}
@@ -2814,7 +2802,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
}
device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER;
if (device) break;
- device = mDefaultOutputDevice->mType;
+ device = mDefaultOutputDevice->mDeviceType;
if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
}
@@ -2896,7 +2884,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
// STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
device |= device2;
if (device) break;
- device = mDefaultOutputDevice->mType;
+ device = mDefaultOutputDevice->mDeviceType;
if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
}
@@ -2982,9 +2970,9 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(AudioOutputDescriptor *ou
}
for (size_t i = 0; i < NUM_STRATEGIES; i++) {
if (outputDesc->isStrategyActive((routing_strategy)i)) {
- setStrategyMute((routing_strategy)i, true, outputDesc->mId);
+ setStrategyMute((routing_strategy)i, true, outputDesc->mIoHandle);
// do tempMute unmute after twice the mute wait time
- setStrategyMute((routing_strategy)i, false, outputDesc->mId,
+ setStrategyMute((routing_strategy)i, false, outputDesc->mIoHandle,
muteWaitMs *2, device);
}
}
@@ -3010,8 +2998,8 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output,
uint32_t muteWaitMs;
if (outputDesc->isDuplicated()) {
- muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
- muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+ muteWaitMs = setOutputDevice(outputDesc->mOutput1->mIoHandle, device, force, delayMs);
+ muteWaitMs += setOutputDevice(outputDesc->mOutput2->mIoHandle, device, force, delayMs);
return muteWaitMs;
}
// no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
@@ -3043,9 +3031,34 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output,
}
ALOGV("setOutputDevice() changing device");
+
// do the routing
- param.addInt(String8(AudioParameter::keyRouting), (int)device);
- mpClientInterface->setParameters(output, param.toString(), delayMs);
+ if (device == AUDIO_DEVICE_NONE) {
+ resetOutputDevice(output, delayMs);
+ } else {
+ DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromType(device);
+ if (!deviceList.isEmpty()) {
+ struct audio_patch patch;
+ outputDesc->toAudioPortConfig(&patch.sources[0]);
+ patch.num_sources = 1;
+ patch.num_sinks = 0;
+ for (size_t i = 0; i < deviceList.size() && i < AUDIO_PATCH_PORTS_MAX; i++) {
+ deviceList.itemAt(i)->toAudioPortConfig(&patch.sinks[i]);
+ patch.sinks[i].ext.device.hw_module = patch.sources[0].ext.mix.hw_module;
+ patch.num_sinks++;
+ }
+ audio_patch_handle_t patchHandle = outputDesc->mPatchHandle;
+ status_t status = mpClientInterface->createAudioPatch(&patch,
+ &patchHandle,
+ delayMs);
+ ALOGV("setOutputDevice() createAudioPatch returned %d patchHandle %d"
+ "num_sources %d num_sinks %d",
+ status, patchHandle, patch.num_sources, patch.num_sinks);
+ if (status == NO_ERROR) {
+ outputDesc->mPatchHandle = patchHandle;
+ }
+ }
+ }
// update stream volumes according to new device
applyStreamVolumes(output, device, delayMs);
@@ -3053,7 +3066,65 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output,
return muteWaitMs;
}
-AudioPolicyManager::IOProfile *AudioPolicyManager::getInputProfile(audio_devices_t device,
+status_t AudioPolicyManager::resetOutputDevice(audio_io_handle_t output,
+ int delayMs)
+{
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ if (outputDesc->mPatchHandle == 0) {
+ return INVALID_OPERATION;
+ }
+ status_t status = mpClientInterface->releaseAudioPatch(outputDesc->mPatchHandle, delayMs);
+ ALOGV("resetOutputDevice() releaseAudioPatch returned %d", status);
+ outputDesc->mPatchHandle = 0;
+ return status;
+}
+
+status_t AudioPolicyManager::setInputDevice(audio_io_handle_t input,
+ audio_devices_t device,
+ bool force)
+{
+ status_t status = NO_ERROR;
+
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+ if ((device != AUDIO_DEVICE_NONE) && ((device != inputDesc->mDevice) || force)) {
+ inputDesc->mDevice = device;
+
+ DeviceVector deviceList = mAvailableInputDevices.getDevicesFromType(device);
+ if (!deviceList.isEmpty()) {
+ struct audio_patch patch;
+ inputDesc->toAudioPortConfig(&patch.sinks[0]);
+ patch.num_sinks = 1;
+ //only one input device for now
+ deviceList.itemAt(0)->toAudioPortConfig(&patch.sources[0]);
+ patch.sources[0].ext.device.hw_module = patch.sinks[0].ext.mix.hw_module;
+ patch.num_sources = 1;
+ audio_patch_handle_t patchHandle = inputDesc->mPatchHandle;
+ status_t status = mpClientInterface->createAudioPatch(&patch,
+ &patchHandle,
+ 0);
+ ALOGV("setInputDevice() createAudioPatch returned %d patchHandle %d",
+ status, patchHandle);
+ if (status == NO_ERROR) {
+ inputDesc->mPatchHandle = patchHandle;
+ }
+ }
+ }
+ return status;
+}
+
+status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input)
+{
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+ if (inputDesc->mPatchHandle == 0) {
+ return INVALID_OPERATION;
+ }
+ status_t status = mpClientInterface->releaseAudioPatch(inputDesc->mPatchHandle, 0);
+ ALOGV("resetInputDevice() releaseAudioPatch returned %d", status);
+ inputDesc->mPatchHandle = 0;
+ return status;
+}
+
+sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask)
@@ -3068,7 +3139,7 @@ AudioPolicyManager::IOProfile *AudioPolicyManager::getInputProfile(audio_devices
}
for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
{
- IOProfile *profile = mHwModules[i]->mInputProfiles[j];
+ sp<IOProfile> profile = mHwModules[i]->mInputProfiles[j];
// profile->log();
if (profile->isCompatibleProfile(device, samplingRate, format,
channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
@@ -3655,10 +3726,10 @@ uint32_t AudioPolicyManager::getMaxEffectsMemory()
// --- AudioOutputDescriptor class implementation
AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor(
- const IOProfile *profile)
- : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
+ const sp<IOProfile>& profile)
+ : mId(0), mIoHandle(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
mChannelMask(0), mLatency(0),
- mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
+ mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0),
mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
{
// clear usage count for all stream types
@@ -3777,6 +3848,32 @@ bool AudioPolicyManager::AudioOutputDescriptor::isStreamActive(audio_stream_type
return false;
}
+void AudioPolicyManager::AudioOutputDescriptor::toAudioPortConfig(
+ struct audio_port_config *config) const
+{
+ config->id = mId;
+ config->role = AUDIO_PORT_ROLE_SOURCE;
+ config->type = AUDIO_PORT_TYPE_MIX;
+ config->sample_rate = mSamplingRate;
+ config->channel_mask = mChannelMask;
+ config->format = mFormat;
+ config->gain.index = -1;
+ config->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+ AUDIO_PORT_CONFIG_FORMAT;
+ config->ext.mix.hw_module = mProfile->mModule->mHandle;
+ config->ext.mix.handle = mIoHandle;
+ config->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
+}
+
+void AudioPolicyManager::AudioOutputDescriptor::toAudioPort(
+ struct audio_port *port) const
+{
+ mProfile->toAudioPort(port);
+ port->id = mId;
+ port->ext.mix.handle = mIoHandle;
+ port->ext.mix.latency_class =
+ mFlags & AUDIO_OUTPUT_FLAG_FAST ? AUDIO_LATENCY_LOW : AUDIO_LATENCY_NORMAL;
+}
status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd)
{
@@ -3810,9 +3907,10 @@ status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd)
// --- AudioInputDescriptor class implementation
-AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile)
- : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
- mDevice(AUDIO_DEVICE_NONE), mRefCount(0),
+AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
+ : mId(0), mIoHandle(0), mSamplingRate(0),
+ mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
+ mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mRefCount(0),
mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile)
{
if (profile != NULL) {
@@ -3822,6 +3920,33 @@ AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *
}
}
+void AudioPolicyManager::AudioInputDescriptor::toAudioPortConfig(
+ struct audio_port_config *config) const
+{
+ config->id = mId;
+ config->role = AUDIO_PORT_ROLE_SINK;
+ config->type = AUDIO_PORT_TYPE_MIX;
+ config->sample_rate = mSamplingRate;
+ config->channel_mask = mChannelMask;
+ config->format = mFormat;
+ config->gain.index = -1;
+ config->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+ AUDIO_PORT_CONFIG_FORMAT;
+ config->ext.mix.hw_module = mProfile->mModule->mHandle;
+ config->ext.mix.handle = mIoHandle;
+ config->ext.mix.usecase.source = (mInputSource == AUDIO_SOURCE_HOTWORD) ?
+ AUDIO_SOURCE_VOICE_RECOGNITION : mInputSource;
+}
+
+void AudioPolicyManager::AudioInputDescriptor::toAudioPort(
+ struct audio_port *port) const
+{
+ mProfile->toAudioPort(port);
+ port->id = mId;
+ port->ext.mix.handle = mIoHandle;
+ port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL;
+}
+
status_t AudioPolicyManager::AudioInputDescriptor::dump(int fd)
{
const size_t SIZE = 256;
@@ -3904,7 +4029,7 @@ status_t AudioPolicyManager::EffectDescriptor::dump(int fd)
return NO_ERROR;
}
-// --- IOProfile class implementation
+// --- HwModule class implementation
AudioPolicyManager::HwModule::HwModule(const char *name)
: mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)), mHandle(0)
@@ -3915,11 +4040,9 @@ AudioPolicyManager::HwModule::~HwModule()
{
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
mOutputProfiles[i]->mSupportedDevices.clear();
- delete mOutputProfiles[i];
}
for (size_t i = 0; i < mInputProfiles.size(); i++) {
mInputProfiles[i]->mSupportedDevices.clear();
- delete mInputProfiles[i];
}
free((void *)mName);
}
@@ -3953,8 +4076,129 @@ void AudioPolicyManager::HwModule::dump(int fd)
}
}
-AudioPolicyManager::IOProfile::IOProfile(HwModule *module)
- : mFlags((audio_output_flags_t)0), mModule(module)
+// --- AudioPort class implementation
+
+void AudioPolicyManager::AudioPort::toAudioPort(struct audio_port *port) const
+{
+ port->role = mRole;
+ port->type = mType;
+ unsigned int i;
+ for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) {
+ port->sample_rates[i] = mSamplingRates[i];
+ }
+ port->num_sample_rates = i;
+ for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
+ port->channel_masks[i] = mChannelMasks[i];
+ }
+ port->num_channel_masks = i;
+ for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) {
+ port->formats[i] = mFormats[i];
+ }
+ port->num_formats = i;
+ port->num_gains = 0;
+}
+
+
+void AudioPolicyManager::AudioPort::loadSamplingRates(char *name)
+{
+ char *str = strtok(name, "|");
+
+ // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
+ // rates should be read from the output stream after it is opened for the first time
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ mSamplingRates.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ uint32_t rate = atoi(str);
+ if (rate != 0) {
+ ALOGV("loadSamplingRates() adding rate %d", rate);
+ mSamplingRates.add(rate);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManager::AudioPort::loadFormats(char *name)
+{
+ char *str = strtok(name, "|");
+
+ // by convention, "0' in the first entry in mFormats indicates the supported formats
+ // should be read from the output stream after it is opened for the first time
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ mFormats.add(AUDIO_FORMAT_DEFAULT);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable,
+ ARRAY_SIZE(sFormatNameToEnumTable),
+ str);
+ if (format != AUDIO_FORMAT_DEFAULT) {
+ mFormats.add(format);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManager::AudioPort::loadInChannels(char *name)
+{
+ const char *str = strtok(name, "|");
+
+ ALOGV("loadInChannels() %s", name);
+
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ mChannelMasks.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_channel_mask_t channelMask =
+ (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable,
+ ARRAY_SIZE(sInChannelsNameToEnumTable),
+ str);
+ if (channelMask != 0) {
+ ALOGV("loadInChannels() adding channelMask %04x", channelMask);
+ mChannelMasks.add(channelMask);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManager::AudioPort::loadOutChannels(char *name)
+{
+ const char *str = strtok(name, "|");
+
+ ALOGV("loadOutChannels() %s", name);
+
+ // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
+ // masks should be read from the output stream after it is opened for the first time
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ mChannelMasks.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_channel_mask_t channelMask =
+ (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable,
+ ARRAY_SIZE(sOutChannelsNameToEnumTable),
+ str);
+ if (channelMask != 0) {
+ mChannelMasks.add(channelMask);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+// --- IOProfile class implementation
+
+AudioPolicyManager::IOProfile::IOProfile(audio_port_role_t role, HwModule *module)
+ : AudioPort(AUDIO_PORT_TYPE_MIX, role, module), mFlags((audio_output_flags_t)0)
{
}
@@ -4090,7 +4334,7 @@ bool AudioPolicyManager::DeviceDescriptor::equals(const sp<DeviceDescriptor>& ot
// - 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
- return (mType == other->mType) &&
+ return (mDeviceType == other->mDeviceType) &&
(mAddress == "" || other->mAddress == "" || mAddress == other->mAddress) &&
(mChannelMask == 0 || other->mChannelMask == 0 ||
mChannelMask == other->mChannelMask);
@@ -4098,11 +4342,11 @@ bool AudioPolicyManager::DeviceDescriptor::equals(const sp<DeviceDescriptor>& ot
void AudioPolicyManager::DeviceVector::refreshTypes()
{
- mTypes = AUDIO_DEVICE_NONE;
+ mDeviceTypes = AUDIO_DEVICE_NONE;
for(size_t i = 0; i < size(); i++) {
- mTypes |= itemAt(i)->mType;
+ mDeviceTypes |= itemAt(i)->mDeviceType;
}
- ALOGV("DeviceVector::refreshTypes() mTypes %08x", mTypes);
+ ALOGV("DeviceVector::refreshTypes() mDeviceTypes %08x", mDeviceTypes);
}
ssize_t AudioPolicyManager::DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const
@@ -4125,7 +4369,7 @@ ssize_t AudioPolicyManager::DeviceVector::add(const sp<DeviceDescriptor>& item)
refreshTypes();
}
} else {
- ALOGW("DeviceVector::add device %08x already in", item->mType);
+ ALOGW("DeviceVector::add device %08x already in", item->mDeviceType);
ret = -1;
}
return ret;
@@ -4137,7 +4381,7 @@ ssize_t AudioPolicyManager::DeviceVector::remove(const sp<DeviceDescriptor>& ite
ssize_t ret = indexOf(item);
if (ret < 0) {
- ALOGW("DeviceVector::remove device %08x not in", item->mType);
+ ALOGW("DeviceVector::remove device %08x not in", item->mDeviceType);
} else {
ret = SortedVector::removeAt(ret);
if (ret >= 0) {
@@ -4162,6 +4406,61 @@ void AudioPolicyManager::DeviceVector::loadDevicesFromType(audio_devices_t types
}
}
+sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDevice(
+ audio_devices_t type, String8 address) const
+{
+ sp<DeviceDescriptor> device;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->mDeviceType == type) {
+ device = itemAt(i);
+ if (itemAt(i)->mAddress = address) {
+ break;
+ }
+ }
+ }
+ ALOGV("DeviceVector::getDevice() for type %d address %s found %p",
+ type, address.string(), device.get());
+ return device;
+}
+
+AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFromType(
+ audio_devices_t type) const
+{
+ DeviceVector devices;
+ for (size_t i = 0; (i < size()) && (type != AUDIO_DEVICE_NONE); i++) {
+ if (itemAt(i)->mDeviceType & type & ~AUDIO_DEVICE_BIT_IN) {
+ devices.add(itemAt(i));
+ type &= ~itemAt(i)->mDeviceType;
+ ALOGV("DeviceVector::getDevicesFromType() for type %x found %p",
+ itemAt(i)->mDeviceType, itemAt(i).get());
+ }
+ }
+ return devices;
+}
+
+void AudioPolicyManager::DeviceDescriptor::toAudioPortConfig(struct audio_port_config *config) const
+{
+ config->id = mId;
+ config->role = audio_is_output_device(mDeviceType) ?
+ AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
+ config->type = AUDIO_PORT_TYPE_DEVICE;
+ config->sample_rate = 0;
+ config->channel_mask = mChannelMask;
+ config->format = AUDIO_FORMAT_DEFAULT;
+ config->config_mask = AUDIO_PORT_CONFIG_CHANNEL_MASK;
+ config->gain.index = -1;
+ config->ext.device.type = mDeviceType;
+ strncpy(config->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
+}
+
+void AudioPolicyManager::DeviceDescriptor::toAudioPort(struct audio_port *port) const
+{
+ AudioPort::toAudioPort(port);
+ port->id = mId;
+ port->ext.device.type = mDeviceType;
+ strncpy(port->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
+}
+
void AudioPolicyManager::DeviceDescriptor::dumpHeader(int fd, int spaces)
{
const size_t SIZE = 256;
@@ -4181,7 +4480,7 @@ status_t AudioPolicyManager::DeviceDescriptor::dump(int fd, int spaces) const
spaces, "",
enumToString(sDeviceNameToEnumTable,
ARRAY_SIZE(sDeviceNameToEnumTable),
- mType),
+ mDeviceType),
mId, mChannelMask, mAddress.string());
write(fd, buffer, strlen(buffer));
@@ -4232,115 +4531,19 @@ audio_devices_t AudioPolicyManager::parseDeviceNames(char *name)
return device;
}
-void AudioPolicyManager::loadSamplingRates(char *name, IOProfile *profile)
-{
- char *str = strtok(name, "|");
-
- // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
- // rates should be read from the output stream after it is opened for the first time
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- profile->mSamplingRates.add(0);
- return;
- }
-
- while (str != NULL) {
- uint32_t rate = atoi(str);
- if (rate != 0) {
- ALOGV("loadSamplingRates() adding rate %d", rate);
- profile->mSamplingRates.add(rate);
- }
- str = strtok(NULL, "|");
- }
- return;
-}
-
-void AudioPolicyManager::loadFormats(char *name, IOProfile *profile)
-{
- char *str = strtok(name, "|");
-
- // by convention, "0' in the first entry in mFormats indicates the supported formats
- // should be read from the output stream after it is opened for the first time
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
- return;
- }
-
- while (str != NULL) {
- audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable,
- ARRAY_SIZE(sFormatNameToEnumTable),
- str);
- if (format != AUDIO_FORMAT_DEFAULT) {
- profile->mFormats.add(format);
- }
- str = strtok(NULL, "|");
- }
- return;
-}
-
-void AudioPolicyManager::loadInChannels(char *name, IOProfile *profile)
-{
- const char *str = strtok(name, "|");
-
- ALOGV("loadInChannels() %s", name);
-
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- profile->mChannelMasks.add(0);
- return;
- }
-
- while (str != NULL) {
- audio_channel_mask_t channelMask =
- (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable,
- ARRAY_SIZE(sInChannelsNameToEnumTable),
- str);
- if (channelMask != 0) {
- ALOGV("loadInChannels() adding channelMask %04x", channelMask);
- profile->mChannelMasks.add(channelMask);
- }
- str = strtok(NULL, "|");
- }
- return;
-}
-
-void AudioPolicyManager::loadOutChannels(char *name, IOProfile *profile)
-{
- const char *str = strtok(name, "|");
-
- ALOGV("loadOutChannels() %s", name);
-
- // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
- // masks should be read from the output stream after it is opened for the first time
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- profile->mChannelMasks.add(0);
- return;
- }
-
- while (str != NULL) {
- audio_channel_mask_t channelMask =
- (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable,
- ARRAY_SIZE(sOutChannelsNameToEnumTable),
- str);
- if (channelMask != 0) {
- profile->mChannelMasks.add(channelMask);
- }
- str = strtok(NULL, "|");
- }
- return;
-}
-
status_t AudioPolicyManager::loadInput(cnode *root, HwModule *module)
{
cnode *node = root->first_child;
- IOProfile *profile = new IOProfile(module);
+ sp<IOProfile> profile = new IOProfile(AUDIO_PORT_ROLE_SINK, module);
while (node) {
if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
- loadSamplingRates((char *)node->value, profile);
+ profile->loadSamplingRates((char *)node->value);
} else if (strcmp(node->name, FORMATS_TAG) == 0) {
- loadFormats((char *)node->value, profile);
+ profile->loadFormats((char *)node->value);
} else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- loadInChannels((char *)node->value, profile);
+ profile->loadInChannels((char *)node->value);
} else if (strcmp(node->name, DEVICES_TAG) == 0) {
profile->mSupportedDevices.loadDevicesFromType(parseDeviceNames((char *)node->value));
}
@@ -4365,7 +4568,6 @@ status_t AudioPolicyManager::loadInput(cnode *root, HwModule *module)
module->mInputProfiles.add(profile);
return NO_ERROR;
} else {
- delete profile;
return BAD_VALUE;
}
}
@@ -4374,15 +4576,15 @@ status_t AudioPolicyManager::loadOutput(cnode *root, HwModule *module)
{
cnode *node = root->first_child;
- IOProfile *profile = new IOProfile(module);
+ sp<IOProfile> profile = new IOProfile(AUDIO_PORT_ROLE_SOURCE, module);
while (node) {
if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
- loadSamplingRates((char *)node->value, profile);
+ profile->loadSamplingRates((char *)node->value);
} else if (strcmp(node->name, FORMATS_TAG) == 0) {
- loadFormats((char *)node->value, profile);
+ profile->loadFormats((char *)node->value);
} else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- loadOutChannels((char *)node->value, profile);
+ profile->loadOutChannels((char *)node->value);
} else if (strcmp(node->name, DEVICES_TAG) == 0) {
profile->mSupportedDevices.loadDevicesFromType(parseDeviceNames((char *)node->value));
} else if (strcmp(node->name, FLAGS_TAG) == 0) {
@@ -4409,7 +4611,6 @@ status_t AudioPolicyManager::loadOutput(cnode *root, HwModule *module)
module->mOutputProfiles.add(profile);
return NO_ERROR;
} else {
- delete profile;
return BAD_VALUE;
}
}
@@ -4487,7 +4688,7 @@ void AudioPolicyManager::loadGlobalConfig(cnode *root)
} else {
ALOGW("loadGlobalConfig() default device not specified");
}
- ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", mDefaultOutputDevice->mType);
+ ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", mDefaultOutputDevice->mDeviceType);
} else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
mAvailableInputDevices.loadDevicesFromType(parseDeviceNames((char *)node->value));
ALOGV("loadGlobalConfig() Available InputDevices %08x", mAvailableInputDevices.types());
@@ -4526,14 +4727,14 @@ status_t AudioPolicyManager::loadAudioPolicyConfig(const char *path)
void AudioPolicyManager::defaultAudioPolicyConfig(void)
{
HwModule *module;
- IOProfile *profile;
+ sp<IOProfile> profile;
sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
mAvailableOutputDevices.add(mDefaultOutputDevice);
mAvailableInputDevices.add(defaultInputDevice);
module = new HwModule("primary");
- profile = new IOProfile(module);
+ profile = new IOProfile(AUDIO_PORT_ROLE_SOURCE, module);
profile->mSamplingRates.add(44100);
profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
@@ -4541,7 +4742,7 @@ void AudioPolicyManager::defaultAudioPolicyConfig(void)
profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY;
module->mOutputProfiles.add(profile);
- profile = new IOProfile(module);
+ profile = new IOProfile(AUDIO_PORT_ROLE_SINK, module);
profile->mSamplingRates.add(8000);
profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index f00fa8a..905a3c8 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -175,58 +175,97 @@ protected:
class IOProfile;
- class DeviceDescriptor: public RefBase
+ class HwModule {
+ public:
+ HwModule(const char *name);
+ ~HwModule();
+
+ void dump(int fd);
+
+ const char *const mName; // base name of the audio HW module (primary, a2dp ...)
+ audio_module_handle_t mHandle;
+ Vector < sp<IOProfile> > mOutputProfiles; // output profiles exposed by this module
+ Vector < sp<IOProfile> > mInputProfiles; // input profiles exposed by this module
+ };
+
+ class AudioPort: public RefBase
+ {
+ public:
+ AudioPort(audio_port_type_t type, audio_port_role_t role, HwModule *module) :
+ mType(type), mRole(role), mModule(module) {}
+ virtual ~AudioPort() {}
+
+ virtual void toAudioPort(struct audio_port *port) const;
+
+ void loadSamplingRates(char *name);
+ void loadFormats(char *name);
+ void loadOutChannels(char *name);
+ void loadInChannels(char *name);
+
+ audio_port_type_t mType;
+ audio_port_role_t mRole;
+ // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
+ // indicates the supported parameters should be read from the output stream
+ // after it is opened for the first time
+ Vector <uint32_t> mSamplingRates; // supported sampling rates
+ Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
+ Vector <audio_format_t> mFormats; // supported audio formats
+ HwModule *mModule; // audio HW module exposing this I/O stream
+ };
+
+
+ class DeviceDescriptor: public AudioPort
{
public:
DeviceDescriptor(audio_devices_t type, String8 address,
audio_channel_mask_t channelMask) :
- mType(type), mAddress(address),
+ AudioPort(AUDIO_PORT_TYPE_DEVICE,
+ audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
+ AUDIO_PORT_ROLE_SOURCE,
+ NULL),
+ mDeviceType(type), mAddress(address),
mChannelMask(channelMask), mId(0) {}
DeviceDescriptor(audio_devices_t type) :
- mType(type), mAddress(""),
- mChannelMask(0), mId(0) {}
+ AudioPort(AUDIO_PORT_TYPE_DEVICE,
+ audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
+ AUDIO_PORT_ROLE_SOURCE,
+ NULL),
+ mDeviceType(type), mAddress(""),
+ mChannelMask(0), mId(0) {}
+ virtual ~DeviceDescriptor() {}
+
+ bool equals(const sp<DeviceDescriptor>& other) const;
+ void toAudioPortConfig(struct audio_port_config *config) const;
+ virtual void toAudioPort(struct audio_port *port) const;
status_t dump(int fd, int spaces) const;
static void dumpHeader(int fd, int spaces);
- bool equals(const sp<DeviceDescriptor>& other) const;
-
- audio_devices_t mType;
+ audio_devices_t mDeviceType;
String8 mAddress;
audio_channel_mask_t mChannelMask;
- uint32_t mId;
+ audio_port_handle_t mId;
};
class DeviceVector : public SortedVector< sp<DeviceDescriptor> >
{
public:
- DeviceVector() : SortedVector(), mTypes(AUDIO_DEVICE_NONE) {}
+ DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
ssize_t add(const sp<DeviceDescriptor>& item);
ssize_t remove(const sp<DeviceDescriptor>& item);
ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
- audio_devices_t types() const { return mTypes; }
+ audio_devices_t types() const { return mDeviceTypes; }
void loadDevicesFromType(audio_devices_t types);
+ sp<DeviceDescriptor> getDevice(audio_devices_t type, String8 address) const;
+ DeviceVector getDevicesFromType(audio_devices_t types) const;
private:
void refreshTypes();
- audio_devices_t mTypes;
- };
-
- class HwModule {
- public:
- HwModule(const char *name);
- ~HwModule();
-
- void dump(int fd);
-
- const char *const mName; // base name of the audio HW module (primary, a2dp ...)
- audio_module_handle_t mHandle;
- Vector <IOProfile *> mOutputProfiles; // output profiles exposed by this module
- Vector <IOProfile *> mInputProfiles; // input profiles exposed by this module
+ audio_devices_t mDeviceTypes;
};
// the IOProfile class describes the capabilities of an output or input stream.
@@ -234,11 +273,11 @@ protected:
// It is used by the policy manager to determine if an output or input is suitable for
// a given use case, open/close it accordingly and connect/disconnect audio tracks
// to/from it.
- class IOProfile
+ class IOProfile : public AudioPort
{
public:
- IOProfile(HwModule *module);
- ~IOProfile();
+ IOProfile(audio_port_role_t role, HwModule *module);
+ virtual ~IOProfile();
bool isCompatibleProfile(audio_devices_t device,
uint32_t samplingRate,
@@ -249,17 +288,10 @@ protected:
void dump(int fd);
void log();
- // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
- // indicates the supported parameters should be read from the output stream
- // after it is opened for the first time
- Vector <uint32_t> mSamplingRates; // supported sampling rates
- Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
- Vector <audio_format_t> mFormats; // supported audio formats
DeviceVector mSupportedDevices; // supported devices
// (devices this output can be routed to)
audio_output_flags_t mFlags; // attribute flags (e.g primary output,
// direct output...). For outputs only.
- HwModule *mModule; // audio HW module exposing this I/O stream
};
// default volume curve
@@ -284,7 +316,7 @@ protected:
class AudioOutputDescriptor
{
public:
- AudioOutputDescriptor(const IOProfile *profile);
+ AudioOutputDescriptor(const sp<IOProfile>& profile);
status_t dump(int fd);
@@ -303,20 +335,25 @@ protected:
uint32_t inPastMs = 0,
nsecs_t sysTime = 0) const;
- audio_io_handle_t mId; // output handle
+ void toAudioPortConfig(struct audio_port_config *config) const;
+ void toAudioPort(struct audio_port *port) const;
+
+ audio_port_handle_t mId;
+ audio_io_handle_t mIoHandle; // output handle
uint32_t mSamplingRate; //
audio_format_t mFormat; //
audio_channel_mask_t mChannelMask; // output configuration
uint32_t mLatency; //
audio_output_flags_t mFlags; //
audio_devices_t mDevice; // current device this output is routed to
+ audio_patch_handle_t mPatchHandle;
uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
nsecs_t mStopTime[AUDIO_STREAM_CNT];
AudioOutputDescriptor *mOutput1; // used by duplicated outputs: first output
AudioOutputDescriptor *mOutput2; // used by duplicated outputs: second output
float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume
int mMuteCount[AUDIO_STREAM_CNT]; // mute request counter
- const IOProfile *mProfile; // I/O profile this output derives from
+ const sp<IOProfile> mProfile; // I/O profile this output derives from
bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
// device selection. See checkDeviceMuteStrategies()
uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
@@ -327,18 +364,23 @@ protected:
class AudioInputDescriptor
{
public:
- AudioInputDescriptor(const IOProfile *profile);
+ AudioInputDescriptor(const sp<IOProfile>& profile);
status_t dump(int fd);
- audio_io_handle_t mId; // input handle
+ audio_port_handle_t mId;
+ audio_io_handle_t mIoHandle; // input handle
uint32_t mSamplingRate; //
audio_format_t mFormat; // input configuration
audio_channel_mask_t mChannelMask; //
audio_devices_t mDevice; // current device this input is routed to
+ audio_patch_handle_t mPatchHandle;
uint32_t mRefCount; // number of AudioRecord clients using this output
audio_source_t mInputSource; // input source selected by application (mediarecorder.h)
- const IOProfile *mProfile; // I/O profile this output derives from
+ const sp<IOProfile> mProfile; // I/O profile this output derives from
+
+ void toAudioPortConfig(struct audio_port_config *config) const;
+ void toAudioPort(struct audio_port *port) const;
};
// stream descriptor used for volume control
@@ -372,8 +414,8 @@ protected:
bool mEnabled; // enabled state: CPU load being used or not
};
- void addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc);
- void addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc);
+ void addOutput(audio_io_handle_t output, AudioOutputDescriptor *outputDesc);
+ void addInput(audio_io_handle_t input, AudioInputDescriptor *inputDesc);
// return the strategy corresponding to a given stream type
static routing_strategy getStrategy(audio_stream_type_t stream);
@@ -398,6 +440,12 @@ protected:
audio_devices_t device,
bool force = false,
int delayMs = 0);
+ status_t resetOutputDevice(audio_io_handle_t output,
+ int delayMs = 0);
+ status_t setInputDevice(audio_io_handle_t input,
+ audio_devices_t device,
+ bool force = false);
+ status_t resetInputDevice(audio_io_handle_t input);
// select input device corresponding to requested audio source
virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource);
@@ -484,16 +532,18 @@ protected:
// must be called every time a condition that affects the device choice for a given output is
// changed: connected device, phone state, force use, output start, output stop..
// see getDeviceForStrategy() for the use of fromCache parameter
+ audio_devices_t getNewOutputDevice(audio_io_handle_t output, bool fromCache);
- audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache);
// updates cache of device used by all strategies (mDeviceForStrategy[])
// must be called every time a condition that affects the device choice for a given strategy is
// changed: connected device, phone state, force use...
// cached values are used by getDeviceForStrategy() if parameter fromCache is true.
// Must be called after checkOutputForAllStrategies()
-
void updateDevicesAndOutputs();
+ // selects the most appropriate device on input for current state
+ audio_devices_t getNewInputDevice(audio_io_handle_t input);
+
virtual uint32_t getMaxEffectsCpuLoad();
virtual uint32_t getMaxEffectsMemory();
#ifdef AUDIO_POLICY_TEST
@@ -525,11 +575,11 @@ protected:
audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
audio_output_flags_t flags);
- IOProfile *getInputProfile(audio_devices_t device,
+ sp<IOProfile> getInputProfile(audio_devices_t device,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask);
- IOProfile *getProfileForDirectOutput(audio_devices_t device,
+ sp<IOProfile> getProfileForDirectOutput(audio_devices_t device,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -551,10 +601,6 @@ protected:
static bool stringToBool(const char *value);
static audio_output_flags_t parseFlagNames(char *name);
static audio_devices_t parseDeviceNames(char *name);
- void loadSamplingRates(char *name, IOProfile *profile);
- void loadFormats(char *name, IOProfile *profile);
- void loadOutChannels(char *name, IOProfile *profile);
- void loadInChannels(char *name, IOProfile *profile);
status_t loadOutput(cnode *root, HwModule *module);
status_t loadInput(cnode *root, HwModule *module);
void loadHwModule(cnode *root);
diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp
index 4e9a2f0..ea573a4 100644
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -150,6 +150,19 @@ AudioPolicyService::~AudioPolicyService()
#endif
}
+status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs)
+{
+ return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
+}
+
+status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs)
+{
+ return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs);
+}
+
void AudioPolicyService::binderDied(const wp<IBinder>& who) {
ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
@@ -357,6 +370,26 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
svc->doReleaseOutput(data->mIO);
mLock.lock();
}break;
+ case CREATE_AUDIO_PATCH: {
+ CreateAudioPatchData *data = (CreateAudioPatchData *)command->mParam.get();
+ ALOGV("AudioCommandThread() processing create audio patch");
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ command->mStatus = PERMISSION_DENIED;
+ } else {
+ command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle);
+ }
+ } break;
+ case RELEASE_AUDIO_PATCH: {
+ ReleaseAudioPatchData *data = (ReleaseAudioPatchData *)command->mParam.get();
+ ALOGV("AudioCommandThread() processing release audio patch");
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ command->mStatus = PERMISSION_DENIED;
+ } else {
+ command->mStatus = af->releaseAudioPatch(data->mHandle);
+ }
+ } break;
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
@@ -516,6 +549,41 @@ void AudioPolicyService::AudioCommandThread::releaseOutputCommand(audio_io_handl
sendCommand(command);
}
+status_t AudioPolicyService::AudioCommandThread::createAudioPatchCommand(
+ const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs)
+{
+ status_t status = NO_ERROR;
+
+ sp<AudioCommand> command = new AudioCommand();
+ command->mCommand = CREATE_AUDIO_PATCH;
+ CreateAudioPatchData *data = new CreateAudioPatchData();
+ data->mPatch = *patch;
+ data->mHandle = *handle;
+ command->mParam = data;
+ command->mWaitStatus = true;
+ ALOGV("AudioCommandThread() adding create patch delay %d", delayMs);
+ status = sendCommand(command, delayMs);
+ if (status == NO_ERROR) {
+ *handle = data->mHandle;
+ }
+ return status;
+}
+
+status_t AudioPolicyService::AudioCommandThread::releaseAudioPatchCommand(audio_patch_handle_t handle,
+ int delayMs)
+{
+ sp<AudioCommand> command = new AudioCommand();
+ command->mCommand = RELEASE_AUDIO_PATCH;
+ ReleaseAudioPatchData *data = new ReleaseAudioPatchData();
+ data->mHandle = handle;
+ command->mParam = data;
+ command->mWaitStatus = true;
+ ALOGV("AudioCommandThread() adding release patch delay %d", delayMs);
+ return sendCommand(command, delayMs);
+}
+
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
{
@@ -534,6 +602,7 @@ status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& c
return command->mStatus;
}
+
// insertCommand_l() must be called with mLock held
void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& command, int delayMs)
{
diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h
index 26037e4..9f88b1e 100644
--- a/services/audiopolicy/AudioPolicyService.h
+++ b/services/audiopolicy/AudioPolicyService.h
@@ -140,11 +140,31 @@ public:
virtual status_t setVoiceVolume(float volume, int delayMs = 0);
virtual bool isOffloadSupported(const audio_offload_info_t &config);
+ virtual status_t listAudioPorts(audio_port_role_t role,
+ audio_port_type_t type,
+ unsigned int *num_ports,
+ struct audio_port *ports,
+ unsigned int *generation);
+ virtual status_t getAudioPort(struct audio_port *port);
+ virtual status_t createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle);
+ virtual status_t releaseAudioPatch(audio_patch_handle_t handle);
+ virtual status_t listAudioPatches(unsigned int *num_patches,
+ struct audio_patch *patches,
+ unsigned int *generation);
+ virtual status_t setAudioPortConfig(const struct audio_port_config *config);
+
status_t doStopOutput(audio_io_handle_t output,
audio_stream_type_t stream,
int session = 0);
void doReleaseOutput(audio_io_handle_t output);
+ status_t clientCreateAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs);
+ status_t clientReleaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs);
+
private:
AudioPolicyService() ANDROID_API;
virtual ~AudioPolicyService();
@@ -169,7 +189,9 @@ private:
SET_PARAMETERS,
SET_VOICE_VOLUME,
STOP_OUTPUT,
- RELEASE_OUTPUT
+ RELEASE_OUTPUT,
+ CREATE_AUDIO_PATCH,
+ RELEASE_AUDIO_PATCH,
};
AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -196,6 +218,13 @@ private:
void releaseOutputCommand(audio_io_handle_t output);
status_t sendCommand(sp<AudioCommand>& command, int delayMs = 0);
void insertCommand_l(sp<AudioCommand>& command, int delayMs = 0);
+ status_t createAudioPatchCommand(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs);
+ status_t releaseAudioPatchCommand(audio_patch_handle_t handle,
+ int delayMs);
+
+ void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
class AudioCommandData;
@@ -261,6 +290,17 @@ private:
audio_io_handle_t mIO;
};
+ class CreateAudioPatchData : public AudioCommandData {
+ public:
+ struct audio_patch mPatch;
+ audio_patch_handle_t mHandle;
+ };
+
+ class ReleaseAudioPatchData : public AudioCommandData {
+ public:
+ audio_patch_handle_t mHandle;
+ };
+
Mutex mLock;
Condition mWaitWorkCV;
Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
@@ -405,6 +445,15 @@ private:
audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput);
+ /* Create a patch between several source and sink ports */
+ virtual status_t createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs);
+
+ /* Release a patch */
+ virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs);
+
private:
AudioPolicyService *mAudioPolicyService;
};
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index fe1e707..9fd35e1 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -39,6 +39,8 @@
#include <utils/String16.h>
#include <utils/Trace.h>
#include <system/camera_vendor_tags.h>
+#include <system/camera_metadata.h>
+#include <system/camera.h>
#include "CameraService.h"
#include "api1/CameraClient.h"
@@ -178,6 +180,9 @@ void CameraService::onDeviceStatusChanged(int cameraId,
{
Mutex::Autolock al(mServiceLock);
+ /* Remove cached parameters from shim cache */
+ mShimParams.removeItem(cameraId);
+
/* Find all clients that we need to disconnect */
sp<BasicClient> client = mClient[cameraId].promote();
if (client.get() != NULL) {
@@ -236,6 +241,96 @@ status_t CameraService::getCameraInfo(int cameraId,
return rc;
}
+
+status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata* cameraInfo) {
+ status_t ret = OK;
+ struct CameraInfo info;
+ if ((ret = getCameraInfo(cameraId, &info)) != OK) {
+ return ret;
+ }
+
+ CameraMetadata shimInfo;
+ int32_t orientation = static_cast<int32_t>(info.orientation);
+ if ((ret = shimInfo.update(ANDROID_SENSOR_ORIENTATION, &orientation, 1)) != OK) {
+ return ret;
+ }
+
+ uint8_t facing = (info.facing == CAMERA_FACING_FRONT) ?
+ ANDROID_LENS_FACING_FRONT : ANDROID_LENS_FACING_BACK;
+ if ((ret = shimInfo.update(ANDROID_LENS_FACING, &facing, 1)) != OK) {
+ return ret;
+ }
+
+ ssize_t index = -1;
+ { // Scope for service lock
+ Mutex::Autolock lock(mServiceLock);
+ index = mShimParams.indexOfKey(cameraId);
+ // Release service lock so initializeShimMetadata can be called correctly.
+ }
+
+ if (index < 0) {
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ ret = initializeShimMetadata(cameraId);
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ if (ret != OK) {
+ return ret;
+ }
+ }
+
+ Vector<Size> sizes;
+ Vector<int32_t> formats;
+ const char* supportedPreviewFormats;
+ { // Scope for service lock
+ Mutex::Autolock lock(mServiceLock);
+ index = mShimParams.indexOfKey(cameraId);
+
+ mShimParams[index].getSupportedPreviewSizes(/*out*/sizes);
+
+ mShimParams[index].getSupportedPreviewFormats(/*out*/formats);
+ }
+
+ // Always include IMPLEMENTATION_DEFINED
+ formats.add(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+
+ const size_t INTS_PER_CONFIG = 4;
+
+ // Build available stream configurations metadata
+ size_t streamConfigSize = sizes.size() * formats.size() * INTS_PER_CONFIG;
+ int32_t streamConfigs[streamConfigSize];
+ size_t configIndex = 0;
+ for (size_t i = 0; i < formats.size(); ++i) {
+ for (size_t j = 0; j < sizes.size(); ++j) {
+ streamConfigs[configIndex++] = formats[i];
+ streamConfigs[configIndex++] = sizes[j].width;
+ streamConfigs[configIndex++] = sizes[j].height;
+ streamConfigs[configIndex++] =
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
+ }
+ }
+
+ if ((ret = shimInfo.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ streamConfigs, streamConfigSize)) != OK) {
+ return ret;
+ }
+
+ int64_t fakeMinFrames[0];
+ // TODO: Fixme, don't fake min frame durations.
+ if ((ret = shimInfo.update(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+ fakeMinFrames, 0)) != OK) {
+ return ret;
+ }
+
+ int64_t fakeStalls[0];
+ // TODO: Fixme, don't fake stall durations.
+ if ((ret = shimInfo.update(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
+ fakeStalls, 0)) != OK) {
+ return ret;
+ }
+
+ *cameraInfo = shimInfo;
+ return OK;
+}
+
status_t CameraService::getCameraCharacteristics(int cameraId,
CameraMetadata* cameraInfo) {
if (!cameraInfo) {
@@ -248,34 +343,38 @@ status_t CameraService::getCameraCharacteristics(int cameraId,
return -ENODEV;
}
- if (mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_0) {
- // TODO: Remove this check once HAL1 shim is in place.
- ALOGE("%s: Only HAL module version V2 or higher supports static metadata", __FUNCTION__);
- return BAD_VALUE;
- }
-
if (cameraId < 0 || cameraId >= mNumberOfCameras) {
ALOGE("%s: Invalid camera id: %d", __FUNCTION__, cameraId);
return BAD_VALUE;
}
int facing;
- if (getDeviceVersion(cameraId, &facing) == CAMERA_DEVICE_API_VERSION_1_0) {
- // TODO: Remove this check once HAL1 shim is in place.
- ALOGE("%s: HAL1 doesn't support static metadata yet", __FUNCTION__);
- return BAD_VALUE;
- }
+ status_t ret = OK;
+ if (mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_0 ||
+ getDeviceVersion(cameraId, &facing) <= CAMERA_DEVICE_API_VERSION_2_1 ) {
+ /**
+ * Backwards compatibility mode for old HALs:
+ * - Convert CameraInfo into static CameraMetadata properties.
+ * - Retrieve cached CameraParameters for this camera. If none exist,
+ * attempt to open CameraClient and retrieve the CameraParameters.
+ * - Convert cached CameraParameters into static CameraMetadata
+ * properties.
+ */
+ ALOGI("%s: Switching to HAL1 shim implementation...", __FUNCTION__);
+
+ if ((ret = generateShimMetadata(cameraId, cameraInfo)) != OK) {
+ return ret;
+ }
- if (getDeviceVersion(cameraId, &facing) <= CAMERA_DEVICE_API_VERSION_2_1) {
- // Disable HAL2.x support for camera2 API for now.
- ALOGW("%s: HAL2.x doesn't support getCameraCharacteristics for now", __FUNCTION__);
- return BAD_VALUE;
+ } else {
+ /**
+ * Normal HAL 2.1+ codepath.
+ */
+ struct camera_info info;
+ ret = mModule->get_camera_info(cameraId, &info);
+ *cameraInfo = info.static_camera_characteristics;
}
- struct camera_info info;
- status_t ret = mModule->get_camera_info(cameraId, &info);
- *cameraInfo = info.static_camera_characteristics;
-
return ret;
}
@@ -285,12 +384,6 @@ status_t CameraService::getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescript
return -ENODEV;
}
- if (mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_2) {
- // TODO: Remove this check once HAL1 shim is in place.
- ALOGW("%s: Only HAL module version V2.2 or higher supports vendor tags", __FUNCTION__);
- return -EOPNOTSUPP;
- }
-
desc = VendorTagDescriptor::getGlobalVendorTagDescriptor();
return OK;
}
@@ -372,6 +465,54 @@ bool CameraService::setUpVendorTags() {
return true;
}
+status_t CameraService::initializeShimMetadata(int cameraId) {
+ int pid = getCallingPid();
+ int uid = getCallingUid();
+ status_t ret = validateConnect(cameraId, uid);
+ if (ret != OK) {
+ return ret;
+ }
+
+ bool needsNewClient = false;
+ sp<Client> client;
+
+ String16 internalPackageName("media");
+ { // Scope for service lock
+ Mutex::Autolock lock(mServiceLock);
+ if (mClient[cameraId] != NULL) {
+ client = static_cast<Client*>(mClient[cameraId].promote().get());
+ }
+ if (client == NULL) {
+ needsNewClient = true;
+ ret = connectHelperLocked(/*cameraClient*/NULL, // Empty binder callbacks
+ cameraId,
+ internalPackageName,
+ uid,
+ pid,
+ client);
+
+ if (ret != OK) {
+ return ret;
+ }
+ }
+
+ if (client == NULL) {
+ ALOGE("%s: Could not connect to client camera device.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ String8 rawParams = client->getParameters();
+ CameraParameters params(rawParams);
+ mShimParams.add(cameraId, params);
+ }
+
+ // Close client if one was opened solely for this call
+ if (needsNewClient) {
+ client->disconnect();
+ }
+ return OK;
+}
+
status_t CameraService::validateConnect(int cameraId,
/*inout*/
int& clientUid) const {
@@ -468,6 +609,64 @@ bool CameraService::canConnectUnsafe(int cameraId,
return true;
}
+status_t CameraService::connectHelperLocked(const sp<ICameraClient>& cameraClient,
+ int cameraId,
+ const String16& clientPackageName,
+ int clientUid,
+ int callingPid,
+ /*out*/
+ sp<Client>& client) {
+
+ int facing = -1;
+ int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+ // If there are other non-exclusive users of the camera,
+ // this will tear them down before we can reuse the camera
+ if (isValidCameraId(cameraId)) {
+ // transition from PRESENT -> NOT_AVAILABLE
+ updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
+ cameraId);
+ }
+
+ switch(deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_1_0:
+ client = new CameraClient(this, cameraClient,
+ clientPackageName, cameraId,
+ facing, callingPid, clientUid, getpid());
+ break;
+ case CAMERA_DEVICE_API_VERSION_2_0:
+ case CAMERA_DEVICE_API_VERSION_2_1:
+ case CAMERA_DEVICE_API_VERSION_3_0:
+ case CAMERA_DEVICE_API_VERSION_3_1:
+ case CAMERA_DEVICE_API_VERSION_3_2:
+ client = new Camera2Client(this, cameraClient,
+ clientPackageName, cameraId,
+ facing, callingPid, clientUid, getpid(),
+ deviceVersion);
+ break;
+ case -1:
+ ALOGE("Invalid camera id %d", cameraId);
+ return BAD_VALUE;
+ default:
+ ALOGE("Unknown camera device HAL version: %d", deviceVersion);
+ return INVALID_OPERATION;
+ }
+
+ status_t status = connectFinishUnsafe(client, client->getRemote());
+ if (status != OK) {
+ // this is probably not recoverable.. maybe the client can try again
+ // OK: we can only get here if we were originally in PRESENT state
+ updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
+ return status;
+ }
+
+ mClient[cameraId] = client;
+ LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
+ getpid());
+
+ return OK;
+}
+
status_t CameraService::connect(
const sp<ICameraClient>& cameraClient,
int cameraId,
@@ -501,52 +700,16 @@ status_t CameraService::connect(
return OK;
}
- int facing = -1;
- int deviceVersion = getDeviceVersion(cameraId, &facing);
-
- // If there are other non-exclusive users of the camera,
- // this will tear them down before we can reuse the camera
- if (isValidCameraId(cameraId)) {
- // transition from PRESENT -> NOT_AVAILABLE
- updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
- cameraId);
- }
-
- switch(deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_1_0:
- client = new CameraClient(this, cameraClient,
- clientPackageName, cameraId,
- facing, callingPid, clientUid, getpid());
- break;
- case CAMERA_DEVICE_API_VERSION_2_0:
- case CAMERA_DEVICE_API_VERSION_2_1:
- case CAMERA_DEVICE_API_VERSION_3_0:
- case CAMERA_DEVICE_API_VERSION_3_1:
- case CAMERA_DEVICE_API_VERSION_3_2:
- client = new Camera2Client(this, cameraClient,
- clientPackageName, cameraId,
- facing, callingPid, clientUid, getpid(),
- deviceVersion);
- break;
- case -1:
- ALOGE("Invalid camera id %d", cameraId);
- return BAD_VALUE;
- default:
- ALOGE("Unknown camera device HAL version: %d", deviceVersion);
- return INVALID_OPERATION;
- }
-
- status_t status = connectFinishUnsafe(client, client->getRemote());
+ status = connectHelperLocked(cameraClient,
+ cameraId,
+ clientPackageName,
+ clientUid,
+ callingPid,
+ client);
if (status != OK) {
- // this is probably not recoverable.. maybe the client can try again
- // OK: we can only get here if we were originally in PRESENT state
- updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
return status;
}
- mClient[cameraId] = client;
- LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
- getpid());
}
// important: release the mutex here so the client can call back
// into the service from its destructor (can be at the end of the call)
@@ -561,8 +724,9 @@ status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
if (status != OK) {
return status;
}
-
- remoteCallback->linkToDeath(this);
+ if (remoteCallback != NULL) {
+ remoteCallback->linkToDeath(this);
+ }
return OK;
}
@@ -800,9 +964,13 @@ void CameraService::removeClientByRemote(const wp<IBinder>& remoteBinder) {
if (client != 0) {
// Found our camera, clear and leave.
LOG1("removeClient: clear camera %d", outIndex);
- mClient[outIndex].clear();
- client->getRemote()->unlinkToDeath(this);
+ sp<IBinder> remote = client->getRemote();
+ if (remote != NULL) {
+ remote->unlinkToDeath(this);
+ }
+
+ mClient[outIndex].clear();
} else {
sp<ProClient> clientPro = findProClientUnsafe(remoteBinder);
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 76ea7be..ee39d52 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -18,6 +18,7 @@
#define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IAppOpsCallback.h>
@@ -32,6 +33,7 @@
#include <camera/camera2/ICameraDeviceCallbacks.h>
#include <camera/VendorTagDescriptor.h>
#include <camera/CaptureResult.h>
+#include <camera/CameraParameters.h>
#include <camera/ICameraServiceListener.h>
@@ -395,6 +397,43 @@ private:
bool isValidCameraId(int cameraId);
bool setUpVendorTags();
+
+ /**
+ * A mapping of camera ids to CameraParameters returned by that camera device.
+ *
+ * This cache is used to generate CameraCharacteristic metadata when using
+ * the HAL1 shim.
+ */
+ KeyedVector<int, CameraParameters> mShimParams;
+
+ /**
+ * Initialize and cache the metadata used by the HAL1 shim for a given cameraId.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ status_t initializeShimMetadata(int cameraId);
+
+ /**
+ * Generate the CameraCharacteristics metadata required by the Camera2 API
+ * from the available HAL1 CameraParameters and CameraInfo.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ status_t generateShimMetadata(int cameraId, /*out*/CameraMetadata* cameraInfo);
+
+ /**
+ * Connect a new camera client. This should only be used while holding the
+ * mutex for mServiceLock.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ status_t connectHelperLocked(const sp<ICameraClient>& cameraClient,
+ int cameraId,
+ const String16& clientPackageName,
+ int clientUid,
+ int callingPid,
+ /*out*/
+ sp<Client>& client);
};
} // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 65592d3..dece764 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -2028,24 +2028,7 @@ const char* Parameters::getStateName(State state) {
}
int Parameters::formatStringToEnum(const char *format) {
- return
- !format ?
- HAL_PIXEL_FORMAT_YCrCb_420_SP :
- !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422SP) ?
- HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16
- !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420SP) ?
- HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21
- !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422I) ?
- HAL_PIXEL_FORMAT_YCbCr_422_I : // YUY2
- !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420P) ?
- HAL_PIXEL_FORMAT_YV12 : // YV12
- !strcmp(format, CameraParameters::PIXEL_FORMAT_RGB565) ?
- HAL_PIXEL_FORMAT_RGB_565 : // RGB565
- !strcmp(format, CameraParameters::PIXEL_FORMAT_RGBA8888) ?
- HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888
- !strcmp(format, CameraParameters::PIXEL_FORMAT_BAYER_RGGB) ?
- HAL_PIXEL_FORMAT_RAW_SENSOR : // Raw sensor data
- -1;
+ return CameraParameters::previewFormatToEnum(format);
}
const char* Parameters::formatEnumToString(int format) {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 5a48a62..4fce1b3 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -246,6 +246,18 @@ status_t CameraDeviceClient::cancelRequest(int requestId, int64_t* lastFrameNumb
return res;
}
+status_t CameraDeviceClient::beginConfigure() {
+ // TODO: Implement this.
+ ALOGE("%s: Not implemented yet.", __FUNCTION__);
+ return OK;
+}
+
+status_t CameraDeviceClient::endConfigure() {
+ // TODO: Implement this.
+ ALOGE("%s: Not implemented yet.", __FUNCTION__);
+ return OK;
+}
+
status_t CameraDeviceClient::deleteStream(int streamId) {
ATRACE_CALL();
ALOGV("%s (streamId = 0x%x)", __FUNCTION__, streamId);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 0b37784..9981dfe 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -76,6 +76,10 @@ public:
/*out*/
int64_t* lastFrameNumber = NULL);
+ virtual status_t beginConfigure();
+
+ virtual status_t endConfigure();
+
// Returns -EBUSY if device is not idle
virtual status_t deleteStream(int streamId);
diff --git a/services/camera/libcameraservice/utils/CameraTraces.cpp b/services/camera/libcameraservice/utils/CameraTraces.cpp
index 346e15f..374dc5e 100644
--- a/services/camera/libcameraservice/utils/CameraTraces.cpp
+++ b/services/camera/libcameraservice/utils/CameraTraces.cpp
@@ -74,10 +74,10 @@ status_t CameraTraces::dump(int fd, const Vector<String16> &args __attribute__((
return BAD_VALUE;
}
- fdprintf(fd, "Camera traces (%zu):\n", pcsList.size());
+ dprintf(fd, "Camera traces (%zu):\n", pcsList.size());
if (pcsList.empty()) {
- fdprintf(fd, " No camera traces collected.\n");
+ dprintf(fd, " No camera traces collected.\n");
}
// Print newest items first
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index 0c7fbbd..41dab1f 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -60,7 +60,7 @@ status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused)
static const String16 sDump("android.permission.DUMP");
if (!(IPCThreadState::self()->getCallingUid() == AID_MEDIA ||
PermissionCache::checkCallingPermission(sDump))) {
- fdprintf(fd, "Permission Denial: can't dump media.log from pid=%d, uid=%d\n",
+ dprintf(fd, "Permission Denial: can't dump media.log from pid=%d, uid=%d\n",
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
return NO_ERROR;
@@ -74,7 +74,7 @@ status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused)
for (size_t i = 0; i < namedReaders.size(); i++) {
const NamedReader& namedReader = namedReaders[i];
if (fd >= 0) {
- fdprintf(fd, "\n%s:\n", namedReader.name());
+ dprintf(fd, "\n%s:\n", namedReader.name());
} else {
ALOGI("%s:", namedReader.name());
}