diff options
60 files changed, 1817 insertions, 841 deletions
diff --git a/include/media/AudioResamplerPublic.h b/include/media/AudioResamplerPublic.h index b705efa..0634741 100644 --- a/include/media/AudioResamplerPublic.h +++ b/include/media/AudioResamplerPublic.h @@ -17,6 +17,8 @@ #ifndef ANDROID_AUDIO_RESAMPLER_PUBLIC_H #define ANDROID_AUDIO_RESAMPLER_PUBLIC_H +#include <stdint.h> + // AUDIO_RESAMPLER_DOWN_RATIO_MAX is the maximum ratio between the original // audio sample rate and the target rate when downsampling, // as permitted in the audio framework, e.g. AudioTrack and AudioFlinger. @@ -26,6 +28,12 @@ // TODO: replace with an API #define AUDIO_RESAMPLER_DOWN_RATIO_MAX 256 +// AUDIO_RESAMPLER_UP_RATIO_MAX is the maximum suggested ratio between the original +// audio sample rate and the target rate when upsampling. It is loosely enforced by +// the system. One issue with large upsampling ratios is the approximation by +// an int32_t of the phase increments, making the resulting sample rate inexact. +#define AUDIO_RESAMPLER_UP_RATIO_MAX 65536 + // Returns the source frames needed to resample to destination frames. This is not a precise // value and depends on the resampler (and possibly how it handles rounding internally). // Nevertheless, this should be an upper bound on the requirements of the resampler. @@ -39,4 +47,15 @@ static inline size_t sourceFramesNeeded( size_t((uint64_t)dstFramesRequired * srcSampleRate / dstSampleRate + 1 + 1); } +// An upper bound for the number of destination frames possible from srcFrames +// after sample rate conversion. This may be used for buffer sizing. +static inline size_t destinationFramesPossible(size_t srcFrames, uint32_t srcSampleRate, + uint32_t dstSampleRate) { + if (srcSampleRate == dstSampleRate) { + return srcFrames; + } + uint64_t dstFrames = (uint64_t)srcFrames * dstSampleRate / srcSampleRate; + return dstFrames > 2 ? dstFrames - 2 : 0; +} + #endif // ANDROID_AUDIO_RESAMPLER_PUBLIC_H diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index f5db1bb..3b6db8c 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -221,14 +221,15 @@ public: audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, const audio_offload_info_t *offloadInfo = NULL); static status_t getOutputForAttr(const audio_attributes_t *attr, - audio_io_handle_t *output, - audio_session_t session, - audio_stream_type_t *stream, - uint32_t samplingRate = 0, - audio_format_t format = AUDIO_FORMAT_DEFAULT, - audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO, - audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, - const audio_offload_info_t *offloadInfo = NULL); + audio_io_handle_t *output, + audio_session_t session, + audio_stream_type_t *stream, + uint32_t samplingRate = 0, + audio_format_t format = AUDIO_FORMAT_DEFAULT, + audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO, + audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, + audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE, + const audio_offload_info_t *offloadInfo = NULL); static status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, audio_session_t session); diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index d9b7057..e7e0703 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -477,6 +477,26 @@ private: audio_io_handle_t getOutput() const; public: + /* Selects the audio device to use for output of this AudioTrack. A value of + * AUDIO_PORT_HANDLE_NONE indicates default (AudioPolicyManager) routing. + * + * Parameters: + * The device ID of the selected device (as returned by the AudioDevicesManager API). + * + * Returned value: + * - NO_ERROR: successful operation + * TODO: what else can happen here? + */ + status_t setOutputDevice(audio_port_handle_t deviceId); + + /* Returns the ID of the audio device used for output of this AudioTrack. + * A value of AUDIO_PORT_HANDLE_NONE indicates default (AudioPolicyManager) routing. + * + * Parameters: + * none. + */ + audio_port_handle_t getOutputDevice(); + /* Returns the unique session ID associated with this track. * * Parameters: @@ -817,6 +837,10 @@ protected: bool mInUnderrun; // whether track is currently in underrun state uint32_t mPausedPosition; + // For Device Selection API + // a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing. + int mSelectedDeviceId; + private: class DeathNotifier : public IBinder::DeathRecipient { public: diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h index fecc6f1..7506153 100644 --- a/include/media/IAudioPolicyService.h +++ b/include/media/IAudioPolicyService.h @@ -66,6 +66,7 @@ public: audio_format_t format = AUDIO_FORMAT_DEFAULT, audio_channel_mask_t channelMask = 0, audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, + audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE, const audio_offload_info_t *offloadInfo = NULL) = 0; virtual status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 100a914..f4cdde2 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -189,13 +189,9 @@ status_t AudioRecord::set( } // validate parameters - if (!audio_is_valid_format(format)) { - ALOGE("Invalid format %#x", format); - return BAD_VALUE; - } - // Temporary restriction: AudioFlinger currently supports 16-bit PCM only - if (format != AUDIO_FORMAT_PCM_16_BIT) { - ALOGE("Format %#x is not supported", format); + // AudioFlinger capture only supports linear PCM + if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) { + ALOGE("Format %#x is not linear pcm", format); return BAD_VALUE; } mFormat = format; diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 9150a94..8db72ee 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -658,13 +658,14 @@ status_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr, audio_format_t format, audio_channel_mask_t channelMask, audio_output_flags_t flags, + audio_port_handle_t selectedDeviceId, const audio_offload_info_t *offloadInfo) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return NO_INIT; return aps->getOutputForAttr(attr, output, session, stream, samplingRate, format, channelMask, - flags, offloadInfo); + flags, selectedDeviceId, offloadInfo); } status_t AudioSystem::startOutput(audio_io_handle_t output, diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index ce30c62..9e9ec5b 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -121,7 +121,8 @@ AudioTrack::AudioTrack() mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), - mPausedPosition(0) + mPausedPosition(0), + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) { mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN; mAttributes.usage = AUDIO_USAGE_UNKNOWN; @@ -149,7 +150,8 @@ AudioTrack::AudioTrack( mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), - mPausedPosition(0) + mPausedPosition(0), + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) { mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, @@ -177,7 +179,8 @@ AudioTrack::AudioTrack( mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), - mPausedPosition(0) + mPausedPosition(0), + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) { mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, @@ -928,6 +931,21 @@ audio_io_handle_t AudioTrack::getOutput() const return mOutput; } +status_t AudioTrack::setOutputDevice(audio_port_handle_t deviceId) { + AutoMutex lock(mLock); + if (mSelectedDeviceId != deviceId) { + mSelectedDeviceId = deviceId; + return restoreTrack_l("setOutputDevice() restart"); + } else { + return NO_ERROR; + } +} + +audio_port_handle_t AudioTrack::getOutputDevice() { + AutoMutex lock(mLock); + return mSelectedDeviceId; +} + status_t AudioTrack::attachAuxEffect(int effectId) { AutoMutex lock(mLock); @@ -960,11 +978,12 @@ status_t AudioTrack::createTrack_l() audio_io_handle_t output; audio_stream_type_t streamType = mStreamType; audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL; - status_t status = AudioSystem::getOutputForAttr(attr, &output, - (audio_session_t)mSessionId, &streamType, - mSampleRate, mFormat, mChannelMask, - mFlags, mOffloadInfo); + status_t status; + status = AudioSystem::getOutputForAttr(attr, &output, + (audio_session_t)mSessionId, &streamType, + mSampleRate, mFormat, mChannelMask, + mFlags, mSelectedDeviceId, mOffloadInfo); if (status != NO_ERROR || output == AUDIO_IO_HANDLE_NONE) { ALOGE("Could not get audio output for session %d, stream type %d, usage %d, sample rate %u, format %#x," diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 39374d8..4b86532 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -173,6 +173,7 @@ public: audio_format_t format, audio_channel_mask_t channelMask, audio_output_flags_t flags, + audio_port_handle_t selectedDeviceId, const audio_offload_info_t *offloadInfo) { Parcel data, reply; @@ -208,6 +209,7 @@ public: data.writeInt32(static_cast <uint32_t>(format)); data.writeInt32(channelMask); data.writeInt32(static_cast <uint32_t>(flags)); + data.writeInt32(selectedDeviceId); // hasOffloadInfo if (offloadInfo == NULL) { data.writeInt32(0); @@ -815,6 +817,7 @@ status_t BnAudioPolicyService::onTransact( audio_channel_mask_t channelMask = data.readInt32(); audio_output_flags_t flags = static_cast <audio_output_flags_t>(data.readInt32()); + audio_port_handle_t selectedDeviceId = data.readInt32(); bool hasOffloadInfo = data.readInt32() != 0; audio_offload_info_t offloadInfo; if (hasOffloadInfo) { @@ -824,7 +827,7 @@ status_t BnAudioPolicyService::onTransact( status_t status = getOutputForAttr(hasAttributes ? &attr : NULL, &output, session, &stream, samplingRate, format, channelMask, - flags, hasOffloadInfo ? &offloadInfo : NULL); + flags, selectedDeviceId, hasOffloadInfo ? &offloadInfo : NULL); reply->writeInt32(status); reply->writeInt32(output); reply->writeInt32(stream); diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index d0f42cc..910ae32 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -1168,6 +1168,11 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { return ERROR_IO; } + if (!timescale) { + ALOGE("timescale should not be ZERO."); + return ERROR_MALFORMED; + } + mLastTrack->timescale = ntohl(timescale); // 14496-12 says all ones means indeterminate, but some files seem to use @@ -2635,6 +2640,11 @@ status_t MPEG4Extractor::verifyTrack(Track *track) { return ERROR_MALFORMED; } + if (track->timescale == 0) { + ALOGE("timescale invalid."); + return ERROR_MALFORMED; + } + return OK; } diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 2d93152..f7a4a0d 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -141,6 +141,21 @@ const char *LiveSession::getKeyForStream(StreamType type) { return NULL; } +//static +const char *LiveSession::getNameForStream(StreamType type) { + switch (type) { + case STREAMTYPE_VIDEO: + return "video"; + case STREAMTYPE_AUDIO: + return "audio"; + case STREAMTYPE_SUBTITLES: + return "subs"; + default: + break; + } + return "unknown"; +} + LiveSession::LiveSession( const sp<AMessage> ¬ify, uint32_t flags, const sp<IMediaHTTPService> &httpService) @@ -192,7 +207,11 @@ status_t LiveSession::dequeueAccessUnit( status_t finalResult = OK; sp<AnotherPacketSource> packetSource = mPacketSources.valueFor(stream); - ssize_t idx = typeToIndex(stream); + ssize_t streamIdx = typeToIndex(stream); + if (streamIdx < 0) { + return INVALID_VALUE; + } + const char *streamStr = getNameForStream(stream); // Do not let client pull data if we don't have data packets yet. // We might only have a format discontinuity queued without data. // When NuPlayerDecoder dequeues the format discontinuity, it will @@ -200,6 +219,9 @@ status_t LiveSession::dequeueAccessUnit( // thinks it can do seamless change, so will not shutdown decoder. // When the actual format arrives, it can't handle it and get stuck. if (!packetSource->hasDataBufferAvailable(&finalResult)) { + ALOGV("[%s] dequeueAccessUnit: no buffer available (finalResult=%d)", + streamStr, finalResult); + if (finalResult == OK) { return -EAGAIN; } else { @@ -212,25 +234,6 @@ status_t LiveSession::dequeueAccessUnit( status_t err = packetSource->dequeueAccessUnit(accessUnit); - size_t streamIdx; - const char *streamStr; - switch (stream) { - case STREAMTYPE_AUDIO: - streamIdx = kAudioIndex; - streamStr = "audio"; - break; - case STREAMTYPE_VIDEO: - streamIdx = kVideoIndex; - streamStr = "video"; - break; - case STREAMTYPE_SUBTITLES: - streamIdx = kSubtitleIndex; - streamStr = "subs"; - break; - default: - TRESPASS(); - } - StreamItem& strm = mStreams[streamIdx]; if (err == INFO_DISCONTINUITY) { // adaptive streaming, discontinuities in the playlist @@ -249,9 +252,10 @@ status_t LiveSession::dequeueAccessUnit( } else if (err == OK) { if (stream == STREAMTYPE_AUDIO || stream == STREAMTYPE_VIDEO) { - int64_t timeUs; + int64_t timeUs, originalTimeUs; int32_t discontinuitySeq = 0; CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); + originalTimeUs = timeUs; (*accessUnit)->meta()->findInt32("discontinuitySeq", &discontinuitySeq); if (discontinuitySeq > (int32_t) strm.mCurDiscontinuitySeq) { int64_t offsetTimeUs; @@ -303,7 +307,8 @@ status_t LiveSession::dequeueAccessUnit( timeUs += mDiscontinuityOffsetTimesUs.valueFor(discontinuitySeq); } - ALOGV("[%s] read buffer at time %" PRId64 " us", streamStr, timeUs); + ALOGV("[%s] dequeueAccessUnit: time %lld us, original %lld us", + streamStr, (long long)timeUs, (long long)originalTimeUs); (*accessUnit)->meta()->setInt64("timeUs", timeUs); mLastDequeuedTimeUs = timeUs; mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; @@ -409,7 +414,7 @@ bool LiveSession::checkSwitchProgress( if (lastDequeueMeta == NULL) { // this means we don't have enough cushion, try again later ALOGV("[%s] up switching failed due to insufficient buffer", - stream == STREAMTYPE_AUDIO ? "audio" : "video"); + getNameForStream(stream)); return false; } } else { @@ -428,7 +433,7 @@ bool LiveSession::checkSwitchProgress( if (firstNewMeta[i] == NULL) { HLSTime dequeueTime(lastDequeueMeta); ALOGV("[%s] dequeue time (%d, %lld) past start time", - stream == STREAMTYPE_AUDIO ? "audio" : "video", + getNameForStream(stream), dequeueTime.mSeq, (long long) dequeueTime.mTimeUs); return false; } @@ -525,6 +530,11 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { break; } + ALOGV("fetcher-%d %s", + mFetcherInfos[index].mFetcher->getFetcherID(), + what == PlaylistFetcher::kWhatPaused ? + "paused" : "stopped"); + if (what == PlaylistFetcher::kWhatStopped) { mFetcherLooper->unregisterHandler( mFetcherInfos[index].mFetcher->id()); @@ -544,6 +554,7 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { if (--mContinuationCounter == 0) { mContinuation->post(); } + ALOGV("%zu fetcher(s) left", mContinuationCounter); } break; } @@ -636,6 +647,9 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { int32_t switchGeneration; CHECK(msg->findInt32("switchGeneration", &switchGeneration)); + ALOGV("kWhatStartedAt: switchGen=%d, mSwitchGen=%d", + switchGeneration, mSwitchGeneration); + if (switchGeneration != mSwitchGeneration) { break; } @@ -667,6 +681,7 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { if (checkSwitchProgress(stopParams, delayUs, &needResumeUntil)) { // playback time hasn't passed startAt time if (!needResumeUntil) { + ALOGV("finish switch"); for (size_t i = 0; i < kMaxStreams; ++i) { if ((mSwapMask & indexToType(i)) && uri == mStreams[i].mNewUri) { @@ -682,6 +697,7 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { // Resume fetcher for the original variant; the resumed fetcher should // continue until the timestamps found in msg, which is stored by the // new fetcher to indicate where the new variant has started buffering. + ALOGV("finish switch with resumeUntilAsync"); for (size_t i = 0; i < mFetcherInfos.size(); i++) { const FetcherInfo &info = mFetcherInfos.valueAt(i); if (info.mToBeRemoved) { @@ -693,8 +709,10 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { // playback time passed startAt time if (switchUp) { // if switching up, cancel and retry if condition satisfies again + ALOGV("cancel up switch because we're too late"); cancelBandwidthSwitch(true /* resume */); } else { + ALOGV("retry down switch at next sample"); resumeFetcher(uri, mSwapMask, -1, true /* newUri */); } } @@ -933,7 +951,8 @@ sp<PlaylistFetcher> LiveSession::addFetcher(const char *uri) { notify->setInt32("switchGeneration", mSwitchGeneration); FetcherInfo info; - info.mFetcher = new PlaylistFetcher(notify, this, uri, mSubtitleGeneration); + info.mFetcher = new PlaylistFetcher( + notify, this, uri, mCurBandwidthIndex, mSubtitleGeneration); info.mDurationUs = -1ll; info.mToBeRemoved = false; info.mToBeResumed = false; @@ -1167,9 +1186,13 @@ bool LiveSession::resumeFetcher( } if (resume) { - ALOGV("resuming fetcher %s, timeUs %lld", uri.c_str(), (long long)timeUs); + sp<PlaylistFetcher> &fetcher = mFetcherInfos.editValueAt(index).mFetcher; SeekMode seekMode = newUri ? kSeekModeNextSample : kSeekModeExactPosition; - mFetcherInfos.editValueAt(index).mFetcher->startAsync( + + ALOGV("resuming fetcher-%d, timeUs=%lld, seekMode=%d", + fetcher->getFetcherID(), (long long)timeUs, seekMode); + + fetcher->startAsync( sources[kAudioIndex], sources[kVideoIndex], sources[kSubtitleIndex], @@ -1406,6 +1429,9 @@ status_t LiveSession::selectTrack(size_t index, bool select) { return INVALID_OPERATION; } + ALOGV("selectTrack: index=%zu, select=%d, mSubtitleGen=%d++", + index, select, mSubtitleGeneration); + ++mSubtitleGeneration; status_t err = mPlaylist->selectTrack(index, select); if (err == OK) { @@ -1426,6 +1452,9 @@ ssize_t LiveSession::getSelectedTrack(media_track_type type) const { void LiveSession::changeConfiguration( int64_t timeUs, ssize_t bandwidthIndex, bool pickTrack) { + ALOGV("changeConfiguration: timeUs=%lld us, bwIndex=%zd, pickTrack=%d", + (long long)timeUs, bandwidthIndex, pickTrack); + cancelBandwidthSwitch(); CHECK(!mReconfigurationInProgress); @@ -1478,6 +1507,7 @@ void LiveSession::changeConfiguration( } if (discardFetcher) { + ALOGV("discarding fetcher-%d", fetcher->getFetcherID()); fetcher->stopAsync(); } else { float threshold = -1.0f; // always finish fetching by default @@ -1490,8 +1520,8 @@ void LiveSession::changeConfiguration( mOrigBandwidthIndex, mCurBandwidthIndex); } - ALOGV("Pausing with threshold %.3f", threshold); - + ALOGV("pausing fetcher-%d, threshold=%.2f", + fetcher->getFetcherID(), threshold); fetcher->pauseAsync(threshold); } } @@ -1526,6 +1556,8 @@ void LiveSession::changeConfiguration( } void LiveSession::onChangeConfiguration(const sp<AMessage> &msg) { + ALOGV("onChangeConfiguration"); + if (!mReconfigurationInProgress) { int32_t pickTrack = 0; msg->findInt32("pickTrack", &pickTrack); @@ -1536,6 +1568,8 @@ void LiveSession::onChangeConfiguration(const sp<AMessage> &msg) { } void LiveSession::onChangeConfiguration2(const sp<AMessage> &msg) { + ALOGV("onChangeConfiguration2"); + mContinuation.clear(); // All fetchers are either suspended or have been removed now. @@ -1670,6 +1704,11 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; } + ALOGV("onChangeConfiguration3: timeUs=%lld, switching=%d, pickTrack=%d, " + "mStreamMask=0x%x, mNewStreamMask=0x%x, mSwapMask=0x%x", + (long long)timeUs, switching, pickTrack, + mStreamMask, mNewStreamMask, mSwapMask); + for (size_t i = 0; i < kMaxStreams; ++i) { if (streamMask & indexToType(i)) { if (switching) { @@ -1687,6 +1726,9 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { for (size_t i = 0; i < mFetcherInfos.size(); ++i) { const AString &uri = mFetcherInfos.keyAt(i); if (!resumeFetcher(uri, resumeMask, timeUs)) { + ALOGV("marking fetcher-%d to be removed", + mFetcherInfos[i].mFetcher->getFetcherID()); + mFetcherInfos.editValueAt(i).mToBeRemoved = true; } } @@ -1776,6 +1818,14 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { } } + ALOGV("[fetcher-%d] startAsync: startTimeUs %lld mLastSeekTimeUs %lld " + "segmentStartTimeUs %lld seekMode %d", + fetcher->getFetcherID(), + (long long)startTime.mTimeUs, + (long long)mLastSeekTimeUs, + (long long)startTime.getSegmentTimeUs(true /* midpoint */), + seekMode); + // Set the target segment start time to the middle point of the // segment where the last sample was. // This gives a better guess if segments of the two variants are not @@ -1795,7 +1845,6 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { // All fetchers have now been started, the configuration change // has completed. - ALOGV("XXX configuration change completed."); mReconfigurationInProgress = false; if (switching) { mSwitchInProgress = true; @@ -1804,13 +1853,16 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { mOrigBandwidthIndex = mCurBandwidthIndex; } + ALOGV("onChangeConfiguration3: mSwitchInProgress %d, mStreamMask 0x%x", + mSwitchInProgress, mStreamMask); + if (mDisconnectReplyID != NULL) { finishDisconnect(); } } void LiveSession::swapPacketSource(StreamType stream) { - ALOGV("swapPacketSource: stream = %d", stream); + ALOGV("[%s] swapPacketSource", getNameForStream(stream)); // transfer packets from source2 to source sp<AnotherPacketSource> &aps = mPacketSources.editValueFor(stream); @@ -1858,7 +1910,7 @@ void LiveSession::tryToFinishBandwidthSwitch(const AString &oldUri) { mFetcherInfos.editValueAt(index).mFetcher->stopAsync(false /* clear */); - ALOGV("tryToFinishBandwidthSwitch: mSwapMask=%x", mSwapMask); + ALOGV("tryToFinishBandwidthSwitch: mSwapMask=0x%x", mSwapMask); if (mSwapMask != 0) { return; } @@ -1983,7 +2035,7 @@ void LiveSession::cancelBandwidthSwitch(bool resume) { } ALOGI("#### Canceled Bandwidth Switch: %zd => %zd", - mCurBandwidthIndex, mOrigBandwidthIndex); + mOrigBandwidthIndex, mCurBandwidthIndex); mSwitchGeneration++; mSwitchInProgress = false; @@ -2022,7 +2074,9 @@ bool LiveSession::checkBuffering( int64_t bufferedDurationUs = mPacketSources[i]->getEstimatedDurationUs(); - ALOGV("source[%zu]: buffered %lld us", i, (long long)bufferedDurationUs); + ALOGV("[%s] buffered %lld us", + getNameForStream(mPacketSources.keyAt(i)), + (long long)bufferedDurationUs); if (durationUs >= 0) { int32_t percent; if (mPacketSources[i]->isFinished(0 /* duration */)) { diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index b5e31c9..e4f1b97 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -91,6 +91,7 @@ struct LiveSession : public AHandler { bool hasDynamicDuration() const; static const char *getKeyForStream(StreamType type); + static const char *getNameForStream(StreamType type); enum { kWhatStreamsChanged, diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 368612d..ce79cc2 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -45,6 +45,10 @@ #include <openssl/aes.h> #include <openssl/md5.h> +#define FLOGV(fmt, ...) ALOGV("[fetcher-%d] " fmt, mFetcherID, ##__VA_ARGS__) +#define FSLOGV(stream, fmt, ...) ALOGV("[fetcher-%d] [%s] " fmt, mFetcherID, \ + LiveSession::getNameForStream(stream), ##__VA_ARGS__) + namespace android { // static @@ -143,10 +147,12 @@ PlaylistFetcher::PlaylistFetcher( const sp<AMessage> ¬ify, const sp<LiveSession> &session, const char *uri, + int32_t id, int32_t subtitleGeneration) : mNotify(notify), mSession(session), mURI(uri), + mFetcherID(id), mStreamTypeMask(0), mStartTimeUs(-1ll), mSegmentStartTimeUs(-1ll), @@ -176,6 +182,10 @@ PlaylistFetcher::PlaylistFetcher( PlaylistFetcher::~PlaylistFetcher() { } +int32_t PlaylistFetcher::getFetcherID() const { + return mFetcherID; +} + int64_t PlaylistFetcher::getSegmentStartTimeUs(int32_t seqNumber) const { CHECK(mPlaylist != NULL); @@ -436,7 +446,7 @@ void PlaylistFetcher::postMonitorQueue(int64_t delayUs, int64_t minDelayUs) { maxDelayUs = minDelayUs; } if (delayUs > maxDelayUs) { - ALOGV("Need to refresh playlist in %" PRId64 , maxDelayUs); + FLOGV("Need to refresh playlist in %lld", (long long)maxDelayUs); delayUs = maxDelayUs; } sp<AMessage> msg = new AMessage(kWhatMonitorQueue, this); @@ -507,6 +517,8 @@ void PlaylistFetcher::stopAsync(bool clear) { } void PlaylistFetcher::resumeUntilAsync(const sp<AMessage> ¶ms) { + FLOGV("resumeUntilAsync: params=%s", params->debugString().c_str()); + AMessage* msg = new AMessage(kWhatResumeUntil, this); msg->setMessage("params", params); msg->post(); @@ -763,8 +775,9 @@ void PlaylistFetcher::onMonitorQueue() { int64_t bufferedStreamDurationUs = mPacketSources.valueAt(i)->getBufferedDurationUs(&finalResult); - ALOGV("buffered %" PRId64 " for stream %d", - bufferedStreamDurationUs, mPacketSources.keyAt(i)); + + FSLOGV(mPacketSources.keyAt(i), "buffered %lld", (long long)bufferedStreamDurationUs); + if (bufferedDurationUs == -1ll || bufferedStreamDurationUs < bufferedDurationUs) { bufferedDurationUs = bufferedStreamDurationUs; @@ -776,8 +789,9 @@ void PlaylistFetcher::onMonitorQueue() { } if (finalResult == OK && bufferedDurationUs < kMinBufferedDurationUs) { - ALOGV("monitoring, buffered=%" PRId64 " < %" PRId64 "", - bufferedDurationUs, kMinBufferedDurationUs); + FLOGV("monitoring, buffered=%lld < %lld", + (long long)bufferedDurationUs, (long long)kMinBufferedDurationUs); + // delay the next download slightly; hopefully this gives other concurrent fetchers // a better chance to run. // onDownloadNext(); @@ -792,8 +806,12 @@ void PlaylistFetcher::onMonitorQueue() { if (delayUs > targetDurationUs / 2) { delayUs = targetDurationUs / 2; } - ALOGV("pausing for %" PRId64 ", buffered=%" PRId64 " > %" PRId64 "", - delayUs, bufferedDurationUs, kMinBufferedDurationUs); + + FLOGV("pausing for %lld, buffered=%lld > %lld", + (long long)delayUs, + (long long)bufferedDurationUs, + (long long)kMinBufferedDurationUs); + postMonitorQueue(delayUs); } } @@ -891,6 +909,12 @@ bool PlaylistFetcher::shouldPauseDownload() { } } lastEnqueueUs -= mSegmentFirstPTS; + + FLOGV("%spausing now, thresholdUs %lld, remaining %lld", + targetDurationUs - lastEnqueueUs > thresholdUs ? "" : "not ", + (long long)thresholdUs, + (long long)(targetDurationUs - lastEnqueueUs)); + if (targetDurationUs - lastEnqueueUs > thresholdUs) { return true; } @@ -940,8 +964,8 @@ bool PlaylistFetcher::initDownloadState( mStartTimeUs -= getSegmentStartTimeUs(mSeqNumber); } mStartTimeUsRelative = true; - ALOGV("Initial sequence number for time %" PRId64 " is %d from (%d .. %d)", - mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist, + FLOGV("Initial sequence number for time %lld is %d from (%d .. %d)", + (long long)mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist); } else { // When adapting or track switching, mSegmentStartTimeUs (relative @@ -966,7 +990,7 @@ bool PlaylistFetcher::initDownloadState( if (mSeqNumber > lastSeqNumberInPlaylist) { mSeqNumber = lastSeqNumberInPlaylist; } - ALOGV("Initial sequence number for live event %d from (%d .. %d)", + FLOGV("Initial sequence number is %d from (%d .. %d)", mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist); } @@ -995,10 +1019,10 @@ bool PlaylistFetcher::initDownloadState( if (delayUs > kMaxMonitorDelayUs) { delayUs = kMaxMonitorDelayUs; } - ALOGV("sequence number high: %d from (%d .. %d), " - "monitor in %" PRId64 " (retry=%d)", + FLOGV("sequence number high: %d from (%d .. %d), " + "monitor in %lld (retry=%d)", mSeqNumber, firstSeqNumberInPlaylist, - lastSeqNumberInPlaylist, delayUs, mNumRetries); + lastSeqNumberInPlaylist, (long long)delayUs, mNumRetries); postMonitorQueue(delayUs); return false; } @@ -1067,9 +1091,9 @@ bool PlaylistFetcher::initDownloadState( // Seek jumped to a new discontinuity sequence. We need to signal // a format change to decoder. Decoder needs to shutdown and be // created again if seamless format change is unsupported. - ALOGV("saw discontinuity: mStartup %d, mLastDiscontinuitySeq %d, " + FLOGV("saw discontinuity: mStartup %d, mLastDiscontinuitySeq %d, " "mDiscontinuitySeq %d, mStartTimeUs %lld", - mStartup, mLastDiscontinuitySeq, mDiscontinuitySeq, (long long)mStartTimeUs); + mStartup, mLastDiscontinuitySeq, mDiscontinuitySeq, (long long)mStartTimeUs); discontinuity = true; } mLastDiscontinuitySeq = -1; @@ -1134,7 +1158,7 @@ bool PlaylistFetcher::initDownloadState( } } - ALOGV("fetching segment %d from (%d .. %d)", + FLOGV("fetching segment %d from (%d .. %d)", mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist); return true; } @@ -1157,7 +1181,7 @@ void PlaylistFetcher::onDownloadNext() { firstSeqNumberInPlaylist, lastSeqNumberInPlaylist); connectHTTP = false; - ALOGV("resuming: '%s'", uri.c_str()); + FLOGV("resuming: '%s'", uri.c_str()); } else { if (!initDownloadState( uri, @@ -1166,7 +1190,7 @@ void PlaylistFetcher::onDownloadNext() { lastSeqNumberInPlaylist)) { return; } - ALOGV("fetching: '%s'", uri.c_str()); + FLOGV("fetching: '%s'", uri.c_str()); } int64_t range_offset, range_length; @@ -1196,6 +1220,11 @@ void PlaylistFetcher::onDownloadNext() { | LiveSession::STREAMTYPE_VIDEO))) { int64_t delayUs = ALooper::GetNowUs() - startUs; mSession->addBandwidthMeasurement(bytesRead, delayUs); + + if (delayUs > 2000000ll) { + FLOGV("bytesRead %zd took %.2f seconds - abnormal bandwidth dip", + bytesRead, (double)delayUs / 1.0e6); + } } connectHTTP = false; @@ -1584,6 +1613,16 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu // (newSeqNumber), start at least 1 segment prior. int32_t newSeqNumber = getSeqNumberWithAnchorTime( timeUs, targetDiffUs); + + FLOGV("guessed wrong seq number: timeUs=%lld, mStartTimeUs=%lld, " + "targetDurationUs=%lld, mSeqNumber=%d, newSeq=%d, firstSeq=%d", + (long long)timeUs, + (long long)mStartTimeUs, + (long long)targetDurationUs, + mSeqNumber, + newSeqNumber, + firstSeqNumberInPlaylist); + if (newSeqNumber >= mSeqNumber) { --mSeqNumber; } else { @@ -1604,8 +1643,13 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu } bool startTimeReached = true; if (mStartTimeUsRelative) { + FLOGV("startTimeUsRelative, timeUs (%lld) - %lld = %lld", + (long long)timeUs, + (long long)mFirstTimeUs, + (long long)(timeUs - mFirstTimeUs)); timeUs -= mFirstTimeUs; if (timeUs < 0) { + FLOGV("clamp negative timeUs to 0"); timeUs = 0; } startTimeReached = (timeUs >= mStartTimeUs); @@ -1614,13 +1658,17 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu if (!startTimeReached || (isAvc && !mIDRFound)) { // buffer up to the closest preceding IDR frame in the next segement, // or the closest succeeding IDR frame after the exact position + FSLOGV(stream, "timeUs=%lld, mStartTimeUs=%lld, mIDRFound=%d", + (long long)timeUs, (long long)mStartTimeUs, mIDRFound); if (isAvc) { if (IsIDR(accessUnit)) { mVideoBuffer->clear(); + FSLOGV(stream, "found IDR, clear mVideoBuffer"); mIDRFound = true; } if (mIDRFound && mStartTimeUsRelative && !startTimeReached) { mVideoBuffer->queueAccessUnit(accessUnit); + FSLOGV(stream, "saving AVC video AccessUnit"); } } if (!startTimeReached || (isAvc && !mIDRFound)) { @@ -1635,15 +1683,17 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu if (!(streamMask & mPacketSources.keyAt(i))) { streamMask |= mPacketSources.keyAt(i); mStartTimeUsNotify->setInt32("streamMask", streamMask); + FSLOGV(stream, "found start point, timeUs=%lld, streamMask becomes %x", + (long long)timeUs, streamMask); if (streamMask == mStreamTypeMask) { + FLOGV("found start point for all streams"); mStartup = false; } } } if (mStopParams != NULL) { - // Queue discontinuity in original stream. int32_t discontinuitySeq; int64_t stopTimeUs; if (!mStopParams->findInt32("discontinuitySeq", &discontinuitySeq) @@ -1651,13 +1701,13 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu || !mStopParams->findInt64(key, &stopTimeUs) || (discontinuitySeq == mDiscontinuitySeq && timeUs >= stopTimeUs)) { + FSLOGV(stream, "reached stop point, timeUs=%lld", (long long)timeUs); mStreamTypeMask &= ~stream; mPacketSources.removeItemsAt(i); break; } } - // Note that we do NOT dequeue any discontinuities except for format change. if (stream == LiveSession::STREAMTYPE_VIDEO) { const bool discard = true; status_t status; @@ -1666,11 +1716,16 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu mVideoBuffer->dequeueAccessUnit(&videoBuffer); setAccessUnitProperties(videoBuffer, source, discard); packetSource->queueAccessUnit(videoBuffer); + int64_t bufferTimeUs; + CHECK(videoBuffer->meta()->findInt64("timeUs", &bufferTimeUs)); + FSLOGV(stream, "queueAccessUnit (saved), timeUs=%lld", + (long long)bufferTimeUs); } } setAccessUnitProperties(accessUnit, source); packetSource->queueAccessUnit(accessUnit); + FSLOGV(stream, "queueAccessUnit, timeUs=%lld", (long long)timeUs); } if (err != OK) { @@ -1688,7 +1743,7 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu if (!mStreamTypeMask) { // Signal gap is filled between original and new stream. - ALOGV("ERROR OUT OF RANGE"); + FLOGV("reached stop point for all streams"); return ERROR_OUT_OF_RANGE; } @@ -1918,7 +1973,6 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( } if (mStopParams != NULL) { - // Queue discontinuity in original stream. int32_t discontinuitySeq; int64_t stopTimeUs; if (!mStopParams->findInt32("discontinuitySeq", &discontinuitySeq) diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index dab56df..f64d160 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -55,8 +55,11 @@ struct PlaylistFetcher : public AHandler { const sp<AMessage> ¬ify, const sp<LiveSession> &session, const char *uri, + int32_t id, int32_t subtitleGeneration); + int32_t getFetcherID() const; + sp<DataSource> getDataSource(); void startAsync( @@ -113,6 +116,8 @@ private: sp<LiveSession> mSession; AString mURI; + int32_t mFetcherID; + uint32_t mStreamTypeMask; int64_t mStartTimeUs; diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index c5bb41b..0676a33 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -514,7 +514,7 @@ void AnotherPacketSource::trimBuffersAfterMeta( } HLSTime stopTime(meta); - ALOGV("trimBuffersAfterMeta: discontinuitySeq %zu, timeUs %lld", + ALOGV("trimBuffersAfterMeta: discontinuitySeq %d, timeUs %lld", stopTime.mSeq, (long long)stopTime.mTimeUs); List<sp<ABuffer> >::iterator it; @@ -554,7 +554,7 @@ void AnotherPacketSource::trimBuffersAfterMeta( sp<AMessage> AnotherPacketSource::trimBuffersBeforeMeta( const sp<AMessage> &meta) { HLSTime startTime(meta); - ALOGV("trimBuffersBeforeMeta: discontinuitySeq %zu, timeUs %lld", + ALOGV("trimBuffersBeforeMeta: discontinuitySeq %d, timeUs %lld", startTime.mSeq, (long long)startTime.mTimeUs); sp<AMessage> firstMeta; diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index f3206cb..5002099 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -45,6 +45,8 @@ #include "AudioFlinger.h" #include "ServiceUtilities.h" +#include <media/AudioResamplerPublic.h> + #include <media/EffectsFactoryApi.h> #include <audio_effects/effect_visualizer.h> #include <audio_effects/effect_ns.h> @@ -1140,19 +1142,46 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t form if (ret != NO_ERROR) { return 0; } + if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) { + return 0; + } AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE; - audio_config_t config; - memset(&config, 0, sizeof(config)); - config.sample_rate = sampleRate; - config.channel_mask = channelMask; - config.format = format; + audio_config_t config, proposed; + memset(&proposed, 0, sizeof(proposed)); + proposed.sample_rate = sampleRate; + proposed.channel_mask = channelMask; + proposed.format = format; audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice(); - size_t size = dev->get_input_buffer_size(dev, &config); + size_t frames; + for (;;) { + // Note: config is currently a const parameter for get_input_buffer_size() + // but we use a copy from proposed in case config changes from the call. + config = proposed; + frames = dev->get_input_buffer_size(dev, &config); + if (frames != 0) { + break; // hal success, config is the result + } + // change one parameter of the configuration each iteration to a more "common" value + // to see if the device will support it. + if (proposed.format != AUDIO_FORMAT_PCM_16_BIT) { + proposed.format = AUDIO_FORMAT_PCM_16_BIT; + } else if (proposed.sample_rate != 44100) { // 44.1 is claimed as must in CDD as well as + proposed.sample_rate = 44100; // legacy AudioRecord.java. TODO: Query hw? + } else { + ALOGW("getInputBufferSize failed with minimum buffer size sampleRate %u, " + "format %#x, channelMask 0x%X", + sampleRate, format, channelMask); + break; // retries failed, break out of loop with frames == 0. + } + } mHardwareStatus = AUDIO_HW_IDLE; - return size; + if (frames > 0 && config.sample_rate != sampleRate) { + frames = destinationFramesPossible(frames, sampleRate, config.sample_rate); + } + return frames; // may be converted to bytes at the Java level. } uint32_t AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const @@ -1419,9 +1448,8 @@ sp<IAudioRecord> AudioFlinger::openRecord( goto Exit; } - // we don't yet support anything other than 16-bit PCM - if (!(audio_is_valid_format(format) && - audio_is_linear_pcm(format) && format == AUDIO_FORMAT_PCM_16_BIT)) { + // we don't yet support anything other than linear PCM + if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) { ALOGE("openRecord() invalid format %#x", format); lStatus = BAD_VALUE; goto Exit; @@ -2002,11 +2030,11 @@ sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t m status, address.string()); // If the input could not be opened with the requested parameters and we can handle the - // conversion internally, try to open again with the proposed parameters. The AudioFlinger can - // resample the input and do mono to stereo or stereo to mono conversions on 16 bit PCM inputs. + // conversion internally, try to open again with the proposed parameters. if (status == BAD_VALUE && - config->format == halconfig.format && halconfig.format == AUDIO_FORMAT_PCM_16_BIT && - (halconfig.sample_rate <= 2 * config->sample_rate) && + audio_is_linear_pcm(config->format) && + audio_is_linear_pcm(halconfig.format) && + (halconfig.sample_rate <= AUDIO_RESAMPLER_DOWN_RATIO_MAX * config->sample_rate) && (audio_channel_count_from_in_mask(halconfig.channel_mask) <= FCC_2) && (audio_channel_count_from_in_mask(config->channel_mask) <= FCC_2)) { // FIXME describe the change proposed by HAL (save old values so we can log them here) diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp index 46e3d6c..e49b7b1 100644 --- a/services/audioflinger/AudioResampler.cpp +++ b/services/audioflinger/AudioResampler.cpp @@ -41,7 +41,7 @@ public: AudioResamplerOrder1(int inChannelCount, int32_t sampleRate) : AudioResampler(inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) { } - virtual void resample(int32_t* out, size_t outFrameCount, + virtual size_t resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); private: // number of bits used in interpolation multiply - 15 bits avoids overflow @@ -51,9 +51,9 @@ private: static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits; void init() {} - void resampleMono16(int32_t* out, size_t outFrameCount, + size_t resampleMono16(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); - void resampleStereo16(int32_t* out, size_t outFrameCount, + size_t resampleStereo16(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); #ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, @@ -329,7 +329,7 @@ void AudioResampler::reset() { // ---------------------------------------------------------------------------- -void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount, +size_t AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { // should never happen, but we overflow if it does @@ -338,15 +338,16 @@ void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount, // select the appropriate resampler switch (mChannelCount) { case 1: - resampleMono16(out, outFrameCount, provider); - break; + return resampleMono16(out, outFrameCount, provider); case 2: - resampleStereo16(out, outFrameCount, provider); - break; + return resampleStereo16(out, outFrameCount, provider); + default: + LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount); + return 0; } } -void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, +size_t AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { int32_t vl = mVolume[0]; @@ -442,9 +443,10 @@ resampleStereo16_exit: // save state mInputIndex = inputIndex; mPhaseFraction = phaseFraction; + return outputIndex / 2 /* channels for stereo */; } -void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, +size_t AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { int32_t vl = mVolume[0]; @@ -538,6 +540,7 @@ resampleMono16_exit: // save state mInputIndex = inputIndex; mPhaseFraction = phaseFraction; + return outputIndex; } #ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h index 863614a..a8e3e6f 100644 --- a/services/audioflinger/AudioResampler.h +++ b/services/audioflinger/AudioResampler.h @@ -67,12 +67,18 @@ public: // Resample int16_t samples from provider and accumulate into 'out'. // A mono provider delivers a sequence of samples. // A stereo provider delivers a sequence of interleaved pairs of samples. - // Multi-channel providers are not supported. + // // In either case, 'out' holds interleaved pairs of fixed-point Q4.27. // That is, for a mono provider, there is an implicit up-channeling. // Since this method accumulates, the caller is responsible for clearing 'out' initially. - // FIXME assumes provider is always successful; it should return the actual frame count. - virtual void resample(int32_t* out, size_t outFrameCount, + // + // For a float resampler, 'out' holds interleaved pairs of float samples. + // + // Multichannel interleaved frames for n > 2 is supported for quality DYN_LOW_QUALITY, + // DYN_MED_QUALITY, and DYN_HIGH_QUALITY. + // + // Returns the number of frames resampled into the out buffer. + virtual size_t resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) = 0; virtual void reset(); diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp index d3cbd1c..172c2a5 100644 --- a/services/audioflinger/AudioResamplerCubic.cpp +++ b/services/audioflinger/AudioResamplerCubic.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "AudioSRC" +#define LOG_TAG "AudioResamplerCubic" #include <stdint.h> #include <string.h> @@ -32,7 +32,7 @@ void AudioResamplerCubic::init() { memset(&right, 0, sizeof(state)); } -void AudioResamplerCubic::resample(int32_t* out, size_t outFrameCount, +size_t AudioResamplerCubic::resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { // should never happen, but we overflow if it does @@ -41,15 +41,16 @@ void AudioResamplerCubic::resample(int32_t* out, size_t outFrameCount, // select the appropriate resampler switch (mChannelCount) { case 1: - resampleMono16(out, outFrameCount, provider); - break; + return resampleMono16(out, outFrameCount, provider); case 2: - resampleStereo16(out, outFrameCount, provider); - break; + return resampleStereo16(out, outFrameCount, provider); + default: + LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount); + return 0; } } -void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount, +size_t AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { int32_t vl = mVolume[0]; @@ -67,7 +68,7 @@ void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount, mBuffer.frameCount = inFrameCount; provider->getNextBuffer(&mBuffer, mPTS); if (mBuffer.raw == NULL) { - return; + return 0; } // ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount); } @@ -115,9 +116,10 @@ save_state: // ALOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction); mInputIndex = inputIndex; mPhaseFraction = phaseFraction; + return outputIndex / 2 /* channels for stereo */; } -void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount, +size_t AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { int32_t vl = mVolume[0]; @@ -135,7 +137,7 @@ void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount, mBuffer.frameCount = inFrameCount; provider->getNextBuffer(&mBuffer, mPTS); if (mBuffer.raw == NULL) { - return; + return 0; } // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount); } @@ -182,6 +184,7 @@ save_state: // ALOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction); mInputIndex = inputIndex; mPhaseFraction = phaseFraction; + return outputIndex; } // ---------------------------------------------------------------------------- diff --git a/services/audioflinger/AudioResamplerCubic.h b/services/audioflinger/AudioResamplerCubic.h index 1ddc5f9..4b45b0b 100644 --- a/services/audioflinger/AudioResamplerCubic.h +++ b/services/audioflinger/AudioResamplerCubic.h @@ -31,7 +31,7 @@ public: AudioResamplerCubic(int inChannelCount, int32_t sampleRate) : AudioResampler(inChannelCount, sampleRate, MED_QUALITY) { } - virtual void resample(int32_t* out, size_t outFrameCount, + virtual size_t resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); private: // number of bits used in interpolation multiply - 14 bits avoids overflow @@ -43,9 +43,9 @@ private: int32_t a, b, c, y0, y1, y2, y3; } state; void init(); - void resampleMono16(int32_t* out, size_t outFrameCount, + size_t resampleMono16(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); - void resampleStereo16(int32_t* out, size_t outFrameCount, + size_t resampleStereo16(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); static inline int32_t interp(state* p, int32_t x) { return (((((p->a * x >> 14) + p->b) * x >> 14) + p->c) * x >> 14) + p->y1; diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp index c21d4ca..6481b85 100644 --- a/services/audioflinger/AudioResamplerDyn.cpp +++ b/services/audioflinger/AudioResamplerDyn.cpp @@ -477,15 +477,15 @@ void AudioResamplerDyn<TC, TI, TO>::setSampleRate(int32_t inSampleRate) } template<typename TC, typename TI, typename TO> -void AudioResamplerDyn<TC, TI, TO>::resample(int32_t* out, size_t outFrameCount, +size_t AudioResamplerDyn<TC, TI, TO>::resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { - (this->*mResampleFunc)(reinterpret_cast<TO*>(out), outFrameCount, provider); + return (this->*mResampleFunc)(reinterpret_cast<TO*>(out), outFrameCount, provider); } template<typename TC, typename TI, typename TO> template<int CHANNELS, bool LOCKED, int STRIDE> -void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount, +size_t AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount, AudioBufferProvider* provider) { // TODO Mono -> Mono is not supported. OUTPUT_CHANNELS reflects minimum of stereo out. @@ -610,6 +610,7 @@ resample_exit: ALOG_ASSERT(mBuffer.frameCount == 0); // there must be no frames in the buffer mInBuffer.setImpulse(impulse); mPhaseFraction = phaseFraction; + return outputIndex / OUTPUT_CHANNELS; } /* instantiate templates used by AudioResampler::create */ diff --git a/services/audioflinger/AudioResamplerDyn.h b/services/audioflinger/AudioResamplerDyn.h index 238b163..3b1c381 100644 --- a/services/audioflinger/AudioResamplerDyn.h +++ b/services/audioflinger/AudioResamplerDyn.h @@ -52,7 +52,7 @@ public: virtual void setVolume(float left, float right); - virtual void resample(int32_t* out, size_t outFrameCount, + virtual size_t resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); private: @@ -111,10 +111,10 @@ private: int inSampleRate, int outSampleRate, double tbwCheat); template<int CHANNELS, bool LOCKED, int STRIDE> - void resample(TO* out, size_t outFrameCount, AudioBufferProvider* provider); + size_t resample(TO* out, size_t outFrameCount, AudioBufferProvider* provider); // define a pointer to member function type for resample - typedef void (AudioResamplerDyn<TC, TI, TO>::*resample_ABP_t)(TO* out, + typedef size_t (AudioResamplerDyn<TC, TI, TO>::*resample_ABP_t)(TO* out, size_t outFrameCount, AudioBufferProvider* provider); // data - the contiguous storage and layout of these is important. diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp index ba9a356..41730ee 100644 --- a/services/audioflinger/AudioResamplerSinc.cpp +++ b/services/audioflinger/AudioResamplerSinc.cpp @@ -256,7 +256,7 @@ void AudioResamplerSinc::setVolume(float left, float right) { mVolumeSIMD[1] = u4_28_from_float(clampFloatVol(right)); } -void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, +size_t AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { // FIXME store current state (up or down sample) and only load the coefs when the state @@ -272,17 +272,18 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, // select the appropriate resampler switch (mChannelCount) { case 1: - resample<1>(out, outFrameCount, provider); - break; + return resample<1>(out, outFrameCount, provider); case 2: - resample<2>(out, outFrameCount, provider); - break; + return resample<2>(out, outFrameCount, provider); + default: + LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount); + return 0; } } template<int CHANNELS> -void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, +size_t AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { const Constants& c(*mConstants); @@ -357,6 +358,7 @@ resample_exit: mImpulse = impulse; mInputIndex = inputIndex; mPhaseFraction = phaseFraction; + return outputIndex / CHANNELS; } template<int CHANNELS> diff --git a/services/audioflinger/AudioResamplerSinc.h b/services/audioflinger/AudioResamplerSinc.h index 6d8e85d..0fbeac8 100644 --- a/services/audioflinger/AudioResamplerSinc.h +++ b/services/audioflinger/AudioResamplerSinc.h @@ -39,7 +39,7 @@ public: virtual ~AudioResamplerSinc(); - virtual void resample(int32_t* out, size_t outFrameCount, + virtual size_t resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); private: void init(); @@ -47,7 +47,7 @@ private: virtual void setVolume(float left, float right); template<int CHANNELS> - void resample(int32_t* out, size_t outFrameCount, + size_t resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); template<int CHANNELS> diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp index efbdcff..834947f 100644 --- a/services/audioflinger/PatchPanel.cpp +++ b/services/audioflinger/PatchPanel.cpp @@ -200,26 +200,17 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa status = BAD_VALUE; goto exit; } - // limit to connections between devices and input streams for HAL before 3.0 - if (patch->sinks[i].ext.mix.hw_module == srcModule && - (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) && - (patch->sinks[i].type != AUDIO_PORT_TYPE_MIX)) { - ALOGW("createAudioPatch() invalid sink type %d for device source", - patch->sinks[i].type); - status = BAD_VALUE; - goto exit; - } } - if (patch->sinks[0].ext.device.hw_module != srcModule) { - // limit to device to device connection if not on same hw module - if (patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE) { - ALOGW("createAudioPatch() invalid sink type for cross hw module"); - status = INVALID_OPERATION; - goto exit; - } - // special case num sources == 2 -=> reuse an exiting output mix to connect to the - // sink + // manage patches requiring a software bridge + // - Device to device AND + // - source HW module != destination HW module OR + // - audio HAL version < 3.0 + // - special patch request with 2 sources (reuse one existing output mix) + if ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) && + ((patch->sinks[0].ext.device.hw_module != srcModule) || + (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) || + (patch->num_sources == 2))) { if (patch->num_sources == 2) { if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX || patch->sinks[0].ext.device.hw_module != @@ -304,6 +295,11 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa &halHandle); } } else { + if (patch->sinks[0].type != AUDIO_PORT_TYPE_MIX) { + status = INVALID_OPERATION; + goto exit; + } + sp<ThreadBase> thread = audioflinger->checkRecordThread_l( patch->sinks[0].ext.mix.handle); if (thread == 0) { @@ -472,6 +468,7 @@ status_t AudioFlinger::PatchPanel::createPatchConnections(Patch *patch, // this track is given the same buffer as the PatchRecord buffer patch->mPatchTrack = new PlaybackThread::PatchTrack( patch->mPlaybackThread.get(), + audioPatch->sources[1].ext.mix.usecase.stream, sampleRate, outChannelMask, format, @@ -578,8 +575,8 @@ status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle break; } - if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE && - patch->sinks[0].ext.device.hw_module != srcModule) { + if (removedPatch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE || + removedPatch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) { clearPatchConnections(removedPatch); break; } @@ -693,5 +690,4 @@ status_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_co return NO_ERROR; } - } // namespace android diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index 45df6a9..c51021b 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -298,6 +298,7 @@ class PatchTrack : public Track, public PatchProxyBufferProvider { public: PatchTrack(PlaybackThread *playbackThread, + audio_stream_type_t streamType, uint32_t sampleRate, audio_channel_mask_t channelMask, audio_format_t format, diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h index 204a9d6..25d6d95 100644 --- a/services/audioflinger/RecordTracks.h +++ b/services/audioflinger/RecordTracks.h @@ -34,6 +34,7 @@ public: IAudioFlinger::track_flags_t flags, track_type type); virtual ~RecordTrack(); + virtual status_t initCheck() const; virtual status_t start(AudioSystem::sync_event_t event, int triggerSession); virtual void stop(); @@ -66,21 +67,6 @@ private: bool mOverflow; // overflow on most recent attempt to fill client buffer - // updated by RecordThread::readInputParameters_l() - AudioResampler *mResampler; - - // interleaved stereo pairs of fixed-point Q4.27 - int32_t *mRsmpOutBuffer; - // current allocated frame count for the above, which may be larger than needed - size_t mRsmpOutFrameCount; - - size_t mRsmpInUnrel; // unreleased frames remaining from - // most recent getNextBuffer - // for debug only - - // rolling counter that is never cleared - int32_t mRsmpInFront; // next available frame - AudioBufferProvider::Buffer mSink; // references client's buffer sink in shared memory // sync event triggering actual audio capture. Frames read before this event will @@ -93,7 +79,10 @@ private: ssize_t mFramesToDrop; // used by resampler to find source frames - ResamplerBufferProvider *mResamplerBufferProvider; + ResamplerBufferProvider *mResamplerBufferProvider; + + // used by the record thread to convert frames to proper destination format + RecordBufferConverter *mRecordBufferConverter; }; // playback track, used by PatchPanel diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 4efb3d7..1a20fae 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -86,7 +86,13 @@ #define ALOGVV(a...) do { } while(0) #endif +// TODO: Move these macro/inlines to a header file. #define max(a, b) ((a) > (b) ? (a) : (b)) +template <typename T> +static inline T min(const T& a, const T& b) +{ + return a < b ? a : b; +} namespace android { @@ -5290,7 +5296,6 @@ failed: ; // FIXME mNormalSource } - AudioFlinger::RecordThread::~RecordThread() { if (mFastCapture != 0) { @@ -5594,6 +5599,9 @@ reacquire_wakelock: continue; } + // TODO: This code probably should be moved to RecordTrack. + // TODO: Update the activeTrack buffer converter in case of reconfigure. + enum { OVERRUN_UNKNOWN, OVERRUN_TRUE, @@ -5608,131 +5616,28 @@ reacquire_wakelock: size_t framesOut = activeTrack->mSink.frameCount; LOG_ALWAYS_FATAL_IF((status == OK) != (framesOut > 0)); - int32_t front = activeTrack->mRsmpInFront; - ssize_t filled = rear - front; + // check available frames and handle overrun conditions + // if the record track isn't draining fast enough. + bool hasOverrun; size_t framesIn; - - if (filled < 0) { - // should not happen, but treat like a massive overrun and re-sync - framesIn = 0; - activeTrack->mRsmpInFront = rear; - overrun = OVERRUN_TRUE; - } else if ((size_t) filled <= mRsmpInFrames) { - framesIn = (size_t) filled; - } else { - // client is not keeping up with server, but give it latest data - framesIn = mRsmpInFrames; - activeTrack->mRsmpInFront = front = rear - framesIn; + activeTrack->mResamplerBufferProvider->sync(&framesIn, &hasOverrun); + if (hasOverrun) { overrun = OVERRUN_TRUE; } - if (framesOut == 0 || framesIn == 0) { break; } - if (activeTrack->mResampler == NULL) { - // no resampling - if (framesIn > framesOut) { - framesIn = framesOut; - } else { - framesOut = framesIn; - } - int8_t *dst = activeTrack->mSink.i8; - while (framesIn > 0) { - front &= mRsmpInFramesP2 - 1; - size_t part1 = mRsmpInFramesP2 - front; - if (part1 > framesIn) { - part1 = framesIn; - } - int8_t *src = (int8_t *)mRsmpInBuffer + (front * mFrameSize); - if (mChannelCount == activeTrack->mChannelCount) { - memcpy(dst, src, part1 * mFrameSize); - } else if (mChannelCount == 1) { - upmix_to_stereo_i16_from_mono_i16((int16_t *)dst, (const int16_t *)src, - part1); - } else { - downmix_to_mono_i16_from_stereo_i16((int16_t *)dst, - (const int16_t *)src, part1); - } - dst += part1 * activeTrack->mFrameSize; - front += part1; - framesIn -= part1; - } - activeTrack->mRsmpInFront += framesOut; - - } else { - // resampling - // FIXME framesInNeeded should really be part of resampler API, and should - // depend on the SRC ratio - // to keep mRsmpInBuffer full so resampler always has sufficient input - size_t framesInNeeded; - // FIXME only re-calculate when it changes, and optimize for common ratios - // Do not precompute in/out because floating point is not associative - // e.g. a*b/c != a*(b/c). - const double in(mSampleRate); - const double out(activeTrack->mSampleRate); - framesInNeeded = ceil(framesOut * in / out) + 1; - ALOGV("need %u frames in to produce %u out given in/out ratio of %.4g", - framesInNeeded, framesOut, in / out); - // Although we theoretically have framesIn in circular buffer, some of those are - // unreleased frames, and thus must be discounted for purpose of budgeting. - size_t unreleased = activeTrack->mRsmpInUnrel; - framesIn = framesIn > unreleased ? framesIn - unreleased : 0; - if (framesIn < framesInNeeded) { - ALOGV("not enough to resample: have %u frames in but need %u in to " - "produce %u out given in/out ratio of %.4g", - framesIn, framesInNeeded, framesOut, in / out); - size_t newFramesOut = framesIn > 0 ? floor((framesIn - 1) * out / in) : 0; - LOG_ALWAYS_FATAL_IF(newFramesOut >= framesOut); - if (newFramesOut == 0) { - break; - } - framesInNeeded = ceil(newFramesOut * in / out) + 1; - ALOGV("now need %u frames in to produce %u out given out/in ratio of %.4g", - framesInNeeded, newFramesOut, out / in); - LOG_ALWAYS_FATAL_IF(framesIn < framesInNeeded); - ALOGV("success 2: have %u frames in and need %u in to produce %u out " - "given in/out ratio of %.4g", - framesIn, framesInNeeded, newFramesOut, in / out); - framesOut = newFramesOut; - } else { - ALOGV("success 1: have %u in and need %u in to produce %u out " - "given in/out ratio of %.4g", - framesIn, framesInNeeded, framesOut, in / out); - } - - // reallocate mRsmpOutBuffer as needed; we will grow but never shrink - if (activeTrack->mRsmpOutFrameCount < framesOut) { - // FIXME why does each track need it's own mRsmpOutBuffer? can't they share? - delete[] activeTrack->mRsmpOutBuffer; - // resampler always outputs stereo - activeTrack->mRsmpOutBuffer = new int32_t[framesOut * FCC_2]; - activeTrack->mRsmpOutFrameCount = framesOut; - } - - // resampler accumulates, but we only have one source track - memset(activeTrack->mRsmpOutBuffer, 0, framesOut * FCC_2 * sizeof(int32_t)); - activeTrack->mResampler->resample(activeTrack->mRsmpOutBuffer, framesOut, - // FIXME how about having activeTrack implement this interface itself? - activeTrack->mResamplerBufferProvider - /*this*/ /* AudioBufferProvider* */); - // ditherAndClamp() works as long as all buffers returned by - // activeTrack->getNextBuffer() are 32 bit aligned which should be always true. - if (activeTrack->mChannelCount == 1) { - // temporarily type pun mRsmpOutBuffer from Q4.27 to int16_t - ditherAndClamp(activeTrack->mRsmpOutBuffer, activeTrack->mRsmpOutBuffer, - framesOut); - // the resampler always outputs stereo samples: - // do post stereo to mono conversion - downmix_to_mono_i16_from_stereo_i16(activeTrack->mSink.i16, - (const int16_t *)activeTrack->mRsmpOutBuffer, framesOut); - } else { - ditherAndClamp((int32_t *)activeTrack->mSink.raw, - activeTrack->mRsmpOutBuffer, framesOut); - } - // now done with mRsmpOutBuffer - - } + // Don't allow framesOut to be larger than what is possible with resampling + // from framesIn. + // This isn't strictly necessary but helps limit buffer resizing in + // RecordBufferConverter. TODO: remove when no longer needed. + framesOut = min(framesOut, + destinationFramesPossible( + framesIn, mSampleRate, activeTrack->mSampleRate)); + // process frames from the RecordThread buffer provider to the RecordTrack buffer + framesOut = activeTrack->mRecordBufferConverter->convert( + activeTrack->mSink.raw, activeTrack->mResamplerBufferProvider, framesOut); if (framesOut > 0 && (overrun == OVERRUN_UNKNOWN)) { overrun = OVERRUN_FALSE; @@ -6041,12 +5946,9 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac // was initialized to some value closer to the thread's mRsmpInFront, then the track could // see previously buffered data before it called start(), but with greater risk of overrun. - recordTrack->mRsmpInFront = mRsmpInRear; - recordTrack->mRsmpInUnrel = 0; - // FIXME why reset? - if (recordTrack->mResampler != NULL) { - recordTrack->mResampler->reset(); - } + recordTrack->mResamplerBufferProvider->reset(); + // clear any converter state as new data will be discontinuous + recordTrack->mRecordBufferConverter->reset(); recordTrack->mState = TrackBase::STARTING_2; // signal thread to start mWaitWorkCV.broadcast(); @@ -6222,12 +6124,52 @@ void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args write(fd, result.string(), result.size()); } + +void AudioFlinger::RecordThread::ResamplerBufferProvider::reset() +{ + sp<ThreadBase> threadBase = mRecordTrack->mThread.promote(); + RecordThread *recordThread = (RecordThread *) threadBase.get(); + mRsmpInFront = recordThread->mRsmpInRear; + mRsmpInUnrel = 0; +} + +void AudioFlinger::RecordThread::ResamplerBufferProvider::sync( + size_t *framesAvailable, bool *hasOverrun) +{ + sp<ThreadBase> threadBase = mRecordTrack->mThread.promote(); + RecordThread *recordThread = (RecordThread *) threadBase.get(); + const int32_t rear = recordThread->mRsmpInRear; + const int32_t front = mRsmpInFront; + const ssize_t filled = rear - front; + + size_t framesIn; + bool overrun = false; + if (filled < 0) { + // should not happen, but treat like a massive overrun and re-sync + framesIn = 0; + mRsmpInFront = rear; + overrun = true; + } else if ((size_t) filled <= recordThread->mRsmpInFrames) { + framesIn = (size_t) filled; + } else { + // client is not keeping up with server, but give it latest data + framesIn = recordThread->mRsmpInFrames; + mRsmpInFront = /* front = */ rear - framesIn; + overrun = true; + } + if (framesAvailable != NULL) { + *framesAvailable = framesIn; + } + if (hasOverrun != NULL) { + *hasOverrun = overrun; + } +} + // AudioBufferProvider interface status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer( AudioBufferProvider::Buffer* buffer, int64_t pts __unused) { - RecordTrack *activeTrack = mRecordTrack; - sp<ThreadBase> threadBase = activeTrack->mThread.promote(); + sp<ThreadBase> threadBase = mRecordTrack->mThread.promote(); if (threadBase == 0) { buffer->frameCount = 0; buffer->raw = NULL; @@ -6235,7 +6177,7 @@ status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer( } RecordThread *recordThread = (RecordThread *) threadBase.get(); int32_t rear = recordThread->mRsmpInRear; - int32_t front = activeTrack->mRsmpInFront; + int32_t front = mRsmpInFront; ssize_t filled = rear - front; // FIXME should not be P2 (don't want to increase latency) // FIXME if client not keeping up, discard @@ -6252,17 +6194,16 @@ status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer( part1 = ask; } if (part1 == 0) { - // Higher-level should keep mRsmpInBuffer full, and not call resampler if empty - LOG_ALWAYS_FATAL("RecordThread::getNextBuffer() starved"); + // out of data is fine since the resampler will return a short-count. buffer->raw = NULL; buffer->frameCount = 0; - activeTrack->mRsmpInUnrel = 0; + mRsmpInUnrel = 0; return NOT_ENOUGH_DATA; } buffer->raw = recordThread->mRsmpInBuffer + front * recordThread->mChannelCount; buffer->frameCount = part1; - activeTrack->mRsmpInUnrel = part1; + mRsmpInUnrel = part1; return NO_ERROR; } @@ -6270,18 +6211,197 @@ status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer( void AudioFlinger::RecordThread::ResamplerBufferProvider::releaseBuffer( AudioBufferProvider::Buffer* buffer) { - RecordTrack *activeTrack = mRecordTrack; size_t stepCount = buffer->frameCount; if (stepCount == 0) { return; } - ALOG_ASSERT(stepCount <= activeTrack->mRsmpInUnrel); - activeTrack->mRsmpInUnrel -= stepCount; - activeTrack->mRsmpInFront += stepCount; + ALOG_ASSERT(stepCount <= mRsmpInUnrel); + mRsmpInUnrel -= stepCount; + mRsmpInFront += stepCount; buffer->raw = NULL; buffer->frameCount = 0; } +AudioFlinger::RecordThread::RecordBufferConverter::RecordBufferConverter( + audio_channel_mask_t srcChannelMask, audio_format_t srcFormat, + uint32_t srcSampleRate, + audio_channel_mask_t dstChannelMask, audio_format_t dstFormat, + uint32_t dstSampleRate) : + mSrcChannelMask(AUDIO_CHANNEL_INVALID), // updateParameters will set following vars + // mSrcFormat + // mSrcSampleRate + // mDstChannelMask + // mDstFormat + // mDstSampleRate + // mSrcChannelCount + // mDstChannelCount + // mDstFrameSize + mBuf(NULL), mBufFrames(0), mBufFrameSize(0), + mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0) +{ + (void)updateParameters(srcChannelMask, srcFormat, srcSampleRate, + dstChannelMask, dstFormat, dstSampleRate); +} + +AudioFlinger::RecordThread::RecordBufferConverter::~RecordBufferConverter() { + free(mBuf); + delete mResampler; + free(mRsmpOutBuffer); +} + +size_t AudioFlinger::RecordThread::RecordBufferConverter::convert(void *dst, + AudioBufferProvider *provider, size_t frames) +{ + if (mSrcSampleRate == mDstSampleRate) { + ALOGVV("NO RESAMPLING sampleRate:%u mSrcFormat:%#x mDstFormat:%#x", + mSrcSampleRate, mSrcFormat, mDstFormat); + + AudioBufferProvider::Buffer buffer; + for (size_t i = frames; i > 0; ) { + buffer.frameCount = i; + status_t status = provider->getNextBuffer(&buffer, 0); + if (status != OK || buffer.frameCount == 0) { + frames -= i; // cannot fill request. + break; + } + // convert to destination buffer + convert(dst, buffer.raw, buffer.frameCount); + + dst = (int8_t*)dst + buffer.frameCount * mDstFrameSize; + i -= buffer.frameCount; + provider->releaseBuffer(&buffer); + } + } else { + ALOGVV("RESAMPLING mSrcSampleRate:%u mDstSampleRate:%u mSrcFormat:%#x mDstFormat:%#x", + mSrcSampleRate, mDstSampleRate, mSrcFormat, mDstFormat); + + // reallocate mRsmpOutBuffer as needed; we will grow but never shrink + if (mRsmpOutFrameCount < frames) { + // FIXME why does each track need it's own mRsmpOutBuffer? can't they share? + free(mRsmpOutBuffer); + // resampler always outputs stereo (FOR NOW) + (void)posix_memalign(&mRsmpOutBuffer, 32, frames * FCC_2 * sizeof(int32_t) /*Q4.27*/); + mRsmpOutFrameCount = frames; + } + // resampler accumulates, but we only have one source track + memset(mRsmpOutBuffer, 0, frames * FCC_2 * sizeof(int32_t)); + frames = mResampler->resample((int32_t*)mRsmpOutBuffer, frames, provider); + + // convert to destination buffer + convert(dst, mRsmpOutBuffer, frames); + } + return frames; +} + +status_t AudioFlinger::RecordThread::RecordBufferConverter::updateParameters( + audio_channel_mask_t srcChannelMask, audio_format_t srcFormat, + uint32_t srcSampleRate, + audio_channel_mask_t dstChannelMask, audio_format_t dstFormat, + uint32_t dstSampleRate) +{ + // quick evaluation if there is any change. + if (mSrcFormat == srcFormat + && mSrcChannelMask == srcChannelMask + && mSrcSampleRate == srcSampleRate + && mDstFormat == dstFormat + && mDstChannelMask == dstChannelMask + && mDstSampleRate == dstSampleRate) { + return NO_ERROR; + } + + const bool valid = + audio_is_input_channel(srcChannelMask) + && audio_is_input_channel(dstChannelMask) + && audio_is_valid_format(srcFormat) && audio_is_linear_pcm(srcFormat) + && audio_is_valid_format(dstFormat) && audio_is_linear_pcm(dstFormat) + && (srcSampleRate <= dstSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) + ; // no upsampling checks for now + if (!valid) { + return BAD_VALUE; + } + + mSrcFormat = srcFormat; + mSrcChannelMask = srcChannelMask; + mSrcSampleRate = srcSampleRate; + mDstFormat = dstFormat; + mDstChannelMask = dstChannelMask; + mDstSampleRate = dstSampleRate; + + // compute derived parameters + mSrcChannelCount = audio_channel_count_from_in_mask(srcChannelMask); + mDstChannelCount = audio_channel_count_from_in_mask(dstChannelMask); + mDstFrameSize = mDstChannelCount * audio_bytes_per_sample(mDstFormat); + + // do we need a format buffer? + if (mSrcFormat != mDstFormat && mDstChannelCount != mSrcChannelCount) { + mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(mSrcFormat); + } else { + mBufFrameSize = 0; + } + mBufFrames = 0; // force the buffer to be resized. + + // do we need to resample? + if (mSrcSampleRate != mDstSampleRate) { + if (mResampler != NULL) { + delete mResampler; + } + mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_16_BIT, + mSrcChannelCount, mDstSampleRate); // may seem confusing... + mResampler->setSampleRate(mSrcSampleRate); + mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT); + } + return NO_ERROR; +} + +void AudioFlinger::RecordThread::RecordBufferConverter::convert( + void *dst, /*const*/ void *src, size_t frames) +{ + // check if a memcpy will do + if (mResampler == NULL + && mSrcChannelCount == mDstChannelCount + && mSrcFormat == mDstFormat) { + memcpy(dst, src, + frames * mDstChannelCount * audio_bytes_per_sample(mDstFormat)); + return; + } + // reallocate buffer if needed + if (mBufFrameSize != 0 && mBufFrames < frames) { + free(mBuf); + mBufFrames = frames; + (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize); + } + // do processing + if (mResampler != NULL) { + // src channel count is always >= 2. + void *dstBuf = mBuf != NULL ? mBuf : dst; + // ditherAndClamp() works as long as all buffers returned by + // activeTrack->getNextBuffer() are 32 bit aligned which should be always true. + if (mDstChannelCount == 1) { + // the resampler always outputs stereo samples. + // FIXME: this rewrites back into src + ditherAndClamp((int32_t *)src, (const int32_t *)src, frames); + downmix_to_mono_i16_from_stereo_i16((int16_t *)dstBuf, + (const int16_t *)src, frames); + } else { + ditherAndClamp((int32_t *)dstBuf, (const int32_t *)src, frames); + } + } else if (mSrcChannelCount != mDstChannelCount) { + void *dstBuf = mBuf != NULL ? mBuf : dst; + if (mSrcChannelCount == 1) { + upmix_to_stereo_i16_from_mono_i16((int16_t *)dstBuf, (const int16_t *)src, + frames); + } else { + downmix_to_mono_i16_from_stereo_i16((int16_t *)dstBuf, + (const int16_t *)src, frames); + } + } + if (mSrcFormat != mDstFormat) { + void *srcBuf = mBuf != NULL ? mBuf : src; + memcpy_by_audio_format(dst, mDstFormat, srcBuf, mSrcFormat, + frames * mDstChannelCount); + } +} + bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair, status_t& status) { @@ -6303,7 +6423,7 @@ bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValueP reconfig = true; } if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) { - if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) { + if (!audio_is_linear_pcm((audio_format_t) value)) { status = BAD_VALUE; } else { reqFormat = (audio_format_t) value; @@ -6377,10 +6497,10 @@ bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValueP } if (reconfig) { if (status == BAD_VALUE && - reqFormat == mInput->stream->common.get_format(&mInput->stream->common) && - reqFormat == AUDIO_FORMAT_PCM_16_BIT && + audio_is_linear_pcm(mInput->stream->common.get_format(&mInput->stream->common)) && + audio_is_linear_pcm(reqFormat) && (mInput->stream->common.get_sample_rate(&mInput->stream->common) - <= (2 * samplingRate)) && + <= (AUDIO_RESAMPLER_DOWN_RATIO_MAX * samplingRate)) && audio_channel_count_from_in_mask( mInput->stream->common.get_channels(&mInput->stream->common)) <= FCC_2 && (channelMask == AUDIO_CHANNEL_IN_MONO || @@ -6451,6 +6571,8 @@ void AudioFlinger::RecordThread::readInputParameters_l() // The value is somewhat arbitrary, and could probably be even larger. // A larger value should allow more old data to be read after a track calls start(), // without increasing latency. + // + // Note this is independent of the maximum downsampling ratio permitted for capture. mRsmpInFrames = mFrameCount * 7; mRsmpInFramesP2 = roundup(mRsmpInFrames); delete[] mRsmpInBuffer; diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index d600ea9..27bc56b 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -1036,17 +1036,127 @@ class RecordThread : public ThreadBase public: class RecordTrack; + + /* The ResamplerBufferProvider is used to retrieve recorded input data from the + * RecordThread. It maintains local state on the relative position of the read + * position of the RecordTrack compared with the RecordThread. + */ class ResamplerBufferProvider : public AudioBufferProvider - // derives from AudioBufferProvider interface for use by resampler { public: - ResamplerBufferProvider(RecordTrack* recordTrack) : mRecordTrack(recordTrack) { } + ResamplerBufferProvider(RecordTrack* recordTrack) : + mRecordTrack(recordTrack), + mRsmpInUnrel(0), mRsmpInFront(0) { } virtual ~ResamplerBufferProvider() { } + + // called to set the ResamplerBufferProvider to head of the RecordThread data buffer, + // skipping any previous data read from the hal. + virtual void reset(); + + /* Synchronizes RecordTrack position with the RecordThread. + * Calculates available frames and handle overruns if the RecordThread + * has advanced faster than the ResamplerBufferProvider has retrieved data. + * TODO: why not do this for every getNextBuffer? + * + * Parameters + * framesAvailable: pointer to optional output size_t to store record track + * frames available. + * hasOverrun: pointer to optional boolean, returns true if track has overrun. + */ + + virtual void sync(size_t *framesAvailable = NULL, bool *hasOverrun = NULL); + // AudioBufferProvider interface virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts); virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer); private: RecordTrack * const mRecordTrack; + size_t mRsmpInUnrel; // unreleased frames remaining from + // most recent getNextBuffer + // for debug only + int32_t mRsmpInFront; // next available frame + // rolling counter that is never cleared + }; + + /* The RecordBufferConverter is used for format, channel, and sample rate + * conversion for a RecordTrack. + * + * TODO: Self contained, so move to a separate file later. + * + * RecordBufferConverter uses the convert() method rather than exposing a + * buffer provider interface; this is to save a memory copy. + */ + class RecordBufferConverter + { + public: + RecordBufferConverter( + audio_channel_mask_t srcChannelMask, audio_format_t srcFormat, + uint32_t srcSampleRate, + audio_channel_mask_t dstChannelMask, audio_format_t dstFormat, + uint32_t dstSampleRate); + + ~RecordBufferConverter(); + + /* Converts input data from an AudioBufferProvider by format, channelMask, + * and sampleRate to a destination buffer. + * + * Parameters + * dst: buffer to place the converted data. + * provider: buffer provider to obtain source data. + * frames: number of frames to convert + * + * Returns the number of frames converted. + */ + size_t convert(void *dst, AudioBufferProvider *provider, size_t frames); + + // returns NO_ERROR if constructor was successful + status_t initCheck() const { + // mSrcChannelMask set on successful updateParameters + return mSrcChannelMask != AUDIO_CHANNEL_INVALID ? NO_ERROR : NO_INIT; + } + + // allows dynamic reconfigure of all parameters + status_t updateParameters( + audio_channel_mask_t srcChannelMask, audio_format_t srcFormat, + uint32_t srcSampleRate, + audio_channel_mask_t dstChannelMask, audio_format_t dstFormat, + uint32_t dstSampleRate); + + // called to reset resampler buffers on record track discontinuity + void reset() { + if (mResampler != NULL) { + mResampler->reset(); + } + } + + private: + // internal convert function for format and channel mask. + void convert(void *dst, /*const*/ void *src, size_t frames); + + // user provided information + audio_channel_mask_t mSrcChannelMask; + audio_format_t mSrcFormat; + uint32_t mSrcSampleRate; + audio_channel_mask_t mDstChannelMask; + audio_format_t mDstFormat; + uint32_t mDstSampleRate; + + // derived information + uint32_t mSrcChannelCount; + uint32_t mDstChannelCount; + size_t mDstFrameSize; + + // format conversion buffer + void *mBuf; + size_t mBufFrames; + size_t mBufFrameSize; + + // resampler info + AudioResampler *mResampler; + // interleaved stereo pairs of fixed-point Q4.27 or float depending on resampler + void *mRsmpOutBuffer; + // current allocated frame count for the above, which may be larger than needed + size_t mRsmpOutFrameCount; }; #include "RecordTracks.h" diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index dc9f249..1566b1f 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -1861,13 +1861,14 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() AudioFlinger::PlaybackThread::PatchTrack::PatchTrack(PlaybackThread *playbackThread, + audio_stream_type_t streamType, uint32_t sampleRate, audio_channel_mask_t channelMask, audio_format_t format, size_t frameCount, void *buffer, IAudioFlinger::track_flags_t flags) - : Track(playbackThread, NULL, AUDIO_STREAM_PATCH, + : Track(playbackThread, NULL, streamType, sampleRate, format, channelMask, frameCount, buffer, 0, 0, getuid(), flags, TYPE_PATCH), mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true)) @@ -1989,29 +1990,30 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( ((flags & IAudioFlinger::TRACK_FAST) ? ALLOC_PIPE : ALLOC_CBLK) : ((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE), type), - mOverflow(false), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0), - // See real initialization of mRsmpInFront at RecordThread::start() - mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL) + mOverflow(false), + mFramesToDrop(0) { if (mCblk == NULL) { return; } + mRecordBufferConverter = new RecordBufferConverter( + thread->mChannelMask, thread->mFormat, thread->mSampleRate, + channelMask, format, sampleRate); + // Check if the RecordBufferConverter construction was successful. + // If not, don't continue with construction. + // + // NOTE: It would be extremely rare that the record track cannot be created + // for the current device, but a pending or future device change would make + // the record track configuration valid. + if (mRecordBufferConverter->initCheck() != NO_ERROR) { + ALOGE("RecordTrack unable to create record buffer converter"); + return; + } + mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, mFrameSize, !isExternalTrack()); - - uint32_t channelCount = audio_channel_count_from_in_mask(channelMask); - // FIXME I don't understand either of the channel count checks - if (thread->mSampleRate != sampleRate && thread->mChannelCount <= FCC_2 && - channelCount <= FCC_2) { - // sink SR - mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_16_BIT, - thread->mChannelCount, sampleRate); - // source SR - mResampler->setSampleRate(thread->mSampleRate); - mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT); - mResamplerBufferProvider = new ResamplerBufferProvider(this); - } + mResamplerBufferProvider = new ResamplerBufferProvider(this); if (flags & IAudioFlinger::TRACK_FAST) { ALOG_ASSERT(thread->mFastTrackAvail); @@ -2022,11 +2024,19 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( AudioFlinger::RecordThread::RecordTrack::~RecordTrack() { ALOGV("%s", __func__); - delete mResampler; - delete[] mRsmpOutBuffer; + delete mRecordBufferConverter; delete mResamplerBufferProvider; } +status_t AudioFlinger::RecordThread::RecordTrack::initCheck() const +{ + status_t status = TrackBase::initCheck(); + if (status == NO_ERROR && mServerProxy == 0) { + status = BAD_VALUE; + } + return status; +} + // AudioBufferProvider interface status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts __unused) diff --git a/services/audioflinger/tests/resampler_tests.cpp b/services/audioflinger/tests/resampler_tests.cpp index d6217ba..9e375db 100644 --- a/services/audioflinger/tests/resampler_tests.cpp +++ b/services/audioflinger/tests/resampler_tests.cpp @@ -48,7 +48,10 @@ void resample(int channels, void *output, if (thisFrames == 0 || thisFrames > outputFrames - i) { thisFrames = outputFrames - i; } - resampler->resample((int32_t*) output + channels*i, thisFrames, provider); + size_t framesResampled = resampler->resample( + (int32_t*) output + channels*i, thisFrames, provider); + // we should have enough buffer space, so there is no short count. + ASSERT_EQ(thisFrames, framesResampled); i += thisFrames; } } diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h index 116d0d6..48d0e29 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -110,6 +110,7 @@ public: audio_format_t format, audio_channel_mask_t channelMask, audio_output_flags_t flags, + int selectedDeviceId, const audio_offload_info_t *offloadInfo) = 0; // indicates to the audio policy manager that the output starts being used by corresponding stream. virtual status_t startOutput(audio_io_handle_t output, diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h index a4cc759..4205589 100755 --- a/services/audiopolicy/common/include/Volume.h +++ b/services/audiopolicy/common/include/Volume.h @@ -18,6 +18,10 @@ #include <system/audio.h> #include <utils/Log.h> +#include <math.h> + +// Absolute min volume in dB (can be represented in single precision normal float value) +#define VOLUME_MIN_DB (-758) class VolumeCurvePoint { @@ -32,7 +36,7 @@ public: /** * 4 points to define the volume attenuation curve, each characterized by the volume * index (from 0 to 100) at which they apply, and the attenuation in dB at that index. - * we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl() + * we use 100 steps to avoid rounding errors when computing the volume in volIndexToDb() * * @todo shall become configurable */ @@ -134,4 +138,20 @@ public: } } + static inline float DbToAmpl(float decibels) + { + if (decibels <= VOLUME_MIN_DB) { + return 0.0f; + } + return exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 ) + } + + static inline float AmplToDb(float amplification) + { + if (amplification == 0) { + return VOLUME_MIN_DB; + } + return 20 * log10(amplification); + } + }; diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk index 71ba1cb..7c265aa 100644 --- a/services/audiopolicy/common/managerdefinitions/Android.mk +++ b/services/audiopolicy/common/managerdefinitions/Android.mk @@ -25,6 +25,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/include \ $(TOPDIR)frameworks/av/services/audiopolicy/common/include \ + $(TOPDIR)frameworks/av/services/audiopolicy LOCAL_EXPORT_C_INCLUDE_DIRS := \ $(LOCAL_PATH)/include diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h index 7536a37..18bcfdb 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h @@ -34,12 +34,11 @@ class AudioInputDescriptor: public AudioPortConfig public: AudioInputDescriptor(const sp<IOProfile>& profile); void setIoHandle(audio_io_handle_t ioHandle); - + audio_port_handle_t getId() const; audio_module_handle_t getModuleHandle() const; status_t dump(int fd); - audio_port_handle_t mId; audio_io_handle_t mIoHandle; // input handle audio_devices_t mDevice; // current device this input is routed to AudioMix *mPolicyMix; // non NULL when used by a dynamic policy @@ -57,6 +56,9 @@ public: const struct audio_port_config *srcConfig = NULL) const; virtual sp<AudioPort> getAudioPort() const { return mProfile; } void toAudioPort(struct audio_port *port) const; + +private: + audio_port_handle_t mId; }; class AudioInputCollection : diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h index 43ee691..f1aee46 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h @@ -27,24 +27,36 @@ namespace android { class IOProfile; class AudioMix; +class AudioPolicyClientInterface; // descriptor for audio outputs. Used to maintain current configuration of each opened audio output // and keep track of the usage of this output by each audio stream type. class AudioOutputDescriptor: public AudioPortConfig { public: - AudioOutputDescriptor(const sp<IOProfile>& profile); + AudioOutputDescriptor(const sp<AudioPort>& port, + AudioPolicyClientInterface *clientInterface); + virtual ~AudioOutputDescriptor() {} status_t dump(int fd); + void log(const char* indent); + + audio_port_handle_t getId() const; + virtual audio_devices_t device() const; + virtual bool sharesHwModuleWith(const sp<AudioOutputDescriptor> outputDesc); + virtual audio_devices_t supportedDevices(); + virtual bool isDuplicated() const { return false; } + virtual uint32_t latency() { return 0; } + virtual bool isFixedVolume(audio_devices_t device); + virtual sp<AudioOutputDescriptor> subOutput1() { return 0; } + virtual sp<AudioOutputDescriptor> subOutput2() { return 0; } + virtual bool setVolume(float volume, + audio_stream_type_t stream, + audio_devices_t device, + uint32_t delayMs, + bool force); + virtual void changeRefCount(audio_stream_type_t stream, int delta); - audio_devices_t device() const; - void changeRefCount(audio_stream_type_t stream, int delta); - - void setIoHandle(audio_io_handle_t ioHandle); - bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); } - audio_devices_t supportedDevices(); - uint32_t latency(); - bool sharesHwModuleWith(const sp<AudioOutputDescriptor> outputDesc); bool isActive(uint32_t inPastMs = 0) const; bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0, @@ -52,32 +64,69 @@ public: virtual void toAudioPortConfig(struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig = NULL) const; - virtual sp<AudioPort> getAudioPort() const { return mProfile; } - void toAudioPort(struct audio_port *port) const; + virtual sp<AudioPort> getAudioPort() const { return mPort; } + virtual void toAudioPort(struct audio_port *port) const; audio_module_handle_t getModuleHandle() const; - audio_port_handle_t mId; - audio_io_handle_t mIoHandle; // output handle - uint32_t mLatency; // - audio_output_flags_t mFlags; // + sp<AudioPort> mPort; audio_devices_t mDevice; // current device this output is routed to - AudioMix *mPolicyMix; // non NULL when used by a dynamic policy 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]; - sp<AudioOutputDescriptor> mOutput1; // used by duplicated outputs: first output - sp<AudioOutputDescriptor> mOutput2; // used by duplicated outputs: second output - float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume + float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume in dB int mMuteCount[AUDIO_STREAM_CNT]; // mute request counter - const sp<IOProfile> mProfile; // I/O profile this output derives from bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible // device selection. See checkDeviceMuteStrategies() + AudioPolicyClientInterface *mClientInterface; + +protected: + audio_port_handle_t mId; +}; + +// Audio output driven by a software mixer in audio flinger. +class SwAudioOutputDescriptor: public AudioOutputDescriptor +{ +public: + SwAudioOutputDescriptor(const sp<IOProfile>& profile, + AudioPolicyClientInterface *clientInterface); + virtual ~SwAudioOutputDescriptor() {} + + status_t dump(int fd); + + void setIoHandle(audio_io_handle_t ioHandle); + + virtual audio_devices_t device() const; + virtual bool sharesHwModuleWith(const sp<AudioOutputDescriptor> outputDesc); + virtual audio_devices_t supportedDevices(); + virtual uint32_t latency(); + virtual bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); } + virtual bool isFixedVolume(audio_devices_t device); + virtual sp<AudioOutputDescriptor> subOutput1() { return mOutput1; } + virtual sp<AudioOutputDescriptor> subOutput2() { return mOutput2; } + virtual void changeRefCount(audio_stream_type_t stream, int delta); + virtual bool setVolume(float volume, + audio_stream_type_t stream, + audio_devices_t device, + uint32_t delayMs, + bool force); + + virtual void toAudioPortConfig(struct audio_port_config *dstConfig, + const struct audio_port_config *srcConfig = NULL) const; + virtual void toAudioPort(struct audio_port *port) const; + + const sp<IOProfile> mProfile; // I/O profile this output derives from + audio_io_handle_t mIoHandle; // output handle + uint32_t mLatency; // + audio_output_flags_t mFlags; // + AudioMix *mPolicyMix; // non NULL when used by a dynamic policy + sp<SwAudioOutputDescriptor> mOutput1; // used by duplicated outputs: first output + sp<SwAudioOutputDescriptor> mOutput2; // used by duplicated outputs: second output uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only) }; -class AudioOutputCollection : - public DefaultKeyedVector< audio_io_handle_t, sp<AudioOutputDescriptor> > +class SwAudioOutputCollection : + public DefaultKeyedVector< audio_io_handle_t, sp<SwAudioOutputDescriptor> > { public: bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const; @@ -96,9 +145,9 @@ public: */ audio_io_handle_t getA2dpOutput() const; - sp<AudioOutputDescriptor> getOutputFromId(audio_port_handle_t id) const; + sp<SwAudioOutputDescriptor> getOutputFromId(audio_port_handle_t id) const; - sp<AudioOutputDescriptor> getPrimaryOutput() const; + sp<SwAudioOutputDescriptor> getPrimaryOutput() const; /** * return true if any output is playing anything besides the stream to ignore diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h index 988aed6..d51f4e1 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h @@ -24,7 +24,7 @@ namespace android { -class AudioOutputDescriptor; +class SwAudioOutputDescriptor; /** * custom mix entry in mPolicyMixes @@ -33,19 +33,19 @@ class AudioPolicyMix : public RefBase { public: AudioPolicyMix() {} - const sp<AudioOutputDescriptor> &getOutput() const; + const sp<SwAudioOutputDescriptor> &getOutput() const; - void setOutput(sp<AudioOutputDescriptor> &output); + void setOutput(sp<SwAudioOutputDescriptor> &output); void clearOutput(); - android::AudioMix &getMix(); + android::AudioMix *getMix(); void setMix(AudioMix &mix); private: AudioMix mMix; // Audio policy mix descriptor - sp<AudioOutputDescriptor> mOutput; // Corresponding output stream + sp<SwAudioOutputDescriptor> mOutput; // Corresponding output stream }; @@ -58,24 +58,24 @@ public: status_t unregisterMix(String8 address); - void closeOutput(sp<AudioOutputDescriptor> &desc); + void closeOutput(sp<SwAudioOutputDescriptor> &desc); /** * Try to find an output descriptor for the given attributes. * - * @param[in] attributes to consider for the research of output descriptor. + * @param[in] attributes to consider fowr the research of output descriptor. * @param[out] desc to return if an output could be found. * * @return NO_ERROR if an output was found for the given attribute (in this case, the * descriptor output param is initialized), error code otherwise. */ - status_t getOutputForAttr(audio_attributes_t attributes, sp<AudioOutputDescriptor> &desc); + status_t getOutputForAttr(audio_attributes_t attributes, sp<SwAudioOutputDescriptor> &desc); audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource, audio_devices_t availableDeviceTypes, AudioMix **policyMix); - status_t getInputMixForAttr(audio_attributes_t attr, AudioMix *&policyMix); + status_t getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix); }; }; // namespace android diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h index 4f7f2bc..dea1b8a 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h @@ -32,13 +32,11 @@ class AudioPort : public virtual RefBase { public: AudioPort(const String8& name, audio_port_type_t type, - audio_port_role_t role, const sp<HwModule>& module); + audio_port_role_t role); virtual ~AudioPort() {} - audio_port_handle_t getHandle() { return mId; } - - void attach(const sp<HwModule>& module); - bool isAttached() { return mId != 0; } + virtual void attach(const sp<HwModule>& module); + bool isAttached() { return mModule != 0; } static audio_port_handle_t getNextUniqueId(); @@ -76,8 +74,11 @@ public: static int compareFormats(audio_format_t format1, audio_format_t format2); audio_module_handle_t getModuleHandle() const; + uint32_t getModuleVersion() const; + const char *getModuleName() const; void dump(int fd, int spaces) const; + void log(const char* indent) const; String8 mName; audio_port_type_t mType; @@ -94,13 +95,6 @@ public: uint32_t mFlags; // attribute flags (e.g primary output, // direct output...). - -protected: - //TODO - clarify the role of mId in this case, both an "attached" indicator - // and a unique ID for identifying a port to the (upcoming) selection API, - // and its relationship to the mId in AudioOutputDescriptor and AudioInputDescriptor. - audio_port_handle_t mId; - private: static volatile int32_t mNextUniqueId; }; diff --git a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h index 14a7d36..f8c4d08 100644 --- a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h +++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h @@ -39,11 +39,12 @@ struct StringToEnum { }; #define STRING_TO_ENUM(string) { #string, string } +#define NAME_TO_ENUM(name, value) { name, value } #ifndef ARRAY_SIZE #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #endif -const StringToEnum sDeviceNameToEnumTable[] = { +const StringToEnum sDeviceTypeToEnumTable[] = { STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE), STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER), STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER_SAFE), @@ -94,6 +95,57 @@ const StringToEnum sDeviceNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_DEVICE_IN_LOOPBACK), }; +const StringToEnum sDeviceNameToEnumTable[] = { + NAME_TO_ENUM("Earpiece", AUDIO_DEVICE_OUT_EARPIECE), + NAME_TO_ENUM("Speaker", AUDIO_DEVICE_OUT_SPEAKER), + NAME_TO_ENUM("Speaker Protected", AUDIO_DEVICE_OUT_SPEAKER_SAFE), + NAME_TO_ENUM("Wired Headset", AUDIO_DEVICE_OUT_WIRED_HEADSET), + NAME_TO_ENUM("Wired Headphones", AUDIO_DEVICE_OUT_WIRED_HEADPHONE), + NAME_TO_ENUM("BT SCO", AUDIO_DEVICE_OUT_BLUETOOTH_SCO), + NAME_TO_ENUM("BT SCO Headset", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET), + NAME_TO_ENUM("BT SCO Car Kit", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT), + NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_SCO), + NAME_TO_ENUM("BT A2DP Out", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP), + NAME_TO_ENUM("BT A2DP Headphones", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES), + NAME_TO_ENUM("BT A2DP Speaker", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), + NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_A2DP), + NAME_TO_ENUM("HDMI Out", AUDIO_DEVICE_OUT_AUX_DIGITAL), + NAME_TO_ENUM("HDMI Out", AUDIO_DEVICE_OUT_HDMI), + NAME_TO_ENUM("Analog Dock Out", AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET), + NAME_TO_ENUM("Digital Dock Out", AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET), + NAME_TO_ENUM("USB Host Out", AUDIO_DEVICE_OUT_USB_ACCESSORY), + NAME_TO_ENUM("USB Device Out", AUDIO_DEVICE_OUT_USB_DEVICE), + NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_USB), + NAME_TO_ENUM("Reroute Submix Out", AUDIO_DEVICE_OUT_REMOTE_SUBMIX), + NAME_TO_ENUM("Telephony Tx", AUDIO_DEVICE_OUT_TELEPHONY_TX), + NAME_TO_ENUM("Line Out", AUDIO_DEVICE_OUT_LINE), + NAME_TO_ENUM("HDMI ARC Out", AUDIO_DEVICE_OUT_HDMI_ARC), + NAME_TO_ENUM("S/PDIF Out", AUDIO_DEVICE_OUT_SPDIF), + NAME_TO_ENUM("FM transceiver Out", AUDIO_DEVICE_OUT_FM), + NAME_TO_ENUM("Aux Line Out", AUDIO_DEVICE_OUT_AUX_LINE), + NAME_TO_ENUM("Ambient Mic", AUDIO_DEVICE_IN_AMBIENT), + NAME_TO_ENUM("Built-In Mic", AUDIO_DEVICE_IN_BUILTIN_MIC), + NAME_TO_ENUM("BT SCO Headset Mic", AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET), + NAME_TO_ENUM("", AUDIO_DEVICE_IN_ALL_SCO), + NAME_TO_ENUM("Wired Headset Mic", AUDIO_DEVICE_IN_WIRED_HEADSET), + NAME_TO_ENUM("HDMI In", AUDIO_DEVICE_IN_AUX_DIGITAL), + NAME_TO_ENUM("HDMI In", AUDIO_DEVICE_IN_HDMI), + NAME_TO_ENUM("Telephony Rx", AUDIO_DEVICE_IN_TELEPHONY_RX), + NAME_TO_ENUM("Telephony Rx", AUDIO_DEVICE_IN_VOICE_CALL), + NAME_TO_ENUM("Built-In Back Mic", AUDIO_DEVICE_IN_BACK_MIC), + NAME_TO_ENUM("Reroute Submix In", AUDIO_DEVICE_IN_REMOTE_SUBMIX), + NAME_TO_ENUM("Analog Dock In", AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET), + NAME_TO_ENUM("Digital Dock In", AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET), + NAME_TO_ENUM("USB Host In", AUDIO_DEVICE_IN_USB_ACCESSORY), + NAME_TO_ENUM("USB Device In", AUDIO_DEVICE_IN_USB_DEVICE), + NAME_TO_ENUM("FM Tuner In", AUDIO_DEVICE_IN_FM_TUNER), + NAME_TO_ENUM("TV Tuner In", AUDIO_DEVICE_IN_TV_TUNER), + NAME_TO_ENUM("Line In", AUDIO_DEVICE_IN_LINE), + NAME_TO_ENUM("S/PDIF In", AUDIO_DEVICE_IN_SPDIF), + NAME_TO_ENUM("BT A2DP In", AUDIO_DEVICE_IN_BLUETOOTH_A2DP), + NAME_TO_ENUM("Loopback In", AUDIO_DEVICE_IN_LOOPBACK), +}; + const StringToEnum sOutputFlagNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT), STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY), diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h index d15f6b4..aa37eec 100644 --- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h @@ -41,19 +41,22 @@ public: const struct audio_port_config *srcConfig = NULL) const; // AudioPort + virtual void attach(const sp<HwModule>& module); virtual void loadGains(cnode *root); virtual void toAudioPort(struct audio_port *port) const; + audio_port_handle_t getId() const; audio_devices_t type() const { return mDeviceType; } status_t dump(int fd, int spaces, int index) const; + void log() const; String8 mAddress; - audio_port_handle_t mId; static String8 emptyNameStr; private: - audio_devices_t mDeviceType; + audio_devices_t mDeviceType; + audio_port_handle_t mId; friend class DeviceVector; }; diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h index 095e759..022257e 100644 --- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h +++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h @@ -33,7 +33,7 @@ class HwModule; class IOProfile : public AudioPort { public: - IOProfile(const String8& name, audio_port_role_t role, const sp<HwModule>& module); + IOProfile(const String8& name, audio_port_role_t role); virtual ~IOProfile(); // This method is used for both output and input. diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp index fa66728..937160b 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp @@ -27,9 +27,9 @@ namespace android { AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile) - : mId(0), mIoHandle(0), + : mIoHandle(0), mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0), - mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false) + mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false), mId(0) { if (profile != NULL) { mSamplingRate = profile->pickSamplingRate(); @@ -49,9 +49,17 @@ void AudioInputDescriptor::setIoHandle(audio_io_handle_t ioHandle) audio_module_handle_t AudioInputDescriptor::getModuleHandle() const { + if (mProfile == 0) { + return 0; + } return mProfile->getModuleHandle(); } +audio_port_handle_t AudioInputDescriptor::getId() const +{ + return mId; +} + void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig) const { @@ -68,7 +76,7 @@ void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig dstConfig->id = mId; dstConfig->role = AUDIO_PORT_ROLE_SINK; dstConfig->type = AUDIO_PORT_TYPE_MIX; - dstConfig->ext.mix.hw_module = mProfile->mModule->mHandle; + dstConfig->ext.mix.hw_module = getModuleHandle(); dstConfig->ext.mix.handle = mIoHandle; dstConfig->ext.mix.usecase.source = mInputSource; } @@ -80,7 +88,7 @@ void AudioInputDescriptor::toAudioPort(struct audio_port *port) const mProfile->toAudioPort(port); port->id = mId; toAudioPortConfig(&port->active_config); - port->ext.mix.hw_module = mProfile->mModule->mHandle; + port->ext.mix.hw_module = getModuleHandle(); port->ext.mix.handle = mIoHandle; port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL; } @@ -91,7 +99,7 @@ status_t AudioInputDescriptor::dump(int fd) char buffer[SIZE]; String8 result; - snprintf(buffer, SIZE, " ID: %d\n", mId); + snprintf(buffer, SIZE, " ID: %d\n", getId()); result.append(buffer); snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate); result.append(buffer); @@ -130,7 +138,7 @@ sp<AudioInputDescriptor> AudioInputCollection::getInputFromId(audio_port_handle_ sp<AudioInputDescriptor> inputDesc = NULL; for (size_t i = 0; i < size(); i++) { inputDesc = valueAt(i); - if (inputDesc->mId == id) { + if (inputDesc->getId() == id) { break; } } diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp index cdb5b51..596aa1d 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp @@ -17,9 +17,11 @@ #define LOG_TAG "APM::AudioOutputDescriptor" //#define LOG_NDEBUG 0 +#include <AudioPolicyInterface.h> #include "AudioOutputDescriptor.h" #include "IOProfile.h" #include "AudioGain.h" +#include "Volume.h" #include "HwModule.h" #include <media/AudioPolicy.h> @@ -29,11 +31,10 @@ namespace android { -AudioOutputDescriptor::AudioOutputDescriptor(const sp<IOProfile>& profile) - : mId(0), mIoHandle(0), mLatency(0), - mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), - mPatchHandle(0), - mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0) +AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port, + AudioPolicyClientInterface *clientInterface) + : mPort(port), mDevice(AUDIO_DEVICE_NONE), + mPatchHandle(0), mClientInterface(clientInterface), mId(0) { // clear usage count for all stream types for (int i = 0; i < AUDIO_STREAM_CNT; i++) { @@ -45,66 +46,50 @@ AudioOutputDescriptor::AudioOutputDescriptor(const sp<IOProfile>& profile) for (int i = 0; i < NUM_STRATEGIES; i++) { mStrategyMutedByDevice[i] = false; } - if (profile != NULL) { - mFlags = (audio_output_flags_t)profile->mFlags; - mSamplingRate = profile->pickSamplingRate(); - mFormat = profile->pickFormat(); - mChannelMask = profile->pickChannelMask(); - if (profile->mGains.size() > 0) { - profile->mGains[0]->getDefaultConfig(&mGain); + if (port != NULL) { + mSamplingRate = port->pickSamplingRate(); + mFormat = port->pickFormat(); + mChannelMask = port->pickChannelMask(); + if (port->mGains.size() > 0) { + port->mGains[0]->getDefaultConfig(&mGain); } } } audio_module_handle_t AudioOutputDescriptor::getModuleHandle() const { - return mProfile->getModuleHandle(); + return mPort->getModuleHandle(); } -audio_devices_t AudioOutputDescriptor::device() const +audio_port_handle_t AudioOutputDescriptor::getId() const { - if (isDuplicated()) { - return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice); - } else { - return mDevice; - } + return mId; } -void AudioOutputDescriptor::setIoHandle(audio_io_handle_t ioHandle) +audio_devices_t AudioOutputDescriptor::device() const { - mId = AudioPort::getNextUniqueId(); - mIoHandle = ioHandle; + return mDevice; } -uint32_t AudioOutputDescriptor::latency() +audio_devices_t AudioOutputDescriptor::supportedDevices() { - if (isDuplicated()) { - return (mOutput1->mLatency > mOutput2->mLatency) ? mOutput1->mLatency : mOutput2->mLatency; - } else { - return mLatency; - } + return mDevice; } bool AudioOutputDescriptor::sharesHwModuleWith( const sp<AudioOutputDescriptor> outputDesc) { - if (isDuplicated()) { - return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc); - } else if (outputDesc->isDuplicated()){ - return sharesHwModuleWith(outputDesc->mOutput1) || sharesHwModuleWith(outputDesc->mOutput2); + if (outputDesc->isDuplicated()) { + return sharesHwModuleWith(outputDesc->subOutput1()) || + sharesHwModuleWith(outputDesc->subOutput2()); } else { - return (mProfile->mModule == outputDesc->mProfile->mModule); + return (getModuleHandle() == outputDesc->getModuleHandle()); } } void AudioOutputDescriptor::changeRefCount(audio_stream_type_t stream, int delta) { - // forward usage count change to attached outputs - if (isDuplicated()) { - mOutput1->changeRefCount(stream, delta); - mOutput2->changeRefCount(stream, delta); - } if ((delta + (int)mRefCount[stream]) < 0) { ALOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]); @@ -115,15 +100,6 @@ void AudioOutputDescriptor::changeRefCount(audio_stream_type_t stream, ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]); } -audio_devices_t AudioOutputDescriptor::supportedDevices() -{ - if (isDuplicated()) { - return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices()); - } else { - return mProfile->mSupportedDevices.types() ; - } -} - bool AudioOutputDescriptor::isActive(uint32_t inPastMs) const { nsecs_t sysTime = 0; @@ -160,12 +136,33 @@ bool AudioOutputDescriptor::isStreamActive(audio_stream_type_t stream, return false; } + +bool AudioOutputDescriptor::isFixedVolume(audio_devices_t device __unused) +{ + return false; +} + +bool AudioOutputDescriptor::setVolume(float volume, + audio_stream_type_t stream, + audio_devices_t device __unused, + uint32_t delayMs, + bool force) +{ + // We actually change the volume if: + // - the float value returned by computeVolume() changed + // - the force flag is set + if (volume != mCurVolume[stream] || force) { + ALOGV("setVolume() for stream %d, volume %f, delay %d", stream, volume, delayMs); + mCurVolume[stream] = volume; + return true; + } + return false; +} + void AudioOutputDescriptor::toAudioPortConfig( struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig) const { - ALOG_ASSERT(!isDuplicated(), "toAudioPortConfig() called on duplicated output %d", mIoHandle); - dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK| AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN; if (srcConfig != NULL) { @@ -176,22 +173,16 @@ void AudioOutputDescriptor::toAudioPortConfig( dstConfig->id = mId; dstConfig->role = AUDIO_PORT_ROLE_SOURCE; dstConfig->type = AUDIO_PORT_TYPE_MIX; - dstConfig->ext.mix.hw_module = mProfile->mModule->mHandle; - dstConfig->ext.mix.handle = mIoHandle; + dstConfig->ext.mix.hw_module = getModuleHandle(); dstConfig->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT; } void AudioOutputDescriptor::toAudioPort( struct audio_port *port) const { - ALOG_ASSERT(!isDuplicated(), "toAudioPort() called on duplicated output %d", mIoHandle); - mProfile->toAudioPort(port); + mPort->toAudioPort(port); port->id = mId; - toAudioPortConfig(&port->active_config); - port->ext.mix.hw_module = mProfile->mModule->mHandle; - port->ext.mix.handle = mIoHandle; - port->ext.mix.latency_class = - mFlags & AUDIO_OUTPUT_FLAG_FAST ? AUDIO_LATENCY_LOW : AUDIO_LATENCY_NORMAL; + port->ext.mix.hw_module = getModuleHandle(); } status_t AudioOutputDescriptor::dump(int fd) @@ -208,10 +199,6 @@ status_t AudioOutputDescriptor::dump(int fd) result.append(buffer); snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask); result.append(buffer); - snprintf(buffer, SIZE, " Latency: %d\n", mLatency); - result.append(buffer); - snprintf(buffer, SIZE, " Flags %08x\n", mFlags); - result.append(buffer); snprintf(buffer, SIZE, " Devices %08x\n", device()); result.append(buffer); snprintf(buffer, SIZE, " Stream volume refCount muteCount\n"); @@ -226,11 +213,165 @@ status_t AudioOutputDescriptor::dump(int fd) return NO_ERROR; } -bool AudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const +void AudioOutputDescriptor::log(const char* indent) +{ + ALOGI("%sID: %d,0x%X, [rt:%d fmt:0x%X ch:0x%X]", + indent, mId, mId, mSamplingRate, mFormat, mChannelMask); +} + +// SwAudioOutputDescriptor implementation +SwAudioOutputDescriptor::SwAudioOutputDescriptor( + const sp<IOProfile>& profile, AudioPolicyClientInterface *clientInterface) + : AudioOutputDescriptor(profile, clientInterface), + mProfile(profile), mIoHandle(0), mLatency(0), + mFlags((audio_output_flags_t)0), mPolicyMix(NULL), + mOutput1(0), mOutput2(0), mDirectOpenCount(0) +{ + if (profile != NULL) { + mFlags = (audio_output_flags_t)profile->mFlags; + } +} + +void SwAudioOutputDescriptor::setIoHandle(audio_io_handle_t ioHandle) +{ + mId = AudioPort::getNextUniqueId(); + mIoHandle = ioHandle; +} + + +status_t SwAudioOutputDescriptor::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, " Latency: %d\n", mLatency); + result.append(buffer); + snprintf(buffer, SIZE, " Flags %08x\n", mFlags); + result.append(buffer); + write(fd, result.string(), result.size()); + + AudioOutputDescriptor::dump(fd); + + return NO_ERROR; +} + +audio_devices_t SwAudioOutputDescriptor::device() const +{ + if (isDuplicated()) { + return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice); + } else { + return mDevice; + } +} + +bool SwAudioOutputDescriptor::sharesHwModuleWith( + const sp<AudioOutputDescriptor> outputDesc) +{ + if (isDuplicated()) { + return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc); + } else if (outputDesc->isDuplicated()){ + return sharesHwModuleWith(outputDesc->subOutput1()) || + sharesHwModuleWith(outputDesc->subOutput2()); + } else { + return AudioOutputDescriptor::sharesHwModuleWith(outputDesc); + } +} + +audio_devices_t SwAudioOutputDescriptor::supportedDevices() +{ + if (isDuplicated()) { + return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices()); + } else { + return mProfile->mSupportedDevices.types() ; + } +} + +uint32_t SwAudioOutputDescriptor::latency() +{ + if (isDuplicated()) { + return (mOutput1->mLatency > mOutput2->mLatency) ? mOutput1->mLatency : mOutput2->mLatency; + } else { + return mLatency; + } +} + +void SwAudioOutputDescriptor::changeRefCount(audio_stream_type_t stream, + int delta) +{ + // forward usage count change to attached outputs + if (isDuplicated()) { + mOutput1->changeRefCount(stream, delta); + mOutput2->changeRefCount(stream, delta); + } + AudioOutputDescriptor::changeRefCount(stream, delta); +} + + +bool SwAudioOutputDescriptor::isFixedVolume(audio_devices_t device) +{ + // unit gain if rerouting to external policy + if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) { + if (mPolicyMix != NULL) { + ALOGV("max gain when rerouting for output=%d", mIoHandle); + return true; + } + } + return false; +} + +void SwAudioOutputDescriptor::toAudioPortConfig( + struct audio_port_config *dstConfig, + const struct audio_port_config *srcConfig) const +{ + + ALOG_ASSERT(!isDuplicated(), "toAudioPortConfig() called on duplicated output %d", mIoHandle); + AudioOutputDescriptor::toAudioPortConfig(dstConfig, srcConfig); + + dstConfig->ext.mix.handle = mIoHandle; +} + +void SwAudioOutputDescriptor::toAudioPort( + struct audio_port *port) const +{ + ALOG_ASSERT(!isDuplicated(), "toAudioPort() called on duplicated output %d", mIoHandle); + + AudioOutputDescriptor::toAudioPort(port); + + toAudioPortConfig(&port->active_config); + port->ext.mix.handle = mIoHandle; + port->ext.mix.latency_class = + mFlags & AUDIO_OUTPUT_FLAG_FAST ? AUDIO_LATENCY_LOW : AUDIO_LATENCY_NORMAL; +} + +bool SwAudioOutputDescriptor::setVolume(float volume, + audio_stream_type_t stream, + audio_devices_t device, + uint32_t delayMs, + bool force) +{ + bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force); + + if (changed) { + // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is + // enabled + float volume = Volume::DbToAmpl(mCurVolume[stream]); + if (stream == AUDIO_STREAM_BLUETOOTH_SCO) { + mClientInterface->setStreamVolume( + AUDIO_STREAM_VOICE_CALL, volume, mIoHandle, delayMs); + } + mClientInterface->setStreamVolume(stream, volume, mIoHandle, delayMs); + } + return changed; +} + +// SwAudioOutputCollection implementation + +bool SwAudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const { nsecs_t sysTime = systemTime(); for (size_t i = 0; i < this->size(); i++) { - const sp<AudioOutputDescriptor> outputDesc = this->valueAt(i); + const sp<SwAudioOutputDescriptor> outputDesc = this->valueAt(i); if (outputDesc->isStreamActive(stream, inPastMs, sysTime)) { return true; } @@ -238,12 +379,12 @@ bool AudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t return false; } -bool AudioOutputCollection::isStreamActiveRemotely(audio_stream_type_t stream, +bool SwAudioOutputCollection::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const { nsecs_t sysTime = systemTime(); for (size_t i = 0; i < size(); i++) { - const sp<AudioOutputDescriptor> outputDesc = valueAt(i); + const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i); if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) && outputDesc->isStreamActive(stream, inPastMs, sysTime)) { // do not consider re routing (when the output is going to a dynamic policy) @@ -256,10 +397,10 @@ bool AudioOutputCollection::isStreamActiveRemotely(audio_stream_type_t stream, return false; } -audio_io_handle_t AudioOutputCollection::getA2dpOutput() const +audio_io_handle_t SwAudioOutputCollection::getA2dpOutput() const { for (size_t i = 0; i < size(); i++) { - sp<AudioOutputDescriptor> outputDesc = valueAt(i); + sp<SwAudioOutputDescriptor> outputDesc = valueAt(i); if (!outputDesc->isDuplicated() && outputDesc->device() & AUDIO_DEVICE_OUT_ALL_A2DP) { return this->keyAt(i); } @@ -267,10 +408,10 @@ audio_io_handle_t AudioOutputCollection::getA2dpOutput() const return 0; } -sp<AudioOutputDescriptor> AudioOutputCollection::getPrimaryOutput() const +sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getPrimaryOutput() const { for (size_t i = 0; i < size(); i++) { - const sp<AudioOutputDescriptor> outputDesc = valueAt(i); + const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i); if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) { return outputDesc; } @@ -278,26 +419,26 @@ sp<AudioOutputDescriptor> AudioOutputCollection::getPrimaryOutput() const return NULL; } -sp<AudioOutputDescriptor> AudioOutputCollection::getOutputFromId(audio_port_handle_t id) const +sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getOutputFromId(audio_port_handle_t id) const { - sp<AudioOutputDescriptor> outputDesc = NULL; + sp<SwAudioOutputDescriptor> outputDesc = NULL; for (size_t i = 0; i < size(); i++) { outputDesc = valueAt(i); - if (outputDesc->mId == id) { + if (outputDesc->getId() == id) { break; } } return outputDesc; } -bool AudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgnore) const +bool SwAudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgnore) const { for (size_t s = 0 ; s < AUDIO_STREAM_CNT ; s++) { if (s == (size_t) streamToIgnore) { continue; } for (size_t i = 0; i < size(); i++) { - const sp<AudioOutputDescriptor> outputDesc = valueAt(i); + const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i); if (outputDesc->mRefCount[s] != 0) { return true; } @@ -306,15 +447,15 @@ bool AudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgnore return false; } -audio_devices_t AudioOutputCollection::getSupportedDevices(audio_io_handle_t handle) const +audio_devices_t SwAudioOutputCollection::getSupportedDevices(audio_io_handle_t handle) const { - sp<AudioOutputDescriptor> outputDesc = valueFor(handle); + sp<SwAudioOutputDescriptor> outputDesc = valueFor(handle); audio_devices_t devices = outputDesc->mProfile->mSupportedDevices.types(); return devices; } -status_t AudioOutputCollection::dump(int fd) const +status_t SwAudioOutputCollection::dump(int fd) const { const size_t SIZE = 256; char buffer[SIZE]; diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp index 3a317fa..a06d867 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp @@ -54,8 +54,8 @@ status_t AudioPatch::dump(int fd, int spaces, int index) const for (size_t i = 0; i < mPatch.num_sources; i++) { if (mPatch.sources[i].type == AUDIO_PORT_TYPE_DEVICE) { snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "", - mPatch.sources[i].id, ConfigParsingUtils::enumToString(sDeviceNameToEnumTable, - ARRAY_SIZE(sDeviceNameToEnumTable), + mPatch.sources[i].id, ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable, + ARRAY_SIZE(sDeviceTypeToEnumTable), mPatch.sources[i].ext.device.type)); } else { snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "", @@ -68,8 +68,8 @@ status_t AudioPatch::dump(int fd, int spaces, int index) const for (size_t i = 0; i < mPatch.num_sinks; i++) { if (mPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE) { snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "", - mPatch.sinks[i].id, ConfigParsingUtils::enumToString(sDeviceNameToEnumTable, - ARRAY_SIZE(sDeviceNameToEnumTable), + mPatch.sinks[i].id, ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable, + ARRAY_SIZE(sDeviceTypeToEnumTable), mPatch.sinks[i].ext.device.type)); } else { snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "", diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp index 84a53eb..77fc0b9 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp @@ -26,12 +26,12 @@ namespace android { -void AudioPolicyMix::setOutput(sp<AudioOutputDescriptor> &output) +void AudioPolicyMix::setOutput(sp<SwAudioOutputDescriptor> &output) { mOutput = output; } -const sp<AudioOutputDescriptor> &AudioPolicyMix::getOutput() const +const sp<SwAudioOutputDescriptor> &AudioPolicyMix::getOutput() const { return mOutput; } @@ -46,9 +46,9 @@ void AudioPolicyMix::setMix(AudioMix &mix) mMix = mix; } -android::AudioMix &AudioPolicyMix::getMix() +android::AudioMix *AudioPolicyMix::getMix() { - return mMix; + return &mMix; } status_t AudioPolicyMixCollection::registerMix(String8 address, AudioMix mix) @@ -88,7 +88,7 @@ status_t AudioPolicyMixCollection::getAudioPolicyMix(String8 address, return NO_ERROR; } -void AudioPolicyMixCollection::closeOutput(sp<AudioOutputDescriptor> &desc) +void AudioPolicyMixCollection::closeOutput(sp<SwAudioOutputDescriptor> &desc) { for (size_t i = 0; i < size(); i++) { sp<AudioPolicyMix> policyMix = valueAt(i); @@ -99,40 +99,40 @@ void AudioPolicyMixCollection::closeOutput(sp<AudioOutputDescriptor> &desc) } status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes, - sp<AudioOutputDescriptor> &desc) + sp<SwAudioOutputDescriptor> &desc) { for (size_t i = 0; i < size(); i++) { sp<AudioPolicyMix> policyMix = valueAt(i); - AudioMix mix = policyMix->getMix(); - - if (mix.mMixType == MIX_TYPE_PLAYERS) { - for (size_t j = 0; j < mix.mCriteria.size(); j++) { - if ((RULE_MATCH_ATTRIBUTE_USAGE == mix.mCriteria[j].mRule && - mix.mCriteria[j].mAttr.mUsage == attributes.usage) || - (RULE_EXCLUDE_ATTRIBUTE_USAGE == mix.mCriteria[j].mRule && - mix.mCriteria[j].mAttr.mUsage != attributes.usage)) { + AudioMix *mix = policyMix->getMix(); + + if (mix->mMixType == MIX_TYPE_PLAYERS) { + for (size_t j = 0; j < mix->mCriteria.size(); j++) { + if ((RULE_MATCH_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule && + mix->mCriteria[j].mAttr.mUsage == attributes.usage) || + (RULE_EXCLUDE_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule && + mix->mCriteria[j].mAttr.mUsage != attributes.usage)) { desc = policyMix->getOutput(); break; } if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && strncmp(attributes.tags + strlen("addr="), - mix.mRegistrationId.string(), + mix->mRegistrationId.string(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) { desc = policyMix->getOutput(); break; } } - } else if (mix.mMixType == MIX_TYPE_RECORDERS) { + } else if (mix->mMixType == MIX_TYPE_RECORDERS) { if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE && strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && strncmp(attributes.tags + strlen("addr="), - mix.mRegistrationId.string(), + mix->mRegistrationId.string(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) { desc = policyMix->getOutput(); } } if (desc != 0) { - desc->mPolicyMix = &mix; + desc->mPolicyMix = mix; return NO_ERROR; } } @@ -144,19 +144,19 @@ audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_so AudioMix **policyMix) { for (size_t i = 0; i < size(); i++) { - AudioMix mix = valueAt(i)->getMix(); + AudioMix *mix = valueAt(i)->getMix(); - if (mix.mMixType != MIX_TYPE_RECORDERS) { + if (mix->mMixType != MIX_TYPE_RECORDERS) { continue; } - for (size_t j = 0; j < mix.mCriteria.size(); j++) { - if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix.mCriteria[j].mRule && - mix.mCriteria[j].mAttr.mSource == inputSource) || - (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix.mCriteria[j].mRule && - mix.mCriteria[j].mAttr.mSource != inputSource)) { + for (size_t j = 0; j < mix->mCriteria.size(); j++) { + if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule && + mix->mCriteria[j].mAttr.mSource == inputSource) || + (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule && + mix->mCriteria[j].mAttr.mSource != inputSource)) { if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { if (policyMix != NULL) { - *policyMix = &mix; + *policyMix = mix; } return AUDIO_DEVICE_IN_REMOTE_SUBMIX; } @@ -167,7 +167,7 @@ audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_so return AUDIO_DEVICE_NONE; } -status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix *&policyMix) +status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix) { if (strncmp(attr.tags, "addr=", strlen("addr=")) != 0) { return BAD_VALUE; @@ -180,13 +180,13 @@ status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, A return BAD_VALUE; } sp<AudioPolicyMix> audioPolicyMix = valueAt(index); - AudioMix mix = audioPolicyMix->getMix(); + AudioMix *mix = audioPolicyMix->getMix(); - if (mix.mMixType != MIX_TYPE_PLAYERS) { + if (mix->mMixType != MIX_TYPE_PLAYERS) { ALOGW("getInputForAttr() bad policy mix type for address %s", address.string()); return BAD_VALUE; } - policyMix = &mix; + *policyMix = mix; return NO_ERROR; } diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp index 46a119e..e8191dd 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp @@ -31,8 +31,8 @@ int32_t volatile AudioPort::mNextUniqueId = 1; // --- AudioPort class implementation AudioPort::AudioPort(const String8& name, audio_port_type_t type, - audio_port_role_t role, const sp<HwModule>& module) : - mName(name), mType(type), mRole(role), mModule(module), mFlags(0), mId(0) + audio_port_role_t role) : + mName(name), mType(type), mRole(role), mFlags(0) { mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) || ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK)); @@ -40,7 +40,6 @@ AudioPort::AudioPort(const String8& name, audio_port_type_t type, void AudioPort::attach(const sp<HwModule>& module) { - mId = getNextUniqueId(); mModule = module; } @@ -51,9 +50,28 @@ audio_port_handle_t AudioPort::getNextUniqueId() audio_module_handle_t AudioPort::getModuleHandle() const { + if (mModule == 0) { + return 0; + } return mModule->mHandle; } +uint32_t AudioPort::getModuleVersion() const +{ + if (mModule == 0) { + return 0; + } + return mModule->mHalVersion; +} + +const char *AudioPort::getModuleName() const +{ + if (mModule == 0) { + return ""; + } + return mModule->mName; +} + void AudioPort::toAudioPort(struct audio_port *port) const { port->role = mRole; @@ -629,7 +647,7 @@ void AudioPort::dump(int fd, int spaces) const char buffer[SIZE]; String8 result; - if (mName.size() != 0) { + if (mName.length() != 0) { snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string()); result.append(buffer); } @@ -687,13 +705,16 @@ void AudioPort::dump(int fd, int spaces) const if (mGains.size() != 0) { snprintf(buffer, SIZE, "%*s- gains:\n", spaces, ""); write(fd, buffer, strlen(buffer) + 1); - result.append(buffer); for (size_t i = 0; i < mGains.size(); i++) { mGains[i]->dump(fd, spaces + 2, i); } } } +void AudioPort::log(const char* indent) const +{ + ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.string(), mType, mRole); +} // --- AudioPortConfig class implementation diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp index fe5bc5f..9ab1d61 100644 --- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp @@ -113,8 +113,8 @@ audio_devices_t ConfigParsingUtils::parseDeviceNames(char *name) char *devName = strtok(name, "|"); while (devName != NULL) { if (strlen(devName) != 0) { - device |= stringToEnum(sDeviceNameToEnumTable, - ARRAY_SIZE(sDeviceNameToEnumTable), + device |= stringToEnum(sDeviceTypeToEnumTable, + ARRAY_SIZE(sDeviceTypeToEnumTable), devName); } devName = strtok(NULL, "|"); @@ -224,8 +224,8 @@ void ConfigParsingUtils::loadGlobalConfig(cnode *root, const sp<HwModule>& modul availableOutputDevices.types()); } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) { audio_devices_t device = (audio_devices_t)stringToEnum( - sDeviceNameToEnumTable, - ARRAY_SIZE(sDeviceNameToEnumTable), + sDeviceTypeToEnumTable, + ARRAY_SIZE(sDeviceTypeToEnumTable), (char *)node->value); if (device != AUDIO_DEVICE_NONE) { defaultOutputDevice = new DeviceDescriptor(String8("default-output"), device); diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp index 7df7d75..9573583 100644 --- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp @@ -29,13 +29,23 @@ String8 DeviceDescriptor::emptyNameStr = String8(""); DeviceDescriptor::DeviceDescriptor(const String8& name, audio_devices_t type) : AudioPort(name, AUDIO_PORT_TYPE_DEVICE, audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK : - AUDIO_PORT_ROLE_SOURCE, - NULL), - mAddress(""), mDeviceType(type) + AUDIO_PORT_ROLE_SOURCE), + mAddress(""), mDeviceType(type), mId(0) { } +audio_port_handle_t DeviceDescriptor::getId() const +{ + return mId; +} + +void DeviceDescriptor::attach(const sp<HwModule>& module) +{ + AudioPort::attach(module); + mId = getNextUniqueId(); +} + bool DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const { // Devices are considered equal if they: @@ -139,11 +149,14 @@ void DeviceVector::loadDevicesFromName(char *name, char *devName = strtok(name, "|"); while (devName != NULL) { if (strlen(devName) != 0) { - audio_devices_t type = ConfigParsingUtils::stringToEnum(sDeviceNameToEnumTable, - ARRAY_SIZE(sDeviceNameToEnumTable), + audio_devices_t type = ConfigParsingUtils::stringToEnum(sDeviceTypeToEnumTable, + ARRAY_SIZE(sDeviceTypeToEnumTable), devName); if (type != AUDIO_DEVICE_NONE) { - sp<DeviceDescriptor> dev = new DeviceDescriptor(String8(name), type); + devName = (char *)ConfigParsingUtils::enumToString(sDeviceNameToEnumTable, + ARRAY_SIZE(sDeviceNameToEnumTable), + type); + sp<DeviceDescriptor> dev = new DeviceDescriptor(String8(devName), type); if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX || type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) { dev->mAddress = String8("0"); @@ -183,7 +196,7 @@ sp<DeviceDescriptor> DeviceVector::getDeviceFromId(audio_port_handle_t id) const { sp<DeviceDescriptor> device; for (size_t i = 0; i < size(); i++) { - if (itemAt(i)->getHandle() == id) { + if (itemAt(i)->getId() == id) { device = itemAt(i); break; } @@ -303,8 +316,8 @@ status_t DeviceDescriptor::dump(int fd, int spaces, int index) const result.append(buffer); } snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "", - ConfigParsingUtils::enumToString(sDeviceNameToEnumTable, - ARRAY_SIZE(sDeviceNameToEnumTable), + ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable, + ARRAY_SIZE(sDeviceTypeToEnumTable), mDeviceType)); result.append(buffer); if (mAddress.size() != 0) { @@ -317,4 +330,16 @@ status_t DeviceDescriptor::dump(int fd, int spaces, int index) const return NO_ERROR; } +void DeviceDescriptor::log() const +{ + ALOGI("Device id:%d type:0x%X:%s, addr:%s", + mId, + mDeviceType, + ConfigParsingUtils::enumToString( + sDeviceNameToEnumTable, ARRAY_SIZE(sDeviceNameToEnumTable), mDeviceType), + mAddress.string()); + + AudioPort::log(" "); +} + }; // namespace android diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp index 0097d69..e955447 100644 --- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp @@ -48,7 +48,7 @@ status_t HwModule::loadInput(cnode *root) { cnode *node = root->first_child; - sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SINK, this); + sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SINK); while (node) { if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) { @@ -83,6 +83,7 @@ status_t HwModule::loadInput(cnode *root) ALOGV("loadInput() adding input Supported Devices %04x", profile->mSupportedDevices.types()); + profile->attach(this); mInputProfiles.add(profile); return NO_ERROR; } else { @@ -94,7 +95,7 @@ status_t HwModule::loadOutput(cnode *root) { cnode *node = root->first_child; - sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SOURCE, this); + sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SOURCE); while (node) { if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) { @@ -128,7 +129,7 @@ status_t HwModule::loadOutput(cnode *root) ALOGV("loadOutput() adding output Supported Devices %04x, mFlags %04x", profile->mSupportedDevices.types(), profile->mFlags); - + profile->attach(this); mOutputProfiles.add(profile); return NO_ERROR; } else { @@ -154,7 +155,6 @@ status_t HwModule::loadDevice(cnode *root) return BAD_VALUE; } sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(String8(root->name), type); - deviceDesc->mModule = this; node = root->first_child; while (node) { @@ -183,7 +183,7 @@ status_t HwModule::loadDevice(cnode *root) status_t HwModule::addOutputProfile(String8 name, const audio_config_t *config, audio_devices_t device, String8 address) { - sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SOURCE, this); + sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SOURCE); profile->mSamplingRates.add(config->sample_rate); profile->mChannelMasks.add(config->channel_mask); @@ -193,6 +193,7 @@ status_t HwModule::addOutputProfile(String8 name, const audio_config_t *config, devDesc->mAddress = address; profile->mSupportedDevices.add(devDesc); + profile->attach(this); mOutputProfiles.add(profile); return NO_ERROR; @@ -213,7 +214,7 @@ status_t HwModule::removeOutputProfile(String8 name) status_t HwModule::addInputProfile(String8 name, const audio_config_t *config, audio_devices_t device, String8 address) { - sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SINK, this); + sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SINK); profile->mSamplingRates.add(config->sample_rate); profile->mChannelMasks.add(config->channel_mask); @@ -225,6 +226,7 @@ status_t HwModule::addInputProfile(String8 name, const audio_config_t *config, ALOGV("addInputProfile() name %s rate %d mask 0x08", name.string(), config->sample_rate, config->channel_mask); + profile->attach(this); mInputProfiles.add(profile); return NO_ERROR; diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp index 376dd22..de6539c 100644 --- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp @@ -23,9 +23,8 @@ namespace android { -IOProfile::IOProfile(const String8& name, audio_port_role_t role, - const sp<HwModule>& module) - : AudioPort(name, AUDIO_PORT_TYPE_MIX, role, module) +IOProfile::IOProfile(const String8& name, audio_port_role_t role) + : AudioPort(name, AUDIO_PORT_TYPE_MIX, role) { } diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h index eadaa77..db0573f 100755 --- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h +++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h @@ -134,16 +134,16 @@ public: audio_policy_dev_state_t state) = 0; /** - * Translate a volume index given by the UI to an amplification value for a stream type + * Translate a volume index given by the UI to an amplification value in dB for a stream type * and a device category. * * @param[in] deviceCategory for which the conversion is requested. * @param[in] stream type for which the conversion is requested. * @param[in] indexInUi index received from the UI to be translated. * - * @return amplification value matching the UI index for this given device and stream. + * @return amplification value in dB matching the UI index for this given device and stream. */ - virtual float volIndexToAmpl(Volume::device_category deviceCategory, audio_stream_type_t stream, + virtual float volIndexToDb(Volume::device_category deviceCategory, audio_stream_type_t stream, int indexInUi) = 0; /** diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h index 4f5427e..6d43df2 100755 --- a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h +++ b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h @@ -43,7 +43,7 @@ public: virtual const AudioPolicyMixCollection &getAudioPolicyMixCollection() const = 0; - virtual const AudioOutputCollection &getOutputs() const = 0; + virtual const SwAudioOutputCollection &getOutputs() const = 0; virtual const AudioInputCollection &getInputs() const = 0; diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp index 1fd3341..50f1609 100755 --- a/services/audiopolicy/enginedefault/src/Engine.cpp +++ b/services/audiopolicy/enginedefault/src/Engine.cpp @@ -63,13 +63,14 @@ status_t Engine::initCheck() return (mApmObserver != NULL) ? NO_ERROR : NO_INIT; } -float Engine::volIndexToAmpl(Volume::device_category category, audio_stream_type_t streamType, +float Engine::volIndexToDb(Volume::device_category category, audio_stream_type_t streamType, int indexInUi) { const StreamDescriptor &streamDesc = mApmObserver->getStreamDescriptors().valueAt(streamType); - return Gains::volIndexToAmpl(category, streamDesc, indexInUi); + return Gains::volIndexToDb(category, streamDesc, indexInUi); } + status_t Engine::initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) { ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax); @@ -243,7 +244,7 @@ routing_strategy Engine::getStrategyForStream(audio_stream_type_t stream) routing_strategy Engine::getStrategyForUsage(audio_usage_t usage) { - const AudioOutputCollection &outputs = mApmObserver->getOutputs(); + const SwAudioOutputCollection &outputs = mApmObserver->getOutputs(); // usage to strategy mapping switch (usage) { @@ -291,7 +292,7 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const const DeviceVector &availableOutputDevices = mApmObserver->getAvailableOutputDevices(); const DeviceVector &availableInputDevices = mApmObserver->getAvailableInputDevices(); - const AudioOutputCollection &outputs = mApmObserver->getOutputs(); + const SwAudioOutputCollection &outputs = mApmObserver->getOutputs(); uint32_t device = AUDIO_DEVICE_NONE; uint32_t availableOutputDevicesType = availableOutputDevices.types(); @@ -358,7 +359,7 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const if (((availableInputDevices.types() & AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) || (((txDevice & availPrimaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) && - (primaryOutput->getAudioPort()->mModule->mHalVersion < + (primaryOutput->getAudioPort()->getModuleVersion() < AUDIO_DEVICE_API_VERSION_3_0))) { availableOutputDevicesType = availPrimaryOutputDevices; } @@ -582,7 +583,7 @@ audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) cons { const DeviceVector &availableOutputDevices = mApmObserver->getAvailableOutputDevices(); const DeviceVector &availableInputDevices = mApmObserver->getAvailableInputDevices(); - const AudioOutputCollection &outputs = mApmObserver->getOutputs(); + const SwAudioOutputCollection &outputs = mApmObserver->getOutputs(); audio_devices_t availableDeviceTypes = availableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN; uint32_t device = AUDIO_DEVICE_NONE; diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h index f44556c..56a4748 100755 --- a/services/audiopolicy/enginedefault/src/Engine.h +++ b/services/audiopolicy/enginedefault/src/Engine.h @@ -101,10 +101,10 @@ private: { return mPolicyEngine->initializeVolumeCurves(isSpeakerDrcEnabled); } - virtual float volIndexToAmpl(Volume::device_category deviceCategory, + virtual float volIndexToDb(Volume::device_category deviceCategory, audio_stream_type_t stream,int indexInUi) { - return mPolicyEngine->volIndexToAmpl(deviceCategory, stream, indexInUi); + return mPolicyEngine->volIndexToDb(deviceCategory, stream, indexInUi); } private: Engine *mPolicyEngine; @@ -141,7 +141,7 @@ private: audio_devices_t getDeviceForStrategy(routing_strategy strategy) const; audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const; - float volIndexToAmpl(Volume::device_category category, + float volIndexToDb(Volume::device_category category, audio_stream_type_t stream, int indexInUi); status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax); void initializeVolumeCurves(bool isSpeakerDrcEnabled); diff --git a/services/audiopolicy/enginedefault/src/Gains.cpp b/services/audiopolicy/enginedefault/src/Gains.cpp index a684fdd..78f2909 100644 --- a/services/audiopolicy/enginedefault/src/Gains.cpp +++ b/services/audiopolicy/enginedefault/src/Gains.cpp @@ -197,10 +197,10 @@ const VolumeCurvePoint *Gains::sVolumeProfiles[AUDIO_STREAM_CNT] }; //static -float Gains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, - int indexInUi) +float Gains::volIndexToDb(Volume::device_category deviceCategory, + const StreamDescriptor& streamDesc, + int indexInUi) { - Volume::device_category deviceCategory = Volume::getDeviceCategory(device); const VolumeCurvePoint *curve = streamDesc.getVolumeCurvePoint(deviceCategory); // the volume index in the UI is relative to the min and max volume indices for this stream type @@ -212,7 +212,7 @@ float Gains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& stre // find what part of the curve this index volume belongs to, or if it's out of bounds int segment = 0; if (volIdx < curve[Volume::VOLMIN].mIndex) { // out of bounds - return 0.0f; + return VOLUME_MIN_DB; } else if (volIdx < curve[Volume::VOLKNEE1].mIndex) { segment = 0; } else if (volIdx < curve[Volume::VOLKNEE2].mIndex) { @@ -220,7 +220,7 @@ float Gains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& stre } else if (volIdx <= curve[Volume::VOLMAX].mIndex) { segment = 2; } else { // out of bounds - return 1.0f; + return 0.0f; } // linear interpolation in the attenuation table in dB @@ -231,17 +231,25 @@ float Gains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& stre ((float)(curve[segment+1].mIndex - curve[segment].mIndex)) ); - float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 ) - - ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f", + ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f]", curve[segment].mIndex, volIdx, curve[segment+1].mIndex, curve[segment].mDBAttenuation, decibels, - curve[segment+1].mDBAttenuation, - amplification); + curve[segment+1].mDBAttenuation); + + return decibels; +} - return amplification; + +//static +float Gains::volIndexToAmpl(Volume::device_category deviceCategory, + const StreamDescriptor& streamDesc, + int indexInUi) +{ + return Volume::DbToAmpl(volIndexToDb(deviceCategory, streamDesc, indexInUi)); } + + }; // namespace android diff --git a/services/audiopolicy/enginedefault/src/Gains.h b/services/audiopolicy/enginedefault/src/Gains.h index b5601ca..7620b7d 100644 --- a/services/audiopolicy/enginedefault/src/Gains.h +++ b/services/audiopolicy/enginedefault/src/Gains.h @@ -29,8 +29,13 @@ class StreamDescriptor; class Gains { public : - static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, - int indexInUi); + static float volIndexToAmpl(Volume::device_category deviceCategory, + const StreamDescriptor& streamDesc, + int indexInUi); + + static float volIndexToDb(Volume::device_category deviceCategory, + const StreamDescriptor& streamDesc, + int indexInUi); // default volume curve static const VolumeCurvePoint sDefaultVolumeCurve[Volume::VOLCNT]; diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 797a2b4..35e80f7 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -157,7 +157,7 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device, // outputs must be closed after checkOutputForAllStrategies() is executed if (!outputs.isEmpty()) { for (size_t i = 0; i < outputs.size(); i++) { - sp<AudioOutputDescriptor> desc = mOutputs.valueFor(outputs[i]); + sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(outputs[i]); // close unused outputs after device disconnection or direct outputs that have been // opened by checkOutputsForDevice() to query dynamic parameters if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) || @@ -176,18 +176,17 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device, updateCallRouting(newDevice); } for (size_t i = 0; i < mOutputs.size(); i++) { - audio_io_handle_t output = mOutputs.keyAt(i); - if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (output != mPrimaryOutput)) { - audio_devices_t newDevice = getNewOutputDevice(mOutputs.keyAt(i), - true /*fromCache*/); + sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); + if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput)) { + audio_devices_t newDevice = getNewOutputDevice(desc, true /*fromCache*/); // do not force device change on duplicated output because if device is 0, it will // also force a device 0 for the two outputs it is duplicated to which may override // a valid device selection on those outputs. - bool force = !mOutputs.valueAt(i)->isDuplicated() + bool force = !desc->isDuplicated() && (!device_distinguishes_on_address(device) // always force when disconnecting (a non-duplicated device) || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)); - setOutputDevice(output, newDevice, force, 0); + setOutputDevice(desc, newDevice, force, 0); } } @@ -349,10 +348,11 @@ void AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, int delayMs AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID); if (output != AUDIO_IO_HANDLE_NONE) { - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); + sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); ALOG_ASSERT(!outputDesc->isDuplicated(), "updateCallRouting() RX device output is duplicated"); outputDesc->toAudioPortConfig(&patch.sources[1]); + patch.sources[1].ext.mix.usecase.stream = AUDIO_STREAM_PATCH; patch.num_sources = 2; } @@ -395,6 +395,7 @@ void AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, int delayMs ALOG_ASSERT(!outputDesc->isDuplicated(), "updateCallRouting() RX device output is duplicated"); outputDesc->toAudioPortConfig(&patch.sources[1]); + patch.sources[1].ext.mix.usecase.stream = AUDIO_STREAM_PATCH; patch.num_sources = 2; } @@ -448,13 +449,13 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) checkOutputForAllStrategies(); updateDevicesAndOutputs(); - sp<AudioOutputDescriptor> hwOutputDesc = mOutputs.valueFor(mPrimaryOutput); + sp<SwAudioOutputDescriptor> hwOutputDesc = mPrimaryOutput; int delayMs = 0; if (isStateInCall(state)) { nsecs_t sysTime = systemTime(); for (size_t i = 0; i < mOutputs.size(); i++) { - sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i); + sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); // mute media and sonification strategies and delay device switch by the largest // latency of any output where either strategy is active. // This avoid sending the ring tone or music tail into the earpiece or headset. @@ -464,14 +465,14 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) isStrategyActive(desc, STRATEGY_SONIFICATION, SONIFICATION_HEADSET_MUSIC_DELAY, sysTime)) && - (delayMs < (int)desc->mLatency*2)) { - delayMs = desc->mLatency*2; + (delayMs < (int)desc->latency()*2)) { + delayMs = desc->latency()*2; } - setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i)); - setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS, + setStrategyMute(STRATEGY_MEDIA, true, desc); + setStrategyMute(STRATEGY_MEDIA, false, desc, MUTE_TIME_MS, getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/)); - setStrategyMute(STRATEGY_SONIFICATION, true, mOutputs.keyAt(i)); - setStrategyMute(STRATEGY_SONIFICATION, false, mOutputs.keyAt(i), MUTE_TIME_MS, + setStrategyMute(STRATEGY_SONIFICATION, true, desc); + setStrategyMute(STRATEGY_SONIFICATION, false, desc, MUTE_TIME_MS, getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/)); } } @@ -547,13 +548,13 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage, updateCallRouting(newDevice); } for (size_t i = 0; i < mOutputs.size(); i++) { - audio_io_handle_t output = mOutputs.keyAt(i); - audio_devices_t newDevice = getNewOutputDevice(output, true /*fromCache*/); - if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (output != mPrimaryOutput)) { - setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE)); + sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i); + audio_devices_t newDevice = getNewOutputDevice(outputDesc, true /*fromCache*/); + if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (outputDesc != mPrimaryOutput)) { + setOutputDevice(outputDesc, newDevice, (newDevice != AUDIO_DEVICE_NONE)); } if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) { - applyStreamVolumes(output, newDevice, 0, true); + applyStreamVolumes(outputDesc, newDevice, 0, true); } } @@ -621,6 +622,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, audio_format_t format, audio_channel_mask_t channelMask, audio_output_flags_t flags, + audio_port_handle_t selectedDeviceId, const audio_offload_info_t *offloadInfo) { audio_attributes_t attributes; @@ -639,7 +641,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, } stream_type_to_audio_attributes(*stream, &attributes); } - sp<AudioOutputDescriptor> desc; + sp<SwAudioOutputDescriptor> desc; if (mPolicyMixes.getOutputForAttr(attributes, desc) == NO_ERROR) { ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr"); if (!audio_is_linear_pcm(format)) { @@ -675,6 +677,17 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, if (*output == AUDIO_IO_HANDLE_NONE) { return INVALID_OPERATION; } + + // Explicit routing? + sp<DeviceDescriptor> deviceDesc; + + for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) { + if (mAvailableOutputDevices[i]->getId() == selectedDeviceId) { + deviceDesc = mAvailableOutputDevices[i]; + break; + } + } + mOutputRoutes.addRoute(session, *stream, deviceDesc); return NO_ERROR; } @@ -699,7 +712,8 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( if (mTestOutputs[mCurOutput] == 0) { ALOGV("getOutput() opening test output"); - sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(NULL); + sp<AudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(NULL, + mpClientInterface); outputDesc->mDevice = mTestDevice; outputDesc->mLatency = mTestLatencyMs; outputDesc->mFlags = @@ -775,10 +789,10 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( } if (profile != 0) { - sp<AudioOutputDescriptor> outputDesc = NULL; + sp<SwAudioOutputDescriptor> outputDesc = NULL; for (size_t i = 0; i < mOutputs.size(); i++) { - sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i); + sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); if (!desc->isDuplicated() && (profile == desc->mProfile)) { outputDesc = desc; // reuse direct output if currently open and configured with same parameters @@ -795,7 +809,7 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( if (outputDesc != NULL) { closeOutput(outputDesc->mIoHandle); } - outputDesc = new AudioOutputDescriptor(profile); + outputDesc = new SwAudioOutputDescriptor(profile, mpClientInterface); outputDesc->mDevice = device; outputDesc->mLatency = 0; outputDesc->mFlags =(audio_output_flags_t) (outputDesc->mFlags | flags); @@ -806,7 +820,7 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( if (offloadInfo != NULL) { config.offload_info = *offloadInfo; } - status = mpClientInterface->openOutput(profile->mModule->mHandle, + status = mpClientInterface->openOutput(profile->getModuleHandle(), &output, &config, &outputDesc->mDevice, @@ -856,7 +870,6 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( } non_direct_output: - // ignoring channel mask due to downmix capability in mixer // open a non direct output @@ -874,7 +887,7 @@ non_direct_output: ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d," "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags); - ALOGV("getOutput() returns output %d", output); + ALOGV(" getOutputForDevice() returns output %d", output); return output; } @@ -902,7 +915,7 @@ audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_h audio_io_handle_t outputPrimary = 0; for (size_t i = 0; i < outputs.size(); i++) { - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputs[i]); + sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputs[i]); if (!outputDesc->isDuplicated()) { // if a valid format is specified, skip output if not compatible if (format != AUDIO_FORMAT_INVALID) { @@ -941,15 +954,59 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, audio_stream_type_t stream, audio_session_t session) { - ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session); + ALOGV("startOutput() output %d, stream %d, session %d", + output, stream, session); ssize_t index = mOutputs.indexOfKey(output); if (index < 0) { ALOGW("startOutput() unknown output %d", output); return BAD_VALUE; } + sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index); + + audio_devices_t newDevice; + if (outputDesc->mPolicyMix != NULL) { + newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + } else { + newDevice = AUDIO_DEVICE_NONE; + } + + uint32_t delayMs = 0; + + // Routing? + mOutputRoutes.incRouteActivity(session); + + status_t status = startSource(outputDesc, stream, newDevice, &delayMs); + + if (status != NO_ERROR) { + mOutputRoutes.decRouteActivity(session); + } + // Automatically enable the remote submix input when output is started on a re routing mix + // of type MIX_TYPE_RECORDERS + if (audio_is_remote_submix_device(newDevice) && outputDesc->mPolicyMix != NULL && + outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) { + setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_AVAILABLE, + outputDesc->mPolicyMix->mRegistrationId, + "remote-submix"); + } + + if (delayMs != 0) { + usleep(delayMs * 1000); + } + + return status; +} + +status_t AudioPolicyManager::startSource(sp<AudioOutputDescriptor> outputDesc, + audio_stream_type_t stream, + audio_devices_t device, + uint32_t *delayMs) +{ // cannot start playback of STREAM_TTS if any other output is being used uint32_t beaconMuteLatency = 0; + + *delayMs = 0; if (stream == AUDIO_STREAM_TTS) { ALOGV("\t found BEACON stream"); if (mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) { @@ -962,8 +1019,6 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, beaconMuteLatency = handleEventForBeacon(STARTING_OUTPUT); } - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index); - // increment usage count for this stream on the requested output: // NOTE that the usage count is the same for duplicated output and hardware output which is // necessary for a correct control of hardware output routing by startOutput() and stopOutput() @@ -971,11 +1026,8 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, if (outputDesc->mRefCount[stream] == 1) { // starting an output being rerouted? - audio_devices_t newDevice; - if (outputDesc->mPolicyMix != NULL) { - newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX; - } else { - newDevice = getNewOutputDevice(output, false /*fromCache*/); + if (device == AUDIO_DEVICE_NONE) { + device = getNewOutputDevice(outputDesc, false /*fromCache*/); } routing_strategy strategy = getStrategy(stream); bool shouldWait = (strategy == STRATEGY_SONIFICATION) || @@ -991,7 +1043,7 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, // In this case, the audio HAL must receive the new device selection so that it can // change the device currently selected by the other active output. if (outputDesc->sharesHwModuleWith(desc) && - desc->device() != newDevice) { + desc->device() != device) { force = true; } // wait for audio on other active outputs to be presented when starting @@ -1003,7 +1055,7 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, } } } - uint32_t muteWaitMs = setOutputDevice(output, newDevice, force); + uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force); // handle special case for sonification while in call if (isInCall()) { @@ -1012,32 +1064,18 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, // apply volume rules for current stream and device if necessary checkAndSetVolume(stream, - mStreams[stream].getVolumeIndex(newDevice), - output, - newDevice); + mStreams.valueFor(stream).getVolumeIndex(device), + outputDesc, + device); // update the outputs if starting an output with a stream that can affect notification // routing handleNotificationRoutingForStream(stream); - // Automatically enable the remote submix input when output is started on a re routing mix - // of type MIX_TYPE_RECORDERS - if (audio_is_remote_submix_device(newDevice) && outputDesc->mPolicyMix != NULL && - outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) { - setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX, - AUDIO_POLICY_DEVICE_STATE_AVAILABLE, - outputDesc->mPolicyMix->mRegistrationId, - "remote-submix"); - } - // force reevaluating accessibility routing when ringtone or alarm starts if (strategy == STRATEGY_SONIFICATION) { mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY); } - - if (waitMs > muteWaitMs) { - usleep((waitMs - muteWaitMs) * 2 * 1000); - } } return NO_ERROR; } @@ -1054,8 +1092,32 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, return BAD_VALUE; } - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index); + sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index); + + if (outputDesc->mRefCount[stream] == 1) { + // Automatically disable the remote submix input when output is stopped on a + // re routing mix of type MIX_TYPE_RECORDERS + if (audio_is_remote_submix_device(outputDesc->mDevice) && + outputDesc->mPolicyMix != NULL && + outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) { + setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, + outputDesc->mPolicyMix->mRegistrationId, + "remote-submix"); + } + } + + // Routing? + if (outputDesc->mRefCount[stream] > 0) { + mOutputRoutes.decRouteActivity(session); + } + + return stopSource(outputDesc, stream); +} +status_t AudioPolicyManager::stopSource(sp<AudioOutputDescriptor> outputDesc, + audio_stream_type_t stream) +{ // always handle stream stop, check which stream type is stopping handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT); @@ -1067,41 +1129,31 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, if (outputDesc->mRefCount[stream] > 0) { // decrement usage count of this stream on the output outputDesc->changeRefCount(stream, -1); + // store time at which the stream was stopped - see isStreamActive() if (outputDesc->mRefCount[stream] == 0) { - // Automatically disable the remote submix input when output is stopped on a - // re routing mix of type MIX_TYPE_RECORDERS - if (audio_is_remote_submix_device(outputDesc->mDevice) && - outputDesc->mPolicyMix != NULL && - outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) { - setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX, - AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, - outputDesc->mPolicyMix->mRegistrationId, - "remote-submix"); - } - outputDesc->mStopTime[stream] = systemTime(); - audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/); + audio_devices_t newDevice = getNewOutputDevice(outputDesc, 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 // and kernel buffers. Also the latency does not always include additional delay in the // audio path (audio DSP, CODEC ...) - setOutputDevice(output, newDevice, false, outputDesc->mLatency*2); + setOutputDevice(outputDesc, newDevice, false, outputDesc->latency()*2); // force restoring the device selection on other active outputs if it differs from the // one being selected for this output for (size_t i = 0; i < mOutputs.size(); i++) { audio_io_handle_t curOutput = mOutputs.keyAt(i); sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i); - if (curOutput != output && + if (desc != outputDesc && desc->isActive() && outputDesc->sharesHwModuleWith(desc) && (newDevice != desc->device())) { - setOutputDevice(curOutput, - getNewOutputDevice(curOutput, false /*fromCache*/), + setOutputDevice(desc, + getNewOutputDevice(desc, false /*fromCache*/), true, - outputDesc->mLatency*2); + outputDesc->latency()*2); } } // update the outputs if stopping one with a stream that can affect notification routing @@ -1109,7 +1161,7 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, } return NO_ERROR; } else { - ALOGW("stopOutput() refcount is already 0 for output %d", output); + ALOGW("stopOutput() refcount is already 0"); return INVALID_OPERATION; } } @@ -1138,7 +1190,10 @@ void AudioPolicyManager::releaseOutput(audio_io_handle_t output, } #endif //AUDIO_POLICY_TEST - sp<AudioOutputDescriptor> desc = mOutputs.valueAt(index); + // Routing + mOutputRoutes.removeRoute(session); + + sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(index); if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { if (desc->mDirectOpenCount <= 0) { ALOGW("releaseOutput() invalid open count %d for output %d", @@ -1150,8 +1205,9 @@ void AudioPolicyManager::releaseOutput(audio_io_handle_t output, // If effects where present on the output, audioflinger moved them to the primary // output by default: move them back to the appropriate output. audio_io_handle_t dstOutput = getOutputForEffect(); - if (dstOutput != mPrimaryOutput) { - mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mPrimaryOutput, dstOutput); + if (dstOutput != mPrimaryOutput->mIoHandle) { + mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, + mPrimaryOutput->mIoHandle, dstOutput); } mpClientInterface->onAudioPortListUpdate(); } @@ -1189,7 +1245,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX && strncmp(attr->tags, "addr=", strlen("addr=")) == 0) { - status_t ret = mPolicyMixes.getInputMixForAttr(*attr, policyMix); + status_t ret = mPolicyMixes.getInputMixForAttr(*attr, &policyMix); if (ret != NO_ERROR) { return ret; } @@ -1265,8 +1321,8 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, } } - if (profile->mModule->mHandle == 0) { - ALOGE("getInputForAttr(): HW module %s not opened", profile->mModule->mName); + if (profile->getModuleHandle() == 0) { + ALOGE("getInputForAttr(): HW module %s not opened", profile->getModuleName()); return NO_INIT; } @@ -1275,7 +1331,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, config.channel_mask = channelMask; config.format = format; - status_t status = mpClientInterface->openInput(profile->mModule->mHandle, + status_t status = mpClientInterface->openInput(profile->getModuleHandle(), input, &config, &device, @@ -1308,7 +1364,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, inputDesc->mIsSoundTrigger = isSoundTrigger; inputDesc->mPolicyMix = policyMix; - ALOGV("getInputForAttr() returns input type = %d", inputType); + ALOGV("getInputForAttr() returns input type = %d", *inputType); addInput(*input, inputDesc); mpClientInterface->onAudioPortListUpdate(); @@ -1505,8 +1561,8 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, audio_devices_t device) { - if ((index < mStreams[stream].getVolumeIndexMin()) || - (index > mStreams[stream].getVolumeIndexMax())) { + if ((index < mStreams.valueFor(stream).getVolumeIndexMin()) || + (index > mStreams.valueFor(stream).getVolumeIndexMax())) { return BAD_VALUE; } if (!audio_is_output_device(device)) { @@ -1514,7 +1570,7 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, } // Force max volume if stream cannot be muted - if (!mStreams.canBeMuted(stream)) index = mStreams[stream].getVolumeIndexMax(); + if (!mStreams.canBeMuted(stream)) index = mStreams.valueFor(stream).getVolumeIndexMax(); ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d", stream, device, index); @@ -1543,16 +1599,17 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, } status_t status = NO_ERROR; for (size_t i = 0; i < mOutputs.size(); i++) { - audio_devices_t curDevice = Volume::getDeviceForVolume(mOutputs.valueAt(i)->device()); + sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); + audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device()); if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & strategyDevice) != 0)) { - status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice); + status_t volStatus = checkAndSetVolume(stream, index, desc, curDevice); if (volStatus != NO_ERROR) { status = volStatus; } } if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0)) { status_t volStatus = checkAndSetVolume(AUDIO_STREAM_ACCESSIBILITY, - index, mOutputs.keyAt(i), curDevice); + index, desc, curDevice); } } return status; @@ -1575,7 +1632,7 @@ status_t AudioPolicyManager::getStreamVolumeIndex(audio_stream_type_t stream, } device = Volume::getDeviceForVolume(device); - *index = mStreams[stream].getVolumeIndex(device); + *index = mStreams.valueFor(stream).getVolumeIndex(device); ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index); return NO_ERROR; } @@ -1599,7 +1656,7 @@ audio_io_handle_t AudioPolicyManager::selectOutputForEffects( audio_io_handle_t outputDeepBuffer = 0; for (size_t i = 0; i < outputs.size(); i++) { - sp<AudioOutputDescriptor> desc = mOutputs.valueFor(outputs[i]); + sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(outputs[i]); ALOGV("selectOutputForEffects outputs[%zu] flags %x", i, desc->mFlags); if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) { outputOffloaded = outputs[i]; @@ -1653,6 +1710,16 @@ status_t AudioPolicyManager::registerEffect(const effect_descriptor_t *desc, return mEffects.registerEffect(desc, io, strategy, session, id); } +bool AudioPolicyManager::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const +{ + return mOutputs.isStreamActive(stream, inPastMs); +} + +bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const +{ + return mOutputs.isStreamActiveRemotely(stream, inPastMs); +} + bool AudioPolicyManager::isSourceActive(audio_source_t source) const { for (size_t i = 0; i < mInputs.size(); i++) { @@ -1803,7 +1870,7 @@ status_t AudioPolicyManager::dump(int fd) snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this); result.append(buffer); - snprintf(buffer, SIZE, " Primary Output: %d\n", mPrimaryOutput); + snprintf(buffer, SIZE, " Primary Output: %d\n", mPrimaryOutput->mIoHandle); result.append(buffer); snprintf(buffer, SIZE, " Phone state: %d\n", mEngine->getPhoneState()); result.append(buffer); @@ -2021,7 +2088,7 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch, } if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) { - sp<AudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id); + sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id); if (outputDesc == NULL) { ALOGV("createAudioPatch() output not found for id %d", patch->sources[0].id); return BAD_VALUE; @@ -2069,7 +2136,7 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch, // TODO: reconfigure output format and channels here ALOGV("createAudioPatch() setting device %08x on output %d", devices.types(), outputDesc->mIoHandle); - setOutputDevice(outputDesc->mIoHandle, devices.types(), true, 0, handle); + setOutputDevice(outputDesc, devices.types(), true, 0, handle); index = mAudioPatches.indexOfKey(*handle); if (index >= 0) { if (patchDesc != 0 && patchDesc != mAudioPatches.valueAt(index)) { @@ -2163,8 +2230,12 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch, } sinkDeviceDesc->toAudioPortConfig(&newPatch.sinks[i], &patch->sinks[i]); - if (srcDeviceDesc->mModule != sinkDeviceDesc->mModule) { - // only one sink supported when connected devices across HW modules + // create a software bridge in PatchPanel if: + // - source and sink devices are on differnt HW modules OR + // - audio HAL version is < 3.0 + if ((srcDeviceDesc->getModuleHandle() != sinkDeviceDesc->getModuleHandle()) || + (srcDeviceDesc->mModule->mHalVersion < AUDIO_DEVICE_API_VERSION_3_0)) { + // support only one sink device for now to simplify output selection logic if (patch->num_sinks > 1) { return INVALID_OPERATION; } @@ -2181,6 +2252,7 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch, return INVALID_OPERATION; } outputDesc->toAudioPortConfig(&newPatch.sources[1], &patch->sources[0]); + newPatch.sources[1].ext.mix.usecase.stream = AUDIO_STREAM_PATCH; newPatch.num_sources = 2; } } @@ -2242,14 +2314,14 @@ status_t AudioPolicyManager::releaseAudioPatch(audio_patch_handle_t handle, struct audio_patch *patch = &patchDesc->mPatch; patchDesc->mUid = mUidCached; if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) { - sp<AudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id); + sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id); if (outputDesc == NULL) { ALOGV("releaseAudioPatch() output not found for id %d", patch->sources[0].id); return BAD_VALUE; } - setOutputDevice(outputDesc->mIoHandle, - getNewOutputDevice(outputDesc->mIoHandle, true /*fromCache*/), + setOutputDevice(outputDesc, + getNewOutputDevice(outputDesc, true /*fromCache*/), true, 0, NULL); @@ -2308,7 +2380,7 @@ status_t AudioPolicyManager::setAudioPortConfig(const struct audio_port_config * sp<AudioPortConfig> audioPortConfig; if (config->type == AUDIO_PORT_TYPE_MIX) { if (config->role == AUDIO_PORT_ROLE_SOURCE) { - sp<AudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(config->id); + sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(config->id); if (outputDesc == NULL) { return BAD_VALUE; } @@ -2390,7 +2462,6 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa #ifdef AUDIO_POLICY_TEST Thread(false), #endif //AUDIO_POLICY_TEST - mPrimaryOutput((audio_io_handle_t)0), mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f), mA2dpSuspended(false), mSpeakerDrcEnabled(false), @@ -2474,7 +2545,8 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa if ((profileType & outputDeviceTypes) == 0) { continue; } - sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(outProfile); + sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile, + mpClientInterface); outputDesc->mDevice = profileType; audio_config_t config = AUDIO_CONFIG_INITIALIZER; @@ -2482,7 +2554,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa config.channel_mask = outputDesc->mChannelMask; config.format = outputDesc->mFormat; audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; - status_t status = mpClientInterface->openOutput(outProfile->mModule->mHandle, + status_t status = mpClientInterface->openOutput(outProfile->getModuleHandle(), &output, &config, &outputDesc->mDevice, @@ -2510,10 +2582,10 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa } if (mPrimaryOutput == 0 && outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) { - mPrimaryOutput = output; + mPrimaryOutput = outputDesc; } addOutput(output, outputDesc); - setOutputDevice(output, + setOutputDevice(outputDesc, outputDesc->mDevice, true); } @@ -2558,7 +2630,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa config.channel_mask = inputDesc->mChannelMask; config.format = inputDesc->mFormat; audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; - status_t status = mpClientInterface->openInput(inProfile->mModule->mHandle, + status_t status = mpClientInterface->openInput(inProfile->getModuleHandle(), &input, &config, &inputDesc->mDevice, @@ -2620,7 +2692,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa if (mPrimaryOutput != 0) { AudioParameter outputCmd = AudioParameter(); outputCmd.addInt(String8("set_id"), 0); - mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString()); + mpClientInterface->setParameters(mPrimaryOutput->mIoHandle, outputCmd.toString()); mTestDevice = AUDIO_DEVICE_OUT_SPEAKER; mTestSamplingRate = 44100; @@ -2760,20 +2832,21 @@ bool AudioPolicyManager::threadLoop() if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) { param.remove(String8("test_cmd_policy_reopen")); - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(mPrimaryOutput); - mpClientInterface->closeOutput(mPrimaryOutput); + mpClientInterface->closeOutput(mpClientInterface->closeOutput(mPrimaryOutput);); - audio_module_handle_t moduleHandle = outputDesc->mModule->mHandle; + audio_module_handle_t moduleHandle = mPrimaryOutput->getModuleHandle(); - removeOutput(mPrimaryOutput); - sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(NULL); + removeOutput(mPrimaryOutput->mIoHandle); + sp<SwAudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(NULL, + mpClientInterface); outputDesc->mDevice = AUDIO_DEVICE_OUT_SPEAKER; audio_config_t config = AUDIO_CONFIG_INITIALIZER; config.sample_rate = outputDesc->mSamplingRate; config.channel_mask = outputDesc->mChannelMask; config.format = outputDesc->mFormat; + audio_io_handle_t handle; status_t status = mpClientInterface->openOutput(moduleHandle, - &mPrimaryOutput, + &handle, &config, &outputDesc->mDevice, String8(""), @@ -2787,10 +2860,11 @@ bool AudioPolicyManager::threadLoop() outputDesc->mSamplingRate = config.sample_rate; outputDesc->mChannelMask = config.channel_mask; outputDesc->mFormat = config.format; + mPrimaryOutput = outputDesc; AudioParameter outputCmd = AudioParameter(); outputCmd.addInt(String8("set_id"), 0); - mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString()); - addOutput(mPrimaryOutput, outputDesc); + mpClientInterface->setParameters(handle, outputCmd.toString()); + addOutput(handle, outputDesc); } } @@ -2822,7 +2896,7 @@ int AudioPolicyManager::testOutputIndex(audio_io_handle_t output) // --- -void AudioPolicyManager::addOutput(audio_io_handle_t output, sp<AudioOutputDescriptor> outputDesc) +void AudioPolicyManager::addOutput(audio_io_handle_t output, sp<SwAudioOutputDescriptor> outputDesc) { outputDesc->setIoHandle(output); mOutputs.add(output, outputDesc); @@ -2841,7 +2915,7 @@ void AudioPolicyManager::addInput(audio_io_handle_t input, sp<AudioInputDescript nextAudioPortGeneration(); } -void AudioPolicyManager::findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/, +void AudioPolicyManager::findIoHandlesByAddress(sp<SwAudioOutputDescriptor> desc /*in*/, const audio_devices_t device /*in*/, const String8 address /*in*/, SortedVector<audio_io_handle_t>& outputs /*out*/) { @@ -2860,7 +2934,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de const String8 address) { audio_devices_t device = devDesc->type(); - sp<AudioOutputDescriptor> desc; + sp<SwAudioOutputDescriptor> desc; // erase all current sample rates, formats and channel masks devDesc->clearCapabilities(); @@ -2868,7 +2942,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de // first list already open outputs that can be routed to this device for (size_t i = 0; i < mOutputs.size(); i++) { desc = mOutputs.valueAt(i); - if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices.types() & device)) { + if (!desc->isDuplicated() && (desc->supportedDevices() & device)) { if (!device_distinguishes_on_address(device)) { ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i)); outputs.add(mOutputs.keyAt(i)); @@ -2927,7 +3001,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de ALOGV("opening output for device %08x with params %s profile %p", device, address.string(), profile.get()); - desc = new AudioOutputDescriptor(profile); + desc = new SwAudioOutputDescriptor(profile, mpClientInterface); desc->mDevice = device; audio_config_t config = AUDIO_CONFIG_INITIALIZER; config.sample_rate = desc->mSamplingRate; @@ -2937,7 +3011,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de config.offload_info.channel_mask = desc->mChannelMask; config.offload_info.format = desc->mFormat; audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; - status_t status = mpClientInterface->openOutput(profile->mModule->mHandle, + status_t status = mpClientInterface->openOutput(profile->getModuleHandle(), &output, &config, &desc->mDevice, @@ -3007,7 +3081,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de config.offload_info.sample_rate = config.sample_rate; config.offload_info.channel_mask = config.channel_mask; config.offload_info.format = config.format; - status = mpClientInterface->openOutput(profile->mModule->mHandle, + status = mpClientInterface->openOutput(profile->getModuleHandle(), &output, &config, &desc->mDevice, @@ -3032,7 +3106,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de address.string()); } policyMix->setOutput(desc); - desc->mPolicyMix = &(policyMix->getMix()); + desc->mPolicyMix = policyMix->getMix(); } else if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) { // no duplicated output for direct outputs and @@ -3040,28 +3114,29 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE; // set initial stream volume for device - applyStreamVolumes(output, device, 0, true); + applyStreamVolumes(desc, device, 0, true); //TODO: configure audio effect output stage here // open a duplicating output thread for the new output and the primary output - duplicatedOutput = mpClientInterface->openDuplicateOutput(output, - mPrimaryOutput); + duplicatedOutput = + mpClientInterface->openDuplicateOutput(output, + mPrimaryOutput->mIoHandle); if (duplicatedOutput != AUDIO_IO_HANDLE_NONE) { // add duplicated output descriptor - sp<AudioOutputDescriptor> dupOutputDesc = - new AudioOutputDescriptor(NULL); - dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput); - dupOutputDesc->mOutput2 = mOutputs.valueFor(output); + sp<SwAudioOutputDescriptor> dupOutputDesc = + new SwAudioOutputDescriptor(NULL, mpClientInterface); + dupOutputDesc->mOutput1 = mPrimaryOutput; + dupOutputDesc->mOutput2 = desc; dupOutputDesc->mSamplingRate = desc->mSamplingRate; dupOutputDesc->mFormat = desc->mFormat; dupOutputDesc->mChannelMask = desc->mChannelMask; dupOutputDesc->mLatency = desc->mLatency; addOutput(duplicatedOutput, dupOutputDesc); - applyStreamVolumes(duplicatedOutput, device, 0, true); + applyStreamVolumes(dupOutputDesc, device, 0, true); } else { ALOGW("checkOutputsForDevice() could not open dup output for %d and %d", - mPrimaryOutput, output); + mPrimaryOutput->mIoHandle, output); mpClientInterface->closeOutput(output); removeOutput(output); nextAudioPortGeneration(); @@ -3083,7 +3158,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de if (device_distinguishes_on_address(device)) { ALOGV("checkOutputsForDevice(): setOutputDevice(dev=0x%x, addr=%s)", device, address.string()); - setOutputDevice(output, device, true/*force*/, 0/*delay*/, + setOutputDevice(desc, device, true/*force*/, 0/*delay*/, NULL/*patch handle*/, address.string()); } ALOGV("checkOutputsForDevice(): adding output %d", output); @@ -3101,10 +3176,9 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de if (!desc->isDuplicated()) { // exact match on device if (device_distinguishes_on_address(device) && - (desc->mProfile->mSupportedDevices.types() == device)) { + (desc->supportedDevices() == device)) { findIoHandlesByAddress(desc, device, address, outputs); - } else if (!(desc->mProfile->mSupportedDevices.types() - & mAvailableOutputDevices.types())) { + } else if (!(desc->supportedDevices() & mAvailableOutputDevices.types())) { ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i)); outputs.add(mOutputs.keyAt(i)); @@ -3212,7 +3286,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, config.channel_mask = desc->mChannelMask; config.format = desc->mFormat; audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; - status_t status = mpClientInterface->openInput(profile->mModule->mHandle, + status_t status = mpClientInterface->openInput(profile->getModuleHandle(), &input, &config, &desc->mDevice, @@ -3339,7 +3413,7 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output) { ALOGV("closeOutput(%d)", output); - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); + sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); if (outputDesc == NULL) { ALOGW("closeOutput() unknown output %d", output); return; @@ -3348,7 +3422,7 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output) // look for duplicated outputs connected to the output being removed. for (size_t i = 0; i < mOutputs.size(); i++) { - sp<AudioOutputDescriptor> dupOutputDesc = mOutputs.valueAt(i); + sp<SwAudioOutputDescriptor> dupOutputDesc = mOutputs.valueAt(i); if (dupOutputDesc->isDuplicated() && (dupOutputDesc->mOutput1 == outputDesc || dupOutputDesc->mOutput2 == outputDesc)) { @@ -3417,8 +3491,9 @@ void AudioPolicyManager::closeInput(audio_io_handle_t input) mInputs.removeItem(input); } -SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(audio_devices_t device, - AudioOutputCollection openOutputs) +SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice( + audio_devices_t device, + SwAudioOutputCollection openOutputs) { SortedVector<audio_io_handle_t> outputs; @@ -3459,14 +3534,14 @@ void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy) // associated with policies in the "before" and "after" output vectors ALOGVV("checkOutputForStrategy(): policy related outputs"); for (size_t i = 0 ; i < mPreviousOutputs.size() ; i++) { - const sp<AudioOutputDescriptor> desc = mPreviousOutputs.valueAt(i); + const sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueAt(i); if (desc != 0 && desc->mPolicyMix != NULL) { srcOutputs.add(desc->mIoHandle); ALOGVV(" previous outputs: adding %d", desc->mIoHandle); } } for (size_t i = 0 ; i < mOutputs.size() ; i++) { - const sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i); + const sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); if (desc != 0 && desc->mPolicyMix != NULL) { dstOutputs.add(desc->mIoHandle); ALOGVV(" new outputs: adding %d", desc->mIoHandle); @@ -3478,10 +3553,10 @@ void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy) strategy, srcOutputs[0], dstOutputs[0]); // mute strategy while moving tracks from one output to another for (size_t i = 0; i < srcOutputs.size(); i++) { - sp<AudioOutputDescriptor> desc = mOutputs.valueFor(srcOutputs[i]); + sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(srcOutputs[i]); if (isStrategyActive(desc, strategy)) { - setStrategyMute(strategy, true, srcOutputs[i]); - setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice); + setStrategyMute(strategy, true, desc); + setStrategyMute(strategy, false, desc, MUTE_TIME_MS, newDevice); } } @@ -3578,12 +3653,11 @@ void AudioPolicyManager::checkA2dpSuspend() } } -audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output, bool fromCache) +audio_devices_t AudioPolicyManager::getNewOutputDevice(const sp<AudioOutputDescriptor>& outputDesc, + bool fromCache) { audio_devices_t device = AUDIO_DEVICE_NONE; - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); - ssize_t index = mAudioPatches.indexOfKey(outputDesc->mPatchHandle); if (index >= 0) { sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index); @@ -3761,9 +3835,9 @@ uint32_t AudioPolicyManager::setBeaconMute(bool mute) { ALOGV("\t muting %d", mute); uint32_t maxLatency = 0; for (size_t i = 0; i < mOutputs.size(); i++) { - sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i); + sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); setStreamMute(AUDIO_STREAM_TTS, mute/*on*/, - desc->mIoHandle, + desc, 0 /*delay*/, AUDIO_DEVICE_NONE); const uint32_t latency = desc->latency() * 2; if (latency > maxLatency) { @@ -3779,6 +3853,21 @@ uint32_t AudioPolicyManager::setBeaconMute(bool mute) { audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy, bool fromCache) { + // Routing + // see if we have an explicit route + // scan the whole RouteMap, for each entry, convert the stream type to a strategy + // (getStrategy(stream)). + // if the strategy from the stream type in the RouteMap is the same as the argument above, + // and activity count is non-zero + // the device = the device from the descriptor in the RouteMap, and exit. + for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) { + sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex); + routing_strategy strat = getStrategy(route->mStreamType); + if (strat == strategy && route->mDeviceDescriptor != 0 /*&& route->mActivityCount != 0*/) { + return route->mDeviceDescriptor->type(); + } + } + if (fromCache) { ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, mDeviceForStrategy[strategy]); @@ -3812,7 +3901,7 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(sp<AudioOutputDescriptor> for (size_t i = 0; i < NUM_STRATEGIES; i++) { audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/); - curDevice = curDevice & outputDesc->mProfile->mSupportedDevices.types(); + curDevice = curDevice & outputDesc->supportedDevices(); bool mute = shouldMute && (curDevice & device) && (curDevice != device); bool doMute = false; @@ -3831,10 +3920,9 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(sp<AudioOutputDescriptor> == AUDIO_DEVICE_NONE) { continue; } - audio_io_handle_t curOutput = mOutputs.keyAt(j); - ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x) on output %d", - mute ? "muting" : "unmuting", i, curDevice, curOutput); - setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs); + ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x)", + mute ? "muting" : "unmuting", i, curDevice); + setStrategyMute((routing_strategy)i, mute, desc, mute ? 0 : delayMs); if (isStrategyActive(desc, (routing_strategy)i)) { if (mute) { // FIXME: should not need to double latency if volume could be applied @@ -3859,9 +3947,9 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(sp<AudioOutputDescriptor> } for (size_t i = 0; i < NUM_STRATEGIES; i++) { if (isStrategyActive(outputDesc, (routing_strategy)i)) { - setStrategyMute((routing_strategy)i, true, outputDesc->mIoHandle); + setStrategyMute((routing_strategy)i, true, outputDesc); // do tempMute unmute after twice the mute wait time - setStrategyMute((routing_strategy)i, false, outputDesc->mIoHandle, + setStrategyMute((routing_strategy)i, false, outputDesc, muteWaitMs *2, device); } } @@ -3876,36 +3964,35 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(sp<AudioOutputDescriptor> return 0; } -uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, +uint32_t AudioPolicyManager::setOutputDevice(const sp<AudioOutputDescriptor>& outputDesc, audio_devices_t device, bool force, int delayMs, audio_patch_handle_t *patchHandle, const char* address) { - ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs); - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); + ALOGV("setOutputDevice() device %04x delayMs %d", device, delayMs); AudioParameter param; uint32_t muteWaitMs; if (outputDesc->isDuplicated()) { - muteWaitMs = setOutputDevice(outputDesc->mOutput1->mIoHandle, device, force, delayMs); - muteWaitMs += setOutputDevice(outputDesc->mOutput2->mIoHandle, device, force, delayMs); + muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs); + muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs); return muteWaitMs; } // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current // output profile if ((device != AUDIO_DEVICE_NONE) && - ((device & outputDesc->mProfile->mSupportedDevices.types()) == 0)) { + ((device & outputDesc->supportedDevices()) == 0)) { return 0; } // filter devices according to output selected - device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices.types()); + device = (audio_devices_t)(device & outputDesc->supportedDevices()); audio_devices_t prevDevice = outputDesc->mDevice; - ALOGV("setOutputDevice() prevDevice %04x", prevDevice); + ALOGV("setOutputDevice() prevDevice 0x%04x", prevDevice); if (device != AUDIO_DEVICE_NONE) { outputDesc->mDevice = device; @@ -3918,10 +4005,10 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, // AND force is not specified // AND the output is connected by a valid audio patch. // Doing this check here allows the caller to call setOutputDevice() without conditions - if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force && - outputDesc->mPatchHandle != 0) { - ALOGV("setOutputDevice() setting same device %04x or null device for output %d", - device, output); + if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && + !force && + outputDesc->mPatchHandle != 0) { + ALOGV("setOutputDevice() setting same device 0x%04x or null device", device); return muteWaitMs; } @@ -3929,7 +4016,7 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, // do the routing if (device == AUDIO_DEVICE_NONE) { - resetOutputDevice(output, delayMs, NULL); + resetOutputDevice(outputDesc, delayMs, NULL); } else { DeviceVector deviceList = (address == NULL) ? mAvailableOutputDevices.getDevicesFromType(device) @@ -3996,16 +4083,15 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, } // update stream volumes according to new device - applyStreamVolumes(output, device, delayMs); + applyStreamVolumes(outputDesc, device, delayMs); return muteWaitMs; } -status_t AudioPolicyManager::resetOutputDevice(audio_io_handle_t output, +status_t AudioPolicyManager::resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc, int delayMs, audio_patch_handle_t *patchHandle) { - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); ssize_t index; if (patchHandle) { index = mAudioPatches.indexOfKey(*patchHandle); @@ -4162,17 +4248,10 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input } float AudioPolicyManager::computeVolume(audio_stream_type_t stream, - int index, - audio_io_handle_t output, - audio_devices_t device) + int index, + audio_devices_t device) { - float volume = 1.0; - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); - - if (device == AUDIO_DEVICE_NONE) { - device = outputDesc->device(); - } - volume = mEngine->volIndexToAmpl(Volume::getDeviceCategory(device), stream, index); + float volumeDb = mEngine->volIndexToDb(Volume::getDeviceCategory(device), stream, index); // if a headset is connected, apply the following rules to ring tones and notifications // to avoid sound level bursts in user's ears: @@ -4190,41 +4269,39 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream, || ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) && (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) && mStreams.canBeMuted(stream)) { - volume *= SONIFICATION_HEADSET_VOLUME_FACTOR; + volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB; // when the phone is ringing we must consider that music could have been paused just before // by the music application and behave as if music was active if the last music track was // just stopped if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) || mLimitRingtoneVolume) { audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/); - float musicVol = computeVolume(AUDIO_STREAM_MUSIC, - mStreams[AUDIO_STREAM_MUSIC].getVolumeIndex(musicDevice), - output, + float musicVolDB = computeVolume(AUDIO_STREAM_MUSIC, + mStreams.valueFor(AUDIO_STREAM_MUSIC).getVolumeIndex(musicDevice), musicDevice); - float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ? - musicVol : SONIFICATION_HEADSET_VOLUME_MIN; - if (volume > minVol) { - volume = minVol; - ALOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol); + float minVolDB = (musicVolDB > SONIFICATION_HEADSET_VOLUME_MIN_DB) ? + musicVolDB : SONIFICATION_HEADSET_VOLUME_MIN_DB; + if (volumeDb > minVolDB) { + volumeDb = minVolDB; + ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDB, musicVolDB); } } } - return volume; + return volumeDb; } status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream, - int index, - audio_io_handle_t output, - audio_devices_t device, - int delayMs, - bool force) + int index, + const sp<AudioOutputDescriptor>& outputDesc, + audio_devices_t device, + int delayMs, + bool force) { - // do not change actual stream volume if the stream is muted - if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) { + if (outputDesc->mMuteCount[stream] != 0) { ALOGVV("checkAndSetVolume() stream %d muted count %d", - stream, mOutputs.valueFor(output)->mMuteCount[stream]); + stream, outputDesc->mMuteCount[stream]); return NO_ERROR; } audio_policy_forced_cfg_t forceUseForComm = @@ -4237,45 +4314,28 @@ status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream, return INVALID_OPERATION; } - float volume = computeVolume(stream, index, output, device); - // unit gain if rerouting to external policy - if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) { - ssize_t index = mOutputs.indexOfKey(output); - if (index >= 0) { - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index); - if (outputDesc->mPolicyMix != NULL) { - ALOGV("max gain when rerouting for output=%d", output); - volume = 1.0f; - } - } - + if (device == AUDIO_DEVICE_NONE) { + device = outputDesc->device(); } - // We actually change the volume if: - // - the float value returned by computeVolume() changed - // - the force flag is set - if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || - force) { - mOutputs.valueFor(output)->mCurVolume[stream] = volume; - ALOGVV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs); - // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is - // enabled - if (stream == AUDIO_STREAM_BLUETOOTH_SCO) { - mpClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volume, output, delayMs); - } - mpClientInterface->setStreamVolume(stream, volume, output, delayMs); + + float volumeDb = computeVolume(stream, index, device); + if (outputDesc->isFixedVolume(device)) { + volumeDb = 0.0f; } + outputDesc->setVolume(volumeDb, stream, device, delayMs, force); + if (stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) { float voiceVolume; // Force voice volume to max for bluetooth SCO as volume is managed by the headset if (stream == AUDIO_STREAM_VOICE_CALL) { - voiceVolume = (float)index/(float)mStreams[stream].getVolumeIndexMax(); + voiceVolume = (float)index/(float)mStreams.valueFor(stream).getVolumeIndexMax(); } else { voiceVolume = 1.0; } - if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) { + if (voiceVolume != mLastVoiceVolume && outputDesc == mPrimaryOutput) { mpClientInterface->setVoiceVolume(voiceVolume, delayMs); mLastVoiceVolume = voiceVolume; } @@ -4284,20 +4344,20 @@ status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream, return NO_ERROR; } -void AudioPolicyManager::applyStreamVolumes(audio_io_handle_t output, - audio_devices_t device, - int delayMs, - bool force) +void AudioPolicyManager::applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc, + audio_devices_t device, + int delayMs, + bool force) { - ALOGVV("applyStreamVolumes() for output %d and device %x", output, device); + ALOGVV("applyStreamVolumes() for device %08x", device); for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { if (stream == AUDIO_STREAM_PATCH) { continue; } checkAndSetVolume((audio_stream_type_t)stream, - mStreams[stream].getVolumeIndex(device), - output, + mStreams.valueFor((audio_stream_type_t)stream).getVolumeIndex(device), + outputDesc, device, delayMs, force); @@ -4305,10 +4365,10 @@ void AudioPolicyManager::applyStreamVolumes(audio_io_handle_t output, } void AudioPolicyManager::setStrategyMute(routing_strategy strategy, - bool on, - audio_io_handle_t output, - int delayMs, - audio_devices_t device) + bool on, + const sp<AudioOutputDescriptor>& outputDesc, + int delayMs, + audio_devices_t device) { ALOGVV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output); for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { @@ -4316,32 +4376,31 @@ void AudioPolicyManager::setStrategyMute(routing_strategy strategy, continue; } if (getStrategy((audio_stream_type_t)stream) == strategy) { - setStreamMute((audio_stream_type_t)stream, on, output, delayMs, device); + setStreamMute((audio_stream_type_t)stream, on, outputDesc, delayMs, device); } } } void AudioPolicyManager::setStreamMute(audio_stream_type_t stream, - bool on, - audio_io_handle_t output, - int delayMs, - audio_devices_t device) + bool on, + const sp<AudioOutputDescriptor>& outputDesc, + int delayMs, + audio_devices_t device) { - const StreamDescriptor &streamDesc = mStreams[stream]; - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); + const StreamDescriptor& streamDesc = mStreams.valueFor(stream); if (device == AUDIO_DEVICE_NONE) { device = outputDesc->device(); } - ALOGVV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d device %04x", - stream, on, output, outputDesc->mMuteCount[stream], device); + ALOGVV("setStreamMute() stream %d, mute %d, mMuteCount %d device %04x", + stream, on, outputDesc->mMuteCount[stream], device); if (on) { if (outputDesc->mMuteCount[stream] == 0) { if (streamDesc.canBeMuted() && ((stream != AUDIO_STREAM_ENFORCED_AUDIBLE) || (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) { - checkAndSetVolume(stream, 0, output, device, delayMs); + checkAndSetVolume(stream, 0, outputDesc, device, delayMs); } } // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored @@ -4354,7 +4413,7 @@ void AudioPolicyManager::setStreamMute(audio_stream_type_t stream, if (--outputDesc->mMuteCount[stream] == 0) { checkAndSetVolume(stream, streamDesc.getVolumeIndex(device), - output, + outputDesc, device, delayMs); } @@ -4373,7 +4432,7 @@ void AudioPolicyManager::handleIncallSonification(audio_stream_type_t stream, const routing_strategy stream_strategy = getStrategy(stream); if ((stream_strategy == STRATEGY_SONIFICATION) || ((stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL))) { - sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(mPrimaryOutput); + sp<SwAudioOutputDescriptor> outputDesc = mPrimaryOutput; ALOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d", stream, starting, outputDesc->mDevice, stateChange); if (outputDesc->mRefCount[stream]) { @@ -4406,6 +4465,70 @@ void AudioPolicyManager::handleIncallSonification(audio_stream_type_t stream, } } +// --- SessionRoute class implementation +void AudioPolicyManager::SessionRoute::log(const char* prefix) { + ALOGI("%s[SessionRoute strm:0x%X, sess:0x%X, dev:0x%X refs:%d act:%d", + prefix, mStreamType, mSession, + mDeviceDescriptor != 0 ? mDeviceDescriptor->type() : AUDIO_DEVICE_NONE, + mRefCount, mActivityCount); +} + +// --- SessionRouteMap class implementation +bool AudioPolicyManager::SessionRouteMap::hasRoute(audio_session_t session) +{ + return indexOfKey(session) >= 0 && valueFor(session)->mDeviceDescriptor != 0; +} + +void AudioPolicyManager::SessionRouteMap::addRoute(audio_session_t session, + audio_stream_type_t streamType, + sp<DeviceDescriptor> deviceDescriptor) +{ + sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0; + if (route != NULL) { + route->mRefCount++; + route->mDeviceDescriptor = deviceDescriptor; + } else { + route = new AudioPolicyManager::SessionRoute(session, streamType, deviceDescriptor); + route->mRefCount++; + add(session, route); + } +} + +void AudioPolicyManager::SessionRouteMap::removeRoute(audio_session_t session) +{ + sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0; + if (route != 0) { + ALOG_ASSERT(route->mRefCount > 0); + --route->mRefCount; + if (route->mRefCount <= 0) { + removeItem(session); + } + } +} + +int AudioPolicyManager::SessionRouteMap::incRouteActivity(audio_session_t session) +{ + sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0; + return route != 0 ? ++(route->mActivityCount) : -1; +} + +int AudioPolicyManager::SessionRouteMap::decRouteActivity(audio_session_t session) +{ + sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0; + if (route != 0 && route->mActivityCount > 0) { + return --(route->mActivityCount); + } else { + return -1; + } +} + +void AudioPolicyManager::SessionRouteMap::log(const char* caption) { + ALOGI("%s ----", caption); + for(size_t index = 0; index < size(); index++) { + valueAt(index)->log(" "); + } +} + void AudioPolicyManager::defaultAudioPolicyConfig(void) { sp<HwModule> module; @@ -4417,7 +4540,8 @@ void AudioPolicyManager::defaultAudioPolicyConfig(void) module = new HwModule("primary"); - profile = new IOProfile(String8("primary"), AUDIO_PORT_ROLE_SOURCE, module); + profile = new IOProfile(String8("primary"), AUDIO_PORT_ROLE_SOURCE); + profile->attach(module); profile->mSamplingRates.add(44100); profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT); profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO); @@ -4425,7 +4549,8 @@ void AudioPolicyManager::defaultAudioPolicyConfig(void) profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY; module->mOutputProfiles.add(profile); - profile = new IOProfile(String8("primary"), AUDIO_PORT_ROLE_SINK, module); + profile = new IOProfile(String8("primary"), AUDIO_PORT_ROLE_SINK); + profile->attach(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/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index 02b678a..11fd5ff 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -49,8 +49,11 @@ namespace android { // Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB #define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5 +#define SONIFICATION_HEADSET_VOLUME_FACTOR_DB (-6) // Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB #define SONIFICATION_HEADSET_VOLUME_MIN 0.016 +#define SONIFICATION_HEADSET_VOLUME_MIN_DB (-36) + // Time in milliseconds during which we consider that music is still active after a music // track was stopped - see computeVolume() #define SONIFICATION_HEADSET_MUSIC_DELAY 5000 @@ -110,6 +113,7 @@ public: audio_format_t format, audio_channel_mask_t channelMask, audio_output_flags_t flags, + audio_port_handle_t selectedDeviceId, const audio_offload_info_t *offloadInfo); virtual status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, @@ -172,19 +176,15 @@ public: return mEffects.setEffectEnabled(id, enabled); } - virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const - { - return mOutputs.isStreamActive(stream, inPastMs); - } + virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const; // return whether a stream is playing remotely, override to change the definition of // local/remote playback, used for instance by notification manager to not make // media players lose audio focus when not playing locally // For the base implementation, "remotely" means playing during screen mirroring which // uses an output for playback with a non-empty, non "0" address. - virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const - { - return mOutputs.isStreamActiveRemotely(stream, inPastMs); - } + virtual bool isStreamActiveRemotely(audio_stream_type_t stream, + uint32_t inPastMs = 0) const; + virtual bool isSourceActive(audio_source_t source) const; virtual status_t dump(int fd); @@ -227,6 +227,46 @@ public: // return the strategy corresponding to a given stream type routing_strategy getStrategy(audio_stream_type_t stream) const; +protected: + class SessionRoute : public RefBase + { + public: + friend class SessionRouteMap; + SessionRoute(audio_session_t session, + audio_stream_type_t streamType, + sp<DeviceDescriptor> deviceDescriptor) + : mSession(session), + mStreamType(streamType), + mDeviceDescriptor(deviceDescriptor), + mRefCount(0), + mActivityCount(0) {} + + audio_session_t mSession; + audio_stream_type_t mStreamType; + + sp<DeviceDescriptor> mDeviceDescriptor; + + // "reference" counting + int mRefCount; // +/- on references + int mActivityCount; // +/- on start/stop + + void log(const char* prefix); + }; + + class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute>> + { + public: + bool hasRoute(audio_session_t session); + void addRoute(audio_session_t session, audio_stream_type_t streamType, + sp<DeviceDescriptor> deviceDescriptor); + void removeRoute(audio_session_t session); + + int incRouteActivity(audio_session_t session); + int decRouteActivity(audio_session_t session); + + void log(const char* caption); + }; + // From AudioPolicyManagerObserver virtual const AudioPatchCollection &getAudioPatches() const { @@ -240,7 +280,7 @@ public: { return mPolicyMixes; } - virtual const AudioOutputCollection &getOutputs() const + virtual const SwAudioOutputCollection &getOutputs() const { return mOutputs; } @@ -265,7 +305,7 @@ public: return mDefaultOutputDevice; } protected: - void addOutput(audio_io_handle_t output, sp<AudioOutputDescriptor> outputDesc); + void addOutput(audio_io_handle_t output, sp<SwAudioOutputDescriptor> outputDesc); void removeOutput(audio_io_handle_t output); void addInput(audio_io_handle_t input, sp<AudioInputDescriptor> inputDesc); @@ -288,13 +328,13 @@ protected: // change the route of the specified output. Returns the number of ms we have slept to // allow new routing to take effect in certain cases. - virtual uint32_t setOutputDevice(audio_io_handle_t output, + virtual uint32_t setOutputDevice(const sp<AudioOutputDescriptor>& outputDesc, audio_devices_t device, bool force = false, int delayMs = 0, audio_patch_handle_t *patchHandle = NULL, const char* address = NULL); - status_t resetOutputDevice(audio_io_handle_t output, + status_t resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc, int delayMs = 0, audio_patch_handle_t *patchHandle = NULL); status_t setInputDevice(audio_io_handle_t input, @@ -309,29 +349,31 @@ protected: // compute the actual volume for a given stream according to the requested index and a particular // device - virtual float computeVolume(audio_stream_type_t stream, int index, - audio_io_handle_t output, audio_devices_t device); + virtual float computeVolume(audio_stream_type_t stream, + int index, + audio_devices_t device); // check that volume change is permitted, compute and send new volume to audio hardware virtual status_t checkAndSetVolume(audio_stream_type_t stream, int index, - audio_io_handle_t output, + const sp<AudioOutputDescriptor>& outputDesc, audio_devices_t device, int delayMs = 0, bool force = false); // apply all stream volumes to the specified output and device - void applyStreamVolumes(audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false); + void applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc, + audio_devices_t device, int delayMs = 0, bool force = false); // Mute or unmute all streams handled by the specified strategy on the specified output void setStrategyMute(routing_strategy strategy, bool on, - audio_io_handle_t output, + const sp<AudioOutputDescriptor>& outputDesc, int delayMs = 0, audio_devices_t device = (audio_devices_t)0); // Mute or unmute the stream on the specified output void setStreamMute(audio_stream_type_t stream, bool on, - audio_io_handle_t output, + const sp<AudioOutputDescriptor>& outputDesc, int delayMs = 0, audio_devices_t device = (audio_devices_t)0); @@ -384,7 +426,8 @@ 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 getNewOutputDevice(const sp<AudioOutputDescriptor>& outputDesc, + 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 @@ -412,7 +455,7 @@ protected: #endif //AUDIO_POLICY_TEST SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device, - AudioOutputCollection openOutputs); + SwAudioOutputCollection openOutputs); bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1, SortedVector<audio_io_handle_t>& outputs2); @@ -453,28 +496,39 @@ protected: audio_devices_t availablePrimaryOutputDevices() const { - return mOutputs.getSupportedDevices(mPrimaryOutput) & mAvailableOutputDevices.types(); + return mPrimaryOutput->supportedDevices() & mAvailableOutputDevices.types(); } audio_devices_t availablePrimaryInputDevices() const { - return mAvailableInputDevices.getDevicesFromHwModule( - mOutputs.valueFor(mPrimaryOutput)->getModuleHandle()); + return mAvailableInputDevices.getDevicesFromHwModule(mPrimaryOutput->getModuleHandle()); } void updateCallRouting(audio_devices_t rxDevice, int delayMs = 0); + status_t startSource(sp<AudioOutputDescriptor> outputDesc, + audio_stream_type_t stream, + audio_devices_t device, + uint32_t *delayMs); + status_t stopSource(sp<AudioOutputDescriptor> outputDesc, + audio_stream_type_t stream); + uid_t mUidCached; AudioPolicyClientInterface *mpClientInterface; // audio policy client interface - audio_io_handle_t mPrimaryOutput; // primary output handle + sp<SwAudioOutputDescriptor> mPrimaryOutput; // primary output descriptor // list of descriptors for outputs currently opened - AudioOutputCollection mOutputs; + + SwAudioOutputCollection mOutputs; // copy of mOutputs before setDeviceConnectionState() opens new outputs // reset to mOutputs when updateDevicesAndOutputs() is called. - AudioOutputCollection mPreviousOutputs; + SwAudioOutputCollection mPreviousOutputs; AudioInputCollection mInputs; // list of input descriptors + DeviceVector mAvailableOutputDevices; // all available output devices DeviceVector mAvailableInputDevices; // all available input devices + SessionRouteMap mOutputRoutes; + SessionRouteMap mInputRoutes; + StreamDescriptorCollection mStreams; // stream descriptors for volume control bool mLimitRingtoneVolume; // limit ringtone volume to music volume if headset connected audio_devices_t mDeviceForStrategy[NUM_STRATEGIES]; @@ -539,7 +593,7 @@ private: // in mProfile->mSupportedDevices) matches the device whose address is to be matched. // see deviceDistinguishesOnAddress(audio_devices_t) for whether the device type is one // where addresses are used to distinguish between one connected device and another. - void findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/, + void findIoHandlesByAddress(sp<SwAudioOutputDescriptor> desc /*in*/, const audio_devices_t device /*in*/, const String8 address /*in*/, SortedVector<audio_io_handle_t>& outputs /*out*/); diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index e9ff838..a763151 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -150,6 +150,7 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, audio_format_t format, audio_channel_mask_t channelMask, audio_output_flags_t flags, + int mSelectedDeviceId, const audio_offload_info_t *offloadInfo) { if (mAudioPolicyManager == NULL) { @@ -158,7 +159,7 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, ALOGV("getOutput()"); Mutex::Autolock _l(mLock); return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, samplingRate, - format, channelMask, flags, offloadInfo); + format, channelMask, flags, mSelectedDeviceId, offloadInfo); } status_t AudioPolicyService::startOutput(audio_io_handle_t output, diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp index 5a91192..372a9fa 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp @@ -569,6 +569,7 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, audio_format_t format, audio_channel_mask_t channelMask, audio_output_flags_t flags, + int selectedDeviceId __unused, const audio_offload_info_t *offloadInfo) { if (attr != NULL) { diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h index 0378384..f8dabd3 100644 --- a/services/audiopolicy/service/AudioPolicyService.h +++ b/services/audiopolicy/service/AudioPolicyService.h @@ -84,6 +84,7 @@ public: audio_format_t format = AUDIO_FORMAT_DEFAULT, audio_channel_mask_t channelMask = 0, audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, + int selectedDeviceId = AUDIO_PORT_HANDLE_NONE, const audio_offload_info_t *offloadInfo = NULL); virtual status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, |