/services/audioflinger/Threads.cpp
C++ | 6415 lines | 4924 code | 641 blank | 850 comment | 1347 complexity | c67907e47d7ffb79b79b5d0f997b1f70 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*
- **
- ** Copyright 2012, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
- #define LOG_TAG "AudioFlinger"
- //#define LOG_NDEBUG 0
- #define ATRACE_TAG ATRACE_TAG_AUDIO
- #include "Configuration.h"
- #include <math.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <cutils/properties.h>
- #include <media/AudioParameter.h>
- #include <media/AudioResamplerPublic.h>
- #include <utils/Log.h>
- #include <utils/Trace.h>
- #include <private/media/AudioTrackShared.h>
- #include <hardware/audio.h>
- #include <audio_effects/effect_ns.h>
- #include <audio_effects/effect_aec.h>
- #include <audio_utils/primitives.h>
- #include <audio_utils/format.h>
- #include <audio_utils/minifloat.h>
- // NBAIO implementations
- #include <media/nbaio/AudioStreamInSource.h>
- #include <media/nbaio/AudioStreamOutSink.h>
- #include <media/nbaio/MonoPipe.h>
- #include <media/nbaio/MonoPipeReader.h>
- #include <media/nbaio/Pipe.h>
- #include <media/nbaio/PipeReader.h>
- #include <media/nbaio/SourceAudioBufferProvider.h>
- #include <powermanager/PowerManager.h>
- #include <common_time/cc_helper.h>
- #include <common_time/local_clock.h>
- #include "AudioFlinger.h"
- #include "AudioMixer.h"
- #include "FastMixer.h"
- #include "FastCapture.h"
- #include "ServiceUtilities.h"
- #include "SchedulingPolicyService.h"
- #ifdef ADD_BATTERY_DATA
- #include <media/IMediaPlayerService.h>
- #include <media/IMediaDeathNotifier.h>
- #endif
- #ifdef DEBUG_CPU_USAGE
- #include <cpustats/CentralTendencyStatistics.h>
- #include <cpustats/ThreadCpuUsage.h>
- #endif
- // ----------------------------------------------------------------------------
- // Note: the following macro is used for extremely verbose logging message. In
- // order to run with ALOG_ASSERT turned on, we need to have LOG_NDEBUG set to
- // 0; but one side effect of this is to turn all LOGV's as well. Some messages
- // are so verbose that we want to suppress them even when we have ALOG_ASSERT
- // turned on. Do not uncomment the #def below unless you really know what you
- // are doing and want to see all of the extremely verbose messages.
- //#define VERY_VERY_VERBOSE_LOGGING
- #ifdef VERY_VERY_VERBOSE_LOGGING
- #define ALOGVV ALOGV
- #else
- #define ALOGVV(a...) do { } while(0)
- #endif
- #define max(a, b) ((a) > (b) ? (a) : (b))
- namespace android {
- // retry counts for buffer fill timeout
- // 50 * ~20msecs = 1 second
- static const int8_t kMaxTrackRetries = 50;
- static const int8_t kMaxTrackStartupRetries = 50;
- // allow less retry attempts on direct output thread.
- // direct outputs can be a scarce resource in audio hardware and should
- // be released as quickly as possible.
- static const int8_t kMaxTrackRetriesDirect = 2;
- // don't warn about blocked writes or record buffer overflows more often than this
- static const nsecs_t kWarningThrottleNs = seconds(5);
- // RecordThread loop sleep time upon application overrun or audio HAL read error
- static const int kRecordThreadSleepUs = 5000;
- // maximum time to wait in sendConfigEvent_l() for a status to be received
- static const nsecs_t kConfigEventTimeoutNs = seconds(2);
- // minimum sleep time for the mixer thread loop when tracks are active but in underrun
- static const uint32_t kMinThreadSleepTimeUs = 5000;
- // maximum divider applied to the active sleep time in the mixer thread loop
- static const uint32_t kMaxThreadSleepTimeShift = 2;
- // minimum normal sink buffer size, expressed in milliseconds rather than frames
- static const uint32_t kMinNormalSinkBufferSizeMs = 20;
- // maximum normal sink buffer size
- static const uint32_t kMaxNormalSinkBufferSizeMs = 24;
- // Offloaded output thread standby delay: allows track transition without going to standby
- static const nsecs_t kOffloadStandbyDelayNs = seconds(1);
- // Whether to use fast mixer
- static const enum {
- FastMixer_Never, // never initialize or use: for debugging only
- FastMixer_Always, // always initialize and use, even if not needed: for debugging only
- // normal mixer multiplier is 1
- FastMixer_Static, // initialize if needed, then use all the time if initialized,
- // multiplier is calculated based on min & max normal mixer buffer size
- FastMixer_Dynamic, // initialize if needed, then use dynamically depending on track load,
- // multiplier is calculated based on min & max normal mixer buffer size
- // FIXME for FastMixer_Dynamic:
- // Supporting this option will require fixing HALs that can't handle large writes.
- // For example, one HAL implementation returns an error from a large write,
- // and another HAL implementation corrupts memory, possibly in the sample rate converter.
- // We could either fix the HAL implementations, or provide a wrapper that breaks
- // up large writes into smaller ones, and the wrapper would need to deal with scheduler.
- } kUseFastMixer = FastMixer_Static;
- // Whether to use fast capture
- static const enum {
- FastCapture_Never, // never initialize or use: for debugging only
- FastCapture_Always, // always initialize and use, even if not needed: for debugging only
- FastCapture_Static, // initialize if needed, then use all the time if initialized
- } kUseFastCapture = FastCapture_Static;
- // Priorities for requestPriority
- static const int kPriorityAudioApp = 2;
- static const int kPriorityFastMixer = 3;
- static const int kPriorityFastCapture = 3;
- // IAudioFlinger::createTrack() reports back to client the total size of shared memory area
- // for the track. The client then sub-divides this into smaller buffers for its use.
- // Currently the client uses N-buffering by default, but doesn't tell us about the value of N.
- // So for now we just assume that client is double-buffered for fast tracks.
- // FIXME It would be better for client to tell AudioFlinger the value of N,
- // so AudioFlinger could allocate the right amount of memory.
- // See the client's minBufCount and mNotificationFramesAct calculations for details.
- // This is the default value, if not specified by property.
- static const int kFastTrackMultiplier = 2;
- // The minimum and maximum allowed values
- static const int kFastTrackMultiplierMin = 1;
- static const int kFastTrackMultiplierMax = 2;
- // The actual value to use, which can be specified per-device via property af.fast_track_multiplier.
- static int sFastTrackMultiplier = kFastTrackMultiplier;
- // See Thread::readOnlyHeap().
- // Initially this heap is used to allocate client buffers for "fast" AudioRecord.
- // Eventually it will be the single buffer that FastCapture writes into via HAL read(),
- // and that all "fast" AudioRecord clients read from. In either case, the size can be small.
- static const size_t kRecordThreadReadOnlyHeapSize = 0x2000;
- // ----------------------------------------------------------------------------
- static pthread_once_t sFastTrackMultiplierOnce = PTHREAD_ONCE_INIT;
- static void sFastTrackMultiplierInit()
- {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("af.fast_track_multiplier", value, NULL) > 0) {
- char *endptr;
- unsigned long ul = strtoul(value, &endptr, 0);
- if (*endptr == '\0' && kFastTrackMultiplierMin <= ul && ul <= kFastTrackMultiplierMax) {
- sFastTrackMultiplier = (int) ul;
- }
- }
- }
- // ----------------------------------------------------------------------------
- #ifdef ADD_BATTERY_DATA
- // To collect the amplifier usage
- static void addBatteryData(uint32_t params) {
- sp<IMediaPlayerService> service = IMediaDeathNotifier::getMediaPlayerService();
- if (service == NULL) {
- // it already logged
- return;
- }
- service->addBatteryData(params);
- }
- #endif
- // ----------------------------------------------------------------------------
- // CPU Stats
- // ----------------------------------------------------------------------------
- class CpuStats {
- public:
- CpuStats();
- void sample(const String8 &title);
- #ifdef DEBUG_CPU_USAGE
- private:
- ThreadCpuUsage mCpuUsage; // instantaneous thread CPU usage in wall clock ns
- CentralTendencyStatistics mWcStats; // statistics on thread CPU usage in wall clock ns
- CentralTendencyStatistics mHzStats; // statistics on thread CPU usage in cycles
- int mCpuNum; // thread's current CPU number
- int mCpukHz; // frequency of thread's current CPU in kHz
- #endif
- };
- CpuStats::CpuStats()
- #ifdef DEBUG_CPU_USAGE
- : mCpuNum(-1), mCpukHz(-1)
- #endif
- {
- }
- void CpuStats::sample(const String8 &title
- #ifndef DEBUG_CPU_USAGE
- __unused
- #endif
- ) {
- #ifdef DEBUG_CPU_USAGE
- // get current thread's delta CPU time in wall clock ns
- double wcNs;
- bool valid = mCpuUsage.sampleAndEnable(wcNs);
- // record sample for wall clock statistics
- if (valid) {
- mWcStats.sample(wcNs);
- }
- // get the current CPU number
- int cpuNum = sched_getcpu();
- // get the current CPU frequency in kHz
- int cpukHz = mCpuUsage.getCpukHz(cpuNum);
- // check if either CPU number or frequency changed
- if (cpuNum != mCpuNum || cpukHz != mCpukHz) {
- mCpuNum = cpuNum;
- mCpukHz = cpukHz;
- // ignore sample for purposes of cycles
- valid = false;
- }
- // if no change in CPU number or frequency, then record sample for cycle statistics
- if (valid && mCpukHz > 0) {
- double cycles = wcNs * cpukHz * 0.000001;
- mHzStats.sample(cycles);
- }
- unsigned n = mWcStats.n();
- // mCpuUsage.elapsed() is expensive, so don't call it every loop
- if ((n & 127) == 1) {
- long long elapsed = mCpuUsage.elapsed();
- if (elapsed >= DEBUG_CPU_USAGE * 1000000000LL) {
- double perLoop = elapsed / (double) n;
- double perLoop100 = perLoop * 0.01;
- double perLoop1k = perLoop * 0.001;
- double mean = mWcStats.mean();
- double stddev = mWcStats.stddev();
- double minimum = mWcStats.minimum();
- double maximum = mWcStats.maximum();
- double meanCycles = mHzStats.mean();
- double stddevCycles = mHzStats.stddev();
- double minCycles = mHzStats.minimum();
- double maxCycles = mHzStats.maximum();
- mCpuUsage.resetElapsed();
- mWcStats.reset();
- mHzStats.reset();
- ALOGD("CPU usage for %s over past %.1f secs\n"
- " (%u mixer loops at %.1f mean ms per loop):\n"
- " us per mix loop: mean=%.0f stddev=%.0f min=%.0f max=%.0f\n"
- " %% of wall: mean=%.1f stddev=%.1f min=%.1f max=%.1f\n"
- " MHz: mean=%.1f, stddev=%.1f, min=%.1f max=%.1f",
- title.string(),
- elapsed * .000000001, n, perLoop * .000001,
- mean * .001,
- stddev * .001,
- minimum * .001,
- maximum * .001,
- mean / perLoop100,
- stddev / perLoop100,
- minimum / perLoop100,
- maximum / perLoop100,
- meanCycles / perLoop1k,
- stddevCycles / perLoop1k,
- minCycles / perLoop1k,
- maxCycles / perLoop1k);
- }
- }
- #endif
- };
- // ----------------------------------------------------------------------------
- // ThreadBase
- // ----------------------------------------------------------------------------
- AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- audio_devices_t outDevice, audio_devices_t inDevice, type_t type)
- : Thread(false /*canCallJava*/),
- mType(type),
- mAudioFlinger(audioFlinger),
- // mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, mFormat, mBufferSize
- // are set by PlaybackThread::readOutputParameters_l() or
- // RecordThread::readInputParameters_l()
- //FIXME: mStandby should be true here. Is this some kind of hack?
- mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
- mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
- // mName will be set by concrete (non-virtual) subclass
- mDeathRecipient(new PMDeathRecipient(this))
- {
- }
- AudioFlinger::ThreadBase::~ThreadBase()
- {
- // mConfigEvents should be empty, but just in case it isn't, free the memory it owns
- mConfigEvents.clear();
- // do not lock the mutex in destructor
- releaseWakeLock_l();
- if (mPowerManager != 0) {
- sp<IBinder> binder = mPowerManager->asBinder();
- binder->unlinkToDeath(mDeathRecipient);
- }
- }
- status_t AudioFlinger::ThreadBase::readyToRun()
- {
- status_t status = initCheck();
- if (status == NO_ERROR) {
- ALOGI("AudioFlinger's thread %p ready to run", this);
- } else {
- ALOGE("No working audio driver found.");
- }
- return status;
- }
- void AudioFlinger::ThreadBase::exit()
- {
- ALOGV("ThreadBase::exit");
- // do any cleanup required for exit to succeed
- preExit();
- {
- // This lock prevents the following race in thread (uniprocessor for illustration):
- // if (!exitPending()) {
- // // context switch from here to exit()
- // // exit() calls requestExit(), what exitPending() observes
- // // exit() calls signal(), which is dropped since no waiters
- // // context switch back from exit() to here
- // mWaitWorkCV.wait(...);
- // // now thread is hung
- // }
- AutoMutex lock(mLock);
- requestExit();
- mWaitWorkCV.broadcast();
- }
- // When Thread::requestExitAndWait is made virtual and this method is renamed to
- // "virtual status_t requestExitAndWait()", replace by "return Thread::requestExitAndWait();"
- requestExitAndWait();
- }
- status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs)
- {
- status_t status;
- ALOGV("ThreadBase::setParameters() %s", keyValuePairs.string());
- Mutex::Autolock _l(mLock);
- return sendSetParameterConfigEvent_l(keyValuePairs);
- }
- // sendConfigEvent_l() must be called with ThreadBase::mLock held
- // Can temporarily release the lock if waiting for a reply from processConfigEvents_l().
- status_t AudioFlinger::ThreadBase::sendConfigEvent_l(sp<ConfigEvent>& event)
- {
- status_t status = NO_ERROR;
- mConfigEvents.add(event);
- ALOGV("sendConfigEvent_l() num events %d event %d", mConfigEvents.size(), event->mType);
- mWaitWorkCV.signal();
- mLock.unlock();
- {
- Mutex::Autolock _l(event->mLock);
- while (event->mWaitStatus) {
- if (event->mCond.waitRelative(event->mLock, kConfigEventTimeoutNs) != NO_ERROR) {
- event->mStatus = TIMED_OUT;
- event->mWaitStatus = false;
- }
- }
- status = event->mStatus;
- }
- mLock.lock();
- return status;
- }
- void AudioFlinger::ThreadBase::sendIoConfigEvent(int event, int param)
- {
- Mutex::Autolock _l(mLock);
- sendIoConfigEvent_l(event, param);
- }
- // sendIoConfigEvent_l() must be called with ThreadBase::mLock held
- void AudioFlinger::ThreadBase::sendIoConfigEvent_l(int event, int param)
- {
- sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event, param);
- sendConfigEvent_l(configEvent);
- }
- // sendPrioConfigEvent_l() must be called with ThreadBase::mLock held
- void AudioFlinger::ThreadBase::sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio)
- {
- sp<ConfigEvent> configEvent = (ConfigEvent *)new PrioConfigEvent(pid, tid, prio);
- sendConfigEvent_l(configEvent);
- }
- // sendSetParameterConfigEvent_l() must be called with ThreadBase::mLock held
- status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8& keyValuePair)
- {
- sp<ConfigEvent> configEvent = (ConfigEvent *)new SetParameterConfigEvent(keyValuePair);
- return sendConfigEvent_l(configEvent);
- }
- status_t AudioFlinger::ThreadBase::sendCreateAudioPatchConfigEvent(
- const struct audio_patch *patch,
- audio_patch_handle_t *handle)
- {
- Mutex::Autolock _l(mLock);
- sp<ConfigEvent> configEvent = (ConfigEvent *)new CreateAudioPatchConfigEvent(*patch, *handle);
- status_t status = sendConfigEvent_l(configEvent);
- if (status == NO_ERROR) {
- CreateAudioPatchConfigEventData *data =
- (CreateAudioPatchConfigEventData *)configEvent->mData.get();
- *handle = data->mHandle;
- }
- return status;
- }
- status_t AudioFlinger::ThreadBase::sendReleaseAudioPatchConfigEvent(
- const audio_patch_handle_t handle)
- {
- Mutex::Autolock _l(mLock);
- sp<ConfigEvent> configEvent = (ConfigEvent *)new ReleaseAudioPatchConfigEvent(handle);
- return sendConfigEvent_l(configEvent);
- }
- // post condition: mConfigEvents.isEmpty()
- void AudioFlinger::ThreadBase::processConfigEvents_l()
- {
- bool configChanged = false;
- while (!mConfigEvents.isEmpty()) {
- ALOGV("processConfigEvents_l() remaining events %d", mConfigEvents.size());
- sp<ConfigEvent> event = mConfigEvents[0];
- mConfigEvents.removeAt(0);
- switch (event->mType) {
- case CFG_EVENT_PRIO: {
- PrioConfigEventData *data = (PrioConfigEventData *)event->mData.get();
- // FIXME Need to understand why this has to be done asynchronously
- int err = requestPriority(data->mPid, data->mTid, data->mPrio,
- true /*asynchronous*/);
- if (err != 0) {
- ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
- data->mPrio, data->mPid, data->mTid, err);
- }
- } break;
- case CFG_EVENT_IO: {
- IoConfigEventData *data = (IoConfigEventData *)event->mData.get();
- audioConfigChanged(data->mEvent, data->mParam);
- } break;
- case CFG_EVENT_SET_PARAMETER: {
- SetParameterConfigEventData *data = (SetParameterConfigEventData *)event->mData.get();
- if (checkForNewParameter_l(data->mKeyValuePairs, event->mStatus)) {
- configChanged = true;
- }
- } break;
- case CFG_EVENT_CREATE_AUDIO_PATCH: {
- CreateAudioPatchConfigEventData *data =
- (CreateAudioPatchConfigEventData *)event->mData.get();
- event->mStatus = createAudioPatch_l(&data->mPatch, &data->mHandle);
- } break;
- case CFG_EVENT_RELEASE_AUDIO_PATCH: {
- ReleaseAudioPatchConfigEventData *data =
- (ReleaseAudioPatchConfigEventData *)event->mData.get();
- event->mStatus = releaseAudioPatch_l(data->mHandle);
- } break;
- default:
- ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType);
- break;
- }
- {
- Mutex::Autolock _l(event->mLock);
- if (event->mWaitStatus) {
- event->mWaitStatus = false;
- event->mCond.signal();
- }
- }
- ALOGV_IF(mConfigEvents.isEmpty(), "processConfigEvents_l() DONE thread %p", this);
- }
- if (configChanged) {
- cacheParameters_l();
- }
- }
- String8 channelMaskToString(audio_channel_mask_t mask, bool output) {
- String8 s;
- if (output) {
- if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT) s.append("front-left, ");
- if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT) s.append("front-right, ");
- if (mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) s.append("front-center, ");
- if (mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) s.append("low freq, ");
- if (mask & AUDIO_CHANNEL_OUT_BACK_LEFT) s.append("back-left, ");
- if (mask & AUDIO_CHANNEL_OUT_BACK_RIGHT) s.append("back-right, ");
- if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER) s.append("front-left-of-center, ");
- if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER) s.append("front-right-of-center, ");
- if (mask & AUDIO_CHANNEL_OUT_BACK_CENTER) s.append("back-center, ");
- if (mask & AUDIO_CHANNEL_OUT_SIDE_LEFT) s.append("side-left, ");
- if (mask & AUDIO_CHANNEL_OUT_SIDE_RIGHT) s.append("side-right, ");
- if (mask & AUDIO_CHANNEL_OUT_TOP_CENTER) s.append("top-center ,");
- if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT) s.append("top-front-left, ");
- if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER) s.append("top-front-center, ");
- if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT) s.append("top-front-right, ");
- if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_LEFT) s.append("top-back-left, ");
- if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_CENTER) s.append("top-back-center, " );
- if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT) s.append("top-back-right, " );
- if (mask & ~AUDIO_CHANNEL_OUT_ALL) s.append("unknown, ");
- } else {
- if (mask & AUDIO_CHANNEL_IN_LEFT) s.append("left, ");
- if (mask & AUDIO_CHANNEL_IN_RIGHT) s.append("right, ");
- if (mask & AUDIO_CHANNEL_IN_FRONT) s.append("front, ");
- if (mask & AUDIO_CHANNEL_IN_BACK) s.append("back, ");
- if (mask & AUDIO_CHANNEL_IN_LEFT_PROCESSED) s.append("left-processed, ");
- if (mask & AUDIO_CHANNEL_IN_RIGHT_PROCESSED) s.append("right-processed, ");
- if (mask & AUDIO_CHANNEL_IN_FRONT_PROCESSED) s.append("front-processed, ");
- if (mask & AUDIO_CHANNEL_IN_BACK_PROCESSED) s.append("back-processed, ");
- if (mask & AUDIO_CHANNEL_IN_PRESSURE) s.append("pressure, ");
- if (mask & AUDIO_CHANNEL_IN_X_AXIS) s.append("X, ");
- if (mask & AUDIO_CHANNEL_IN_Y_AXIS) s.append("Y, ");
- if (mask & AUDIO_CHANNEL_IN_Z_AXIS) s.append("Z, ");
- if (mask & AUDIO_CHANNEL_IN_VOICE_UPLINK) s.append("voice-uplink, ");
- if (mask & AUDIO_CHANNEL_IN_VOICE_DNLINK) s.append("voice-dnlink, ");
- if (mask & ~AUDIO_CHANNEL_IN_ALL) s.append("unknown, ");
- }
- int len = s.length();
- if (s.length() > 2) {
- char *str = s.lockBuffer(len);
- s.unlockBuffer(len - 2);
- }
- return s;
- }
- void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __unused)
- {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- bool locked = AudioFlinger::dumpTryLock(mLock);
- if (!locked) {
- dprintf(fd, "thread %p maybe dead locked\n", this);
- }
- dprintf(fd, " I/O handle: %d\n", mId);
- dprintf(fd, " TID: %d\n", getTid());
- dprintf(fd, " Standby: %s\n", mStandby ? "yes" : "no");
- dprintf(fd, " Sample rate: %u\n", mSampleRate);
- dprintf(fd, " HAL frame count: %zu\n", mFrameCount);
- dprintf(fd, " HAL buffer size: %u bytes\n", mBufferSize);
- dprintf(fd, " Channel Count: %u\n", mChannelCount);
- dprintf(fd, " Channel Mask: 0x%08x (%s)\n", mChannelMask,
- channelMaskToString(mChannelMask, mType != RECORD).string());
- dprintf(fd, " Format: 0x%x (%s)\n", mHALFormat, formatToString(mHALFormat));
- dprintf(fd, " Frame size: %zu\n", mFrameSize);
- dprintf(fd, " Pending config events:");
- size_t numConfig = mConfigEvents.size();
- if (numConfig) {
- for (size_t i = 0; i < numConfig; i++) {
- mConfigEvents[i]->dump(buffer, SIZE);
- dprintf(fd, "\n %s", buffer);
- }
- dprintf(fd, "\n");
- } else {
- dprintf(fd, " none\n");
- }
- if (locked) {
- mLock.unlock();
- }
- }
- void AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>& args)
- {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- size_t numEffectChains = mEffectChains.size();
- snprintf(buffer, SIZE, " %zu Effect Chains\n", numEffectChains);
- write(fd, buffer, strlen(buffer));
- for (size_t i = 0; i < numEffectChains; ++i) {
- sp<EffectChain> chain = mEffectChains[i];
- if (chain != 0) {
- chain->dump(fd, args);
- }
- }
- }
- void AudioFlinger::ThreadBase::acquireWakeLock(int uid)
- {
- Mutex::Autolock _l(mLock);
- acquireWakeLock_l(uid);
- }
- String16 AudioFlinger::ThreadBase::getWakeLockTag()
- {
- switch (mType) {
- case MIXER:
- return String16("AudioMix");
- case DIRECT:
- return String16("AudioDirectOut");
- case DUPLICATING:
- return String16("AudioDup");
- case RECORD:
- return String16("AudioIn");
- case OFFLOAD:
- return String16("AudioOffload");
- default:
- ALOG_ASSERT(false);
- return String16("AudioUnknown");
- }
- }
- void AudioFlinger::ThreadBase::acquireWakeLock_l(int uid)
- {
- getPowerManager_l();
- if (mPowerManager != 0) {
- sp<IBinder> binder = new BBinder();
- status_t status;
- if (uid >= 0) {
- status = mPowerManager->acquireWakeLockWithUid(POWERMANAGER_PARTIAL_WAKE_LOCK,
- binder,
- getWakeLockTag(),
- String16("media"),
- uid,
- true /* FIXME force oneway contrary to .aidl */);
- } else {
- status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
- binder,
- getWakeLockTag(),
- String16("media"),
- true /* FIXME force oneway contrary to .aidl */);
- }
- if (status == NO_ERROR) {
- mWakeLockToken = binder;
- }
- ALOGV("acquireWakeLock_l() %s status %d", mName, status);
- }
- }
- void AudioFlinger::ThreadBase::releaseWakeLock()
- {
- Mutex::Autolock _l(mLock);
- releaseWakeLock_l();
- }
- void AudioFlinger::ThreadBase::releaseWakeLock_l()
- {
- if (mWakeLockToken != 0) {
- ALOGV("releaseWakeLock_l() %s", mName);
- if (mPowerManager != 0) {
- mPowerManager->releaseWakeLock(mWakeLockToken, 0,
- true /* FIXME force oneway contrary to .aidl */);
- }
- mWakeLockToken.clear();
- }
- }
- void AudioFlinger::ThreadBase::updateWakeLockUids(const SortedVector<int> &uids) {
- Mutex::Autolock _l(mLock);
- updateWakeLockUids_l(uids);
- }
- void AudioFlinger::ThreadBase::getPowerManager_l() {
- if (mPowerManager == 0) {
- // use checkService() to avoid blocking if power service is not up yet
- sp<IBinder> binder =
- defaultServiceManager()->checkService(String16("power"));
- if (binder == 0) {
- ALOGW("Thread %s cannot connect to the power manager service", mName);
- } else {
- mPowerManager = interface_cast<IPowerManager>(binder);
- binder->linkToDeath(mDeathRecipient);
- }
- }
- }
- void AudioFlinger::ThreadBase::updateWakeLockUids_l(const SortedVector<int> &uids) {
- getPowerManager_l();
- if (mWakeLockToken == NULL) {
- ALOGE("no wake lock to update!");
- return;
- }
- if (mPowerManager != 0) {
- sp<IBinder> binder = new BBinder();
- status_t status;
- status = mPowerManager->updateWakeLockUids(mWakeLockToken, uids.size(), uids.array(),
- true /* FIXME force oneway contrary to .aidl */);
- ALOGV("acquireWakeLock_l() %s status %d", mName, status);
- }
- }
- void AudioFlinger::ThreadBase::clearPowerManager()
- {
- Mutex::Autolock _l(mLock);
- releaseWakeLock_l();
- mPowerManager.clear();
- }
- void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& who __unused)
- {
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- thread->clearPowerManager();
- }
- ALOGW("power manager service died !!!");
- }
- void AudioFlinger::ThreadBase::setEffectSuspended(
- const effect_uuid_t *type, bool suspend, int sessionId)
- {
- Mutex::Autolock _l(mLock);
- setEffectSuspended_l(type, suspend, sessionId);
- }
- void AudioFlinger::ThreadBase::setEffectSuspended_l(
- const effect_uuid_t *type, bool suspend, int sessionId)
- {
- sp<EffectChain> chain = getEffectChain_l(sessionId);
- if (chain != 0) {
- if (type != NULL) {
- chain->setEffectSuspended_l(type, suspend);
- } else {
- chain->setEffectSuspendedAll_l(suspend);
- }
- }
- updateSuspendedSessions_l(type, suspend, sessionId);
- }
- void AudioFlinger::ThreadBase::checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain)
- {
- ssize_t index = mSuspendedSessions.indexOfKey(chain->sessionId());
- if (index < 0) {
- return;
- }
- const KeyedVector <int, sp<SuspendedSessionDesc> >& sessionEffects =
- mSuspendedSessions.valueAt(index);
- for (size_t i = 0; i < sessionEffects.size(); i++) {
- sp<SuspendedSessionDesc> desc = sessionEffects.valueAt(i);
- for (int j = 0; j < desc->mRefCount; j++) {
- if (sessionEffects.keyAt(i) == EffectChain::kKeyForSuspendAll) {
- chain->setEffectSuspendedAll_l(true);
- } else {
- ALOGV("checkSuspendOnAddEffectChain_l() suspending effects %08x",
- desc->mType.timeLow);
- chain->setEffectSuspended_l(&desc->mType, true);
- }
- }
- }
- }
- void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *type,
- bool suspend,
- int sessionId)
- {
- ssize_t index = mSuspendedSessions.indexOfKey(sessionId);
- KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects;
- if (suspend) {
- if (index >= 0) {
- sessionEffects = mSuspendedSessions.valueAt(index);
- } else {
- mSuspendedSessions.add(sessionId, sessionEffects);
- }
- } else {
- if (index < 0) {
- return;
- }
- sessionEffects = mSuspendedSessions.valueAt(index);
- }
- int key = EffectChain::kKeyForSuspendAll;
- if (type != NULL) {
- key = type->timeLow;
- }
- index = sessionEffects.indexOfKey(key);
- sp<SuspendedSessionDesc> desc;
- if (suspend) {
- if (index >= 0) {
- desc = sessionEffects.valueAt(index);
- } else {
- desc = new SuspendedSessionDesc();
- if (type != NULL) {
- desc->mType = *type;
- }
- sessionEffects.add(key, desc);
- ALOGV("updateSuspendedSessions_l() suspend adding effect %08x", key);
- }
- desc->mRefCount++;
- } else {
- if (index < 0) {
- return;
- }
- desc = sessionEffects.valueAt(index);
- if (--desc->mRefCount == 0) {
- ALOGV("updateSuspendedSessions_l() restore removing effect %08x", key);
- sessionEffects.removeItemsAt(index);
- if (sessionEffects.isEmpty()) {
- ALOGV("updateSuspendedSessions_l() restore removing session %d",
- sessionId);
- mSuspendedSessions.removeItem(sessionId);
- }
- }
- }
- if (!sessionEffects.isEmpty()) {
- mSuspendedSessions.replaceValueFor(sessionId, sessionEffects);
- }
- }
- void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
- bool enabled,
- int sessionId)
- {
- Mutex::Autolock _l(mLock);
- checkSuspendOnEffectEnabled_l(effect, enabled, sessionId);
- }
- void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModule>& effect,
- bool enabled,
- int sessionId)
- {
- if (mType != RECORD) {
- // suspend all effects in AUDIO_SESSION_OUTPUT_MIX when enabling any effect on
- // another session. This gives the priority to well behaved effect control panels
- // and applications not using global effects.
- // Enabling post processing in AUDIO_SESSION_OUTPUT_STAGE session does not affect
- // global effects
- if ((sessionId != AUDIO_SESSION_OUTPUT_MIX) && (sessionId != AUDIO_SESSION_OUTPUT_STAGE)) {
- setEffectSuspended_l(NULL, enabled, AUDIO_SESSION_OUTPUT_MIX);
- }
- }
- sp<EffectChain> chain = getEffectChain_l(sessionId);
- if (chain != 0) {
- chain->checkSuspendOnEffectEnabled(effect, enabled);
- }
- }
- // ThreadBase::createEffect_l() must be called with AudioFlinger::mLock held
- sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
- const sp<AudioFlinger::Client>& client,
- const sp<IEffectClient>& effectClient,
- int32_t priority,
- int sessionId,
- effect_descriptor_t *desc,
- int *enabled,
- status_t *status)
- {
- sp<EffectModule> effect;
- sp<EffectHandle> handle;
- status_t lStatus;
- sp<EffectChain> chain;
- bool chainCreated = false;
- bool effectCreated = false;
- bool effectRegistered = false;
- lStatus = initCheck();
- if (lStatus != NO_ERROR) {
- ALOGW("createEffect_l() Audio driver not initialized.");
- goto Exit;
- }
- // Reject any effect on Direct output threads for now, since the format of
- // mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo).
- if (mType == DIRECT) {
- ALOGW("createEffect_l() Cannot add effect %s on Direct output type thread %s",
- desc->name, mName);
- lStatus = BAD_VALUE;
- goto Exit;
- }
- // Reject any effect on mixer or duplicating multichannel sinks.
- // TODO: fix both format and multichannel issues with effects.
- if ((mType == MIXER || mType == DUPLICATING) && mChannelCount != FCC_2) {
- ALOGW("createEffect_l() Cannot add effect %s for multichannel(%d) %s threads",
- desc->name, mChannelCount, mType == MIXER ? "MIXER" : "DUPLICATING");
- lStatus = BAD_VALUE;
- goto Exit;
- }
- // Allow global effects only on offloaded and mixer threads
- if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
- switch (mType) {
- case MIXER:
- case OFFLOAD:
- break;
- case DIRECT:
- case DUPLICATING:
- case RECORD:
- default:
- ALOGW("createEffect_l() Cannot add global effect %s on thread %s", desc->name, mName);
- lStatus = BAD_VALUE;
- goto Exit;
- }
- }
- // Only Pre processor effects are allowed on input threads and only on input threads
- if ((mType == RECORD) != ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) {
- ALOGW("createEffect_l() effect %s (flags %08x) created on wrong thread type %d",
- desc->name, desc->flags, mType);
- lStatus = BAD_VALUE;
- goto Exit;
- }
- ALOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId);
- { // scope for mLock
- Mutex::Autolock _l(mLock);
- // check for existing effect chain with the requested audio session
- chain = getEffectChain_l(sessionId);
- if (chain == 0) {
- // create a new chain for this session
- ALOGV("createEffect_l() new effect chain for session %d", sessionId);
- chain = new EffectChain(this, sessionId);
- addEffectChain_l(chain);
- chain->setStrategy(getStrategyForSession_l(sessionId));
- chainCreated = true;
- } else {
- effect = chain->getEffectFromDesc_l(desc);
- }
- ALOGV("createEffect_l() got effect %p on chain %p", effect.get(), chain.get());
- if (effect == 0) {
- int id = mAudioFlinger->nextUniqueId();
- // Check CPU and memory usage
- lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id);
- if (lStatus != NO_ERROR) {
- goto Exit;
- }
- effectRegistered = true;
- // create a new effect module if none present in the chain
- effect = new EffectModule(this, chain, desc, id, sessionId);
- lStatus = effect->status();
- if (lStatus != NO_ERROR) {
- goto Exit;
- }
- effect->setOffloaded(mType == OFFLOAD, mId);
- lStatus = chain->addEffect_l(effect);
- if (lStatus != NO_ERROR) {
- goto Exit;
- }
- effectCreated = true;
- effect->setDevice(mOutDevice);
- effect->setDevice(mInDevice);
- effect->setMode(mAudioFlinger->getMode());
- effect->setAudioSource(mAudioSource);
- }
- // create effect handle and connect it to effect module
- handle = new EffectHandle(effect, client, effectClient, priority);
- lStatus = handle->initCheck();
- if (lStatus == OK) {
- lStatus = effect->addHandle(handle.get());
- }
- if (enabled != NULL) {
- *enabled = (int)effect->isEnabled();
- }
- }
- Exit:
- if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
- Mutex::Autolock _l(mLock);
- if (effectCreated) {
- chain->removeEffect_l(effect);
- }
- if (effectRegistered) {
- AudioSystem::unregisterEffect(effect->id());
- }
- if (chainCreated) {
- removeEffectChain_l(chain);
- }
- handle.clear();
- }
- *status = lStatus;
- return handle;
- }
- sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect(int sessionId, int effectId)
- {
- Mutex::Autolock _l(mLock);
- return getEffect_l(sessionId, effectId);
- }
- sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect_l(int sessionId, int effectId)
- {
- sp<EffectChain> chain = getEffectChain_l(sessionId);
- return chain != 0 ? chain->getEffectFromId_l(effectId) : 0;
- }
- // PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and
- // PlaybackThread::mLock held
- status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect)
- {
- // check for existing effect chain with the requested audio session
- int sessionId = effect->sessionId();
- sp<EffectChain> chain = getEffectChain_l(sessionId);
- bool chainCreated = false;
- ALOGD_IF((mType == OFFLOAD) && !effect->isOffloadable(),
- "addEffect_l() on offloaded thread %p: effect %s does not support offload flags %x",
- this, effect->desc().name, effect->desc().flags);
- if (chain == 0) {
- // create a new chain for this session
- ALOGV("addEffect_l() new effect chain for session %d", sessionId);
- chain = new EffectChain(this, sessionId);
- addEffectChain_l(chain);
- chain->setStrategy(getStrategyForSession_l(sessionId));
- chainCreated = true;
- }
- ALOGV("addEffect_l() %p chain %p effect %p", this, chain.get(), effect.get());
- if (chain->getEffectFromId_l(effect->id()) != 0) {
- ALOGW("addEffect_l() %p effect %s already present in chain %p",
- this, effect->desc().name, chain.get());
- return BAD_VALUE;
- }
- effect->setOffloaded(mType == OFFLOAD, mId);
- status_t status = chain->addEffect_l(effect);
- if (status != NO_ERROR) {
- if (chainCreated) {
- removeEffectChain_l(chain);
- }
- return status;
- }
- effect->setDevice(mOutDevice);
- effect->setDevice(mInDevice);
- effect->setMode(mAudioFlinger->getMode());
- effect->setAudioSource(mAudioSource);
- return NO_ERROR;
- }
- void AudioFlinger::ThreadBase::removeEffect_l(const sp<EffectModule>& effect) {
- ALOGV("removeEffect_l() %p effect %p", this, effect.get());
- effect_descriptor_t desc = effect->desc();
- if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
- detachAuxEffect_l(effect->id());
- }
- sp<EffectChain> chain = effect->chain().promote();
- if (chain != 0) {
- // remove effect chain if removing last effect
- if (chain->removeEffect_l(effect) == 0) {
- removeEffectChain_l(chain);
- }
- } else {
- ALOGW("removeEffect_l() %p cannot promote chain for effect %p", this, effect.get());
- }
- }
- void AudioFlinger::ThreadBase::lockEffectChains_l(
- Vector< sp<AudioFlinger::EffectChain> >& effectChains)
- {
- effectChains = mEffectChains;
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->lock();
- }
- }
- void AudioFlinger::ThreadBase::unlockEffectChains(
- const Vector< sp<AudioFlinger::EffectChain> >& effectChains)
- {
- for (size_t i = 0; i < effectChains.size(); i++) {
- effectChains[i]->unlock();
- }
- }
- sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain(int sessionId)
- {
- Mutex::Autolock _l(mLock);
- return getEffectChain_l(sessionId);
- }
- sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain_l(int sessionId) const
- {
- size_t size = mEffectChains.size();
- for (size_t i = 0; i < size; i++) {
- if (mEffectChains[i]->sessionId() == sessionId) {
- return mEffectChains[i];
- }
- }
- return 0;
- }
- void AudioFlinger::ThreadBase::setMode(audio_mode_t mode)
- {
- Mutex::Autolock _l(mLock);
- size_t size = mEffectChains.size();
- for (size_t i = 0; i < size; i++) {
- mEffectChains[i]->setMode_l(mode);
- }
- }
- void AudioFlinger::ThreadBase::getAudioPortConfig(struct audio_port_config *config)
- {
- config->type = AUDIO_PORT_TYPE_MIX;
- config->ext.mix.handle = mId;
- config->sample_rate = mSampleRate;
- config->format = mFormat;
- config->channel_mask = mChannelMask;
- config->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
- AUDIO_PORT_CONFIG_FORMAT;
- }
- // ----------------------------------------------------------------------------
- // Playback
- // ----------------------------------------------------------------------------
- AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
- AudioStreamOut* output,
- audio_io_handle_t id,
- audio_devices_t device,
- type_t type)
- : ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type),
- mNormalFrameCount(0), mSinkBuffer(NULL),
- mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
- mMixerBuffer(NULL),
- mMixerBufferSize(0),
- mMixerBufferFormat(AUDIO_FORMAT_INVALID),
- mMixerBufferValid(false),
- mEffectBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
- mEffectBuffer(NULL),
- mEffectBufferSize(0),
- mEffectBufferFormat(AUDIO_FORMAT_INVALID),
- mEffectBufferValid(false),
- mSuspended(0), mBytesWritten(0),
- mActiveTracksGeneration(0),
- // mStreamTypes[] initialized in constructor body
- mOutput(output),
- mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
- mMixerStatus(MIXER_IDLE),
- mMixerStatusIgnoringFastTracks(MIXER_IDLE),
- standbyDelay(AudioFlinger::mStandbyTimeInNsecs),
- mBytesRemaining(0),
- mCurrentWriteLength(0),
- mUseAsyncWrite(false),
- mWriteAckSequence(0),
- mDrainSequence(0),
- mSignalPending(false),
- mScreenState(AudioFlinger::mScreenState),
- // index 0 is reserved for normal mixer's submix
- mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1),
- mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
- // mLatchD, mLatchQ,
- mLatchDValid(false), mLatchQValid(false)
- {
- snprintf(mName, kNameLength, "AudioOut_%X", id);
- mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);
- // Assumes constructor is called by AudioFlinger with it's mLock held, but
- // it would be safer to explicitly pass initial masterVolume/masterMute as
- // parameter.
- //
- // If the HAL we are using has support for master volume or master mute,
- // then do not attenuate or mute during mixing (just leave the volume at 1.0
- // and the mute set to false).
- mMasterVolume = audioFlinger->masterVolume_l();
- mMasterMute = audioFlinger->masterMute_l();
- if (mOutput && mOutput->audioHwDev) {
- if (mOutput->audioHwDev->canSetMasterVolume()) {
- mMasterVolume = 1.0;
- }
- if (mOutput->audioHwDev->canSetMasterMute()) {
- mMasterMute = false;
- }
- }
- readOutputParameters_l();
- // ++ operator does not compile
- for (audio_stream_type_t stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_CNT;
- stream = (audio_stream_type_t) (stream + 1)) {
- mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream);
- mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream);
- }
- }
- AudioFlinger::PlaybackThread::~PlaybackThread()
- {
- mAudioFlinger->unregisterWriter(mNBLogWriter);
- free(mSinkBuffer);
- free(mMixerBuffer);
- free(mEffectBuffer);
- }
- void AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
- {
- dumpInternals(fd, args);
- dumpTracks(fd, args);
- dumpEffectChains(fd, args);
- }
- void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args __unused)
- {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- result.appendFormat(" Stream volumes in dB: ");
- for (int i = 0; i < AUDIO_STREAM_CNT; ++i) {
- const stream_type_t *st = &mStreamTypes[i];
- if (i > 0) {
- result.appendFormat(", ");
- }
- result.appendFormat("%d:%.2g", i, 20.0 * log10(st->volume));
- if (st->mute) {
- result.append("M");
- }
- }
- result.append("\n");
- write(fd, result.string(), result.length());
- result.clear();
- // These values are "raw"; they will wrap around. See prepareTracks_l() for a better way.
- FastTrackUnderruns underruns = getFastTrackUnderruns(0);
- dprintf(fd, " Normal mixer raw underrun counters: partial=%u empty=%u\n",
- underruns.mBitFields.mPartial, underruns.mBitFields.mEmpty);
- size_t numtracks = mTracks.size();
- size_t numactive = mActiveTracks.size();
- dprintf(fd, " %d Tracks", numtracks);
- size_t numactiveseen = 0;
- if (numtracks) {
- dprintf(fd, " of which %d are active\n", numactive);
- Track::appendDumpHeader(result);
- for (size_t i = 0; i < numtracks; ++i) {
- sp<Track> track = mTracks[i];
- if (track != 0) {
- bool active = mActiveTracks.indexOf(track) >= 0;
- if (active) {
- numactiveseen++;
- }
- track->dump(buffer, SIZE, active);
- result.append(buffer);
- }
- }
- } else {
- result.append("\n");
- }
- if (numactiveseen != numactive) {
- // some tracks in the active list were not in the tracks list
- snprintf(buffer, SIZE, " The following tracks are in the active list but"
- " not in the track list\n");
- result.append(buffer);
- Track::appendDumpHeader(result);
- for (size_t i = 0; i < numactive; ++i) {
- sp<Track> track = mActiveTracks[i].promote();
- if (track != 0 && mTracks.indexOf(track) < 0) {
- track->dump(buffer, SIZE, true);
- result.append(buffer);
- }
- }
- }
- write(fd, result.string(), result.size());
- }
- void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
- {
- dprintf(fd, "\nOutput thread %p:\n", this);
- dprintf(fd, " Normal frame count: %zu\n", mNormalFrameCount);
- dprintf(fd, " Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
- dprintf(fd, " Total writes: %d\n", mNumWrites);
- dprintf(fd, " Delayed writes: %d\n", mNumDelayedWrites);
- dprintf(fd, " Blocked in write: %s\n", mInWrite ? "yes" : "no");
- dprintf(fd, " Suspend count: %d\n", mSuspended);
- dprintf(fd, " Sink buffer : %p\n", mSinkBuffer);
- dprintf(fd, " Mixer buffer: %p\n", mMixerBuffer);
- dprintf(fd, " Effect buffer: %p\n", mEffectBuffer);
- dprintf(fd, " Fast track availMask=%#x\n", mFastTrackAvailMask);
- dumpBase(fd, args);
- }
- // Thread virtuals
- void AudioFlinger::PlaybackThread::onFirstRef()
- {
- run(mName, ANDROID_PRIORITY_URGENT_AUDIO);
- }
- // ThreadBase virtuals
- void AudioFlinger::PlaybackThread::preExit()
- {
- ALOGV(" preExit()");
- // FIXME this is using hard-coded strings but in the future, this functionality will be
- // converted to use audio HAL extensions required to support tunneling
- mOutput->stream->common.set_parameters(&mOutput->stream->common, "exiting=1");
- }
- // PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held
- sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
- const sp<AudioFlinger::Client>& client,
- audio_stream_type_t streamType,
- uint32_t sampleRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- size_t *pFrameCount,
- const sp<IMemory>& sharedBuffer,
- int sessionId,
- IAudioFlinger::track_flags_t *flags,
- pid_t tid,
- int uid,
- status_t *status)
- {
- size_t frameCount = *pFrameCount;
- sp<Track> track;
- status_t lStatus;
- bool isTimed = (*flags & IAudioFlinger::TRACK_TIMED) != …
Large files files are truncated, but you can click here to view the full file