summaryrefslogtreecommitdiffstats
path: root/services/audioflinger
diff options
context:
space:
mode:
Diffstat (limited to 'services/audioflinger')
-rw-r--r--services/audioflinger/Android.mk2
-rw-r--r--services/audioflinger/AudioBufferProviderSource.cpp14
-rw-r--r--services/audioflinger/AudioBufferProviderSource.h5
-rw-r--r--services/audioflinger/AudioFlinger.cpp1033
-rw-r--r--services/audioflinger/AudioFlinger.h351
-rw-r--r--services/audioflinger/AudioMixer.cpp2
-rw-r--r--services/audioflinger/AudioPolicyService.cpp53
-rw-r--r--services/audioflinger/AudioPolicyService.h10
-rw-r--r--services/audioflinger/AudioStreamOutSink.cpp12
-rw-r--r--services/audioflinger/AudioStreamOutSink.h5
-rw-r--r--services/audioflinger/FastMixer.cpp11
-rw-r--r--services/audioflinger/MonoPipe.cpp134
-rw-r--r--services/audioflinger/MonoPipe.h41
-rw-r--r--services/audioflinger/MonoPipeReader.cpp18
-rw-r--r--services/audioflinger/MonoPipeReader.h2
-rw-r--r--services/audioflinger/NBAIO.cpp7
-rw-r--r--services/audioflinger/NBAIO.h28
-rw-r--r--services/audioflinger/Soaker.h45
-rw-r--r--services/audioflinger/SourceAudioBufferProvider.cpp2
19 files changed, 1067 insertions, 708 deletions
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 8473fab..c2d2790 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -89,7 +89,7 @@ LOCAL_CFLAGS += -DFAST_MIXER_STATISTICS
LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
-LOCAL_CFLAGS += -DHAVE_REQUEST_PRIORITY -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE -USOAKER
+LOCAL_CFLAGS += -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE
# uncomment for systrace
# LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_AUDIO
diff --git a/services/audioflinger/AudioBufferProviderSource.cpp b/services/audioflinger/AudioBufferProviderSource.cpp
index 4342171..613e924 100644
--- a/services/audioflinger/AudioBufferProviderSource.cpp
+++ b/services/audioflinger/AudioBufferProviderSource.cpp
@@ -46,14 +46,16 @@ ssize_t AudioBufferProviderSource::availableToRead()
return mBuffer.raw != NULL ? mBuffer.frameCount - mConsumed : 0;
}
-ssize_t AudioBufferProviderSource::read(void *buffer, size_t count)
+ssize_t AudioBufferProviderSource::read(void *buffer,
+ size_t count,
+ int64_t readPTS)
{
if (CC_UNLIKELY(!mNegotiated)) {
return NEGOTIATE;
}
if (CC_UNLIKELY(mBuffer.raw == NULL)) {
mBuffer.frameCount = count;
- status_t status = mProvider->getNextBuffer(&mBuffer, AudioBufferProvider::kInvalidPTS);
+ status_t status = mProvider->getNextBuffer(&mBuffer, readPTS);
if (status != OK) {
return status == NOT_ENOUGH_DATA ? (ssize_t) WOULD_BLOCK : (ssize_t) status;
}
@@ -79,7 +81,8 @@ ssize_t AudioBufferProviderSource::read(void *buffer, size_t count)
return count;
}
-ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user, size_t block)
+ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user,
+ int64_t readPTS, size_t block)
{
if (CC_UNLIKELY(!mNegotiated)) {
return NEGOTIATE;
@@ -99,7 +102,7 @@ ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *us
// 1 <= count <= block
if (CC_UNLIKELY(mBuffer.raw == NULL)) {
mBuffer.frameCount = count;
- status_t status = mProvider->getNextBuffer(&mBuffer, AudioBufferProvider::kInvalidPTS);
+ status_t status = mProvider->getNextBuffer(&mBuffer, readPTS);
if (CC_LIKELY(status == OK)) {
ALOG_ASSERT(mBuffer.raw != NULL && mBuffer.frameCount <= count);
// mConsumed is 0 either from constructor or after releaseBuffer()
@@ -117,7 +120,8 @@ ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *us
count = available;
}
if (CC_LIKELY(count > 0)) {
- ssize_t ret = via(user, (char *) mBuffer.raw + (mConsumed << mBitShift), count);
+ char* readTgt = (char *) mBuffer.raw + (mConsumed << mBitShift);
+ ssize_t ret = via(user, readTgt, count, readPTS);
if (CC_UNLIKELY(ret <= 0)) {
if (CC_LIKELY(accumulator > 0)) {
return accumulator;
diff --git a/services/audioflinger/AudioBufferProviderSource.h b/services/audioflinger/AudioBufferProviderSource.h
index 2b39937..1435a84 100644
--- a/services/audioflinger/AudioBufferProviderSource.h
+++ b/services/audioflinger/AudioBufferProviderSource.h
@@ -42,8 +42,9 @@ public:
//virtual size_t framesOverrun();
//virtual size_t overruns();
virtual ssize_t availableToRead();
- virtual ssize_t read(void *buffer, size_t count);
- virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block);
+ virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
+ virtual ssize_t readVia(readVia_t via, size_t total, void *user,
+ int64_t readPTS, size_t block);
private:
AudioBufferProvider * const mProvider;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index aab9984..7e5f102 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -83,13 +83,7 @@
#include "PipeReader.h"
#include "SourceAudioBufferProvider.h"
-#ifdef HAVE_REQUEST_PRIORITY
#include "SchedulingPolicyService.h"
-#endif
-
-#ifdef SOAKER
-#include "Soaker.h"
-#endif
// ----------------------------------------------------------------------------
@@ -167,6 +161,10 @@ static const enum {
static uint32_t gScreenState; // incremented by 2 when screen state changes, bit 0 == 1 means "off"
// AudioFlinger::setParameters() updates, other threads read w/o lock
+// Priorities for requestPriority
+static const int kPriorityAudioApp = 2;
+static const int kPriorityFastMixer = 3;
+
// ----------------------------------------------------------------------------
#ifdef ADD_BATTERY_DATA
@@ -216,9 +214,8 @@ out:
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
mPrimaryHardwareDev(NULL),
- mHardwareStatus(AUDIO_HW_IDLE), // see also onFirstRef()
+ mHardwareStatus(AUDIO_HW_IDLE),
mMasterVolume(1.0f),
- mMasterVolumeSupportLvl(MVS_NONE),
mMasterMute(false),
mNextUniqueId(1),
mMode(AUDIO_MODE_INVALID),
@@ -247,21 +244,17 @@ void AudioFlinger::onFirstRef()
}
mMode = AUDIO_MODE_NORMAL;
- mMasterVolumeSW = 1.0;
- mMasterVolume = 1.0;
- mHardwareStatus = AUDIO_HW_IDLE;
}
AudioFlinger::~AudioFlinger()
{
-
while (!mRecordThreads.isEmpty()) {
// closeInput() will remove first entry from mRecordThreads
- closeInput(mRecordThreads.keyAt(0));
+ closeInput_nonvirtual(mRecordThreads.keyAt(0));
}
while (!mPlaybackThreads.isEmpty()) {
// closeOutput() will remove first entry from mPlaybackThreads
- closeOutput(mPlaybackThreads.keyAt(0));
+ closeOutput_nonvirtual(mPlaybackThreads.keyAt(0));
}
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
@@ -278,7 +271,9 @@ static const char * const audio_interfaces[] = {
};
#define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))
-audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices)
+AudioFlinger::AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
+ audio_module_handle_t module,
+ audio_devices_t devices)
{
// if module is 0, the request comes from an old policy manager and we should load
// well known modules
@@ -289,22 +284,23 @@ audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(audio_module_handle_t modul
}
} else {
// check a match for the requested module handle
- AudioHwDevice *audioHwdevice = mAudioHwDevs.valueFor(module);
- if (audioHwdevice != NULL) {
- return audioHwdevice->hwDevice();
+ AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(module);
+ if (audioHwDevice != NULL) {
+ return audioHwDevice;
}
}
// then try to find a module supporting the requested device.
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
- audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+ AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(i);
+ audio_hw_device_t *dev = audioHwDevice->hwDevice();
if ((dev->get_supported_devices(dev) & devices) == devices)
- return dev;
+ return audioHwDevice;
}
return NULL;
}
-status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -327,11 +323,10 @@ status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
result.append(buffer);
}
write(fd, result.string(), result.size());
- return NO_ERROR;
}
-status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -344,10 +339,9 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
(uint32_t)(mStandbyTimeInNsecs / 1000000));
result.append(buffer);
write(fd, result.string(), result.size());
- return NO_ERROR;
}
-status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -358,7 +352,6 @@ status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args
IPCThreadState::self()->getCallingUid());
result.append(buffer);
write(fd, result.string(), result.size());
- return NO_ERROR;
}
static bool tryLock(Mutex& mutex)
@@ -440,7 +433,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
IAudioFlinger::track_flags_t flags,
const sp<IMemory>& sharedBuffer,
@@ -610,30 +603,27 @@ status_t AudioFlinger::setMasterVolume(float value)
return PERMISSION_DENIED;
}
- float swmv = value;
-
Mutex::Autolock _l(mLock);
+ mMasterVolume = value;
- // when hw supports master volume, don't scale in sw mixer
- if (MVS_NONE != mMasterVolumeSupportLvl) {
- for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
- AutoMutex lock(mHardwareLock);
- audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+ // Set master volume in the HALs which support it.
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ AutoMutex lock(mHardwareLock);
+ AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
- mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
- if (NULL != dev->set_master_volume) {
- dev->set_master_volume(dev, value);
- }
- mHardwareStatus = AUDIO_HW_IDLE;
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ if (dev->canSetMasterVolume()) {
+ dev->hwDevice()->set_master_volume(dev->hwDevice(), value);
}
-
- swmv = 1.0;
+ mHardwareStatus = AUDIO_HW_IDLE;
}
- mMasterVolume = value;
- mMasterVolumeSW = swmv;
+ // Now set the master volume in each playback thread. Playback threads
+ // assigned to HALs which do not have master volume support will apply
+ // master volume during the mix operation. Threads with HALs which do
+ // support master volume will simply ignore the setting.
for (size_t i = 0; i < mPlaybackThreads.size(); i++)
- mPlaybackThreads.valueAt(i)->setMasterVolume(swmv);
+ mPlaybackThreads.valueAt(i)->setMasterVolume(value);
return NO_ERROR;
}
@@ -656,8 +646,9 @@ status_t AudioFlinger::setMode(audio_mode_t mode)
{ // scope for the lock
AutoMutex lock(mHardwareLock);
+ audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
mHardwareStatus = AUDIO_HW_SET_MODE;
- ret = mPrimaryHardwareDev->set_mode(mPrimaryHardwareDev, mode);
+ ret = dev->set_mode(dev, mode);
mHardwareStatus = AUDIO_HW_IDLE;
}
@@ -684,8 +675,9 @@ status_t AudioFlinger::setMicMute(bool state)
}
AutoMutex lock(mHardwareLock);
+ audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
- ret = mPrimaryHardwareDev->set_mic_mute(mPrimaryHardwareDev, state);
+ ret = dev->set_mic_mute(dev, state);
mHardwareStatus = AUDIO_HW_IDLE;
return ret;
}
@@ -699,22 +691,44 @@ bool AudioFlinger::getMicMute() const
bool state = AUDIO_MODE_INVALID;
AutoMutex lock(mHardwareLock);
+ audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
- mPrimaryHardwareDev->get_mic_mute(mPrimaryHardwareDev, &state);
+ dev->get_mic_mute(dev, &state);
mHardwareStatus = AUDIO_HW_IDLE;
return state;
}
status_t AudioFlinger::setMasterMute(bool muted)
{
+ status_t ret = initCheck();
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+
// check calling permissions
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
Mutex::Autolock _l(mLock);
- // This is an optimization, so PlaybackThread doesn't have to look at the one from AudioFlinger
mMasterMute = muted;
+
+ // Set master mute in the HALs which support it.
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ AutoMutex lock(mHardwareLock);
+ AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
+
+ mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
+ if (dev->canSetMasterMute()) {
+ dev->hwDevice()->set_master_mute(dev->hwDevice(), muted);
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ }
+
+ // Now set the master mute in each playback thread. Playback threads
+ // assigned to HALs which do not have master mute support will apply master
+ // mute during the mix operation. Threads with HALs which do support master
+ // mute will simply ignore the setting.
for (size_t i = 0; i < mPlaybackThreads.size(); i++)
mPlaybackThreads.valueAt(i)->setMasterMute(muted);
@@ -727,12 +741,6 @@ float AudioFlinger::masterVolume() const
return masterVolume_l();
}
-float AudioFlinger::masterVolumeSW() const
-{
- Mutex::Autolock _l(mLock);
- return masterVolumeSW_l();
-}
-
bool AudioFlinger::masterMute() const
{
Mutex::Autolock _l(mLock);
@@ -741,23 +749,14 @@ bool AudioFlinger::masterMute() const
float AudioFlinger::masterVolume_l() const
{
- if (MVS_FULL == mMasterVolumeSupportLvl) {
- float ret_val;
- AutoMutex lock(mHardwareLock);
-
- mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
- ALOG_ASSERT((NULL != mPrimaryHardwareDev) &&
- (NULL != mPrimaryHardwareDev->get_master_volume),
- "can't get master volume");
-
- mPrimaryHardwareDev->get_master_volume(mPrimaryHardwareDev, &ret_val);
- mHardwareStatus = AUDIO_HW_IDLE;
- return ret_val;
- }
-
return mMasterVolume;
}
+bool AudioFlinger::masterMute_l() const
+{
+ return mMasterMute;
+}
+
status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output)
{
@@ -876,17 +875,19 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8&
if (mBtNrecIsOff != btNrecIsOff) {
for (size_t i = 0; i < mRecordThreads.size(); i++) {
sp<RecordThread> thread = mRecordThreads.valueAt(i);
- RecordThread::RecordTrack *track = thread->track();
- if (track != NULL) {
- audio_devices_t device = (audio_devices_t)(
- thread->device() & AUDIO_DEVICE_IN_ALL);
- bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff;
+ audio_devices_t device = thread->device() & AUDIO_DEVICE_IN_ALL;
+ bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff;
+ // collect all of the thread's session IDs
+ KeyedVector<int, bool> ids = thread->sessionIds();
+ // suspend effects associated with those session IDs
+ for (size_t j = 0; j < ids.size(); ++j) {
+ int sessionId = ids.keyAt(j);
thread->setEffectSuspended(FX_IID_AEC,
suspend,
- track->sessionId());
+ sessionId);
thread->setEffectSuspended(FX_IID_NS,
suspend,
- track->sessionId());
+ sessionId);
}
}
mBtNrecIsOff = btNrecIsOff;
@@ -908,7 +909,7 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8&
{
Mutex::Autolock _l(mLock);
thread = checkPlaybackThread_l(ioHandle);
- if (thread == NULL) {
+ if (thread == 0) {
thread = checkRecordThread_l(ioHandle);
} else if (thread == primaryPlaybackThread_l()) {
// indicate output device change to all input threads for pre processing
@@ -964,7 +965,8 @@ String8 AudioFlinger::getParameters(audio_io_handle_t ioHandle, const String8& k
return String8("");
}
-size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const
+size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
+ audio_channel_mask_t channelMask) const
{
status_t ret = initCheck();
if (ret != NO_ERROR) {
@@ -975,20 +977,17 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t form
mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
struct audio_config config = {
sample_rate: sampleRate,
- channel_mask: audio_channel_in_mask_from_count(channelCount),
+ channel_mask: channelMask,
format: format,
};
- size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, &config);
+ audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
+ size_t size = dev->get_input_buffer_size(dev, &config);
mHardwareStatus = AUDIO_HW_IDLE;
return size;
}
unsigned int AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const
{
- if (ioHandle == 0) {
- return 0;
- }
-
Mutex::Autolock _l(mLock);
RecordThread *recordThread = checkRecordThread_l(ioHandle);
@@ -1011,8 +1010,9 @@ status_t AudioFlinger::setVoiceVolume(float value)
}
AutoMutex lock(mHardwareLock);
+ audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
mHardwareStatus = AUDIO_HW_SET_VOICE_VOLUME;
- ret = mPrimaryHardwareDev->set_voice_volume(mPrimaryHardwareDev, value);
+ ret = dev->set_voice_volume(dev, value);
mHardwareStatus = AUDIO_HW_IDLE;
return ret;
@@ -1124,7 +1124,7 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::getEffectThread_l(int sessionId,
// ----------------------------------------------------------------------------
AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- uint32_t device, type_t type)
+ audio_devices_t device, type_t type)
: Thread(false),
mType(type),
mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mNormalFrameCount(0),
@@ -1132,8 +1132,7 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio
mChannelCount(0),
mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID),
mParamStatus(NO_ERROR),
- mStandby(false), mId(id),
- mDevice(device),
+ mStandby(false), mDevice(device), mId(id),
mDeathRecipient(new PMDeathRecipient(this))
{
}
@@ -1226,7 +1225,7 @@ void AudioFlinger::ThreadBase::processConfigEvents()
mLock.unlock();
}
-status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
+void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -1283,10 +1282,9 @@ status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args
if (locked) {
mLock.unlock();
}
- return NO_ERROR;
}
-status_t AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>& args)
+void AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -1301,7 +1299,6 @@ status_t AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String1
chain->dump(fd, args);
}
}
- return NO_ERROR;
}
void AudioFlinger::ThreadBase::acquireWakeLock()
@@ -1397,8 +1394,8 @@ void AudioFlinger::ThreadBase::checkSuspendOnAddEffectChain_l(const sp<EffectCha
return;
}
- KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects =
- mSuspendedSessions.editValueAt(index);
+ const KeyedVector <int, sp<SuspendedSessionDesc> >& sessionEffects =
+ mSuspendedSessions.valueAt(index);
for (size_t i = 0; i < sessionEffects.size(); i++) {
sp<SuspendedSessionDesc> desc = sessionEffects.valueAt(i);
@@ -1424,7 +1421,7 @@ void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *ty
if (suspend) {
if (index >= 0) {
- sessionEffects = mSuspendedSessions.editValueAt(index);
+ sessionEffects = mSuspendedSessions.valueAt(index);
} else {
mSuspendedSessions.add(sessionId, sessionEffects);
}
@@ -1432,7 +1429,7 @@ void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *ty
if (index < 0) {
return;
}
- sessionEffects = mSuspendedSessions.editValueAt(index);
+ sessionEffects = mSuspendedSessions.valueAt(index);
}
@@ -1449,7 +1446,7 @@ void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *ty
} else {
desc = new SuspendedSessionDesc();
if (type != NULL) {
- memcpy(&desc->mType, type, sizeof(effect_uuid_t));
+ desc->mType = *type;
}
sessionEffects.add(key, desc);
ALOGV("updateSuspendedSessions_l() suspend adding effect %08x", key);
@@ -1509,18 +1506,12 @@ void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModu
AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output,
audio_io_handle_t id,
- uint32_t device,
+ audio_devices_t device,
type_t type)
: ThreadBase(audioFlinger, id, device, type),
mMixBuffer(NULL), mSuspended(0), mBytesWritten(0),
- // Assumes constructor is called by AudioFlinger with it's mLock held,
- // but it would be safer to explicitly pass initial masterMute as parameter
- mMasterMute(audioFlinger->masterMute_l()),
// mStreamTypes[] initialized in constructor body
mOutput(output),
- // Assumes constructor is called by AudioFlinger with it's mLock held,
- // but it would be safer to explicitly pass initial masterVolume as parameter
- mMasterVolume(audioFlinger->masterVolumeSW_l()),
mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
mMixerStatus(MIXER_IDLE),
mMixerStatusIgnoringFastTracks(MIXER_IDLE),
@@ -1531,6 +1522,25 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
{
snprintf(mName, kNameLength, "AudioOut_%X", id);
+ // 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();
// mStreamTypes[AUDIO_STREAM_CNT] is initialized by stream_type_t default constructor
@@ -1549,15 +1559,14 @@ AudioFlinger::PlaybackThread::~PlaybackThread()
delete [] mMixBuffer;
}
-status_t AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
+void AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
{
dumpInternals(fd, args);
dumpTracks(fd, args);
dumpEffectChains(fd, args);
- return NO_ERROR;
}
-status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args)
+void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -1605,11 +1614,9 @@ status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>
FastTrackUnderruns underruns = getFastTrackUnderruns(0);
fdprintf(fd, "Normal mixer raw underrun counters: partial=%u empty=%u\n",
underruns.mBitFields.mPartial, underruns.mBitFields.mEmpty);
-
- return NO_ERROR;
}
-status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -1633,8 +1640,6 @@ status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String
fdprintf(fd, "Fast track availMask=%#x\n", mFastTrackAvailMask);
dumpBase(fd, args);
-
- return NO_ERROR;
}
// Thread virtuals
@@ -1660,7 +1665,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId,
@@ -1715,7 +1720,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
frameCount, mFrameCount);
} else {
ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: isTimed=%d sharedBuffer=%p frameCount=%d "
- "mFrameCount=%d format=%d isLinear=%d channelMask=%d sampleRate=%d mSampleRate=%d "
+ "mFrameCount=%d format=%d isLinear=%d channelMask=%#x sampleRate=%d mSampleRate=%d "
"hasFastMixer=%d tid=%d fastTrackAvailMask=%#x",
isTimed, sharedBuffer.get(), frameCount, mFrameCount, format,
audio_is_linear_pcm(format),
@@ -1789,7 +1794,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
track = TimedTrack::create(this, client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, sessionId);
}
- if (track == NULL || track->getCblk() == NULL || track->name() < 0) {
+ if (track == 0 || track->getCblk() == NULL || track->name() < 0) {
lStatus = NO_MEMORY;
goto Exit;
}
@@ -1804,18 +1809,16 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
}
}
-#ifdef HAVE_REQUEST_PRIORITY
if ((flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
// we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
// so ask activity manager to do this on our behalf
- int err = requestPriority(callingPid, tid, 1);
+ int err = requestPriority(callingPid, tid, kPriorityAudioApp);
if (err != 0) {
ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
- 1, callingPid, tid, err);
+ kPriorityAudioApp, callingPid, tid, err);
}
}
-#endif
lStatus = NO_ERROR;
@@ -1857,13 +1860,25 @@ uint32_t AudioFlinger::PlaybackThread::latency_l() const
void AudioFlinger::PlaybackThread::setMasterVolume(float value)
{
Mutex::Autolock _l(mLock);
- mMasterVolume = value;
+ // Don't apply master volume in SW if our HAL can do it for us.
+ if (mOutput && mOutput->audioHwDev &&
+ mOutput->audioHwDev->canSetMasterVolume()) {
+ mMasterVolume = 1.0;
+ } else {
+ mMasterVolume = value;
+ }
}
void AudioFlinger::PlaybackThread::setMasterMute(bool muted)
{
Mutex::Autolock _l(mLock);
- setMasterMute_l(muted);
+ // Don't apply master mute in SW if our HAL can do it for us.
+ if (mOutput && mOutput->audioHwDev &&
+ mOutput->audioHwDev->canSetMasterMute()) {
+ mMasterMute = false;
+ } else {
+ mMasterMute = muted;
+ }
}
void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
@@ -2192,28 +2207,25 @@ void AudioFlinger::PlaybackThread::threadLoop_removeTracks(const Vector< sp<Trac
// ----------------------------------------------------------------------------
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
- audio_io_handle_t id, uint32_t device, type_t type)
+ audio_io_handle_t id, audio_devices_t device, type_t type)
: PlaybackThread(audioFlinger, output, id, device, type),
// mAudioMixer below
-#ifdef SOAKER
- mSoaker(NULL),
-#endif
// mFastMixer below
mFastMixerFutex(0)
// mOutputSink below
// mPipeSink below
// mNormalSink below
{
- ALOGV("MixerThread() id=%d device=%d type=%d", id, device, type);
- ALOGV("mSampleRate=%d, mChannelMask=%d, mChannelCount=%d, mFormat=%d, mFrameSize=%d, "
+ ALOGV("MixerThread() id=%d device=%#x type=%d", id, device, type);
+ ALOGV("mSampleRate=%d, mChannelMask=%#x, mChannelCount=%d, mFormat=%d, mFrameSize=%d, "
"mFrameCount=%d, mNormalFrameCount=%d",
mSampleRate, mChannelMask, mChannelCount, mFormat, mFrameSize, mFrameCount,
mNormalFrameCount);
mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
// FIXME - Current mixer implementation only supports stereo output
- if (mChannelCount == 1) {
- ALOGE("Invalid audio hardware channel count");
+ if (mChannelCount != FCC_2) {
+ ALOGE("Invalid audio hardware channel count %d", mChannelCount);
}
// create an NBAIO sink for the HAL output stream, and negotiate
@@ -2267,13 +2279,6 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
mTeeSource = teeSource;
#endif
-#ifdef SOAKER
- // create a soaker as workaround for governor issues
- mSoaker = new Soaker();
- // FIXME Soaker should only run when needed, i.e. when FastMixer is not in COLD_IDLE
- mSoaker->run("Soaker", PRIORITY_LOWEST);
-#endif
-
// create fast mixer and configure it initially with just one fast track for our submix
mFastMixer = new FastMixer();
FastMixerStateQueue *sq = mFastMixer->sq();
@@ -2305,14 +2310,12 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
// start the fast mixer
mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO);
-#ifdef HAVE_REQUEST_PRIORITY
pid_t tid = mFastMixer->getTid();
- int err = requestPriority(getpid_cached, tid, 2);
+ int err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
if (err != 0) {
ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
- 2, getpid_cached, tid, err);
+ kPriorityFastMixer, getpid_cached, tid, err);
}
-#endif
#ifdef AUDIO_WATCHDOG
// create and start the watchdog
@@ -2320,10 +2323,10 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
mAudioWatchdog->setDump(&mAudioWatchdogDump);
mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO);
tid = mAudioWatchdog->getTid();
- err = requestPriority(getpid_cached, tid, 1);
+ err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
if (err != 0) {
ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
- 1, getpid_cached, tid, err);
+ kPriorityFastMixer, getpid_cached, tid, err);
}
#endif
@@ -2370,12 +2373,6 @@ AudioFlinger::MixerThread::~MixerThread()
delete fastTrack->mBufferProvider;
sq->end(false /*didModify*/);
delete mFastMixer;
-#ifdef SOAKER
- if (mSoaker != NULL) {
- mSoaker->requestExitAndWait();
- }
- delete mSoaker;
-#endif
if (mAudioWatchdog != 0) {
mAudioWatchdog->requestExit();
mAudioWatchdog->requestExitAndWait();
@@ -2508,9 +2505,6 @@ bool AudioFlinger::PlaybackThread::threadLoop()
// MIXER
nsecs_t lastWarning = 0;
-if (mType == MIXER) {
- longStandbyExit = false;
-}
// DUPLICATING
// FIXME could this be made local to while loop?
@@ -2519,9 +2513,9 @@ if (mType == MIXER) {
cacheParameters_l();
sleepTime = idleSleepTime;
-if (mType == MIXER) {
- sleepTimeShift = 0;
-}
+ if (mType == MIXER) {
+ sleepTimeShift = 0;
+ }
CpuStats cpuStats;
const String8 myName(String8::format("thread %p type %d TID %d", this, mType, gettid()));
@@ -2548,7 +2542,7 @@ if (mType == MIXER) {
// put audio hardware into standby after short delay
if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) ||
- mSuspended > 0)) {
+ isSuspended())) {
if (!mStandby) {
threadLoop_standby();
@@ -2602,7 +2596,7 @@ if (mType == MIXER) {
threadLoop_sleepTime();
}
- if (mSuspended > 0) {
+ if (isSuspended()) {
sleepTime = suspendSleepTimeUs();
}
@@ -2635,11 +2629,6 @@ if (mType == MIXER) {
ns2ms(delta), mNumDelayedWrites, this);
lastWarning = now;
}
- // FIXME this is broken: longStandbyExit should be handled out of the if() and with
- // a different threshold. Or completely removed for what it is worth anyway...
- if (mStandby) {
- longStandbyExit = true;
- }
}
}
@@ -2667,15 +2656,13 @@ if (mType == MIXER) {
// is now local to this block, but will keep it for now (at least until merge done).
}
-if (mType == MIXER || mType == DIRECT) {
- // put output stream into standby mode
- if (!mStandby) {
- mOutput->stream->common.standby(&mOutput->stream->common);
+ // for DuplicatingThread, standby mode is handled by the outputTracks, otherwise ...
+ if (mType == MIXER || mType == DIRECT) {
+ // put output stream into standby mode
+ if (!mStandby) {
+ mOutput->stream->common.standby(&mOutput->stream->common);
+ }
}
-}
-if (mType == DUPLICATING) {
- // for DuplicatingThread, standby mode is handled by the outputTracks
-}
releaseWakeLock();
@@ -2794,7 +2781,7 @@ void AudioFlinger::MixerThread::threadLoop_standby()
// shared by MIXER and DIRECT, overridden by DUPLICATING
void AudioFlinger::PlaybackThread::threadLoop_standby()
{
- ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
+ ALOGV("Audio hardware entering standby, mixer %p, suspend count %d", this, mSuspended);
mOutput->stream->common.standby(&mOutput->stream->common);
}
@@ -2804,9 +2791,10 @@ void AudioFlinger::MixerThread::threadLoop_mix()
int64_t pts;
status_t status = INVALID_OPERATION;
- if (NULL != mOutput->stream->get_next_write_timestamp) {
- status = mOutput->stream->get_next_write_timestamp(
- mOutput->stream, &pts);
+ if (mNormalSink != 0) {
+ status = mNormalSink->getNextWriteTimestamp(&pts);
+ } else {
+ status = mOutputSink->getNextWriteTimestamp(&pts);
}
if (status != NO_ERROR) {
@@ -2847,11 +2835,10 @@ void AudioFlinger::MixerThread::threadLoop_sleepTime()
} else {
sleepTime = idleSleepTime;
}
- } else if (mBytesWritten != 0 ||
- (mMixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
+ } else if (mBytesWritten != 0 || (mMixerStatus == MIXER_TRACKS_ENABLED)) {
memset (mMixBuffer, 0, mixBufferSize);
sleepTime = 0;
- ALOGV_IF((mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
+ ALOGV_IF((mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED)), "anticipated start");
}
// TODO add standby time extension fct of effect tail
}
@@ -3229,7 +3216,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
}
//ALOGV("track %d u=%08x, s=%08x [NOT READY] on thread %p", name, cblk->user, cblk->server, this);
- if ((track->sharedBuffer() != 0) || track->isTerminated() ||
+ if ((track->sharedBuffer() != 0) ||
track->isStopped() || track->isPaused()) {
// We have consumed all the buffers of this track.
// Remove it from the list of active tracks.
@@ -3249,8 +3236,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
track->mUnderrunCount++;
// No buffers for this track. Give it a few chances to
// fill a buffer, then remove it from active list.
- if (--(track->mRetryCount) <= 0) {
- ALOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", name, this);
+ if (--(track->mRetryCount) <= 0 || track->isTerminated()) {
+ ALOGV_IF(track->mRetryCount <= 0, "BUFFER TIMEOUT: remove(%d) from active list on thread %p", name, this);
tracksToRemove->add(track);
// indicate to client process that the track was disabled because of underrun;
// it will then automatically call start() when data is available
@@ -3373,7 +3360,7 @@ void AudioFlinger::PlaybackThread::cacheParameters_l()
idleSleepTime = idleSleepTimeUs();
}
-void AudioFlinger::MixerThread::invalidateTracks(audio_stream_type_t streamType)
+void AudioFlinger::PlaybackThread::invalidateTracks(audio_stream_type_t streamType)
{
ALOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d",
this, streamType, mTracks.size());
@@ -3460,14 +3447,14 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
#ifdef ADD_BATTERY_DATA
// when changing the audio output device, call addBatteryData to notify
// the change
- if ((int)mDevice != value) {
+ if (mDevice != value) {
uint32_t params = 0;
// check whether speaker is on
if (value & AUDIO_DEVICE_OUT_SPEAKER) {
params |= IMediaPlayerService::kBatteryDataSpeakerOn;
}
- int deviceWithoutSpeaker
+ audio_devices_t deviceWithoutSpeaker
= AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
// check if any other device (except speaker) is on
if (value & deviceWithoutSpeaker ) {
@@ -3482,7 +3469,7 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
// forward device change to effects that have requested to be
// aware of attached audio device.
- mDevice = (uint32_t)value;
+ mDevice = value;
for (size_t i = 0; i < mEffectChains.size(); i++) {
mEffectChains[i]->setDevice_l(mDevice);
}
@@ -3505,7 +3492,7 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
readOutputParameters();
mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
for (size_t i = 0; i < mTracks.size() ; i++) {
- int name = getTrackName_l((audio_channel_mask_t)mTracks[i]->mChannelMask);
+ int name = getTrackName_l(mTracks[i]->mChannelMask);
if (name < 0) break;
mTracks[i]->mName = name;
// limit track sample rate to 2 x new output sample rate
@@ -3539,7 +3526,7 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
return reconfig;
}
-status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -3593,7 +3580,8 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>
#define TEE_SINK_READ 1024
short buffer[TEE_SINK_READ * FCC_2];
size_t count = TEE_SINK_READ;
- ssize_t actual = teeSource->read(buffer, count);
+ ssize_t actual = teeSource->read(buffer, count,
+ AudioBufferProvider::kInvalidPTS);
bool wasFirstRead = firstRead;
firstRead = false;
if (actual <= 0) {
@@ -3602,7 +3590,7 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>
}
break;
}
- ALOG_ASSERT(actual <= count);
+ ALOG_ASSERT(actual <= (ssize_t)count);
write(teeFd, buffer, actual * channelCount * sizeof(short));
total += actual;
}
@@ -3624,8 +3612,6 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>
AudioWatchdogDump wdCopy = mAudioWatchdogDump;
wdCopy.dump(fd);
}
-
- return NO_ERROR;
}
uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
@@ -3651,7 +3637,7 @@ void AudioFlinger::MixerThread::cacheParameters_l()
// ----------------------------------------------------------------------------
AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
- AudioStreamOut* output, audio_io_handle_t id, uint32_t device)
+ AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device)
: PlaybackThread(audioFlinger, output, id, device, DIRECT)
// mLeftVolFloat, mRightVolFloat
{
@@ -3751,7 +3737,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
}
//ALOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
- if ((track->sharedBuffer() != 0) || track->isTerminated() ||
+ if ((track->sharedBuffer() != 0) ||
track->isStopped() || track->isPaused()) {
// We have consumed all the buffers of this track.
// Remove it from the list of active tracks.
@@ -3769,8 +3755,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
} else {
// No buffers for this track. Give it a few chances to
// fill a buffer, then remove it from active list.
- if (--(track->mRetryCount) <= 0) {
- ALOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+ if (--(track->mRetryCount) <= 0 || track->isTerminated()) {
+ ALOGV_IF(track->mRetryCount <= 0, "BUFFER TIMEOUT: remove(%d) from active list", track->name());
trackToRemove = track;
} else {
mixerStatus = MIXER_TRACKS_ENABLED;
@@ -4070,6 +4056,7 @@ bool AudioFlinger::DuplicatingThread::outputsReady(const SortedVector< sp<Output
return false;
}
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ // see note at standby() declaration
if (playbackThread->standby() && !playbackThread->isSuspended()) {
ALOGV("DuplicatingThread output track %p on thread %p Not Ready", outputTracks[i].get(), thread.get());
return false;
@@ -4099,7 +4086,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
const sp<Client>& client,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId)
@@ -4274,7 +4261,7 @@ AudioFlinger::PlaybackThread::Track::Track(
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId,
@@ -4300,7 +4287,7 @@ AudioFlinger::PlaybackThread::Track::Track(
// 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack
mCblk->frameSize = audio_is_linear_pcm(format) ? mChannelCount * sizeof(int16_t) : sizeof(uint8_t);
// to avoid leaking a track name, do not allocate one unless there is an mCblk
- mName = thread->getTrackName_l((audio_channel_mask_t)channelMask);
+ mName = thread->getTrackName_l(channelMask);
mCblk->mName = mName;
if (mName < 0) {
ALOGE("no more track names available");
@@ -4329,11 +4316,6 @@ AudioFlinger::PlaybackThread::Track::Track(
AudioFlinger::PlaybackThread::Track::~Track()
{
ALOGV("PlaybackThread::Track destructor");
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- Mutex::Autolock _l(thread->mLock);
- mState = TERMINATED;
- }
}
void AudioFlinger::PlaybackThread::Track::destroy()
@@ -4496,8 +4478,6 @@ status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
}
buffer->raw = getBuffer(s, framesReq);
- if (buffer->raw == NULL) goto getNextBuffer_exit;
-
buffer->frameCount = framesReq;
return NO_ERROR;
}
@@ -4821,12 +4801,12 @@ AudioFlinger::PlaybackThread::TimedTrack::create(
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId) {
if (!client->reserveTimedTrack())
- return NULL;
+ return 0;
return new TimedTrack(
thread, client, streamType, sampleRate, format, channelMask, frameCount,
@@ -4839,7 +4819,7 @@ AudioFlinger::PlaybackThread::TimedTrack::TimedTrack(
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId)
@@ -5061,7 +5041,7 @@ status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer(
AudioBufferProvider::Buffer* buffer, int64_t pts)
{
if (pts == AudioBufferProvider::kInvalidPTS) {
- buffer->raw = 0;
+ buffer->raw = NULL;
buffer->frameCount = 0;
mTimedAudioOutputOnTime = false;
return INVALID_OPERATION;
@@ -5076,7 +5056,7 @@ status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer(
// if we have no timed buffers, then fail
if (mTimedBufferQueue.isEmpty()) {
- buffer->raw = 0;
+ buffer->raw = NULL;
buffer->frameCount = 0;
return NOT_ENOUGH_DATA;
}
@@ -5103,7 +5083,7 @@ status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer(
// the transform failed. this shouldn't happen, but if it does
// then just drop this buffer
ALOGW("timedGetNextBuffer transform failed");
- buffer->raw = 0;
+ buffer->raw = NULL;
buffer->frameCount = 0;
trimTimedBufferQueueHead_l("getNextBuffer; no transform");
return NO_ERROR;
@@ -5112,7 +5092,7 @@ status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer(
if (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) {
if (OK != mCCHelper.commonTimeToLocalTime(transformedPTS,
&headLocalPTS)) {
- buffer->raw = 0;
+ buffer->raw = NULL;
buffer->frameCount = 0;
return INVALID_OPERATION;
}
@@ -5334,7 +5314,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
const sp<Client>& client,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
int sessionId)
: TrackBase(thread, client, sampleRate, format,
@@ -5355,10 +5335,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
{
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- AudioSystem::releaseInput(thread->id());
- }
+ ALOGV("%s", __func__);
}
// AudioBufferProvider interface
@@ -5389,8 +5366,6 @@ status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvi
}
buffer->raw = getBuffer(s, framesReq);
- if (buffer->raw == NULL) goto getNextBuffer_exit;
-
buffer->frameCount = framesReq;
return NO_ERROR;
}
@@ -5418,14 +5393,26 @@ void AudioFlinger::RecordThread::RecordTrack::stop()
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
RecordThread *recordThread = (RecordThread *)thread.get();
- recordThread->stop(this);
- TrackBase::reset();
- // Force overrun condition to avoid false overrun callback until first data is
- // read from buffer
- android_atomic_or(CBLK_UNDERRUN_ON, &mCblk->flags);
+ recordThread->mLock.lock();
+ bool doStop = recordThread->stop_l(this);
+ if (doStop) {
+ TrackBase::reset();
+ // Force overrun condition to avoid false overrun callback until first data is
+ // read from buffer
+ android_atomic_or(CBLK_UNDERRUN_ON, &mCblk->flags);
+ }
+ recordThread->mLock.unlock();
+ if (doStop) {
+ AudioSystem::stopInput(recordThread->id());
+ }
}
}
+/*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result)
+{
+ result.append(" Clien Fmt Chn mask Session Buf S SRate Serv User\n");
+}
+
void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
{
snprintf(buffer, size, " %05d %03u 0x%08x %05d %04u %01d %05u %08x %08x\n",
@@ -5448,7 +5435,7 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
DuplicatingThread *sourceThread,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount)
: Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount,
NULL, 0, IAudioFlinger::TRACK_DEFAULT),
@@ -5836,9 +5823,10 @@ sp<IAudioRecord> AudioFlinger::openRecord(
audio_io_handle_t input,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
IAudioFlinger::track_flags_t flags,
+ pid_t tid,
int *sessionId,
status_t *status)
{
@@ -5877,13 +5865,8 @@ sp<IAudioRecord> AudioFlinger::openRecord(
}
}
// create new record track. The record track uses one track in mHardwareMixerThread by convention.
- recordTrack = thread->createRecordTrack_l(client,
- sampleRate,
- format,
- channelMask,
- frameCount,
- lSessionId,
- &lStatus);
+ recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
+ frameCount, lSessionId, flags, tid, &lStatus);
}
if (lStatus != NO_ERROR) {
// remove local strong reference to Client before deleting the RecordTrack so that the Client
@@ -5913,19 +5896,24 @@ AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordThread::Re
}
AudioFlinger::RecordHandle::~RecordHandle() {
- stop();
+ stop_nonvirtual();
+ mRecordTrack->destroy();
}
sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
return mRecordTrack->getCblk();
}
-status_t AudioFlinger::RecordHandle::start(int event, int triggerSession) {
+status_t AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event, int triggerSession) {
ALOGV("RecordHandle::start()");
return mRecordTrack->start((AudioSystem::sync_event_t)event, triggerSession);
}
void AudioFlinger::RecordHandle::stop() {
+ stop_nonvirtual();
+}
+
+void AudioFlinger::RecordHandle::stop_nonvirtual() {
ALOGV("RecordHandle::stop()");
mRecordTrack->stop();
}
@@ -5941,13 +5929,13 @@ status_t AudioFlinger::RecordHandle::onTransact(
AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamIn *input,
uint32_t sampleRate,
- uint32_t channels,
+ audio_channel_mask_t channelMask,
audio_io_handle_t id,
- uint32_t device) :
+ audio_devices_t device) :
ThreadBase(audioFlinger, id, device, RECORD),
- mInput(input), mTrack(NULL), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
+ mInput(input), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
// mRsmpInIndex and mInputBytes set by readInputParameters()
- mReqChannelCount(popcount(channels)),
+ mReqChannelCount(popcount(channelMask)),
mReqSampleRate(sampleRate)
// mBytesRead is only meaningful while active, and so is cleared in start()
// (but might be better to also clear here for dump?)
@@ -5985,6 +5973,7 @@ bool AudioFlinger::RecordThread::threadLoop()
nsecs_t lastWarning = 0;
+ inputStandBy();
acquireWakeLock();
// start recording
@@ -5996,10 +5985,7 @@ bool AudioFlinger::RecordThread::threadLoop()
Mutex::Autolock _l(mLock);
checkForNewParameters_l();
if (mActiveTrack == 0 && mConfigEvents.isEmpty()) {
- if (!mStandby) {
- mInput->stream->common.standby(&mInput->stream->common);
- mStandby = true;
- }
+ standby();
if (exitPending()) break;
@@ -6013,10 +5999,7 @@ bool AudioFlinger::RecordThread::threadLoop()
}
if (mActiveTrack != 0) {
if (mActiveTrack->mState == TrackBase::PAUSING) {
- if (!mStandby) {
- mInput->stream->common.standby(&mInput->stream->common);
- mStandby = true;
- }
+ standby();
mActiveTrack.clear();
mStartStopCond.broadcast();
} else if (mActiveTrack->mState == TrackBase::RESUMING) {
@@ -6034,6 +6017,9 @@ bool AudioFlinger::RecordThread::threadLoop()
mStartStopCond.broadcast();
}
mStandby = false;
+ } else if (mActiveTrack->mState == TrackBase::TERMINATED) {
+ removeTrack_l(mActiveTrack);
+ mActiveTrack.clear();
}
}
lockEffectChains_l(effectChains);
@@ -6068,18 +6054,12 @@ bool AudioFlinger::RecordThread::threadLoop()
mFormat != AUDIO_FORMAT_PCM_16_BIT) {
memcpy(dst, src, framesIn * mFrameSize);
} else {
- int16_t *src16 = (int16_t *)src;
- int16_t *dst16 = (int16_t *)dst;
if (mChannelCount == 1) {
- while (framesIn--) {
- *dst16++ = *src16;
- *dst16++ = *src16++;
- }
+ upmix_to_stereo_i16_from_mono_i16((int16_t *)dst,
+ (int16_t *)src, framesIn);
} else {
- while (framesIn--) {
- *dst16++ = (int16_t)(((int32_t)*src16 + (int32_t)*(src16 + 1)) >> 1);
- src16 += 2;
- }
+ downmix_to_mono_i16_from_stereo_i16((int16_t *)dst,
+ (int16_t *)src, framesIn);
}
}
}
@@ -6097,7 +6077,7 @@ bool AudioFlinger::RecordThread::threadLoop()
if (mActiveTrack->mState == TrackBase::ACTIVE) {
// Force input into standby so that it tries to
// recover at next read attempt
- mInput->stream->common.standby(&mInput->stream->common);
+ inputStandBy();
usleep(kRecordThreadSleepUs);
}
mRsmpInIndex = mFrameCount;
@@ -6120,12 +6100,8 @@ bool AudioFlinger::RecordThread::threadLoop()
if (mChannelCount == 2 && mReqChannelCount == 1) {
ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut);
// the resampler always outputs stereo samples: do post stereo to mono conversion
- int16_t *src = (int16_t *)mRsmpOutBuffer;
- int16_t *dst = buffer.i16;
- while (framesOut--) {
- *dst++ = (int16_t)(((int32_t)*src + (int32_t)*(src + 1)) >> 1);
- src += 2;
- }
+ downmix_to_mono_i16_from_stereo_i16(buffer.i16, (int16_t *)mRsmpOutBuffer,
+ framesOut);
} else {
ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut);
}
@@ -6151,7 +6127,7 @@ bool AudioFlinger::RecordThread::threadLoop()
}
}
}
- mActiveTrack->overflow();
+ mActiveTrack->clearOverflow();
}
// client isn't retrieving buffers fast enough
else {
@@ -6173,12 +6149,13 @@ bool AudioFlinger::RecordThread::threadLoop()
effectChains.clear();
}
- if (!mStandby) {
- mInput->stream->common.standby(&mInput->stream->common);
- }
- mActiveTrack.clear();
+ standby();
- mStartStopCond.broadcast();
+ {
+ Mutex::Autolock _l(mLock);
+ mActiveTrack.clear();
+ mStartStopCond.broadcast();
+ }
releaseWakeLock();
@@ -6186,14 +6163,28 @@ bool AudioFlinger::RecordThread::threadLoop()
return false;
}
+void AudioFlinger::RecordThread::standby()
+{
+ if (!mStandby) {
+ inputStandBy();
+ mStandby = true;
+ }
+}
+
+void AudioFlinger::RecordThread::inputStandBy()
+{
+ mInput->stream->common.standby(&mInput->stream->common);
+}
sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
const sp<AudioFlinger::Client>& client,
uint32_t sampleRate,
audio_format_t format,
- int channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
int sessionId,
+ IAudioFlinger::track_flags_t flags,
+ pid_t tid,
status_t *status)
{
sp<RecordTrack> track;
@@ -6205,6 +6196,8 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createR
goto Exit;
}
+ // FIXME use flags and tid similar to createTrack_l()
+
{ // scope for mLock
Mutex::Autolock _l(mLock);
@@ -6215,11 +6208,11 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createR
lStatus = NO_MEMORY;
goto Exit;
}
+ mTracks.add(track);
- mTrack = track.get();
// disable AEC and NS if the device is a BT SCO headset supporting those pre processings
- bool suspend = audio_is_bluetooth_sco_device(
- (audio_devices_t)(mDevice & AUDIO_DEVICE_IN_ALL)) && mAudioFlinger->btNrecIsOff();
+ bool suspend = audio_is_bluetooth_sco_device(mDevice & AUDIO_DEVICE_IN_ALL) &&
+ mAudioFlinger->btNrecIsOff();
setEffectSuspended_l(FX_IID_AEC, suspend, sessionId);
setEffectSuspended_l(FX_IID_NS, suspend, sessionId);
}
@@ -6337,27 +6330,23 @@ void AudioFlinger::RecordThread::handleSyncStartEvent(const sp<SyncEvent>& event
}
}
-void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
+bool AudioFlinger::RecordThread::stop_l(RecordThread::RecordTrack* recordTrack) {
ALOGV("RecordThread::stop");
- sp<ThreadBase> strongMe = this;
- {
- AutoMutex lock(mLock);
- if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
- mActiveTrack->mState = TrackBase::PAUSING;
- // do not wait for mStartStopCond if exiting
- if (exitPending()) {
- return;
- }
- mStartStopCond.wait(mLock);
- // if we have been restarted, recordTrack == mActiveTrack.get() here
- if (mActiveTrack == 0 || recordTrack != mActiveTrack.get()) {
- mLock.unlock();
- AudioSystem::stopInput(mId);
- mLock.lock();
- ALOGV("Record stopped OK");
- }
- }
+ if (recordTrack != mActiveTrack.get() || recordTrack->mState == TrackBase::PAUSING) {
+ return false;
+ }
+ recordTrack->mState = TrackBase::PAUSING;
+ // do not wait for mStartStopCond if exiting
+ if (exitPending()) {
+ return true;
+ }
+ mStartStopCond.wait(mLock);
+ // if we have been restarted, recordTrack == mActiveTrack.get() here
+ if (exitPending() || recordTrack != mActiveTrack.get()) {
+ ALOGV("Record stopped OK");
+ return true;
}
+ return false;
}
bool AudioFlinger::RecordThread::isValidSyncEvent(const sp<SyncEvent>& event)
@@ -6371,16 +6360,63 @@ status_t AudioFlinger::RecordThread::setSyncEvent(const sp<SyncEvent>& event)
return BAD_VALUE;
}
+ int eventSession = event->triggerSession();
+ status_t ret = NAME_NOT_FOUND;
+
Mutex::Autolock _l(mLock);
- if (mTrack != NULL && event->triggerSession() == mTrack->sessionId()) {
- mTrack->setSyncEvent(event);
- return NO_ERROR;
+ for (size_t i = 0; i < mTracks.size(); i++) {
+ sp<RecordTrack> track = mTracks[i];
+ if (eventSession == track->sessionId()) {
+ track->setSyncEvent(event);
+ ret = NO_ERROR;
+ }
}
- return NAME_NOT_FOUND;
+ return ret;
+}
+
+void AudioFlinger::RecordThread::RecordTrack::destroy()
+{
+ // see comments at AudioFlinger::PlaybackThread::Track::destroy()
+ sp<RecordTrack> keep(this);
+ {
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ if (mState == ACTIVE || mState == RESUMING) {
+ AudioSystem::stopInput(thread->id());
+ }
+ AudioSystem::releaseInput(thread->id());
+ Mutex::Autolock _l(thread->mLock);
+ RecordThread *recordThread = (RecordThread *) thread.get();
+ recordThread->destroyTrack_l(this);
+ }
+ }
+}
+
+// destroyTrack_l() must be called with ThreadBase::mLock held
+void AudioFlinger::RecordThread::destroyTrack_l(const sp<RecordTrack>& track)
+{
+ track->mState = TrackBase::TERMINATED;
+ // active tracks are removed by threadLoop()
+ if (mActiveTrack != track) {
+ removeTrack_l(track);
+ }
+}
+
+void AudioFlinger::RecordThread::removeTrack_l(const sp<RecordTrack>& track)
+{
+ mTracks.remove(track);
+ // need anything related to effects here?
}
-status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
+void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
+{
+ dumpInternals(fd, args);
+ dumpTracks(fd, args);
+ dumpEffectChains(fd, args);
+}
+
+void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -6390,11 +6426,6 @@ status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
result.append(buffer);
if (mActiveTrack != 0) {
- result.append("Active Track:\n");
- result.append(" Clien Fmt Chn mask Session Buf S SRate Serv User\n");
- mActiveTrack->dump(buffer, SIZE);
- result.append(buffer);
-
snprintf(buffer, SIZE, "In index: %d\n", mRsmpInIndex);
result.append(buffer);
snprintf(buffer, SIZE, "In size: %d\n", mInputBytes);
@@ -6405,17 +6436,41 @@ status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
result.append(buffer);
snprintf(buffer, SIZE, "Out sample rate: %d\n", mReqSampleRate);
result.append(buffer);
-
-
} else {
- result.append("No record client\n");
+ result.append("No active record client\n");
}
+
write(fd, result.string(), result.size());
dumpBase(fd, args);
- dumpEffectChains(fd, args);
+}
- return NO_ERROR;
+void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "Input thread %p tracks\n", this);
+ result.append(buffer);
+ RecordTrack::appendDumpHeader(result);
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ sp<RecordTrack> track = mTracks[i];
+ if (track != 0) {
+ track->dump(buffer, SIZE);
+ result.append(buffer);
+ }
+ }
+
+ if (mActiveTrack != 0) {
+ snprintf(buffer, SIZE, "\nInput thread %p active tracks\n", this);
+ result.append(buffer);
+ RecordTrack::appendDumpHeader(result);
+ mActiveTrack->dump(buffer, SIZE);
+ result.append(buffer);
+
+ }
+ write(fd, result.string(), result.size());
}
// AudioBufferProvider interface
@@ -6432,7 +6487,7 @@ status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer*
if (mActiveTrack->mState == TrackBase::ACTIVE) {
// Force input into standby so that it tries to
// recover at next read attempt
- mInput->stream->common.standby(&mInput->stream->common);
+ inputStandBy();
usleep(kRecordThreadSleepUs);
}
buffer->raw = NULL;
@@ -6508,25 +6563,30 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l()
// 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()
+ audio_devices_t newDevice = mDevice;
if (value & AUDIO_DEVICE_OUT_ALL) {
- mDevice &= (uint32_t)~(value & AUDIO_DEVICE_OUT_ALL);
+ newDevice &= ~(value & AUDIO_DEVICE_OUT_ALL);
status = BAD_VALUE;
} else {
- mDevice &= (uint32_t)~(value & AUDIO_DEVICE_IN_ALL);
+ newDevice &= ~(value & AUDIO_DEVICE_IN_ALL);
// disable AEC and NS if the device is a BT SCO headset supporting those pre processings
- if (mTrack != NULL) {
+ if (mTracks.size() > 0) {
bool suspend = audio_is_bluetooth_sco_device(
(audio_devices_t)value) && mAudioFlinger->btNrecIsOff();
- setEffectSuspended_l(FX_IID_AEC, suspend, mTrack->sessionId());
- setEffectSuspended_l(FX_IID_NS, suspend, mTrack->sessionId());
+ 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());
+ }
}
}
- mDevice |= (uint32_t)value;
+ newDevice |= value;
+ mDevice = newDevice; // since mDevice is read by other threads, only write to it once
}
if (status == NO_ERROR) {
status = mInput->stream->common.set_parameters(&mInput->stream->common, keyValuePair.string());
if (status == INVALID_OPERATION) {
- mInput->stream->common.standby(&mInput->stream->common);
+ inputStandBy();
status = mInput->stream->common.set_parameters(&mInput->stream->common,
keyValuePair.string());
}
@@ -6656,23 +6716,28 @@ uint32_t AudioFlinger::RecordThread::hasAudioSession(int sessionId)
result = EFFECT_SESSION;
}
- if (mTrack != NULL && sessionId == mTrack->sessionId()) {
- result |= TRACK_SESSION;
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ if (sessionId == mTracks[i]->sessionId()) {
+ result |= TRACK_SESSION;
+ break;
+ }
}
return result;
}
-AudioFlinger::RecordThread::RecordTrack* AudioFlinger::RecordThread::track()
+KeyedVector<int, bool> AudioFlinger::RecordThread::sessionIds()
{
+ KeyedVector<int, bool> ids;
Mutex::Autolock _l(mLock);
- return mTrack;
-}
-
-AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::getInput() const
-{
- Mutex::Autolock _l(mLock);
- return mInput;
+ for (size_t j = 0; j < mTracks.size(); ++j) {
+ sp<RecordThread::RecordTrack> track = mTracks[j];
+ int sessionId = track->sessionId();
+ if (ids.indexOfKey(sessionId) < 0) {
+ ids.add(sessionId, true);
+ }
+ }
+ return ids;
}
AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::clearInput()
@@ -6730,16 +6795,52 @@ audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
return 0;
}
- if ((mMasterVolumeSupportLvl != MVS_NONE) &&
- (NULL != dev->set_master_volume)) {
+ // Check and cache this HAL's level of support for master mute and master
+ // volume. If this is the first HAL opened, and it supports the get
+ // methods, use the initial values provided by the HAL as the current
+ // master mute and volume settings.
+
+ AudioHwDevice::Flags flags = static_cast<AudioHwDevice::Flags>(0);
+ { // scope for auto-lock pattern
AutoMutex lock(mHardwareLock);
+
+ if (0 == mAudioHwDevs.size()) {
+ mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
+ if (NULL != dev->get_master_volume) {
+ float mv;
+ if (OK == dev->get_master_volume(dev, &mv)) {
+ mMasterVolume = mv;
+ }
+ }
+
+ mHardwareStatus = AUDIO_HW_GET_MASTER_MUTE;
+ if (NULL != dev->get_master_mute) {
+ bool mm;
+ if (OK == dev->get_master_mute(dev, &mm)) {
+ mMasterMute = mm;
+ }
+ }
+ }
+
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
- dev->set_master_volume(dev, mMasterVolume);
+ if ((NULL != dev->set_master_volume) &&
+ (OK == dev->set_master_volume(dev, mMasterVolume))) {
+ flags = static_cast<AudioHwDevice::Flags>(flags |
+ AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME);
+ }
+
+ mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
+ if ((NULL != dev->set_master_mute) &&
+ (OK == dev->set_master_mute(dev, mMasterMute))) {
+ flags = static_cast<AudioHwDevice::Flags>(flags |
+ AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE);
+ }
+
mHardwareStatus = AUDIO_HW_IDLE;
}
audio_module_handle_t handle = nextUniqueId();
- mAudioHwDevs.add(handle, new AudioHwDevice(name, dev));
+ mAudioHwDevs.add(handle, new AudioHwDevice(name, dev, flags));
ALOGI("loadHwModule() Loaded %s audio interface from %s (%s) handle %d",
name, dev->common.module->name, dev->common.module->id, handle);
@@ -6764,11 +6865,11 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
format: pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT,
};
audio_stream_out_t *outStream = NULL;
- audio_hw_device_t *outHwDev;
+ AudioHwDevice *outHwDev;
ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
module,
- (pDevices != NULL) ? (int)*pDevices : 0,
+ (pDevices != NULL) ? *pDevices : 0,
config.sample_rate,
config.format,
config.channel_mask,
@@ -6784,11 +6885,12 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
if (outHwDev == NULL)
return 0;
+ audio_hw_device_t *hwDevHal = outHwDev->hwDevice();
audio_io_handle_t id = nextUniqueId();
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
- status = outHwDev->open_output_stream(outHwDev,
+ status = hwDevHal->open_output_stream(hwDevHal,
id,
*pDevices,
(audio_output_flags_t)flags,
@@ -6832,41 +6934,8 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_SET_MODE;
- outHwDev->set_mode(outHwDev, mMode);
-
- // Determine the level of master volume support the primary audio HAL has,
- // and set the initial master volume at the same time.
- float initialVolume = 1.0;
- mMasterVolumeSupportLvl = MVS_NONE;
-
- mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
- if ((NULL != outHwDev->get_master_volume) &&
- (NO_ERROR == outHwDev->get_master_volume(outHwDev, &initialVolume))) {
- mMasterVolumeSupportLvl = MVS_FULL;
- } else {
- mMasterVolumeSupportLvl = MVS_SETONLY;
- initialVolume = 1.0;
- }
-
- mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
- if ((NULL == outHwDev->set_master_volume) ||
- (NO_ERROR != outHwDev->set_master_volume(outHwDev, initialVolume))) {
- mMasterVolumeSupportLvl = MVS_NONE;
- }
- // now that we have a primary device, initialize master volume on other devices
- for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
- audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
-
- if ((dev != mPrimaryHardwareDev) &&
- (NULL != dev->set_master_volume)) {
- dev->set_master_volume(dev, initialVolume);
- }
- }
+ hwDevHal->set_mode(hwDevHal, mMode);
mHardwareStatus = AUDIO_HW_IDLE;
- mMasterVolumeSW = (MVS_NONE == mMasterVolumeSupportLvl)
- ? initialVolume
- : 1.0;
- mMasterVolume = initialVolume;
}
return id;
}
@@ -6897,6 +6966,11 @@ audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1,
status_t AudioFlinger::closeOutput(audio_io_handle_t output)
{
+ return closeOutput_nonvirtual(output);
+}
+
+status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output)
+{
// keep strong reference on the playback thread so that
// it is not destroyed while exit() is executed
sp<PlaybackThread> thread;
@@ -6928,7 +7002,7 @@ status_t AudioFlinger::closeOutput(audio_io_handle_t output)
AudioStreamOut *out = thread->clearOutput();
ALOG_ASSERT(out != NULL, "out shouldn't be NULL");
// from now on thread->mOutput is NULL
- out->hwDev->close_output_stream(out->hwDev, out->stream);
+ out->hwDev()->close_output_stream(out->hwDev(), out->stream);
delete out;
}
return NO_ERROR;
@@ -6969,7 +7043,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
audio_devices_t *pDevices,
uint32_t *pSamplingRate,
audio_format_t *pFormat,
- uint32_t *pChannelMask)
+ audio_channel_mask_t *pChannelMask)
{
status_t status;
RecordThread *thread = NULL;
@@ -6982,7 +7056,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
audio_format_t reqFormat = config.format;
audio_channel_mask_t reqChannels = config.channel_mask;
audio_stream_in_t *inStream = NULL;
- audio_hw_device_t *inHwDev;
+ AudioHwDevice *inHwDev;
if (pDevices == NULL || *pDevices == 0) {
return 0;
@@ -6994,9 +7068,10 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
if (inHwDev == NULL)
return 0;
+ audio_hw_device_t *inHwHal = inHwDev->hwDevice();
audio_io_handle_t id = nextUniqueId();
- status = inHwDev->open_input_stream(inHwDev, id, *pDevices, &config,
+ status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config,
&inStream);
ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, status %d",
inStream,
@@ -7012,9 +7087,9 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT &&
(config.sample_rate <= 2 * reqSamplingRate) &&
(popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
- ALOGV("openInput() reopening with proposed sampling rate and channels");
+ ALOGV("openInput() reopening with proposed sampling rate and channel mask");
inStream = NULL;
- status = inHwDev->open_input_stream(inHwDev, id, *pDevices, &config, &inStream);
+ status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config, &inStream);
}
if (status == NO_ERROR && inStream != NULL) {
@@ -7023,7 +7098,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
// Start record thread
// RecorThread require both input and output device indication to forward to audio
// pre processing modules
- uint32_t device = (*pDevices) | primaryOutputDevice_l();
+ audio_devices_t device = (*pDevices) | primaryOutputDevice_l();
thread = new RecordThread(this,
input,
reqSamplingRate,
@@ -7036,8 +7111,6 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
if (pFormat != NULL) *pFormat = config.format;
if (pChannelMask != NULL) *pChannelMask = reqChannels;
- input->stream->common.standby(&input->stream->common);
-
// notify client processes of the new input creation
thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED);
return id;
@@ -7048,13 +7121,18 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
status_t AudioFlinger::closeInput(audio_io_handle_t input)
{
+ return closeInput_nonvirtual(input);
+}
+
+status_t AudioFlinger::closeInput_nonvirtual(audio_io_handle_t input)
+{
// keep strong reference on the record thread so that
// it is not destroyed while exit() is executed
sp<RecordThread> thread;
{
Mutex::Autolock _l(mLock);
thread = checkRecordThread_l(input);
- if (thread == NULL) {
+ if (thread == 0) {
return BAD_VALUE;
}
@@ -7069,7 +7147,7 @@ status_t AudioFlinger::closeInput(audio_io_handle_t input)
AudioStreamIn *in = thread->clearInput();
ALOG_ASSERT(in != NULL, "in shouldn't be NULL");
// from now on thread->mInput is NULL
- in->hwDev->close_input_stream(in->hwDev, in->stream);
+ in->hwDev()->close_input_stream(in->hwDev(), in->stream);
delete in;
return NO_ERROR;
@@ -7078,21 +7156,11 @@ status_t AudioFlinger::closeInput(audio_io_handle_t input)
status_t AudioFlinger::setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output)
{
Mutex::Autolock _l(mLock);
- MixerThread *dstThread = checkMixerThread_l(output);
- if (dstThread == NULL) {
- ALOGW("setStreamOutput() bad output id %d", output);
- return BAD_VALUE;
- }
-
ALOGV("setStreamOutput() stream %d to output %d", stream, output);
- audioConfigChanged_l(AudioSystem::STREAM_CONFIG_CHANGED, output, &stream);
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
- if (thread != dstThread && thread->type() != ThreadBase::DIRECT) {
- MixerThread *srcThread = (MixerThread *)thread;
- srcThread->invalidateTracks(stream);
- }
+ thread->invalidateTracks(stream);
}
return NO_ERROR;
@@ -7186,20 +7254,14 @@ void AudioFlinger::purgeStaleEffects_l() {
}
}
if (!found) {
+ Mutex::Autolock _l (t->mLock);
// remove all effects from the chain
while (ec->mEffects.size()) {
sp<EffectModule> effect = ec->mEffects[0];
effect->unPin();
- Mutex::Autolock _l (t->mLock);
t->removeEffect_l(effect);
- for (size_t j = 0; j < effect->mHandles.size(); j++) {
- sp<EffectHandle> handle = effect->mHandles[j].promote();
- if (handle != 0) {
- handle->mEffect.clear();
- if (handle->mHasControl && handle->mEnabled) {
- t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
- }
- }
+ if (effect->purgeHandles()) {
+ t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
}
AudioSystem::unregisterEffect(effect->id());
}
@@ -7237,14 +7299,14 @@ AudioFlinger::PlaybackThread *AudioFlinger::primaryPlaybackThread_l() const
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
AudioStreamOut *output = thread->getOutput();
- if (output != NULL && output->hwDev == mPrimaryHardwareDev) {
+ if (output != NULL && output->audioHwDev == mPrimaryHardwareDev) {
return thread;
}
}
return NULL;
}
-uint32_t AudioFlinger::primaryOutputDevice_l() const
+audio_devices_t AudioFlinger::primaryOutputDevice_l() const
{
PlaybackThread *thread = primaryPlaybackThread_l();
@@ -7401,7 +7463,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
// 0 and the effect is not auxiliary, continue enumeration in case
// an auxiliary version of this effect type is available
found = true;
- memcpy(&d, &desc, sizeof(effect_descriptor_t));
+ d = desc;
if (sessionId != AUDIO_SESSION_OUTPUT_MIX ||
(desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
break;
@@ -7417,7 +7479,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
// connect to output mix (Compliance to OpenSL ES)
if (sessionId == AUDIO_SESSION_OUTPUT_MIX &&
(d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {
- memcpy(&desc, &d, sizeof(effect_descriptor_t));
+ desc = d;
}
}
@@ -7436,7 +7498,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
}
// return effect descriptor
- memcpy(pDesc, &desc, sizeof(effect_descriptor_t));
+ *pDesc = desc;
// If output is not specified try to find a matching audio session ID in one of the
// output threads.
@@ -7670,7 +7732,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
}
// create effect handle and connect it to effect module
handle = new EffectHandle(effect, client, effectClient, priority);
- lStatus = effect->addHandle(handle);
+ lStatus = effect->addHandle(handle.get());
if (enabled != NULL) {
*enabled = (int)effect->isEnabled();
}
@@ -7810,7 +7872,7 @@ void AudioFlinger::ThreadBase::setMode(audio_mode_t mode)
}
void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
- const wp<EffectHandle>& handle,
+ EffectHandle *handle,
bool unpinIfLast) {
Mutex::Autolock _l(mLock);
@@ -8002,16 +8064,18 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread,
effect_descriptor_t *desc,
int id,
int sessionId)
- : mThread(thread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL),
- mStatus(NO_INIT), mState(IDLE), mSuspended(false)
+ : mPinned(sessionId > AUDIO_SESSION_OUTPUT_MIX),
+ mThread(thread), mChain(chain), mId(id), mSessionId(sessionId),
+ mDescriptor(*desc),
+ // mConfig is set by configure() and not used before then
+ mEffectInterface(NULL),
+ mStatus(NO_INIT), mState(IDLE),
+ // mMaxDisableWaitCnt is set by configure() and not used before then
+ // mDisableWaitCnt is set by process() and updateState() and not used before then
+ mSuspended(false)
{
ALOGV("Constructor %p", this);
int lStatus;
- if (thread == NULL) {
- return;
- }
-
- memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t));
// create effect engine from effect factory
mStatus = EffectCreate(&desc->uuid, sessionId, thread->id(), &mEffectInterface);
@@ -8025,9 +8089,6 @@ AudioFlinger::EffectModule::EffectModule(ThreadBase *thread,
goto Error;
}
- if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) {
- mPinned = true;
- }
ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface);
return;
Error:
@@ -8055,38 +8116,41 @@ AudioFlinger::EffectModule::~EffectModule()
}
}
-status_t AudioFlinger::EffectModule::addHandle(const sp<EffectHandle>& handle)
+status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle)
{
status_t status;
Mutex::Autolock _l(mLock);
int priority = handle->priority();
size_t size = mHandles.size();
- sp<EffectHandle> h;
+ EffectHandle *controlHandle = NULL;
size_t i;
for (i = 0; i < size; i++) {
- h = mHandles[i].promote();
- if (h == 0) continue;
+ EffectHandle *h = mHandles[i];
+ if (h == NULL || h->destroyed_l()) continue;
+ // first non destroyed handle is considered in control
+ if (controlHandle == NULL)
+ controlHandle = h;
if (h->priority() <= priority) break;
}
// if inserted in first place, move effect control from previous owner to this handle
if (i == 0) {
bool enabled = false;
- if (h != 0) {
- enabled = h->enabled();
- h->setControl(false/*hasControl*/, true /*signal*/, enabled /*enabled*/);
+ if (controlHandle != NULL) {
+ enabled = controlHandle->enabled();
+ controlHandle->setControl(false/*hasControl*/, true /*signal*/, enabled /*enabled*/);
}
handle->setControl(true /*hasControl*/, false /*signal*/, enabled /*enabled*/);
status = NO_ERROR;
} else {
status = ALREADY_EXISTS;
}
- ALOGV("addHandle() %p added handle %p in position %d", this, handle.get(), i);
+ ALOGV("addHandle() %p added handle %p in position %d", this, handle, i);
mHandles.insertAt(handle, i);
return status;
}
-size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle)
+size_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle)
{
Mutex::Autolock _l(mLock);
size_t size = mHandles.size();
@@ -8097,43 +8161,44 @@ size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle)
if (i == size) {
return size;
}
- ALOGV("removeHandle() %p removed handle %p in position %d", this, handle.unsafe_get(), i);
+ ALOGV("removeHandle() %p removed handle %p in position %d", this, handle, i);
- bool enabled = false;
- EffectHandle *hdl = handle.unsafe_get();
- if (hdl != NULL) {
- ALOGV("removeHandle() unsafe_get OK");
- enabled = hdl->enabled();
- }
mHandles.removeAt(i);
- size = mHandles.size();
// if removed from first place, move effect control from this handle to next in line
- if (i == 0 && size != 0) {
- sp<EffectHandle> h = mHandles[0].promote();
- if (h != 0) {
- h->setControl(true /*hasControl*/, true /*signal*/ , enabled /*enabled*/);
+ if (i == 0) {
+ EffectHandle *h = controlHandle_l();
+ if (h != NULL) {
+ h->setControl(true /*hasControl*/, true /*signal*/ , handle->enabled() /*enabled*/);
}
}
// Prevent calls to process() and other functions on effect interface from now on.
// The effect engine will be released by the destructor when the last strong reference on
// this object is released which can happen after next process is called.
- if (size == 0 && !mPinned) {
+ if (mHandles.size() == 0 && !mPinned) {
mState = DESTROYED;
}
- return size;
+ return mHandles.size();
}
-sp<AudioFlinger::EffectHandle> AudioFlinger::EffectModule::controlHandle()
+// must be called with EffectModule::mLock held
+AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l()
{
- Mutex::Autolock _l(mLock);
- return mHandles.size() != 0 ? mHandles[0].promote() : 0;
+ // the first valid handle in the list has control over the module
+ for (size_t i = 0; i < mHandles.size(); i++) {
+ EffectHandle *h = mHandles[i];
+ if (h != NULL && !h->destroyed_l()) {
+ return h;
+ }
+ }
+
+ return NULL;
}
-void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpinIfLast)
+size_t AudioFlinger::EffectModule::disconnect(EffectHandle *handle, bool unpinIfLast)
{
- ALOGV("disconnect() %p handle %p", this, handle.unsafe_get());
+ ALOGV("disconnect() %p handle %p", this, handle);
// keep a strong reference on this EffectModule to avoid calling the
// destructor before we exit
sp<EffectModule> keep(this);
@@ -8143,6 +8208,7 @@ void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool
thread->disconnectEffect(keep, handle, unpinIfLast);
}
}
+ return mHandles.size();
}
void AudioFlinger::EffectModule::updateState() {
@@ -8240,7 +8306,6 @@ void AudioFlinger::EffectModule::reset_l()
status_t AudioFlinger::EffectModule::configure()
{
- uint32_t channels;
if (mEffectInterface == NULL) {
return NO_INIT;
}
@@ -8251,18 +8316,14 @@ status_t AudioFlinger::EffectModule::configure()
}
// TODO: handle configuration of effects replacing track process
- if (thread->channelCount() == 1) {
- channels = AUDIO_CHANNEL_OUT_MONO;
- } else {
- channels = AUDIO_CHANNEL_OUT_STEREO;
- }
+ audio_channel_mask_t channelMask = thread->channelMask();
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO;
} else {
- mConfig.inputCfg.channels = channels;
+ mConfig.inputCfg.channels = channelMask;
}
- mConfig.outputCfg.channels = channels;
+ mConfig.outputCfg.channels = channelMask;
mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
mConfig.inputCfg.samplingRate = thread->sampleRate();
@@ -8452,8 +8513,8 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode,
if (cmdCode != EFFECT_CMD_GET_PARAM && status == NO_ERROR) {
uint32_t size = (replySize == NULL) ? 0 : *replySize;
for (size_t i = 1; i < mHandles.size(); i++) {
- sp<EffectHandle> h = mHandles[i].promote();
- if (h != 0) {
+ EffectHandle *h = mHandles[i];
+ if (h != NULL && !h->destroyed_l()) {
h->commandExecuted(cmdCode, cmdSize, pCmdData, size, pReplyData);
}
}
@@ -8463,8 +8524,14 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode,
status_t AudioFlinger::EffectModule::setEnabled(bool enabled)
{
-
Mutex::Autolock _l(mLock);
+ return setEnabled_l(enabled);
+}
+
+// must be called with EffectModule::mLock held
+status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled)
+{
+
ALOGV("setEnabled %p enabled %d", this, enabled);
if (enabled != isEnabled()) {
@@ -8499,8 +8566,8 @@ status_t AudioFlinger::EffectModule::setEnabled(bool enabled)
return NO_ERROR; // simply ignore as we are being destroyed
}
for (size_t i = 1; i < mHandles.size(); i++) {
- sp<EffectHandle> h = mHandles[i].promote();
- if (h != 0) {
+ EffectHandle *h = mHandles[i];
+ if (h != NULL && !h->destroyed_l()) {
h->setEnabled(enabled);
}
}
@@ -8573,14 +8640,14 @@ status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right,
return status;
}
-status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
+status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device)
{
Mutex::Autolock _l(mLock);
status_t status = NO_ERROR;
if (device && (mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
// audio pre processing modules on RecordThread can receive both output and
// input device indication in the same call
- uint32_t dev = device & AUDIO_DEVICE_OUT_ALL;
+ audio_devices_t dev = device & AUDIO_DEVICE_OUT_ALL;
if (dev) {
status_t cmdStatus;
uint32_t size = sizeof(status_t);
@@ -8649,7 +8716,23 @@ bool AudioFlinger::EffectModule::suspended() const
return mSuspended;
}
-status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
+bool AudioFlinger::EffectModule::purgeHandles()
+{
+ bool enabled = false;
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mHandles.size(); i++) {
+ EffectHandle *handle = mHandles[i];
+ if (handle != NULL && !handle->destroyed_l()) {
+ handle->effect().clear();
+ if (handle->hasControl()) {
+ enabled = handle->enabled();
+ }
+ }
+ }
+ return enabled;
+}
+
+void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -8715,8 +8798,8 @@ status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
result.append(buffer);
result.append("\t\t\tPid Priority Ctrl Locked client server\n");
for (size_t i = 0; i < mHandles.size(); ++i) {
- sp<EffectHandle> handle = mHandles[i].promote();
- if (handle != 0) {
+ EffectHandle *handle = mHandles[i];
+ if (handle != NULL && !handle->destroyed_l()) {
handle->dump(buffer, SIZE);
result.append(buffer);
}
@@ -8729,8 +8812,6 @@ status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
if (locked) {
mLock.unlock();
}
-
- return NO_ERROR;
}
// ----------------------------------------------------------------------------
@@ -8746,7 +8827,7 @@ AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect,
int32_t priority)
: BnEffect(),
mEffect(effect), mEffectClient(effectClient), mClient(client), mCblk(NULL),
- mPriority(priority), mHasControl(false), mEnabled(false)
+ mPriority(priority), mHasControl(false), mEnabled(false), mDestroyed(false)
{
ALOGV("constructor %p", this);
@@ -8771,8 +8852,15 @@ AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect,
AudioFlinger::EffectHandle::~EffectHandle()
{
ALOGV("Destructor %p", this);
+
+ if (mEffect == 0) {
+ mDestroyed = true;
+ return;
+ }
+ mEffect->lock();
+ mDestroyed = true;
+ mEffect->unlock();
disconnect(false);
- ALOGV("Destructor DONE %p", this);
}
status_t AudioFlinger::EffectHandle::enable()
@@ -8843,9 +8931,8 @@ void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast)
if (mEffect == 0) {
return;
}
- mEffect->disconnect(this, unpinIfLast);
-
- if (mHasControl && mEnabled) {
+ // restore suspended effects if the disconnected handle was enabled and the last one.
+ if ((mEffect->disconnect(this, unpinIfLast) == 0) && mEnabled) {
sp<ThreadBase> thread = mEffect->thread().promote();
if (thread != 0) {
thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
@@ -9275,7 +9362,7 @@ size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect)
}
// setDevice_l() must be called with PlaybackThread::mLock held
-void AudioFlinger::EffectChain::setDevice_l(uint32_t device)
+void AudioFlinger::EffectChain::setDevice_l(audio_devices_t device)
{
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
@@ -9350,7 +9437,7 @@ bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right)
return hasControl;
}
-status_t AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
+void AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -9384,8 +9471,6 @@ status_t AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
if (locked) {
mLock.unlock();
}
-
- return NO_ERROR;
}
// must be called with ThreadBase::mLock held
@@ -9401,7 +9486,7 @@ void AudioFlinger::EffectChain::setEffectSuspended_l(
desc = mSuspendedEffects.valueAt(index);
} else {
desc = new SuspendedEffectDesc();
- memcpy(&desc->mType, type, sizeof(effect_uuid_t));
+ desc->mType = *type;
mSuspendedEffects.add(type->timeLow, desc);
ALOGV("setEffectSuspended_l() add entry for %08x", type->timeLow);
}
@@ -9428,10 +9513,12 @@ void AudioFlinger::EffectChain::setEffectSuspended_l(
sp<EffectModule> effect = desc->mEffect.promote();
if (effect != 0) {
effect->setSuspended(false);
- sp<EffectHandle> handle = effect->controlHandle();
- if (handle != 0) {
- effect->setEnabled(handle->enabled());
+ effect->lock();
+ EffectHandle *handle = effect->controlHandle_l();
+ if (handle != NULL && !handle->destroyed_l()) {
+ effect->setEnabled_l(handle->enabled());
}
+ effect->unlock();
}
desc->mEffect.clear();
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index cfd718f..e5176a9 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -91,7 +91,7 @@ public:
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
IAudioFlinger::track_flags_t flags,
const sp<IMemory>& sharedBuffer,
@@ -105,9 +105,10 @@ public:
audio_io_handle_t input,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
IAudioFlinger::track_flags_t flags,
+ pid_t tid,
int *sessionId,
status_t *status);
@@ -121,7 +122,6 @@ public:
virtual status_t setMasterMute(bool muted);
virtual float masterVolume() const;
- virtual float masterVolumeSW() const;
virtual bool masterMute() const;
virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
@@ -142,7 +142,8 @@ public:
virtual void registerClient(const sp<IAudioFlingerClient>& client);
- virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const;
+ virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
+ audio_channel_mask_t channelMask) const;
virtual audio_io_handle_t openOutput(audio_module_handle_t module,
audio_devices_t *pDevices,
@@ -255,6 +256,8 @@ public:
void *cookie);
private:
+ class AudioHwDevice; // fwd declaration for findSuitableHwDev_l
+
audio_mode_t getMode() const { return mMode; }
bool btNrecIsOff() const { return mBtNrecIsOff; }
@@ -268,17 +271,17 @@ private:
// RefBase
virtual void onFirstRef();
- audio_hw_device_t* findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices);
+ AudioHwDevice* findSuitableHwDev_l(audio_module_handle_t module, audio_devices_t devices);
void purgeStaleEffects_l();
// standby delay for MIXER and DUPLICATING playback threads is read from property
// ro.audio.flinger_standbytime_ms or defaults to kDefaultStandbyTimeInNsecs
static nsecs_t mStandbyTimeInNsecs;
- // Internal dump utilites.
- status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
- status_t dumpClients(int fd, const Vector<String16>& args);
- status_t dumpInternals(int fd, const Vector<String16>& args);
+ // Internal dump utilities.
+ void dumpPermissionDenial(int fd, const Vector<String16>& args);
+ void dumpClients(int fd, const Vector<String16>& args);
+ void dumpInternals(int fd, const Vector<String16>& args);
// --- Client ---
class Client : public RefBase {
@@ -350,11 +353,11 @@ private:
RECORD // Thread class is RecordThread
};
- ThreadBase (const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, uint32_t device, type_t type);
+ ThreadBase (const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, audio_devices_t device, type_t type);
virtual ~ThreadBase();
- status_t dumpBase(int fd, const Vector<String16>& args);
- status_t dumpEffectChains(int fd, const Vector<String16>& args);
+ void dumpBase(int fd, const Vector<String16>& args);
+ void dumpEffectChains(int fd, const Vector<String16>& args);
void clearPowerManager();
@@ -380,14 +383,14 @@ private:
const sp<Client>& client,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId);
virtual ~TrackBase();
- virtual status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
- int triggerSession = 0) = 0;
+ virtual status_t start(AudioSystem::sync_event_t event,
+ int triggerSession) = 0;
virtual void stop() = 0;
sp<IMemory> getCblk() const { return mCblkMemory; }
audio_track_cblk_t* cblk() const { return mCblk; }
@@ -412,10 +415,17 @@ private:
int channelCount() const { return mChannelCount; }
- uint32_t channelMask() const { return mChannelMask; }
+ audio_channel_mask_t channelMask() const { return mChannelMask; }
int sampleRate() const; // FIXME inline after cblk sr moved
+ // Return a pointer to the start of a contiguous slice of the track buffer.
+ // Parameter 'offset' is the requested start position, expressed in
+ // monotonically increasing frame units relative to the track epoch.
+ // Parameter 'frames' is the requested length, also in frame units.
+ // Always returns non-NULL. It is the caller's responsibility to
+ // verify that this will be successful; the result of calling this
+ // function with invalid 'offset' or 'frames' is undefined.
void* getBuffer(uint32_t offset, uint32_t frames) const;
bool isStopped() const {
@@ -455,7 +465,7 @@ private:
bool mStepServerFailed;
const int mSessionId;
uint8_t mChannelCount;
- uint32_t mChannelMask;
+ audio_channel_mask_t mChannelMask;
Vector < sp<SyncEvent> >mSyncEvents;
};
@@ -483,14 +493,20 @@ private:
};
virtual status_t initCheck() const = 0;
+
+ // static externally-visible
type_t type() const { return mType; }
+ audio_io_handle_t id() const { return mId;}
+
+ // dynamic externally-visible
uint32_t sampleRate() const { return mSampleRate; }
int channelCount() const { return mChannelCount; }
+ audio_channel_mask_t channelMask() const { return mChannelMask; }
audio_format_t format() const { return mFormat; }
// Called by AudioFlinger::frameCount(audio_io_handle_t output) and effects,
// and returns the normal mix buffer's frame count. No API for HAL frame count.
size_t frameCount() const { return mNormalFrameCount; }
- void wakeUp() { mWaitWorkCV.broadcast(); }
+
// Should be "virtual status_t requestExitAndWait()" and override same
// method in Thread, but Thread::requestExitAndWait() is not yet virtual.
void exit();
@@ -501,9 +517,11 @@ private:
void sendConfigEvent(int event, int param = 0);
void sendConfigEvent_l(int event, int param = 0);
void processConfigEvents();
- audio_io_handle_t id() const { return mId;}
+
+ // see note at declaration of mStandby and mDevice
bool standby() const { return mStandby; }
- uint32_t device() const { return mDevice; }
+ audio_devices_t device() const { return mDevice; }
+
virtual audio_stream_t* stream() const = 0;
sp<EffectHandle> createEffect_l(
@@ -515,7 +533,7 @@ private:
int *enabled,
status_t *status);
void disconnectEffect(const sp< EffectModule>& effect,
- const wp<EffectHandle>& handle,
+ EffectHandle *handle,
bool unpinIfLast);
// return values for hasAudioSession (bit field)
@@ -598,7 +616,7 @@ private:
void releaseWakeLock_l();
void setEffectSuspended_l(const effect_uuid_t *type,
bool suspend,
- int sessionId = AUDIO_SESSION_OUTPUT_MIX);
+ int sessionId);
// updated mSuspendedSessions when an effect suspended or restored
void updateSuspendedSessions_l(const effect_uuid_t *type,
bool suspend,
@@ -617,7 +635,7 @@ private:
uint32_t mSampleRate;
size_t mFrameCount; // output HAL, direct output, record
size_t mNormalFrameCount; // normal mixer and effects
- uint32_t mChannelMask;
+ audio_channel_mask_t mChannelMask;
uint16_t mChannelCount;
size_t mFrameSize;
audio_format_t mFormat;
@@ -646,11 +664,19 @@ private:
status_t mParamStatus;
Vector<ConfigEvent> mConfigEvents;
- bool mStandby;
+
+ // These fields are written and read by thread itself without lock or barrier,
+ // and read by other threads without lock or barrier via standby() and device().
+ // Because of the absence of a lock or barrier, any other thread that reads
+ // these fields must use the information in isolation, or be prepared to deal
+ // with possibility that it might be inconsistent with other information.
+ bool mStandby; // Whether thread is currently in standby.
+ audio_devices_t mDevice; // output device for PlaybackThread
+ // input + output devices for RecordThread
+
const audio_io_handle_t mId;
Vector< sp<EffectChain> > mEffectChains;
- uint32_t mDevice; // output device for PlaybackThread
- // input + output devices for RecordThread
+
static const int kNameLength = 16; // prctl(PR_SET_NAME) limit
char mName[kNameLength];
sp<IPowerManager> mPowerManager;
@@ -691,7 +717,7 @@ private:
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId,
@@ -708,9 +734,7 @@ private:
void flush();
void destroy();
void mute(bool);
- int name() const {
- return mName;
- }
+ int name() const { return mName; }
audio_stream_type_t streamType() const {
return mStreamType;
@@ -767,10 +791,14 @@ private:
void triggerEvents(AudioSystem::sync_event_t type);
virtual bool isTimedTrack() const { return false; }
bool isFastTrack() const { return (mFlags & IAudioFlinger::TRACK_FAST) != 0; }
+
protected:
- // we don't really need a lock for these
- volatile bool mMute;
+ // written by Track::mute() called by binder thread(s), without a mutex or barrier.
+ // read by Track::isMuted() called by playback thread, also without a mutex or barrier.
+ // The lack of mutex or barrier is safe because the mute status is only used by itself.
+ bool mMute;
+
// FILLED state is used for suppressing volume ramp at begin of playing
enum {FS_INVALID, FS_FILLING, FS_FILLED, FS_ACTIVE};
mutable uint8_t mFillingUpStatus;
@@ -813,11 +841,11 @@ private:
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId);
- ~TimedTrack();
+ virtual ~TimedTrack();
class TimedBuffer {
public:
@@ -856,7 +884,7 @@ private:
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId);
@@ -905,7 +933,7 @@ private:
DuplicatingThread *sourceThread,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount);
virtual ~OutputTrack();
@@ -936,10 +964,10 @@ private:
}; // end of OutputTrack
PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
- audio_io_handle_t id, uint32_t device, type_t type);
+ audio_io_handle_t id, audio_devices_t device, type_t type);
virtual ~PlaybackThread();
- status_t dump(int fd, const Vector<String16>& args);
+ void dump(int fd, const Vector<String16>& args);
// Thread virtuals
virtual status_t readyToRun();
@@ -984,7 +1012,7 @@ public:
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId,
@@ -996,9 +1024,19 @@ public:
AudioStreamOut* clearOutput();
virtual audio_stream_t* stream() const;
- void suspend() { mSuspended++; }
- void restore() { if (mSuspended > 0) mSuspended--; }
- bool isSuspended() const { return (mSuspended > 0); }
+ // a very large number of suspend() will eventually wraparound, but unlikely
+ void suspend() { (void) android_atomic_inc(&mSuspended); }
+ void restore()
+ {
+ // if restore() is done without suspend(), get back into
+ // range so that the next suspend() will operate correctly
+ if (android_atomic_dec(&mSuspended) <= 0) {
+ android_atomic_release_store(0, &mSuspended);
+ }
+ }
+ bool isSuspended() const
+ { return android_atomic_acquire_load(&mSuspended) > 0; }
+
virtual String8 getParameters(const String8& keys);
virtual void audioConfigChanged_l(int event, int param = 0);
status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
@@ -1018,10 +1056,19 @@ public:
virtual status_t setSyncEvent(const sp<SyncEvent>& event);
virtual bool isValidSyncEvent(const sp<SyncEvent>& event);
+ void invalidateTracks(audio_stream_type_t streamType);
+
protected:
int16_t* mMixBuffer;
- uint32_t mSuspended; // suspend count, > 0 means suspended
+
+ // suspend count, > 0 means suspended. While suspended, the thread continues to pull from
+ // tracks and mix, but doesn't write to HAL. A2DP and SCO HAL implementations can't handle
+ // concurrent use of both of them, so Audio Policy Service suspends one of the threads to
+ // workaround that restriction.
+ // 'volatile' means accessed via atomic operations and no lock.
+ volatile int32_t mSuspended;
+
int mBytesWritten;
private:
// mMasterMute is in both PlaybackThread and in AudioFlinger. When a
@@ -1069,13 +1116,14 @@ public:
void readOutputParameters();
- virtual status_t dumpInternals(int fd, const Vector<String16>& args);
- status_t dumpTracks(int fd, const Vector<String16>& args);
+ virtual void dumpInternals(int fd, const Vector<String16>& args);
+ void dumpTracks(int fd, const Vector<String16>& args);
SortedVector< sp<Track> > mTracks;
// mStreamTypes[] uses 1 additional stream type internally for the OutputTrack used by DuplicatingThread
stream_type_t mStreamTypes[AUDIO_STREAM_CNT + 1];
AudioStreamOut *mOutput;
+
float mMasterVolume;
nsecs_t mLastWriteTime;
int mNumWrites;
@@ -1100,7 +1148,6 @@ public:
// FIXME move these declarations into the specific sub-class that needs them
// MIXER only
- bool longStandbyExit;
uint32_t sleepTimeShift;
// same as AudioFlinger::mStandbyTimeInNsecs except for DIRECT which uses a shorter value
@@ -1139,15 +1186,14 @@ public:
MixerThread (const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output,
audio_io_handle_t id,
- uint32_t device,
+ audio_devices_t device,
type_t type = MIXER);
virtual ~MixerThread();
// Thread virtuals
- void invalidateTracks(audio_stream_type_t streamType);
virtual bool checkForNewParameters_l();
- virtual status_t dumpInternals(int fd, const Vector<String16>& args);
+ virtual void dumpInternals(int fd, const Vector<String16>& args);
protected:
virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
@@ -1167,9 +1213,6 @@ public:
AudioMixer* mAudioMixer; // normal mixer
private:
-#ifdef SOAKER
- Thread* mSoaker;
-#endif
// one-time initialization, no locks required
FastMixer* mFastMixer; // non-NULL if there is also a fast mixer
sp<AudioWatchdog> mAudioWatchdog; // non-0 if there is an audio watchdog thread
@@ -1198,7 +1241,7 @@ public:
public:
DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
- audio_io_handle_t id, uint32_t device);
+ audio_io_handle_t id, audio_devices_t device);
virtual ~DirectOutputThread();
// Thread virtuals
@@ -1287,7 +1330,7 @@ private:
bool reRegister);
// return thread associated with primary hardware device, or NULL
PlaybackThread *primaryPlaybackThread_l() const;
- uint32_t primaryOutputDevice_l() const;
+ audio_devices_t primaryOutputDevice_l() const;
sp<PlaybackThread> getEffectThread_l(int sessionId, int EffectId);
@@ -1331,18 +1374,22 @@ private:
const sp<Client>& client,
uint32_t sampleRate,
audio_format_t format,
- uint32_t channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
int sessionId);
virtual ~RecordTrack();
- virtual status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
- int triggerSession = 0);
+ virtual status_t start(AudioSystem::sync_event_t event, int triggerSession);
virtual void stop();
- bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+ void destroy();
+
+ // clear the buffer overflow flag
+ void clearOverflow() { mOverflow = false; }
+ // set the buffer overflow flag and return previous value
bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+ static void appendDumpHeader(String8& result);
void dump(char* buffer, size_t size);
private:
@@ -1355,18 +1402,24 @@ private:
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts = kInvalidPTS);
// releaseBuffer() not overridden
- bool mOverflow;
+ bool mOverflow; // overflow on most recent attempt to fill client buffer
};
-
RecordThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamIn *input,
uint32_t sampleRate,
- uint32_t channels,
+ audio_channel_mask_t channelMask,
audio_io_handle_t id,
- uint32_t device);
+ audio_devices_t device);
virtual ~RecordThread();
+ // no addTrack_l ?
+ void destroyTrack_l(const sp<RecordTrack>& track);
+ void removeTrack_l(const sp<RecordTrack>& track);
+
+ void dumpInternals(int fd, const Vector<String16>& args);
+ void dumpTracks(int fd, const Vector<String16>& args);
+
// Thread
virtual bool threadLoop();
virtual status_t readyToRun();
@@ -1379,17 +1432,22 @@ private:
const sp<AudioFlinger::Client>& client,
uint32_t sampleRate,
audio_format_t format,
- int channelMask,
+ audio_channel_mask_t channelMask,
int frameCount,
int sessionId,
+ IAudioFlinger::track_flags_t flags,
+ pid_t tid,
status_t *status);
status_t start(RecordTrack* recordTrack,
AudioSystem::sync_event_t event,
int triggerSession);
- void stop(RecordTrack* recordTrack);
- status_t dump(int fd, const Vector<String16>& args);
- AudioStreamIn* getInput() const;
+
+ // ask the thread to stop the specified track, and
+ // return true if the caller should then do it's part of the stopping process
+ bool stop_l(RecordTrack* recordTrack);
+
+ void dump(int fd, const Vector<String16>& args);
AudioStreamIn* clearInput();
virtual audio_stream_t* stream() const;
@@ -1406,7 +1464,11 @@ private:
virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
virtual uint32_t hasAudioSession(int sessionId);
- RecordTrack* track();
+
+ // Return the set of unique session IDs across all tracks.
+ // The keys are the session IDs, and the associated values are meaningless.
+ // FIXME replace by Set [and implement Bag/Multiset for other uses].
+ KeyedVector<int, bool> sessionIds();
virtual status_t setSyncEvent(const sp<SyncEvent>& event);
virtual bool isValidSyncEvent(const sp<SyncEvent>& event);
@@ -1417,9 +1479,16 @@ private:
private:
void clearSyncStartEvent();
- RecordThread();
+ // Enter standby if not already in standby, and set mStandby flag
+ void standby();
+
+ // Call the HAL standby method unconditionally, and don't change mStandby flag
+ void inputStandBy();
+
AudioStreamIn *mInput;
- RecordTrack* mTrack;
+ SortedVector < sp<RecordTrack> > mTracks;
+ // mActiveTrack has dual roles: it indicates the current active track, and
+ // is used together with mStartStopCond to indicate start()/stop() progress
sp<RecordTrack> mActiveTrack;
Condition mStartStopCond;
AudioResampler *mResampler;
@@ -1445,12 +1514,15 @@ private:
RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
virtual ~RecordHandle();
virtual sp<IMemory> getCblk() const;
- virtual status_t start(int event, int triggerSession);
+ virtual status_t start(int /*AudioSystem::sync_event_t*/ event, int triggerSession);
virtual void stop();
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
const sp<RecordThread::RecordTrack> mRecordTrack;
+
+ // for use from destructor
+ void stop_nonvirtual();
};
//--- Audio Effect Management
@@ -1510,6 +1582,7 @@ private:
return mSessionId;
}
status_t setEnabled(bool enabled);
+ status_t setEnabled_l(bool enabled);
bool isEnabled() const;
bool isProcessEnabled() const;
@@ -1521,14 +1594,14 @@ private:
void setThread(const wp<ThreadBase>& thread) { mThread = thread; }
const wp<ThreadBase>& thread() { return mThread; }
- status_t addHandle(const sp<EffectHandle>& handle);
- void disconnect(const wp<EffectHandle>& handle, bool unpinIfLast);
- size_t removeHandle (const wp<EffectHandle>& handle);
+ status_t addHandle(EffectHandle *handle);
+ size_t disconnect(EffectHandle *handle, bool unpinIfLast);
+ size_t removeHandle(EffectHandle *handle);
- effect_descriptor_t& desc() { return mDescriptor; }
+ const effect_descriptor_t& desc() const { return mDescriptor; }
wp<EffectChain>& chain() { return mChain; }
- status_t setDevice(uint32_t device);
+ status_t setDevice(audio_devices_t device);
status_t setVolume(uint32_t *left, uint32_t *right, bool controller);
status_t setMode(audio_mode_t mode);
status_t start();
@@ -1536,12 +1609,15 @@ private:
void setSuspended(bool suspended);
bool suspended() const;
- sp<EffectHandle> controlHandle();
+ EffectHandle* controlHandle_l();
bool isPinned() const { return mPinned; }
void unPin() { mPinned = false; }
+ bool purgeHandles();
+ void lock() { mLock.lock(); }
+ void unlock() { mLock.unlock(); }
- status_t dump(int fd, const Vector<String16>& args);
+ void dump(int fd, const Vector<String16>& args);
protected:
friend class AudioFlinger; // for mHandles
@@ -1559,14 +1635,14 @@ private:
mutable Mutex mLock; // mutex for process, commands and handles list protection
wp<ThreadBase> mThread; // parent thread
wp<EffectChain> mChain; // parent effect chain
- int mId; // this instance unique ID
- int mSessionId; // audio session ID
- effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
+ const int mId; // this instance unique ID
+ const int mSessionId; // audio session ID
+ const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
effect_config_t mConfig; // input and output audio configuration
effect_handle_t mEffectInterface; // Effect module C API
status_t mStatus; // initialization status
effect_state mState; // current activation state
- Vector< wp<EffectHandle> > mHandles; // list of client handles
+ Vector<EffectHandle *> mHandles; // list of client handles
// First handle in mHandles has highest priority and controls the effect module
uint32_t mMaxDisableWaitCnt; // maximum grace period before forcing an effect off after
// sending disable command.
@@ -1624,6 +1700,8 @@ mutable Mutex mLock; // mutex for process, commands and handl
int priority() const { return mPriority; }
bool hasControl() const { return mHasControl; }
sp<EffectModule> effect() const { return mEffect; }
+ // destroyed_l() must be called with the associated EffectModule mLock held
+ bool destroyed_l() const { return mDestroyed; }
void dump(char* buffer, size_t size);
@@ -1642,6 +1720,8 @@ mutable Mutex mLock; // mutex for process, commands and handl
bool mHasControl; // true if this handle is controlling the effect
bool mEnabled; // cached enable state: needed when the effect is
// restored after being suspended
+ bool mDestroyed; // Set to true by destructor. Access with EffectModule
+ // mLock held
};
// the EffectChain class represents a group of effects associated to one audio session.
@@ -1684,7 +1764,7 @@ mutable Mutex mLock; // mutex for process, commands and handl
sp<EffectModule> getEffectFromId_l(int id);
sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
bool setVolume_l(uint32_t *left, uint32_t *right);
- void setDevice_l(uint32_t device);
+ void setDevice_l(audio_devices_t device);
void setMode_l(audio_mode_t mode);
void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
@@ -1703,12 +1783,12 @@ mutable Mutex mLock; // mutex for process, commands and handl
void incTrackCnt() { android_atomic_inc(&mTrackCnt); }
void decTrackCnt() { android_atomic_dec(&mTrackCnt); }
- int32_t trackCnt() const { return mTrackCnt;}
+ int32_t trackCnt() const { return android_atomic_acquire_load(&mTrackCnt); }
void incActiveTrackCnt() { android_atomic_inc(&mActiveTrackCnt);
mTailBufferCount = mMaxTailBuffers; }
void decActiveTrackCnt() { android_atomic_dec(&mActiveTrackCnt); }
- int32_t activeTrackCnt() const { return mActiveTrackCnt;}
+ int32_t activeTrackCnt() const { return android_atomic_acquire_load(&mActiveTrackCnt); }
uint32_t strategy() const { return mStrategy; }
void setStrategy(uint32_t strategy)
@@ -1725,7 +1805,7 @@ mutable Mutex mLock; // mutex for process, commands and handl
void clearInputBuffer();
- status_t dump(int fd, const Vector<String16>& args);
+ void dump(int fd, const Vector<String16>& args);
protected:
friend class AudioFlinger; // for mThread, mEffects
@@ -1760,8 +1840,11 @@ mutable Mutex mLock; // mutex for process, commands and handl
int mSessionId; // audio session ID
int16_t *mInBuffer; // chain input buffer
int16_t *mOutBuffer; // chain output buffer
- volatile int32_t mActiveTrackCnt; // number of active tracks connected
- volatile int32_t mTrackCnt; // number of tracks connected
+
+ // 'volatile' here means these are accessed with atomic operations instead of mutex
+ volatile int32_t mActiveTrackCnt; // number of active tracks connected
+ volatile int32_t mTrackCnt; // number of tracks connected
+
int32_t mTailBufferCount; // current effect tail buffer count
int32_t mMaxTailBuffers; // maximum effect tail buffers
bool mOwnInBuffer; // true if the chain owns its input buffer
@@ -1778,24 +1861,59 @@ mutable Mutex mLock; // mutex for process, commands and handl
KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
};
+ class AudioHwDevice {
+ public:
+ enum Flags {
+ AHWD_CAN_SET_MASTER_VOLUME = 0x1,
+ AHWD_CAN_SET_MASTER_MUTE = 0x2,
+ };
+
+ AudioHwDevice(const char *moduleName,
+ audio_hw_device_t *hwDevice,
+ Flags flags)
+ : mModuleName(strdup(moduleName))
+ , mHwDevice(hwDevice)
+ , mFlags(flags) { }
+ /*virtual*/ ~AudioHwDevice() { free((void *)mModuleName); }
+
+ bool canSetMasterVolume() const {
+ return (0 != (mFlags & AHWD_CAN_SET_MASTER_VOLUME));
+ }
+
+ bool canSetMasterMute() const {
+ return (0 != (mFlags & AHWD_CAN_SET_MASTER_MUTE));
+ }
+
+ const char *moduleName() const { return mModuleName; }
+ audio_hw_device_t *hwDevice() const { return mHwDevice; }
+ private:
+ const char * const mModuleName;
+ audio_hw_device_t * const mHwDevice;
+ Flags mFlags;
+ };
+
// AudioStreamOut and AudioStreamIn are immutable, so their fields are const.
// For emphasis, we could also make all pointers to them be "const *",
// but that would clutter the code unnecessarily.
struct AudioStreamOut {
- audio_hw_device_t* const hwDev;
+ AudioHwDevice* const audioHwDev;
audio_stream_out_t* const stream;
- AudioStreamOut(audio_hw_device_t *dev, audio_stream_out_t *out) :
- hwDev(dev), stream(out) {}
+ audio_hw_device_t* hwDev() const { return audioHwDev->hwDevice(); }
+
+ AudioStreamOut(AudioHwDevice *dev, audio_stream_out_t *out) :
+ audioHwDev(dev), stream(out) {}
};
struct AudioStreamIn {
- audio_hw_device_t* const hwDev;
+ AudioHwDevice* const audioHwDev;
audio_stream_in_t* const stream;
- AudioStreamIn(audio_hw_device_t *dev, audio_stream_in_t *in) :
- hwDev(dev), stream(in) {}
+ audio_hw_device_t* hwDev() const { return audioHwDev->hwDevice(); }
+
+ AudioStreamIn(AudioHwDevice *dev, audio_stream_in_t *in) :
+ audioHwDev(dev), stream(in) {}
};
// for mAudioSessionRefs only
@@ -1807,41 +1925,6 @@ mutable Mutex mLock; // mutex for process, commands and handl
int mCnt;
};
- enum master_volume_support {
- // MVS_NONE:
- // Audio HAL has no support for master volume, either setting or
- // getting. All master volume control must be implemented in SW by the
- // AudioFlinger mixing core.
- MVS_NONE,
-
- // MVS_SETONLY:
- // Audio HAL has support for setting master volume, but not for getting
- // master volume (original HAL design did not include a getter).
- // AudioFlinger needs to keep track of the last set master volume in
- // addition to needing to set an initial, default, master volume at HAL
- // load time.
- MVS_SETONLY,
-
- // MVS_FULL:
- // Audio HAL has support both for setting and getting master volume.
- // AudioFlinger should send all set and get master volume requests
- // directly to the HAL.
- MVS_FULL,
- };
-
- class AudioHwDevice {
- public:
- AudioHwDevice(const char *moduleName, audio_hw_device_t *hwDevice) :
- mModuleName(strdup(moduleName)), mHwDevice(hwDevice){}
- ~AudioHwDevice() { free((void *)mModuleName); }
-
- const char *moduleName() const { return mModuleName; }
- audio_hw_device_t *hwDevice() const { return mHwDevice; }
- private:
- const char * const mModuleName;
- audio_hw_device_t * const mHwDevice;
- };
-
mutable Mutex mLock;
DefaultKeyedVector< pid_t, wp<Client> > mClients; // see ~Client()
@@ -1851,7 +1934,7 @@ mutable Mutex mLock; // mutex for process, commands and handl
// always take mLock before mHardwareLock
// These two fields are immutable after onFirstRef(), so no lock needed to access
- audio_hw_device_t* mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL
+ AudioHwDevice* mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL
DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*> mAudioHwDevs;
// for dump, indicates which hardware operation is currently in progress (but not stream ops)
@@ -1875,6 +1958,8 @@ mutable Mutex mLock; // mutex for process, commands and handl
AUDIO_HW_GET_INPUT_BUFFER_SIZE, // get_input_buffer_size
AUDIO_HW_GET_MASTER_VOLUME, // get_master_volume
AUDIO_HW_GET_PARAMETER, // get_parameters
+ AUDIO_HW_SET_MASTER_MUTE, // set_master_mute
+ AUDIO_HW_GET_MASTER_MUTE, // get_master_mute
};
mutable hardware_call_state mHardwareStatus; // for dump only
@@ -1885,8 +1970,6 @@ mutable Mutex mLock; // mutex for process, commands and handl
// both are protected by mLock
float mMasterVolume;
- float mMasterVolumeSW;
- master_volume_support mMasterVolumeSupportLvl;
bool mMasterMute;
DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads;
@@ -1900,8 +1983,7 @@ mutable Mutex mLock; // mutex for process, commands and handl
Vector<AudioSessionRef*> mAudioSessionRefs;
float masterVolume_l() const;
- float masterVolumeSW_l() const { return mMasterVolumeSW; }
- bool masterMute_l() const { return mMasterMute; }
+ bool masterMute_l() const;
audio_module_handle_t loadHwModule_l(const char *name);
Vector < sp<SyncEvent> > mPendingSyncEvents; // sync events awaiting for a session
@@ -1910,6 +1992,9 @@ mutable Mutex mLock; // mutex for process, commands and handl
private:
sp<Client> registerPid_l(pid_t pid); // always returns non-0
+ // for use from destructor
+ status_t closeOutput_nonvirtual(audio_io_handle_t output);
+ status_t closeInput_nonvirtual(audio_io_handle_t input);
};
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 3e4c55e..a9814a1 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -416,7 +416,7 @@ void AudioMixer::setParameter(int name, int target, int param, void *value)
case TRACK:
switch (param) {
case CHANNEL_MASK: {
- uint32_t mask = (uint32_t)value;
+ audio_channel_mask_t mask = (audio_channel_mask_t) value;
if (track.channelMask != mask) {
uint32_t channelCount = popcount(mask);
ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount);
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 0d13970..3a2dbe2 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -223,7 +223,7 @@ audio_policy_forced_cfg_t AudioPolicyService::getForceUse(audio_policy_force_use
audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream,
uint32_t samplingRate,
audio_format_t format,
- uint32_t channels,
+ audio_channel_mask_t channelMask,
audio_output_flags_t flags)
{
if (mpAudioPolicy == NULL) {
@@ -231,7 +231,7 @@ audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream,
}
ALOGV("getOutput() tid %d", gettid());
Mutex::Autolock _l(mLock);
- return mpAudioPolicy->get_output(mpAudioPolicy, stream, samplingRate, format, channels, flags);
+ return mpAudioPolicy->get_output(mpAudioPolicy, stream, samplingRate, format, channelMask, flags);
}
status_t AudioPolicyService::startOutput(audio_io_handle_t output,
@@ -271,8 +271,7 @@ void AudioPolicyService::releaseOutput(audio_io_handle_t output)
audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource,
uint32_t samplingRate,
audio_format_t format,
- uint32_t channels,
- audio_in_acoustics_t acoustics,
+ audio_channel_mask_t channelMask,
int audioSession)
{
if (mpAudioPolicy == NULL) {
@@ -283,8 +282,9 @@ audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource,
return 0;
}
Mutex::Autolock _l(mLock);
+ // the audio_in_acoustics_t parameter is ignored by get_input()
audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
- format, channels, acoustics);
+ format, channelMask, (audio_in_acoustics_t) 0);
if (input == 0) {
return input;
@@ -373,6 +373,7 @@ status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream,
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
return BAD_VALUE;
}
+ Mutex::Autolock _l(mLock);
mpAudioPolicy->init_stream_volume(mpAudioPolicy, stream, indexMin, indexMax);
return NO_ERROR;
}
@@ -390,7 +391,7 @@ status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
return BAD_VALUE;
}
-
+ Mutex::Autolock _l(mLock);
if (mpAudioPolicy->set_stream_volume_index_for_device) {
return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy,
stream,
@@ -411,6 +412,7 @@ status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream,
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
return BAD_VALUE;
}
+ Mutex::Autolock _l(mLock);
if (mpAudioPolicy->get_stream_volume_index_for_device) {
return mpAudioPolicy->get_stream_volume_index_for_device(mpAudioPolicy,
stream,
@@ -439,7 +441,7 @@ audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stre
return mpAudioPolicy->get_devices_for_stream(mpAudioPolicy, stream);
}
-audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *desc)
+audio_io_handle_t AudioPolicyService::getOutputForEffect(const effect_descriptor_t *desc)
{
if (mpAudioPolicy == NULL) {
return NO_INIT;
@@ -448,7 +450,7 @@ audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *de
return mpAudioPolicy->get_output_for_effect(mpAudioPolicy, desc);
}
-status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc,
+status_t AudioPolicyService::registerEffect(const effect_descriptor_t *desc,
audio_io_handle_t io,
uint32_t strategy,
int session,
@@ -512,7 +514,7 @@ status_t AudioPolicyService::queryDefaultPreProcessing(int audioSession,
for (size_t i = 0; i < effects.size(); i++) {
effect_descriptor_t desc = effects[i]->descriptor();
if (i < *count) {
- memcpy(descriptors + i, &desc, sizeof(effect_descriptor_t));
+ descriptors[i] = desc;
}
}
if (effects.size() > *count) {
@@ -778,7 +780,6 @@ void AudioPolicyService::AudioCommandThread::startToneCommand(ToneGenerator::ton
data->mType = type;
data->mStream = stream;
command->mParam = (void *)data;
- command->mWaitStatus = false;
Mutex::Autolock _l(mLock);
insertCommand_l(command);
ALOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream);
@@ -790,7 +791,6 @@ void AudioPolicyService::AudioCommandThread::stopToneCommand()
AudioCommand *command = new AudioCommand();
command->mCommand = STOP_TONE;
command->mParam = NULL;
- command->mWaitStatus = false;
Mutex::Autolock _l(mLock);
insertCommand_l(command);
ALOGV("AudioCommandThread() adding tone stop");
@@ -811,11 +811,6 @@ status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type
data->mVolume = volume;
data->mIO = output;
command->mParam = data;
- if (delayMs == 0) {
- command->mWaitStatus = true;
- } else {
- command->mWaitStatus = false;
- }
Mutex::Autolock _l(mLock);
insertCommand_l(command, delayMs);
ALOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d",
@@ -841,11 +836,6 @@ status_t AudioPolicyService::AudioCommandThread::parametersCommand(audio_io_hand
data->mIO = ioHandle;
data->mKeyValuePairs = String8(keyValuePairs);
command->mParam = data;
- if (delayMs == 0) {
- command->mWaitStatus = true;
- } else {
- command->mWaitStatus = false;
- }
Mutex::Autolock _l(mLock);
insertCommand_l(command, delayMs);
ALOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d",
@@ -868,11 +858,6 @@ status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume
VoiceVolumeData *data = new VoiceVolumeData();
data->mVolume = volume;
command->mParam = data;
- if (delayMs == 0) {
- command->mWaitStatus = true;
- } else {
- command->mWaitStatus = false;
- }
Mutex::Autolock _l(mLock);
insertCommand_l(command, delayMs);
ALOGV("AudioCommandThread() adding set voice volume volume %f", volume);
@@ -891,6 +876,7 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
ssize_t i; // not size_t because i will count down to -1
Vector <AudioCommand *> removedCommands;
+ nsecs_t time = 0;
command->mTime = systemTime() + milliseconds(delayMs);
// acquire wake lock to make sure delayed commands are processed
@@ -936,6 +922,7 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
} else {
data2->mKeyValuePairs = param2.toString();
}
+ time = command2->mTime;
} break;
case SET_VOLUME: {
@@ -946,6 +933,7 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
ALOGV("Filtering out volume command on output %d for stream %d",
data->mIO, data->mStream);
removedCommands.add(command2);
+ time = command2->mTime;
} break;
case START_TONE:
case STOP_TONE:
@@ -967,6 +955,17 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
}
removedCommands.clear();
+ // wait for status only if delay is 0 and command time was not modified above
+ if (delayMs == 0 && time == 0) {
+ command->mWaitStatus = true;
+ } else {
+ command->mWaitStatus = false;
+ }
+ // update command time if modified above
+ if (time != 0) {
+ command->mTime = time;
+ }
+
// insert command at the right place according to its time stamp
ALOGV("inserting command: %d at index %d, num commands %d",
command->mCommand, (int)i+1, mAudioCommands.size());
@@ -1422,7 +1421,7 @@ static int aps_restore_output(void *service, audio_io_handle_t output)
return af->restoreOutput(output);
}
-// deprecated: replaced by aps_open_input_on_module()
+// deprecated: replaced by aps_open_input_on_module(), and acoustics parameter is ignored
static audio_io_handle_t aps_open_input(void *service,
audio_devices_t *pDevices,
uint32_t *pSamplingRate,
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index fbca000..a086734 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -64,7 +64,7 @@ public:
virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
uint32_t samplingRate = 0,
audio_format_t format = AUDIO_FORMAT_DEFAULT,
- uint32_t channels = 0,
+ audio_channel_mask_t channelMask = 0,
audio_output_flags_t flags =
AUDIO_OUTPUT_FLAG_NONE);
virtual status_t startOutput(audio_io_handle_t output,
@@ -77,9 +77,7 @@ public:
virtual audio_io_handle_t getInput(audio_source_t inputSource,
uint32_t samplingRate = 0,
audio_format_t format = AUDIO_FORMAT_DEFAULT,
- uint32_t channels = 0,
- audio_in_acoustics_t acoustics =
- (audio_in_acoustics_t)0 /*AUDIO_IN_ACOUSTICS_NONE*/,
+ audio_channel_mask_t channelMask = 0,
int audioSession = 0);
virtual status_t startInput(audio_io_handle_t input);
virtual status_t stopInput(audio_io_handle_t input);
@@ -97,8 +95,8 @@ public:
virtual uint32_t getStrategyForStream(audio_stream_type_t stream);
virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
- virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
- virtual status_t registerEffect(effect_descriptor_t *desc,
+ virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc);
+ virtual status_t registerEffect(const effect_descriptor_t *desc,
audio_io_handle_t io,
uint32_t strategy,
int session,
diff --git a/services/audioflinger/AudioStreamOutSink.cpp b/services/audioflinger/AudioStreamOutSink.cpp
index 8a5aa0c..bc2d15b 100644
--- a/services/audioflinger/AudioStreamOutSink.cpp
+++ b/services/audioflinger/AudioStreamOutSink.cpp
@@ -67,4 +67,16 @@ ssize_t AudioStreamOutSink::write(const void *buffer, size_t count)
return ret;
}
+status_t AudioStreamOutSink::getNextWriteTimestamp(int64_t *timestamp) {
+ ALOG_ASSERT(timestamp != NULL);
+
+ if (NULL == mStream)
+ return INVALID_OPERATION;
+
+ if (NULL == mStream->get_next_write_timestamp)
+ return INVALID_OPERATION;
+
+ return mStream->get_next_write_timestamp(mStream, timestamp);
+}
+
} // namespace android
diff --git a/services/audioflinger/AudioStreamOutSink.h b/services/audioflinger/AudioStreamOutSink.h
index 1eff3f6..5976b18 100644
--- a/services/audioflinger/AudioStreamOutSink.h
+++ b/services/audioflinger/AudioStreamOutSink.h
@@ -47,6 +47,11 @@ public:
virtual ssize_t write(const void *buffer, size_t count);
+ // AudioStreamOutSink wraps a HAL's output stream. Its
+ // getNextWriteTimestamp method is simply a passthru to the HAL's underlying
+ // implementation of GNWT (if any)
+ virtual status_t getNextWriteTimestamp(int64_t *timestamp);
+
// NBAIO_Sink end
#if 0 // until necessary
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 7652132..fbcc11a 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -222,8 +222,8 @@ bool FastMixer::threadLoop()
mixBuffer = new short[frameCount * 2];
periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00
underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75
- overrunNs = (frameCount * 250000000LL) / sampleRate; // 0.25
- forceNs = (frameCount * 750000000LL) / sampleRate; // 0.75
+ overrunNs = (frameCount * 500000000LL) / sampleRate; // 0.50
+ forceNs = (frameCount * 950000000LL) / sampleRate; // 0.95
warmupNs = (frameCount * 500000000LL) / sampleRate; // 0.50
} else {
periodNs = 0;
@@ -399,8 +399,13 @@ bool FastMixer::threadLoop()
ftDump->mUnderruns = underruns;
ftDump->mFramesReady = framesReady;
}
+
+ int64_t pts;
+ if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts)))
+ pts = AudioBufferProvider::kInvalidPTS;
+
// process() is CPU-bound
- mixer->process(AudioBufferProvider::kInvalidPTS);
+ mixer->process(pts);
mixBufferState = MIXED;
} else if (mixBufferState == MIXED) {
mixBufferState = UNDEFINED;
diff --git a/services/audioflinger/MonoPipe.cpp b/services/audioflinger/MonoPipe.cpp
index f3fc19a..bd876b4 100644
--- a/services/audioflinger/MonoPipe.cpp
+++ b/services/audioflinger/MonoPipe.cpp
@@ -17,17 +17,22 @@
#define LOG_TAG "MonoPipe"
//#define LOG_NDEBUG 0
+#include <common_time/cc_helper.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
+#include <utils/LinearTransform.h>
#include <utils/Log.h>
#include <utils/Trace.h>
+#include "AudioBufferProvider.h"
#include "MonoPipe.h"
#include "roundup.h"
+
namespace android {
MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) :
NBAIO_Sink(format),
+ mUpdateSeq(0),
mReqFrames(reqFrames),
mMaxFrames(roundup(reqFrames)),
mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
@@ -38,6 +43,37 @@ MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) :
mSetpoint((reqFrames * 11) / 16),
mWriteCanBlock(writeCanBlock)
{
+ CCHelper tmpHelper;
+ status_t res;
+ uint64_t N, D;
+
+ mNextRdPTS = AudioBufferProvider::kInvalidPTS;
+
+ mSamplesToLocalTime.a_zero = 0;
+ mSamplesToLocalTime.b_zero = 0;
+ mSamplesToLocalTime.a_to_b_numer = 0;
+ mSamplesToLocalTime.a_to_b_denom = 0;
+
+ D = Format_sampleRate(format);
+ if (OK != (res = tmpHelper.getLocalFreq(&N))) {
+ ALOGE("Failed to fetch local time frequency when constructing a"
+ " MonoPipe (res = %d). getNextWriteTimestamp calls will be"
+ " non-functional", res);
+ return;
+ }
+
+ LinearTransform::reduce(&N, &D);
+ static const uint64_t kSignedHiBitsMask = ~(0x7FFFFFFFull);
+ static const uint64_t kUnsignedHiBitsMask = ~(0xFFFFFFFFull);
+ if ((N & kSignedHiBitsMask) || (D & kUnsignedHiBitsMask)) {
+ ALOGE("Cannot reduce sample rate to local clock frequency ratio to fit"
+ " in a 32/32 bit rational. (max reduction is 0x%016llx/0x%016llx"
+ "). getNextWriteTimestamp calls will be non-functional", N, D);
+ return;
+ }
+
+ mSamplesToLocalTime.a_to_b_numer = static_cast<int32_t>(N);
+ mSamplesToLocalTime.a_to_b_denom = static_cast<uint32_t>(D);
}
MonoPipe::~MonoPipe()
@@ -162,4 +198,102 @@ void MonoPipe::setAvgFrames(size_t setpoint)
mSetpoint = setpoint;
}
+status_t MonoPipe::getNextWriteTimestamp(int64_t *timestamp)
+{
+ int32_t front;
+
+ ALOG_ASSERT(NULL != timestamp);
+
+ if (0 == mSamplesToLocalTime.a_to_b_denom)
+ return UNKNOWN_ERROR;
+
+ observeFrontAndNRPTS(&front, timestamp);
+
+ if (AudioBufferProvider::kInvalidPTS != *timestamp) {
+ // If we have a valid read-pointer and next read timestamp pair, then
+ // use the current value of the write pointer to figure out how many
+ // frames are in the buffer, and offset the timestamp by that amt. Then
+ // next time we write to the MonoPipe, the data will hit the speakers at
+ // the next read timestamp plus the current amount of data in the
+ // MonoPipe.
+ size_t pendingFrames = (mRear - front) & (mMaxFrames - 1);
+ *timestamp = offsetTimestampByAudioFrames(*timestamp, pendingFrames);
+ }
+
+ return OK;
+}
+
+void MonoPipe::updateFrontAndNRPTS(int32_t newFront, int64_t newNextRdPTS)
+{
+ // Set the MSB of the update sequence number to indicate that there is a
+ // multi-variable update in progress. Use an atomic store with an "acquire"
+ // barrier to make sure that the next operations cannot be re-ordered and
+ // take place before the change to mUpdateSeq is commited..
+ int32_t tmp = mUpdateSeq | 0x80000000;
+ android_atomic_acquire_store(tmp, &mUpdateSeq);
+
+ // Update mFront and mNextRdPTS
+ mFront = newFront;
+ mNextRdPTS = newNextRdPTS;
+
+ // We are finished with the update. Compute the next sequnce number (which
+ // should be the old sequence number, plus one, and with the MSB cleared)
+ // and then store it in mUpdateSeq using an atomic store with a "release"
+ // barrier so our update operations cannot be re-ordered past the update of
+ // the sequence number.
+ tmp = (tmp + 1) & 0x7FFFFFFF;
+ android_atomic_release_store(tmp, &mUpdateSeq);
+}
+
+void MonoPipe::observeFrontAndNRPTS(int32_t *outFront, int64_t *outNextRdPTS)
+{
+ // Perform an atomic observation of mFront and mNextRdPTS. Basically,
+ // atomically observe the sequence number, then observer the variables, then
+ // atomically observe the sequence number again. If the two observations of
+ // the sequence number match, and the update-in-progress bit was not set,
+ // then we know we have a successful atomic observation. Otherwise, we loop
+ // around and try again.
+ //
+ // Note, it is very important that the observer be a lower priority thread
+ // than the updater. If the updater is lower than the observer, or they are
+ // the same priority and running with SCHED_FIFO (implying that quantum
+ // based premption is disabled) then we run the risk of deadlock.
+ int32_t seqOne, seqTwo;
+
+ do {
+ seqOne = android_atomic_acquire_load(&mUpdateSeq);
+ *outFront = mFront;
+ *outNextRdPTS = mNextRdPTS;
+ seqTwo = android_atomic_release_load(&mUpdateSeq);
+ } while ((seqOne != seqTwo) || (seqOne & 0x80000000));
+}
+
+int64_t MonoPipe::offsetTimestampByAudioFrames(int64_t ts, size_t audFrames)
+{
+ if (0 == mSamplesToLocalTime.a_to_b_denom)
+ return AudioBufferProvider::kInvalidPTS;
+
+ if (ts == AudioBufferProvider::kInvalidPTS)
+ return AudioBufferProvider::kInvalidPTS;
+
+ int64_t frame_lt_duration;
+ if (!mSamplesToLocalTime.doForwardTransform(audFrames,
+ &frame_lt_duration)) {
+ // This should never fail, but if there is a bug which is causing it
+ // to fail, this message would probably end up flooding the logs
+ // because the conversion would probably fail forever. Log the
+ // error, but then zero out the ratio in the linear transform so
+ // that we don't try to do any conversions from now on. This
+ // MonoPipe's getNextWriteTimestamp is now broken for good.
+ ALOGE("Overflow when attempting to convert %d audio frames to"
+ " duration in local time. getNextWriteTimestamp will fail from"
+ " now on.", audFrames);
+ mSamplesToLocalTime.a_to_b_numer = 0;
+ mSamplesToLocalTime.a_to_b_denom = 0;
+ return AudioBufferProvider::kInvalidPTS;
+ }
+
+ return ts + frame_lt_duration;
+}
+
} // namespace android
diff --git a/services/audioflinger/MonoPipe.h b/services/audioflinger/MonoPipe.h
index f6e2cb3..c47bf6c 100644
--- a/services/audioflinger/MonoPipe.h
+++ b/services/audioflinger/MonoPipe.h
@@ -18,6 +18,7 @@
#define ANDROID_AUDIO_MONO_PIPE_H
#include <time.h>
+#include <utils/LinearTransform.h>
#include "NBAIO.h"
namespace android {
@@ -56,6 +57,20 @@ public:
virtual ssize_t write(const void *buffer, size_t count);
//virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block);
+ // MonoPipe's implementation of getNextWriteTimestamp works in conjunction
+ // with MonoPipeReader. Every time a MonoPipeReader reads from the pipe, it
+ // receives a "readPTS" indicating the point in time for which the reader
+ // would like to read data. This "last read PTS" is offset by the amt of
+ // data the reader is currently mixing and then cached cached along with the
+ // updated read pointer. This cached value is the local time for which the
+ // reader is going to request data next time it reads data (assuming we are
+ // in steady state and operating with no underflows). Writers to the
+ // MonoPipe who would like to know when their next write operation will hit
+ // the speakers can call getNextWriteTimestamp which will return the value
+ // of the last read PTS plus the duration of the amt of data waiting to be
+ // read in the MonoPipe.
+ virtual status_t getNextWriteTimestamp(int64_t *timestamp);
+
// average number of frames present in the pipe under normal conditions.
// See throttling mechanism in MonoPipe::write()
size_t getAvgFrames() const { return mSetpoint; }
@@ -63,20 +78,42 @@ public:
size_t maxFrames() const { return mMaxFrames; }
private:
+ // A pair of methods and a helper variable which allows the reader and the
+ // writer to update and observe the values of mFront and mNextRdPTS in an
+ // atomic lock-less fashion.
+ //
+ // :: Important ::
+ // Two assumptions must be true in order for this lock-less approach to
+ // function properly on all systems. First, there may only be one updater
+ // thread in the system. Second, the updater thread must be running at a
+ // strictly higher priority than the observer threads. Currently, both of
+ // these assumptions are true. The only updater is always a single
+ // FastMixer thread (which runs with SCHED_FIFO/RT priority while the only
+ // observer is always an AudioFlinger::PlaybackThread running with
+ // traditional (non-RT) audio priority.
+ void updateFrontAndNRPTS(int32_t newFront, int64_t newNextRdPTS);
+ void observeFrontAndNRPTS(int32_t *outFront, int64_t *outNextRdPTS);
+ volatile int32_t mUpdateSeq;
+
const size_t mReqFrames; // as requested in constructor, unrounded
const size_t mMaxFrames; // always a power of 2
void * const mBuffer;
// mFront and mRear will never be separated by more than mMaxFrames.
// 32-bit overflow is possible if the pipe is active for a long time, but if that happens it's
// safe because we "&" with (mMaxFrames-1) at end of computations to calculate a buffer index.
- volatile int32_t mFront; // written by reader with android_atomic_release_store,
- // read by writer with android_atomic_acquire_load
+ volatile int32_t mFront; // written by the reader with updateFrontAndNRPTS, observed by
+ // the writer with observeFrontAndNRPTS
volatile int32_t mRear; // written by writer with android_atomic_release_store,
// read by reader with android_atomic_acquire_load
+ volatile int64_t mNextRdPTS; // written by the reader with updateFrontAndNRPTS, observed by
+ // the writer with observeFrontAndNRPTS
bool mWriteTsValid; // whether mWriteTs is valid
struct timespec mWriteTs; // time that the previous write() completed
size_t mSetpoint; // target value for pipe fill depth
const bool mWriteCanBlock; // whether write() should block if the pipe is full
+
+ int64_t offsetTimestampByAudioFrames(int64_t ts, size_t audFrames);
+ LinearTransform mSamplesToLocalTime;
};
} // namespace android
diff --git a/services/audioflinger/MonoPipeReader.cpp b/services/audioflinger/MonoPipeReader.cpp
index b80d0c0..39a07de 100644
--- a/services/audioflinger/MonoPipeReader.cpp
+++ b/services/audioflinger/MonoPipeReader.cpp
@@ -43,11 +43,25 @@ ssize_t MonoPipeReader::availableToRead()
return ret;
}
-ssize_t MonoPipeReader::read(void *buffer, size_t count)
+ssize_t MonoPipeReader::read(void *buffer, size_t count, int64_t readPTS)
{
+ // Compute the "next read PTS" and cache it. Callers of read pass a read
+ // PTS indicating the local time for which they are requesting data along
+ // with a count (which is the number of audio frames they are going to
+ // ultimately pass to the next stage of the pipeline). Offsetting readPTS
+ // by the duration of count will give us the readPTS which will be passed to
+ // us next time, assuming they system continues to operate in steady state
+ // with no discontinuities. We stash this value so it can be used by the
+ // MonoPipe writer to imlement getNextWriteTimestamp.
+ int64_t nextReadPTS;
+ nextReadPTS = mPipe->offsetTimestampByAudioFrames(readPTS, count);
+
// count == 0 is unlikely and not worth checking for explicitly; will be handled automatically
ssize_t red = availableToRead();
if (CC_UNLIKELY(red <= 0)) {
+ // Uh-oh, looks like we are underflowing. Update the next read PTS and
+ // get out.
+ mPipe->updateFrontAndNRPTS(mPipe->mFront, nextReadPTS);
return red;
}
if (CC_LIKELY((size_t) red > count)) {
@@ -66,7 +80,7 @@ ssize_t MonoPipeReader::read(void *buffer, size_t count)
memcpy((char *) buffer + (part1 << mBitShift), mPipe->mBuffer, part2 << mBitShift);
}
}
- android_atomic_release_store(red + mPipe->mFront, &mPipe->mFront);
+ mPipe->updateFrontAndNRPTS(red + mPipe->mFront, nextReadPTS);
mFramesRead += red;
}
return red;
diff --git a/services/audioflinger/MonoPipeReader.h b/services/audioflinger/MonoPipeReader.h
index 9bb0a94..0e1c992 100644
--- a/services/audioflinger/MonoPipeReader.h
+++ b/services/audioflinger/MonoPipeReader.h
@@ -47,7 +47,7 @@ public:
virtual ssize_t availableToRead();
- virtual ssize_t read(void *buffer, size_t count);
+ virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
// NBAIO_Source end
diff --git a/services/audioflinger/NBAIO.cpp b/services/audioflinger/NBAIO.cpp
index 9d71eae..2c07ebf 100644
--- a/services/audioflinger/NBAIO.cpp
+++ b/services/audioflinger/NBAIO.cpp
@@ -128,7 +128,8 @@ ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t bl
}
// This is a default implementation; it is expected that subclasses will optimize this.
-ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, size_t block)
+ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user,
+ int64_t readPTS, size_t block)
{
if (!mNegotiated) {
return (ssize_t) NEGOTIATE;
@@ -147,11 +148,11 @@ ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, size_t bl
if (count > block) {
count = block;
}
- ssize_t ret = read(buffer, count);
+ ssize_t ret = read(buffer, count, readPTS);
if (ret > 0) {
ALOG_ASSERT((size_t) ret <= count);
size_t maxRet = ret;
- ret = via(user, buffer, maxRet);
+ ret = via(user, buffer, maxRet, readPTS);
if (ret > 0) {
ALOG_ASSERT((size_t) ret <= maxRet);
accumulator += ret;
diff --git a/services/audioflinger/NBAIO.h b/services/audioflinger/NBAIO.h
index b5ae0f1..81f42ed 100644
--- a/services/audioflinger/NBAIO.h
+++ b/services/audioflinger/NBAIO.h
@@ -26,6 +26,7 @@
#include <limits.h>
#include <stdlib.h>
+#include <utils/Errors.h>
#include <utils/RefBase.h>
namespace android {
@@ -74,7 +75,8 @@ unsigned Format_channelCount(NBAIO_Format format);
// Callbacks used by NBAIO_Sink::writeVia() and NBAIO_Source::readVia() below.
typedef ssize_t (*writeVia_t)(void *user, void *buffer, size_t count);
-typedef ssize_t (*readVia_t)(void *user, const void *buffer, size_t count);
+typedef ssize_t (*readVia_t)(void *user, const void *buffer,
+ size_t count, int64_t readPTS);
// Abstract class (interface) representing a data port.
class NBAIO_Port : public RefBase {
@@ -198,6 +200,21 @@ public:
// < 0 status_t error occurred prior to the first frame transfer during this callback.
virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block = 0);
+ // Get the time (on the LocalTime timeline) at which the first frame of audio of the next write
+ // operation to this sink will be eventually rendered by the HAL.
+ // Inputs:
+ // ts A pointer pointing to the int64_t which will hold the result.
+ // Return value:
+ // OK Everything went well, *ts holds the time at which the first audio frame of the next
+ // write operation will be rendered, or AudioBufferProvider::kInvalidPTS if this sink
+ // does not know the answer for some reason. Sinks which eventually lead to a HAL
+ // which implements get_next_write_timestamp may return Invalid temporarily if the DMA
+ // output of the audio driver has not started yet. Sinks which lead to a HAL which
+ // does not implement get_next_write_timestamp, or which don't lead to a HAL at all,
+ // will always return kInvalidPTS.
+ // <other> Something unexpected happened internally. Check the logs and start debugging.
+ virtual status_t getNextWriteTimestamp(int64_t *ts) { return INVALID_OPERATION; }
+
protected:
NBAIO_Sink(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
virtual ~NBAIO_Sink() { }
@@ -238,6 +255,8 @@ public:
// Inputs:
// buffer Non-NULL destination buffer owned by consumer.
// count Maximum number of frames to transfer.
+ // readPTS The presentation time (on the LocalTime timeline) for which data
+ // is being requested, or kInvalidPTS if not known.
// Return value:
// > 0 Number of frames successfully transferred prior to first error.
// = 0 Count was zero.
@@ -247,7 +266,7 @@ public:
// WOULD_BLOCK No frames can be transferred without blocking.
// OVERRUN read() has not been called frequently enough, or with enough frames to keep up.
// One or more frames were lost due to overrun, try again to read more recent data.
- virtual ssize_t read(void *buffer, size_t count) = 0;
+ virtual ssize_t read(void *buffer, size_t count, int64_t readPTS) = 0;
// Transfer data from source using a series of callbacks. More suitable for zero-fill,
// synthesis, and non-contiguous transfers (e.g. circular buffer or readv).
@@ -256,6 +275,8 @@ public:
// total Estimate of the number of frames the consumer desires. This is an estimate,
// and it can consume a different number of frames during the series of callbacks.
// user Arbitrary void * reserved for data consumer.
+ // readPTS The presentation time (on the LocalTime timeline) for which data
+ // is being requested, or kInvalidPTS if not known.
// block Number of frames per block, that is a suggested value for 'count' in each callback.
// Zero means no preference. This parameter is a hint only, and may be ignored.
// Return value:
@@ -278,7 +299,8 @@ public:
// > 0 Number of frames successfully transferred during this callback prior to first error.
// = 0 Count was zero.
// < 0 status_t error occurred prior to the first frame transfer during this callback.
- virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block = 0);
+ virtual ssize_t readVia(readVia_t via, size_t total, void *user,
+ int64_t readPTS, size_t block = 0);
protected:
NBAIO_Source(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
diff --git a/services/audioflinger/Soaker.h b/services/audioflinger/Soaker.h
deleted file mode 100644
index 43d9d2f..0000000
--- a/services/audioflinger/Soaker.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef _ANDROID_AUDIO_SOAKER_H
-#define _ANDROID_AUDIO_SOAKER_H
-
-#include <utils/Thread.h>
-
-namespace android {
-
-class Soaker : public Thread {
-public:
- Soaker() : Thread() { }
- virtual ~Soaker() { }
-protected:
- virtual bool threadLoop() {
- int j = 0;
- for (;;) {
- for (int i = 0; i < 10000; ++i) {
- j += i * i;
- }
- if (exitPending()) {
- return false;
- }
- }
- return j < 555555;
- }
-};
-
-} // namespace android
-
-#endif // _ANDROID_AUDIO_SOAKER_H
diff --git a/services/audioflinger/SourceAudioBufferProvider.cpp b/services/audioflinger/SourceAudioBufferProvider.cpp
index e9d6d2c..3343b53 100644
--- a/services/audioflinger/SourceAudioBufferProvider.cpp
+++ b/services/audioflinger/SourceAudioBufferProvider.cpp
@@ -65,7 +65,7 @@ status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer, int64_t pts)
mSize = buffer->frameCount;
}
// read from source
- ssize_t actual = mSource->read(mAllocated, buffer->frameCount);
+ ssize_t actual = mSource->read(mAllocated, buffer->frameCount, pts);
if (actual > 0) {
ALOG_ASSERT((size_t) actual <= buffer->frameCount);
mOffset = 0;