diff options
Diffstat (limited to 'services')
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()); } |