summaryrefslogtreecommitdiffstats
path: root/services/audioflinger
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2014-05-09 23:18:47 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-05-09 23:18:48 +0000
commit26d5ff926fa3323b39ae4408bcd29826a9523c9b (patch)
tree6abb6b28dfeffa2f5c602d350021dd8b4e6bd460 /services/audioflinger
parent16821ec9e1619f4edcc87f21ea1537580109b14d (diff)
parent1035194cee4fbd57e35ea15c56e66cd09b63d56e (diff)
downloadframeworks_av-26d5ff926fa3323b39ae4408bcd29826a9523c9b.zip
frameworks_av-26d5ff926fa3323b39ae4408bcd29826a9523c9b.tar.gz
frameworks_av-26d5ff926fa3323b39ae4408bcd29826a9523c9b.tar.bz2
Merge "audioflinger: refactor thread config events"
Diffstat (limited to 'services/audioflinger')
-rw-r--r--services/audioflinger/AudioFlinger.cpp23
-rw-r--r--services/audioflinger/AudioFlinger.h9
-rw-r--r--services/audioflinger/Threads.cpp617
-rw-r--r--services/audioflinger/Threads.h171
4 files changed, 436 insertions, 384 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index c1c95f8..e256f32 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1195,12 +1195,17 @@ void AudioFlinger::removeNotificationClient(pid_t pid)
}
// audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::audioConfigChanged_l(int event, audio_io_handle_t ioHandle, const void *param2)
+void AudioFlinger::audioConfigChanged_l(
+ const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+ int event,
+ audio_io_handle_t ioHandle,
+ const void *param2)
{
- size_t size = mNotificationClients.size();
+ size_t size = notificationClients.size();
for (size_t i = 0; i < size; i++) {
- mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioHandle,
- param2);
+ notificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event,
+ ioHandle,
+ param2);
}
}
@@ -1633,7 +1638,7 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
}
// notify client processes of the new output creation
- thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
+ thread->audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_OPENED);
// the first primary output opened designates the primary hw device
if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
@@ -1669,7 +1674,7 @@ audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1,
thread->addOutputTrack(thread2);
mPlaybackThreads.add(id, thread);
// notify client processes of the new output creation
- thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
+ thread->audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_OPENED);
return id;
}
@@ -1719,7 +1724,7 @@ status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output)
}
}
}
- audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, NULL);
+ audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_CLOSED, output, NULL);
}
thread->exit();
// The thread entity (active unit of execution) is no longer running here,
@@ -1899,7 +1904,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
}
// notify client processes of the new input creation
- thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED);
+ thread->audioConfigChanged_l(mNotificationClients, AudioSystem::INPUT_OPENED);
return id;
}
@@ -1924,7 +1929,7 @@ status_t AudioFlinger::closeInput_nonvirtual(audio_io_handle_t input)
}
ALOGV("closeInput() %d", input);
- audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, NULL);
+ audioConfigChanged_l(mNotificationClients, AudioSystem::INPUT_CLOSED, input, NULL);
mRecordThreads.removeItem(input);
}
thread->exit();
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 462f9e2..e0965b8 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -454,7 +454,11 @@ private:
// no range check, doesn't check per-thread stream volume, AudioFlinger::mLock held
float streamVolume_l(audio_stream_type_t stream) const
{ return mStreamTypes[stream].volume; }
- void audioConfigChanged_l(int event, audio_io_handle_t ioHandle, const void *param2);
+ void audioConfigChanged_l(const DefaultKeyedVector< pid_t,sp<NotificationClient> >&
+ notificationClients,
+ int event,
+ audio_io_handle_t ioHandle,
+ const void *param2);
// Allocate an audio_io_handle_t, session ID, effect ID, or audio_module_handle_t.
// They all share the same ID space, but the namespaces are actually independent
@@ -479,7 +483,8 @@ private:
void removeClient_l(pid_t pid);
void removeNotificationClient(pid_t pid);
-
+ DefaultKeyedVector< pid_t,sp<NotificationClient> > notificationClients() {
+ Mutex::Autolock _l(mLock); return mNotificationClients; }
bool isNonOffloadableGlobalEffectEnabled_l();
void onNonOffloadableGlobalEffectEnable();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index be7d725..77236b9 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -97,8 +97,8 @@ 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 for setParameters to complete
-static const nsecs_t kSetParametersTimeoutNs = seconds(2);
+// 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;
@@ -283,7 +283,6 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio
// mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, mFormat, mBufferSize
// are set by PlaybackThread::readOutputParameters_l() or
// RecordThread::readInputParameters_l()
- mParamStatus(NO_ERROR),
//FIXME: mStandby should be true here. Is this some kind of hack?
mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
@@ -295,12 +294,8 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio
AudioFlinger::ThreadBase::~ThreadBase()
{
// mConfigEvents should be empty, but just in case it isn't, free the memory it owns
- for (size_t i = 0; i < mConfigEvents.size(); i++) {
- delete mConfigEvents[i];
- }
mConfigEvents.clear();
- mParamCond.broadcast();
// do not lock the mutex in destructor
releaseWakeLock_l();
if (mPowerManager != 0) {
@@ -351,16 +346,30 @@ status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs)
ALOGV("ThreadBase::setParameters() %s", keyValuePairs.string());
Mutex::Autolock _l(mLock);
- mNewParameters.add(keyValuePairs);
+ 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();
- // wait condition with timeout in case the thread loop has exited
- // before the request could be processed
- if (mParamCond.waitRelative(mLock, kSetParametersTimeoutNs) == NO_ERROR) {
- status = mParamStatus;
- mWaitWorkCV.signal();
- } else {
- status = TIMED_OUT;
+ 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;
}
@@ -373,63 +382,71 @@ void AudioFlinger::ThreadBase::sendIoConfigEvent(int event, int param)
// sendIoConfigEvent_l() must be called with ThreadBase::mLock held
void AudioFlinger::ThreadBase::sendIoConfigEvent_l(int event, int param)
{
- IoConfigEvent *ioEvent = new IoConfigEvent(event, param);
- mConfigEvents.add(static_cast<ConfigEvent *>(ioEvent));
- ALOGV("sendIoConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event,
- param);
- mWaitWorkCV.signal();
+ 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)
{
- PrioConfigEvent *prioEvent = new PrioConfigEvent(pid, tid, prio);
- mConfigEvents.add(static_cast<ConfigEvent *>(prioEvent));
- ALOGV("sendPrioConfigEvent_l() num events %d pid %d, tid %d prio %d",
- mConfigEvents.size(), pid, tid, prio);
- mWaitWorkCV.signal();
+ sp<ConfigEvent> configEvent = (ConfigEvent *)new PrioConfigEvent(pid, tid, prio);
+ sendConfigEvent_l(configEvent);
}
-void AudioFlinger::ThreadBase::processConfigEvents()
+// sendSetParameterConfigEvent_l() must be called with ThreadBase::mLock held
+status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8& keyValuePair)
{
- Mutex::Autolock _l(mLock);
- processConfigEvents_l();
+ sp<ConfigEvent> configEvent = (ConfigEvent *)new SetParameterConfigEvent(keyValuePair);
+ return sendConfigEvent_l(configEvent);
}
// post condition: mConfigEvents.isEmpty()
-void AudioFlinger::ThreadBase::processConfigEvents_l()
+void AudioFlinger::ThreadBase::processConfigEvents_l(
+ const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients)
{
+ bool configChanged = false;
+
while (!mConfigEvents.isEmpty()) {
- ALOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
- ConfigEvent *event = mConfigEvents[0];
+ ALOGV("processConfigEvents_l() remaining events %d", mConfigEvents.size());
+ sp<ConfigEvent> event = mConfigEvents[0];
mConfigEvents.removeAt(0);
- // release mLock before locking AudioFlinger mLock: lock order is always
- // AudioFlinger then ThreadBase to avoid cross deadlock
- mLock.unlock();
- switch (event->type()) {
+ switch (event->mType) {
case CFG_EVENT_PRIO: {
- PrioConfigEvent *prioEvent = static_cast<PrioConfigEvent *>(event);
- // FIXME Need to understand why this has be done asynchronously
- int err = requestPriority(prioEvent->pid(), prioEvent->tid(), prioEvent->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",
- prioEvent->prio(), prioEvent->pid(), prioEvent->tid(), err);
+ data->mPrio, data->mPid, data->mTid, err);
}
} break;
case CFG_EVENT_IO: {
- IoConfigEvent *ioEvent = static_cast<IoConfigEvent *>(event);
- {
- Mutex::Autolock _l(mAudioFlinger->mLock);
- audioConfigChanged_l(ioEvent->event(), ioEvent->param());
+ IoConfigEventData *data = (IoConfigEventData *)event->mData.get();
+ audioConfigChanged_l(notificationClients, 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;
default:
- ALOGE("processConfigEvents() unknown event type %d", event->type());
+ ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType);
break;
}
- delete event;
- mLock.lock();
+ {
+ 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();
}
}
@@ -502,18 +519,6 @@ void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __u
channelMaskToString(mChannelMask, mType != RECORD).string());
fdprintf(fd, " Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
fdprintf(fd, " Frame size: %zu\n", mFrameSize);
- fdprintf(fd, " Pending setParameters commands:");
- size_t numParams = mNewParameters.size();
- if (numParams) {
- fdprintf(fd, "\n Index Command");
- for (size_t i = 0; i < numParams; ++i) {
- fdprintf(fd, "\n %02zu ", i);
- fdprintf(fd, mNewParameters[i]);
- }
- fdprintf(fd, "\n");
- } else {
- fdprintf(fd, " none\n");
- }
fdprintf(fd, " Pending config events:");
size_t numConfig = mConfigEvents.size();
if (numConfig) {
@@ -1634,7 +1639,10 @@ String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)
}
// audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::PlaybackThread::audioConfigChanged_l(int event, int param) {
+void AudioFlinger::PlaybackThread::audioConfigChanged_l(
+ const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+ int event,
+ int param) {
AudioSystem::OutputDescriptor desc;
void *param2 = NULL;
@@ -1649,7 +1657,7 @@ void AudioFlinger::PlaybackThread::audioConfigChanged_l(int event, int param) {
desc.format = mFormat;
desc.frameCount = mNormalFrameCount; // FIXME see
// AudioFlinger::frameCount(audio_io_handle_t)
- desc.latency = latency();
+ desc.latency = latency_l();
param2 = &desc;
break;
@@ -1659,7 +1667,7 @@ void AudioFlinger::PlaybackThread::audioConfigChanged_l(int event, int param) {
default:
break;
}
- mAudioFlinger->audioConfigChanged_l(event, mId, param2);
+ mAudioFlinger->audioConfigChanged_l(notificationClients, event, mId, param2);
}
void AudioFlinger::PlaybackThread::writeCallback()
@@ -2309,12 +2317,16 @@ bool AudioFlinger::PlaybackThread::threadLoop()
Vector< sp<EffectChain> > effectChains;
- processConfigEvents();
+ DefaultKeyedVector< pid_t,sp<NotificationClient> > notificationClients =
+ mAudioFlinger->notificationClients();
{ // scope for mLock
Mutex::Autolock _l(mLock);
+ processConfigEvents_l(notificationClients);
+ notificationClients.clear();
+
if (logString != NULL) {
mNBLogWriter->logTimestamp();
mNBLogWriter->log(logString);
@@ -2327,10 +2339,6 @@ bool AudioFlinger::PlaybackThread::threadLoop()
mLatchQValid = true;
}
- if (checkForNewParameters_l()) {
- cacheParameters_l();
- }
-
saveOutputTracks();
if (mSignalPending) {
// A signal was raised while we were unlocked
@@ -3535,128 +3543,117 @@ void AudioFlinger::MixerThread::deleteTrackName_l(int name)
mAudioMixer->deleteTrackName(name);
}
-// checkForNewParameters_l() must be called with ThreadBase::mLock held
-bool AudioFlinger::MixerThread::checkForNewParameters_l()
+// checkForNewParameter_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePair,
+ status_t& status)
{
- // if !&IDLE, holds the FastMixer state to restore after new parameters processed
- FastMixerState::Command previousCommand = FastMixerState::HOT_IDLE;
bool reconfig = false;
- while (!mNewParameters.isEmpty()) {
+ status = NO_ERROR;
- if (mFastMixer != NULL) {
- FastMixerStateQueue *sq = mFastMixer->sq();
- FastMixerState *state = sq->begin();
- if (!(state->mCommand & FastMixerState::IDLE)) {
- previousCommand = state->mCommand;
- state->mCommand = FastMixerState::HOT_IDLE;
- sq->end();
- sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);
- } else {
- sq->end(false /*didModify*/);
- }
+ // if !&IDLE, holds the FastMixer state to restore after new parameters processed
+ FastMixerState::Command previousCommand = FastMixerState::HOT_IDLE;
+ if (mFastMixer != NULL) {
+ FastMixerStateQueue *sq = mFastMixer->sq();
+ FastMixerState *state = sq->begin();
+ if (!(state->mCommand & FastMixerState::IDLE)) {
+ previousCommand = state->mCommand;
+ state->mCommand = FastMixerState::HOT_IDLE;
+ sq->end();
+ sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);
+ } else {
+ sq->end(false /*didModify*/);
}
+ }
- status_t status = NO_ERROR;
- String8 keyValuePair = mNewParameters[0];
- AudioParameter param = AudioParameter(keyValuePair);
- int value;
-
- if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+ AudioParameter param = AudioParameter(keyValuePair);
+ int value;
+ if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
+ if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
+ status = BAD_VALUE;
+ } else {
+ // no need to save value, since it's constant
reconfig = true;
}
- if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
- if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
- status = BAD_VALUE;
- } else {
- // no need to save value, since it's constant
- reconfig = true;
- }
- }
- if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
- if ((audio_channel_mask_t) value != AUDIO_CHANNEL_OUT_STEREO) {
- status = BAD_VALUE;
- } else {
- // no need to save value, since it's constant
- reconfig = true;
- }
+ }
+ if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
+ if ((audio_channel_mask_t) value != AUDIO_CHANNEL_OUT_STEREO) {
+ status = BAD_VALUE;
+ } else {
+ // no need to save value, since it's constant
+ reconfig = true;
}
- if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
- // do not accept frame count changes if tracks are open as the track buffer
- // size depends on frame count and correct behavior would not be guaranteed
- // if frame count is changed after track creation
- if (!mTracks.isEmpty()) {
- status = INVALID_OPERATION;
- } else {
- reconfig = true;
- }
+ }
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be guaranteed
+ // if frame count is changed after track creation
+ if (!mTracks.isEmpty()) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
}
- if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+ }
+ if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
#ifdef ADD_BATTERY_DATA
- // when changing the audio output device, call addBatteryData to notify
- // the change
- if (mOutDevice != value) {
- uint32_t params = 0;
- // check whether speaker is on
- if (value & AUDIO_DEVICE_OUT_SPEAKER) {
- params |= IMediaPlayerService::kBatteryDataSpeakerOn;
- }
+ // when changing the audio output device, call addBatteryData to notify
+ // the change
+ if (mOutDevice != value) {
+ uint32_t params = 0;
+ // check whether speaker is on
+ if (value & AUDIO_DEVICE_OUT_SPEAKER) {
+ params |= IMediaPlayerService::kBatteryDataSpeakerOn;
+ }
- audio_devices_t deviceWithoutSpeaker
- = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
- // check if any other device (except speaker) is on
- if (value & deviceWithoutSpeaker ) {
- params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn;
- }
+ audio_devices_t deviceWithoutSpeaker
+ = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
+ // check if any other device (except speaker) is on
+ if (value & deviceWithoutSpeaker ) {
+ params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn;
+ }
- if (params != 0) {
- addBatteryData(params);
- }
+ if (params != 0) {
+ addBatteryData(params);
}
+ }
#endif
- // forward device change to effects that have requested to be
- // aware of attached audio device.
- if (value != AUDIO_DEVICE_NONE) {
- mOutDevice = value;
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setDevice_l(mOutDevice);
- }
+ // forward device change to effects that have requested to be
+ // aware of attached audio device.
+ if (value != AUDIO_DEVICE_NONE) {
+ mOutDevice = value;
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ mEffectChains[i]->setDevice_l(mOutDevice);
}
}
+ }
- if (status == NO_ERROR) {
+ if (status == NO_ERROR) {
+ status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
+ keyValuePair.string());
+ if (!mStandby && status == INVALID_OPERATION) {
+ mOutput->stream->common.standby(&mOutput->stream->common);
+ mStandby = true;
+ mBytesWritten = 0;
status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
- keyValuePair.string());
- if (!mStandby && status == INVALID_OPERATION) {
- mOutput->stream->common.standby(&mOutput->stream->common);
- mStandby = true;
- mBytesWritten = 0;
- status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
- keyValuePair.string());
- }
- if (status == NO_ERROR && reconfig) {
- readOutputParameters_l();
- delete mAudioMixer;
- mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
- for (size_t i = 0; i < mTracks.size() ; i++) {
- int name = getTrackName_l(mTracks[i]->mChannelMask, mTracks[i]->mSessionId);
- if (name < 0) {
- break;
- }
- mTracks[i]->mName = name;
+ keyValuePair.string());
+ }
+ if (status == NO_ERROR && reconfig) {
+ readOutputParameters_l();
+ delete mAudioMixer;
+ mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
+ for (size_t i = 0; i < mTracks.size() ; i++) {
+ int name = getTrackName_l(mTracks[i]->mChannelMask, mTracks[i]->mSessionId);
+ if (name < 0) {
+ break;
}
- sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
+ mTracks[i]->mName = name;
}
+ sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
}
-
- mNewParameters.removeAt(0);
-
- mParamStatus = status;
- mParamCond.signal();
- // wait for condition with time out in case the thread calling ThreadBase::setParameters()
- // already timed out waiting for the status and will never signal the condition.
- mWaitWorkCV.waitRelative(mLock, kSetParametersTimeoutNs);
}
if (!(previousCommand & FastMixerState::IDLE)) {
@@ -3946,61 +3943,52 @@ void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name __unused)
{
}
-// checkForNewParameters_l() must be called with ThreadBase::mLock held
-bool AudioFlinger::DirectOutputThread::checkForNewParameters_l()
+// checkForNewParameter_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::DirectOutputThread::checkForNewParameter_l(const String8& keyValuePair,
+ status_t& status)
{
bool reconfig = false;
- while (!mNewParameters.isEmpty()) {
- status_t status = NO_ERROR;
- String8 keyValuePair = mNewParameters[0];
- AudioParameter param = AudioParameter(keyValuePair);
- int value;
-
- if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
- // forward device change to effects that have requested to be
- // aware of attached audio device.
- if (value != AUDIO_DEVICE_NONE) {
- mOutDevice = value;
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setDevice_l(mOutDevice);
- }
+ status = NO_ERROR;
+
+ AudioParameter param = AudioParameter(keyValuePair);
+ int value;
+ if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+ // forward device change to effects that have requested to be
+ // aware of attached audio device.
+ if (value != AUDIO_DEVICE_NONE) {
+ mOutDevice = value;
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ mEffectChains[i]->setDevice_l(mOutDevice);
}
}
- if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
- // do not accept frame count changes if tracks are open as the track buffer
- // size depends on frame count and correct behavior would not be garantied
- // if frame count is changed after track creation
- if (!mTracks.isEmpty()) {
- status = INVALID_OPERATION;
- } else {
- reconfig = true;
- }
+ }
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be garantied
+ // if frame count is changed after track creation
+ if (!mTracks.isEmpty()) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
}
- if (status == NO_ERROR) {
+ }
+ if (status == NO_ERROR) {
+ status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
+ keyValuePair.string());
+ if (!mStandby && status == INVALID_OPERATION) {
+ mOutput->stream->common.standby(&mOutput->stream->common);
+ mStandby = true;
+ mBytesWritten = 0;
status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
- keyValuePair.string());
- if (!mStandby && status == INVALID_OPERATION) {
- mOutput->stream->common.standby(&mOutput->stream->common);
- mStandby = true;
- mBytesWritten = 0;
- status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
- keyValuePair.string());
- }
- if (status == NO_ERROR && reconfig) {
- readOutputParameters_l();
- sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
- }
+ keyValuePair.string());
+ }
+ if (status == NO_ERROR && reconfig) {
+ readOutputParameters_l();
+ sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
}
-
- mNewParameters.removeAt(0);
-
- mParamStatus = status;
- mParamCond.signal();
- // wait for condition with time out in case the thread calling ThreadBase::setParameters()
- // already timed out waiting for the status and will never signal the condition.
- mWaitWorkCV.waitRelative(mLock, kSetParametersTimeoutNs);
}
+
return reconfig;
}
@@ -4707,12 +4695,14 @@ reacquire_wakelock:
// activeTracks accumulates a copy of a subset of mActiveTracks
Vector< sp<RecordTrack> > activeTracks;
+ DefaultKeyedVector< pid_t,sp<NotificationClient> > notificationClients =
+ mAudioFlinger->notificationClients();
+
{ // scope for mLock
Mutex::Autolock _l(mLock);
- processConfigEvents_l();
- // return value 'reconfig' is currently unused
- bool reconfig = checkForNewParameters_l();
+ processConfigEvents_l(notificationClients);
+ notificationClients.clear();
// check exitPending here because checkForNewParameters_l() and
// checkForNewParameters_l() can temporarily release mLock
@@ -5487,126 +5477,118 @@ void AudioFlinger::RecordThread::ResamplerBufferProvider::releaseBuffer(
buffer->frameCount = 0;
}
-bool AudioFlinger::RecordThread::checkForNewParameters_l()
+bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair,
+ status_t& status)
{
bool reconfig = false;
- while (!mNewParameters.isEmpty()) {
- status_t status = NO_ERROR;
- String8 keyValuePair = mNewParameters[0];
- AudioParameter param = AudioParameter(keyValuePair);
- int value;
- audio_format_t reqFormat = mFormat;
- uint32_t samplingRate = mSampleRate;
- audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(mChannelCount);
-
- // TODO Investigate when this code runs. Check with audio policy when a sample rate and
- // channel count change can be requested. Do we mandate the first client defines the
- // HAL sampling rate and channel count or do we allow changes on the fly?
- if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
- samplingRate = value;
+ status = NO_ERROR;
+
+ audio_format_t reqFormat = mFormat;
+ uint32_t samplingRate = mSampleRate;
+ audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(mChannelCount);
+
+ AudioParameter param = AudioParameter(keyValuePair);
+ int value;
+ // TODO Investigate when this code runs. Check with audio policy when a sample rate and
+ // channel count change can be requested. Do we mandate the first client defines the
+ // HAL sampling rate and channel count or do we allow changes on the fly?
+ if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+ samplingRate = value;
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
+ if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
+ status = BAD_VALUE;
+ } else {
+ reqFormat = (audio_format_t) value;
reconfig = true;
}
- if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
- if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
- status = BAD_VALUE;
- } else {
- reqFormat = (audio_format_t) value;
- reconfig = true;
- }
+ }
+ if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
+ audio_channel_mask_t mask = (audio_channel_mask_t) value;
+ if (mask != AUDIO_CHANNEL_IN_MONO && mask != AUDIO_CHANNEL_IN_STEREO) {
+ status = BAD_VALUE;
+ } else {
+ channelMask = mask;
+ reconfig = true;
}
- if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
- audio_channel_mask_t mask = (audio_channel_mask_t) value;
- if (mask != AUDIO_CHANNEL_IN_MONO && mask != AUDIO_CHANNEL_IN_STEREO) {
- status = BAD_VALUE;
- } else {
- channelMask = mask;
- reconfig = true;
- }
+ }
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be guaranteed
+ // if frame count is changed after track creation
+ if (mActiveTracks.size() > 0) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
}
- if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
- // do not accept frame count changes if tracks are open as the track buffer
- // size depends on frame count and correct behavior would not be guaranteed
- // if frame count is changed after track creation
- if (mActiveTracks.size() > 0) {
- status = INVALID_OPERATION;
- } else {
- reconfig = true;
- }
+ }
+ if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+ // forward device change to effects that have requested to be
+ // aware of attached audio device.
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ mEffectChains[i]->setDevice_l(value);
}
- if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
- // forward device change to effects that have requested to be
- // aware of attached audio device.
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setDevice_l(value);
- }
- // store input device and output device but do not forward output device to audio HAL.
- // Note that status is ignored by the caller for output device
- // (see AudioFlinger::setParameters()
- if (audio_is_output_devices(value)) {
- mOutDevice = value;
- status = BAD_VALUE;
- } else {
- mInDevice = value;
- // disable AEC and NS if the device is a BT SCO headset supporting those
- // pre processings
- if (mTracks.size() > 0) {
- bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
- mAudioFlinger->btNrecIsOff();
- for (size_t i = 0; i < mTracks.size(); i++) {
- sp<RecordTrack> track = mTracks[i];
- setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
- setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
- }
+ // store input device and output device but do not forward output device to audio HAL.
+ // Note that status is ignored by the caller for output device
+ // (see AudioFlinger::setParameters()
+ if (audio_is_output_devices(value)) {
+ mOutDevice = value;
+ status = BAD_VALUE;
+ } else {
+ mInDevice = value;
+ // disable AEC and NS if the device is a BT SCO headset supporting those
+ // pre processings
+ if (mTracks.size() > 0) {
+ bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
+ mAudioFlinger->btNrecIsOff();
+ for (size_t i = 0; i < mTracks.size(); i++) {
+ sp<RecordTrack> track = mTracks[i];
+ setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
+ setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
}
}
}
- if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR &&
- mAudioSource != (audio_source_t)value) {
- // forward device change to effects that have requested to be
- // aware of attached audio device.
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setAudioSource_l((audio_source_t)value);
- }
- mAudioSource = (audio_source_t)value;
+ }
+ if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR &&
+ mAudioSource != (audio_source_t)value) {
+ // forward device change to effects that have requested to be
+ // aware of attached audio device.
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ mEffectChains[i]->setAudioSource_l((audio_source_t)value);
}
+ mAudioSource = (audio_source_t)value;
+ }
- if (status == NO_ERROR) {
+ if (status == NO_ERROR) {
+ status = mInput->stream->common.set_parameters(&mInput->stream->common,
+ keyValuePair.string());
+ if (status == INVALID_OPERATION) {
+ inputStandBy();
status = mInput->stream->common.set_parameters(&mInput->stream->common,
keyValuePair.string());
- if (status == INVALID_OPERATION) {
- inputStandBy();
- status = mInput->stream->common.set_parameters(&mInput->stream->common,
- keyValuePair.string());
+ }
+ if (reconfig) {
+ if (status == BAD_VALUE &&
+ reqFormat == mInput->stream->common.get_format(&mInput->stream->common) &&
+ reqFormat == AUDIO_FORMAT_PCM_16_BIT &&
+ (mInput->stream->common.get_sample_rate(&mInput->stream->common)
+ <= (2 * samplingRate)) &&
+ popcount(mInput->stream->common.get_channels(&mInput->stream->common))
+ <= FCC_2 &&
+ (channelMask == AUDIO_CHANNEL_IN_MONO ||
+ channelMask == AUDIO_CHANNEL_IN_STEREO)) {
+ status = NO_ERROR;
}
- if (reconfig) {
- if (status == BAD_VALUE &&
- reqFormat == mInput->stream->common.get_format(&mInput->stream->common) &&
- reqFormat == AUDIO_FORMAT_PCM_16_BIT &&
- (mInput->stream->common.get_sample_rate(&mInput->stream->common)
- <= (2 * samplingRate)) &&
- popcount(mInput->stream->common.get_channels(&mInput->stream->common))
- <= FCC_2 &&
- (channelMask == AUDIO_CHANNEL_IN_MONO ||
- channelMask == AUDIO_CHANNEL_IN_STEREO)) {
- status = NO_ERROR;
- }
- if (status == NO_ERROR) {
- readInputParameters_l();
- sendIoConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
- }
+ if (status == NO_ERROR) {
+ readInputParameters_l();
+ sendIoConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
}
}
-
- mNewParameters.removeAt(0);
-
- mParamStatus = status;
- mParamCond.signal();
- // wait for condition with time out in case the thread calling ThreadBase::setParameters()
- // already timed out waiting for the status and will never signal the condition.
- mWaitWorkCV.waitRelative(mLock, kSetParametersTimeoutNs);
}
+
return reconfig;
}
@@ -5623,7 +5605,10 @@ String8 AudioFlinger::RecordThread::getParameters(const String8& keys)
return out_s8;
}
-void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param __unused) {
+void AudioFlinger::RecordThread::audioConfigChanged_l(
+ const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+ int event,
+ int param __unused) {
AudioSystem::OutputDescriptor desc;
const void *param2 = NULL;
@@ -5642,7 +5627,7 @@ void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param __unu
default:
break;
}
- mAudioFlinger->audioConfigChanged_l(event, mId, param2);
+ mAudioFlinger->audioConfigChanged_l(notificationClients, event, mId, param2);
}
void AudioFlinger::RecordThread::readInputParameters_l()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8ea8683..9578993 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -46,60 +46,121 @@ public:
// base for record and playback
enum {
CFG_EVENT_IO,
- CFG_EVENT_PRIO
+ CFG_EVENT_PRIO,
+ CFG_EVENT_SET_PARAMETER,
};
- class ConfigEvent {
+ class ConfigEventData: public RefBase {
+ public:
+ virtual ~ConfigEventData() {}
+
+ virtual void dump(char *buffer, size_t size) = 0;
+ protected:
+ ConfigEventData() {}
+ };
+
+ // Config event sequence by client if status needed (e.g binder thread calling setParameters()):
+ // 1. create SetParameterConfigEvent. This sets mWaitStatus in config event
+ // 2. Lock mLock
+ // 3. Call sendConfigEvent_l(): Append to mConfigEvents and mWaitWorkCV.signal
+ // 4. sendConfigEvent_l() reads status from event->mStatus;
+ // 5. sendConfigEvent_l() returns status
+ // 6. Unlock
+ //
+ // Parameter sequence by server: threadLoop calling processConfigEvents_l():
+ // 1. Lock mLock
+ // 2. If there is an entry in mConfigEvents proceed ...
+ // 3. Read first entry in mConfigEvents
+ // 4. Remove first entry from mConfigEvents
+ // 5. Process
+ // 6. Set event->mStatus
+ // 7. event->mCond.signal
+ // 8. Unlock
+
+ class ConfigEvent: public RefBase {
public:
- ConfigEvent(int type) : mType(type) {}
virtual ~ConfigEvent() {}
- int type() const { return mType; }
+ void dump(char *buffer, size_t size) { mData->dump(buffer, size); }
- virtual void dump(char *buffer, size_t size) = 0;
+ const int mType; // event type e.g. CFG_EVENT_IO
+ Mutex mLock; // mutex associated with mCond
+ Condition mCond; // condition for status return
+ status_t mStatus; // status communicated to sender
+ bool mWaitStatus; // true if sender is waiting for status
+ sp<ConfigEventData> mData; // event specific parameter data
- private:
- const int mType;
+ protected:
+ ConfigEvent(int type) : mType(type), mStatus(NO_ERROR), mWaitStatus(false), mData(NULL) {}
};
- class IoConfigEvent : public ConfigEvent {
+ class IoConfigEventData : public ConfigEventData {
public:
- IoConfigEvent(int event, int param) :
- ConfigEvent(CFG_EVENT_IO), mEvent(event), mParam(param) {}
- virtual ~IoConfigEvent() {}
-
- int event() const { return mEvent; }
- int param() const { return mParam; }
+ IoConfigEventData(int event, int param) :
+ mEvent(event), mParam(param) {}
virtual void dump(char *buffer, size_t size) {
snprintf(buffer, size, "IO event: event %d, param %d\n", mEvent, mParam);
}
- private:
const int mEvent;
const int mParam;
};
- class PrioConfigEvent : public ConfigEvent {
+ class IoConfigEvent : public ConfigEvent {
public:
- PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio) :
- ConfigEvent(CFG_EVENT_PRIO), mPid(pid), mTid(tid), mPrio(prio) {}
- virtual ~PrioConfigEvent() {}
+ IoConfigEvent(int event, int param) :
+ ConfigEvent(CFG_EVENT_IO) {
+ mData = new IoConfigEventData(event, param);
+ }
+ virtual ~IoConfigEvent() {}
+ };
- pid_t pid() const { return mPid; }
- pid_t tid() const { return mTid; }
- int32_t prio() const { return mPrio; }
+ class PrioConfigEventData : public ConfigEventData {
+ public:
+ PrioConfigEventData(pid_t pid, pid_t tid, int32_t prio) :
+ mPid(pid), mTid(tid), mPrio(prio) {}
virtual void dump(char *buffer, size_t size) {
snprintf(buffer, size, "Prio event: pid %d, tid %d, prio %d\n", mPid, mTid, mPrio);
}
- private:
const pid_t mPid;
const pid_t mTid;
const int32_t mPrio;
};
+ class PrioConfigEvent : public ConfigEvent {
+ public:
+ PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio) :
+ ConfigEvent(CFG_EVENT_PRIO) {
+ mData = new PrioConfigEventData(pid, tid, prio);
+ }
+ virtual ~PrioConfigEvent() {}
+ };
+
+ class SetParameterConfigEventData : public ConfigEventData {
+ public:
+ SetParameterConfigEventData(String8 keyValuePairs) :
+ mKeyValuePairs(keyValuePairs) {}
+
+ virtual void dump(char *buffer, size_t size) {
+ snprintf(buffer, size, "KeyValue: %s\n", mKeyValuePairs.string());
+ }
+
+ const String8 mKeyValuePairs;
+ };
+
+ class SetParameterConfigEvent : public ConfigEvent {
+ public:
+ SetParameterConfigEvent(String8 keyValuePairs) :
+ ConfigEvent(CFG_EVENT_SET_PARAMETER) {
+ mData = new SetParameterConfigEventData(keyValuePairs);
+ mWaitStatus = true;
+ }
+ virtual ~SetParameterConfigEvent() {}
+ };
+
class PMDeathRecipient : public IBinder::DeathRecipient {
public:
@@ -135,15 +196,25 @@ public:
// Should be "virtual status_t requestExitAndWait()" and override same
// method in Thread, but Thread::requestExitAndWait() is not yet virtual.
void exit();
- virtual bool checkForNewParameters_l() = 0;
+ virtual bool checkForNewParameter_l(const String8& keyValuePair,
+ status_t& status) = 0;
virtual status_t setParameters(const String8& keyValuePairs);
virtual String8 getParameters(const String8& keys) = 0;
- virtual void audioConfigChanged_l(int event, int param = 0) = 0;
+ virtual void audioConfigChanged_l(
+ const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+ int event,
+ int param = 0) = 0;
+ // sendConfigEvent_l() must be called with ThreadBase::mLock held
+ // Can temporarily release the lock if waiting for a reply from
+ // processConfigEvents_l().
+ status_t sendConfigEvent_l(sp<ConfigEvent>& event);
void sendIoConfigEvent(int event, int param = 0);
void sendIoConfigEvent_l(int event, int param = 0);
void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
- void processConfigEvents();
- void processConfigEvents_l();
+ status_t sendSetParameterConfigEvent_l(const String8& keyValuePair);
+ void processConfigEvents_l(
+ const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients);
+ virtual void cacheParameters_l() = 0;
// see note at declaration of mStandby, mOutDevice and mInDevice
bool standby() const { return mStandby; }
@@ -287,31 +358,7 @@ protected:
audio_format_t mFormat;
size_t mBufferSize; // HAL buffer size for read() or write()
- // Parameter sequence by client: binder thread calling setParameters():
- // 1. Lock mLock
- // 2. Append to mNewParameters
- // 3. mWaitWorkCV.signal
- // 4. mParamCond.waitRelative with timeout
- // 5. read mParamStatus
- // 6. mWaitWorkCV.signal
- // 7. Unlock
- //
- // Parameter sequence by server: threadLoop calling checkForNewParameters_l():
- // 1. Lock mLock
- // 2. If there is an entry in mNewParameters proceed ...
- // 2. Read first entry in mNewParameters
- // 3. Process
- // 4. Remove first entry from mNewParameters
- // 5. Set mParamStatus
- // 6. mParamCond.signal
- // 7. mWaitWorkCV.wait with timeout (this is to avoid overwriting mParamStatus)
- // 8. Unlock
- Condition mParamCond;
- Vector<String8> mNewParameters;
- status_t mParamStatus;
-
- // vector owns each ConfigEvent *, so must delete after removing
- Vector<ConfigEvent *> mConfigEvents;
+ Vector< sp<ConfigEvent> > mConfigEvents;
// These fields are written and read by thread itself without lock or barrier,
// and read by other threads without lock or barrier via standby(), outDevice()
@@ -455,7 +502,10 @@ public:
{ return android_atomic_acquire_load(&mSuspended) > 0; }
virtual String8 getParameters(const String8& keys);
- virtual void audioConfigChanged_l(int event, int param = 0);
+ virtual void audioConfigChanged_l(
+ const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+ int event,
+ int param = 0);
status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
// FIXME rename mixBuffer() to sinkBuffer() and remove int16_t* dependency.
// Consider also removing and passing an explicit mMainBuffer initialization
@@ -724,7 +774,8 @@ public:
// Thread virtuals
- virtual bool checkForNewParameters_l();
+ virtual bool checkForNewParameter_l(const String8& keyValuePair,
+ status_t& status);
virtual void dumpInternals(int fd, const Vector<String16>& args);
protected:
@@ -778,7 +829,8 @@ public:
// Thread virtuals
- virtual bool checkForNewParameters_l();
+ virtual bool checkForNewParameter_l(const String8& keyValuePair,
+ status_t& status);
protected:
virtual int getTrackName_l(audio_channel_mask_t channelMask, int sessionId);
@@ -981,9 +1033,14 @@ public:
virtual audio_stream_t* stream() const;
- virtual bool checkForNewParameters_l();
+ virtual bool checkForNewParameter_l(const String8& keyValuePair,
+ status_t& status);
+ virtual void cacheParameters_l() {}
virtual String8 getParameters(const String8& keys);
- virtual void audioConfigChanged_l(int event, int param = 0);
+ virtual void audioConfigChanged_l(
+ const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+ int event,
+ int param = 0);
void readInputParameters_l();
virtual uint32_t getInputFramesLost();