summaryrefslogtreecommitdiffstats
path: root/services/audioflinger
diff options
context:
space:
mode:
Diffstat (limited to 'services/audioflinger')
-rw-r--r--services/audioflinger/AudioFlinger.cpp70
-rw-r--r--services/audioflinger/AudioFlinger.h6
-rw-r--r--services/audioflinger/AudioMixer.cpp17
-rw-r--r--services/audioflinger/AudioPolicyService.cpp36
-rw-r--r--services/audioflinger/AudioResampler.cpp6
-rw-r--r--services/audioflinger/AudioResamplerCubic.cpp12
-rw-r--r--services/audioflinger/Effects.cpp3
-rw-r--r--services/audioflinger/FastMixer.cpp3
-rw-r--r--services/audioflinger/PlaybackTracks.h1
-rw-r--r--services/audioflinger/RecordTracks.h1
-rw-r--r--services/audioflinger/Threads.cpp495
-rw-r--r--services/audioflinger/Threads.h21
-rw-r--r--services/audioflinger/TrackBase.h10
-rw-r--r--services/audioflinger/Tracks.cpp19
14 files changed, 385 insertions, 315 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 626b5c2..fc98891 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -163,12 +163,15 @@ AudioFlinger::AudioFlinger()
(void) property_get("af.tee", value, "0");
teeEnabled = atoi(value);
}
- if (teeEnabled & 1)
+ if (teeEnabled & 1) {
mTeeSinkInputEnabled = true;
- if (teeEnabled & 2)
+ }
+ if (teeEnabled & 2) {
mTeeSinkOutputEnabled = true;
- if (teeEnabled & 4)
+ }
+ if (teeEnabled & 4) {
mTeeSinkTrackEnabled = true;
+ }
#endif
}
@@ -506,10 +509,12 @@ sp<IAudioTrack> AudioFlinger::createTrack(
track = thread->createTrack_l(client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, &lStatus);
+ // we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
// move effect chain to this output thread if an effect on same session was waiting
// for a track to be created
if (lStatus == NO_ERROR && effectThread != NULL) {
+ // no risk of deadlock because AudioFlinger::mLock is held
Mutex::Autolock _dl(thread->mLock);
Mutex::Autolock _sl(effectThread->mLock);
moveEffectChain_l(lSessionId, effectThread, thread, true);
@@ -529,7 +534,9 @@ sp<IAudioTrack> AudioFlinger::createTrack(
}
}
}
+
}
+
if (lStatus == NO_ERROR) {
// s for server's pid, n for normal mixer name, f for fast index
name = String8::format("s:%d;n:%d;f:%d", getpid_cached, track->name() - AudioMixer::TRACK0,
@@ -543,9 +550,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(
}
Exit:
- if (status != NULL) {
- *status = lStatus;
- }
+ *status = lStatus;
return trackHandle;
}
@@ -1279,6 +1284,7 @@ sp<IAudioRecord> AudioFlinger::openRecord(
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 destructor is called by the TrackBase destructor with mLock held
@@ -1287,14 +1293,11 @@ sp<IAudioRecord> AudioFlinger::openRecord(
goto Exit;
}
- // return to handle to client
+ // return handle to client
recordHandle = new RecordHandle(recordTrack);
- lStatus = NO_ERROR;
Exit:
- if (status) {
- *status = lStatus;
- }
+ *status = lStatus;
return recordHandle;
}
@@ -1435,18 +1438,15 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo)
{
- PlaybackThread *thread = NULL;
struct audio_config config;
+ memset(&config, 0, sizeof(config));
config.sample_rate = (pSamplingRate != NULL) ? *pSamplingRate : 0;
config.channel_mask = (pChannelMask != NULL) ? *pChannelMask : 0;
config.format = (pFormat != NULL) ? *pFormat : AUDIO_FORMAT_DEFAULT;
- if (offloadInfo) {
+ if (offloadInfo != NULL) {
config.offload_info = *offloadInfo;
}
- audio_stream_out_t *outStream = NULL;
- AudioHwDevice *outHwDev;
-
ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %#08x, Channels %x, flags %x",
module,
(pDevices != NULL) ? *pDevices : 0,
@@ -1455,7 +1455,7 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
config.channel_mask,
flags);
ALOGV("openOutput(), offloadInfo %p version 0x%04x",
- offloadInfo, offloadInfo == NULL ? -1 : offloadInfo->version );
+ offloadInfo, offloadInfo == NULL ? -1 : offloadInfo->version);
if (pDevices == NULL || *pDevices == 0) {
return 0;
@@ -1463,15 +1463,17 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
Mutex::Autolock _l(mLock);
- outHwDev = findSuitableHwDev_l(module, *pDevices);
- if (outHwDev == NULL)
+ AudioHwDevice *outHwDev = findSuitableHwDev_l(module, *pDevices);
+ if (outHwDev == NULL) {
return 0;
+ }
audio_hw_device_t *hwDevHal = outHwDev->hwDevice();
audio_io_handle_t id = nextUniqueId();
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
+ audio_stream_out_t *outStream = NULL;
status_t status = hwDevHal->open_output_stream(hwDevHal,
id,
*pDevices,
@@ -1491,6 +1493,7 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
if (status == NO_ERROR && outStream != NULL) {
AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream, flags);
+ PlaybackThread *thread;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, output, id, *pDevices);
ALOGV("openOutput() created offload output: ID %d thread %p", id, thread);
@@ -1658,18 +1661,15 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
audio_format_t *pFormat,
audio_channel_mask_t *pChannelMask)
{
- status_t status;
- RecordThread *thread = NULL;
struct audio_config config;
+ memset(&config, 0, sizeof(config));
config.sample_rate = (pSamplingRate != NULL) ? *pSamplingRate : 0;
config.channel_mask = (pChannelMask != NULL) ? *pChannelMask : 0;
config.format = (pFormat != NULL) ? *pFormat : AUDIO_FORMAT_DEFAULT;
uint32_t reqSamplingRate = config.sample_rate;
audio_format_t reqFormat = config.format;
- audio_channel_mask_t reqChannels = config.channel_mask;
- audio_stream_in_t *inStream = NULL;
- AudioHwDevice *inHwDev;
+ audio_channel_mask_t reqChannelMask = config.channel_mask;
if (pDevices == NULL || *pDevices == 0) {
return 0;
@@ -1677,14 +1677,16 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
Mutex::Autolock _l(mLock);
- inHwDev = findSuitableHwDev_l(module, *pDevices);
- if (inHwDev == NULL)
+ AudioHwDevice *inHwDev = findSuitableHwDev_l(module, *pDevices);
+ if (inHwDev == NULL) {
return 0;
+ }
audio_hw_device_t *inHwHal = inHwDev->hwDevice();
audio_io_handle_t id = nextUniqueId();
- status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config,
+ audio_stream_in_t *inStream = NULL;
+ status_t status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config,
&inStream);
ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, "
"status %d",
@@ -1700,7 +1702,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
if (status == BAD_VALUE &&
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)) {
+ (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannelMask) <= FCC_2)) {
ALOGV("openInput() reopening with proposed sampling rate and channel mask");
inStream = NULL;
status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config, &inStream);
@@ -1762,10 +1764,10 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
// Start record thread
// RecordThread requires both input and output device indication to forward to audio
// pre processing modules
- thread = new RecordThread(this,
+ RecordThread *thread = new RecordThread(this,
input,
reqSamplingRate,
- reqChannels,
+ reqChannelMask,
id,
primaryOutputDevice_l(),
*pDevices
@@ -1782,7 +1784,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
*pFormat = config.format;
}
if (pChannelMask != NULL) {
- *pChannelMask = reqChannels;
+ *pChannelMask = reqChannelMask;
}
// notify client processes of the new input creation
@@ -1928,7 +1930,7 @@ void AudioFlinger::purgeStaleEffects_l() {
}
}
if (!found) {
- Mutex::Autolock _l (t->mLock);
+ Mutex::Autolock _l(t->mLock);
// remove all effects from the chain
while (ec->mEffects.size()) {
sp<EffectModule> effect = ec->mEffects[0];
@@ -2225,9 +2227,7 @@ sp<IEffect> AudioFlinger::createEffect(
}
Exit:
- if (status != NULL) {
- *status = lStatus;
- }
+ *status = lStatus;
return handle;
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 0992308..39cdec0 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -109,7 +109,7 @@ public:
pid_t tid,
int *sessionId,
String8& name,
- status_t *status);
+ status_t *status /*non-NULL*/);
virtual sp<IAudioRecord> openRecord(
audio_io_handle_t input,
@@ -120,7 +120,7 @@ public:
IAudioFlinger::track_flags_t *flags,
pid_t tid,
int *sessionId,
- status_t *status);
+ status_t *status /*non-NULL*/);
virtual uint32_t sampleRate(audio_io_handle_t output) const;
virtual int channelCount(audio_io_handle_t output) const;
@@ -209,7 +209,7 @@ public:
int32_t priority,
audio_io_handle_t io,
int sessionId,
- status_t *status,
+ status_t *status /*non-NULL*/,
int *id,
int *enabled);
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index df4e029..91aedbb 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -229,7 +229,7 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId)
void AudioMixer::invalidateState(uint32_t mask)
{
- if (mask) {
+ if (mask != 0) {
mState.needsChanged |= mask;
mState.hook = process__validate;
}
@@ -709,7 +709,7 @@ void AudioMixer::process__validate(state_t* state, int64_t pts)
// select the processing hooks
state->hook = process__nop;
- if (countActiveTracks) {
+ if (countActiveTracks > 0) {
if (resampling) {
if (!state->outputTemp) {
state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
@@ -745,15 +745,14 @@ void AudioMixer::process__validate(state_t* state, int64_t pts)
// Now that the volume ramp has been done, set optimal state and
// track hooks for subsequent mixer process
- if (countActiveTracks) {
+ if (countActiveTracks > 0) {
bool allMuted = true;
uint32_t en = state->enabledTracks;
while (en) {
const int i = 31 - __builtin_clz(en);
en &= ~(1<<i);
track_t& t = state->tracks[i];
- if (!t.doesResample() && t.volumeRL == 0)
- {
+ if (!t.doesResample() && t.volumeRL == 0) {
t.needs |= NEEDS_MUTE_ENABLED;
t.hook = track__nop;
} else {
@@ -1124,8 +1123,9 @@ void AudioMixer::process__genericNoResampling(state_t* state, int64_t pts)
t.in = t.buffer.raw;
// t.in == NULL can happen if the track was flushed just after having
// been enabled for mixing.
- if (t.in == NULL)
+ if (t.in == NULL) {
enabledTracks &= ~(1<<i);
+ }
}
e0 = enabledTracks;
@@ -1162,7 +1162,7 @@ void AudioMixer::process__genericNoResampling(state_t* state, int64_t pts)
}
while (outFrames) {
size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
- if (inFrames) {
+ if (inFrames > 0) {
t.hook(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames,
state->resampleTemp, aux);
t.frameCount -= inFrames;
@@ -1445,8 +1445,9 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state,
int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS,
int outputFrameIndex)
{
- if (AudioBufferProvider::kInvalidPTS == basePTS)
+ if (AudioBufferProvider::kInvalidPTS == basePTS) {
return AudioBufferProvider::kInvalidPTS;
+ }
return basePTS + ((outputFrameIndex * sLocalTimeFreq) / t.sampleRate);
}
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 900b411..d6ea758 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -77,24 +77,28 @@ AudioPolicyService::AudioPolicyService()
mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
/* instantiate the audio policy manager */
rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);
- if (rc)
+ if (rc) {
return;
+ }
rc = audio_policy_dev_open(module, &mpAudioPolicyDev);
ALOGE_IF(rc, "couldn't open audio policy device (%s)", strerror(-rc));
- if (rc)
+ if (rc) {
return;
+ }
rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,
&mpAudioPolicy);
ALOGE_IF(rc, "couldn't create audio policy (%s)", strerror(-rc));
- if (rc)
+ if (rc) {
return;
+ }
rc = mpAudioPolicy->init_check(mpAudioPolicy);
ALOGE_IF(rc, "couldn't init_check the audio policy (%s)", strerror(-rc));
- if (rc)
+ if (rc) {
return;
+ }
ALOGI("Loaded audio policy from %s (%s)", module->name, module->id);
@@ -126,10 +130,12 @@ AudioPolicyService::~AudioPolicyService()
}
mInputs.clear();
- if (mpAudioPolicy != NULL && mpAudioPolicyDev != NULL)
+ if (mpAudioPolicy != NULL && mpAudioPolicyDev != NULL) {
mpAudioPolicyDev->destroy_audio_policy(mpAudioPolicyDev, mpAudioPolicy);
- if (mpAudioPolicyDev != NULL)
+ }
+ if (mpAudioPolicyDev != NULL) {
audio_policy_dev_close(mpAudioPolicyDev);
+ }
}
status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
@@ -1105,11 +1111,13 @@ int AudioPolicyService::setStreamVolume(audio_stream_type_t stream,
int AudioPolicyService::startTone(audio_policy_tone_t tone,
audio_stream_type_t stream)
{
- if (tone != AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION)
+ if (tone != AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION) {
ALOGE("startTone: illegal tone requested (%d)", tone);
- if (stream != AUDIO_STREAM_VOICE_CALL)
+ }
+ if (stream != AUDIO_STREAM_VOICE_CALL) {
ALOGE("startTone: illegal stream (%d) requested for tone %d", stream,
tone);
+ }
mTonePlaybackThread->startToneCommand(ToneGenerator::TONE_SUP_CALL_WAITING,
AUDIO_STREAM_VOICE_CALL);
return 0;
@@ -1500,8 +1508,9 @@ static audio_io_handle_t aps_open_dup_output(void *service,
static int aps_close_output(void *service, audio_io_handle_t output)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == 0)
+ if (af == 0) {
return PERMISSION_DENIED;
+ }
return af->closeOutput(output);
}
@@ -1564,8 +1573,9 @@ static audio_io_handle_t aps_open_input_on_module(void *service,
static int aps_close_input(void *service, audio_io_handle_t input)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == 0)
+ if (af == 0) {
return PERMISSION_DENIED;
+ }
return af->closeInput(input);
}
@@ -1574,8 +1584,9 @@ static int aps_set_stream_output(void *service, audio_stream_type_t stream,
audio_io_handle_t output)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == 0)
+ if (af == 0) {
return PERMISSION_DENIED;
+ }
return af->setStreamOutput(stream, output);
}
@@ -1585,8 +1596,9 @@ static int aps_move_effects(void *service, int session,
audio_io_handle_t dst_output)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == 0)
+ if (af == 0) {
return PERMISSION_DENIED;
+ }
return af->moveEffects(session, src_output, dst_output);
}
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 2c3c719..323f1a4 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -339,8 +339,9 @@ void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
Advance(&inputIndex, &phaseFraction, phaseIncrement);
- if (outputIndex == outputSampleCount)
+ if (outputIndex == outputSampleCount) {
break;
+ }
}
// process input samples
@@ -434,8 +435,9 @@ void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
out[outputIndex++] += vl * sample;
out[outputIndex++] += vr * sample;
Advance(&inputIndex, &phaseFraction, phaseIncrement);
- if (outputIndex == outputSampleCount)
+ if (outputIndex == outputSampleCount) {
break;
+ }
}
// process input samples
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index 18e59e9..1f9714b 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -66,8 +66,9 @@ void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount,
if (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
provider->getNextBuffer(&mBuffer, mPTS);
- if (mBuffer.raw == NULL)
+ if (mBuffer.raw == NULL) {
return;
+ }
// ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
}
int16_t *in = mBuffer.i16;
@@ -97,8 +98,9 @@ void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount,
mBuffer.frameCount = inFrameCount;
provider->getNextBuffer(&mBuffer,
calculateOutputPTS(outputIndex / 2));
- if (mBuffer.raw == NULL)
+ if (mBuffer.raw == NULL) {
goto save_state; // ugly, but efficient
+ }
in = mBuffer.i16;
// ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount);
}
@@ -132,8 +134,9 @@ void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount,
if (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
provider->getNextBuffer(&mBuffer, mPTS);
- if (mBuffer.raw == NULL)
+ if (mBuffer.raw == NULL) {
return;
+ }
// ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount);
}
int16_t *in = mBuffer.i16;
@@ -163,8 +166,9 @@ void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount,
mBuffer.frameCount = inFrameCount;
provider->getNextBuffer(&mBuffer,
calculateOutputPTS(outputIndex / 2));
- if (mBuffer.raw == NULL)
+ if (mBuffer.raw == NULL) {
goto save_state; // ugly, but efficient
+ }
// ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
in = mBuffer.i16;
}
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 86671a9..fc45caa 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -116,8 +116,9 @@ status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle)
continue;
}
// first non destroyed handle is considered in control
- if (controlHandle == NULL)
+ if (controlHandle == NULL) {
controlHandle = h;
+ }
if (h->priority() <= priority) {
break;
}
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index f27ea17..7126e92 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -459,8 +459,9 @@ bool FastMixer::threadLoop()
}
int64_t pts;
- if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts)))
+ if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts))) {
pts = AudioBufferProvider::kInvalidPTS;
+ }
// process() is CPU-bound
mixer->process(pts);
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 0308b99..829b5d6 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -33,6 +33,7 @@ public:
int sessionId,
IAudioFlinger::track_flags_t flags);
virtual ~Track();
+ virtual status_t initCheck() const;
static void appendDumpHeader(String8& result);
void dump(char* buffer, size_t size);
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index ffe3e9f..6c0d1d3 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -57,5 +57,4 @@ private:
// releaseBuffer() not overridden
bool mOverflow; // overflow on most recent attempt to fill client buffer
- AudioRecordServerProxy* mAudioRecordServerProxy;
};
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index e35f47e..f2f2d6b 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -266,8 +266,8 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio
: Thread(false /*canCallJava*/),
mType(type),
mAudioFlinger(audioFlinger),
- // mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, and mFormat are
- // set by PlaybackThread::readOutputParameters() or RecordThread::readInputParameters()
+ // mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, mFormat, mBufferSize
+ // are set by PlaybackThread::readOutputParameters() or RecordThread::readInputParameters()
mParamStatus(NO_ERROR),
mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
@@ -293,6 +293,17 @@ AudioFlinger::ThreadBase::~ThreadBase()
}
}
+status_t AudioFlinger::ThreadBase::readyToRun()
+{
+ status_t status = initCheck();
+ if (status == NO_ERROR) {
+ ALOGI("AudioFlinger's thread %p ready to run", this);
+ } else {
+ ALOGE("No working audio driver found.");
+ }
+ return status;
+}
+
void AudioFlinger::ThreadBase::exit()
{
ALOGV("ThreadBase::exit");
@@ -365,7 +376,13 @@ void AudioFlinger::ThreadBase::sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32
void AudioFlinger::ThreadBase::processConfigEvents()
{
- mLock.lock();
+ Mutex::Autolock _l(mLock);
+ processConfigEvents_l();
+}
+
+// post condition: mConfigEvents.isEmpty()
+void AudioFlinger::ThreadBase::processConfigEvents_l()
+{
while (!mConfigEvents.isEmpty()) {
ALOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
ConfigEvent *event = mConfigEvents[0];
@@ -373,32 +390,31 @@ void AudioFlinger::ThreadBase::processConfigEvents()
// release mLock before locking AudioFlinger mLock: lock order is always
// AudioFlinger then ThreadBase to avoid cross deadlock
mLock.unlock();
- switch(event->type()) {
- case CFG_EVENT_PRIO: {
- PrioConfigEvent *prioEvent = static_cast<PrioConfigEvent *>(event);
- // FIXME Need to understand why this has be done asynchronously
- int err = requestPriority(prioEvent->pid(), prioEvent->tid(), prioEvent->prio(),
- true /*asynchronous*/);
- if (err != 0) {
- ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; "
- "error %d",
- prioEvent->prio(), prioEvent->pid(), prioEvent->tid(), err);
- }
- } break;
- case CFG_EVENT_IO: {
- IoConfigEvent *ioEvent = static_cast<IoConfigEvent *>(event);
- mAudioFlinger->mLock.lock();
+ switch (event->type()) {
+ case CFG_EVENT_PRIO: {
+ PrioConfigEvent *prioEvent = static_cast<PrioConfigEvent *>(event);
+ // FIXME Need to understand why this has be done asynchronously
+ int err = requestPriority(prioEvent->pid(), prioEvent->tid(), prioEvent->prio(),
+ true /*asynchronous*/);
+ if (err != 0) {
+ ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
+ prioEvent->prio(), prioEvent->pid(), prioEvent->tid(), err);
+ }
+ } break;
+ case CFG_EVENT_IO: {
+ IoConfigEvent *ioEvent = static_cast<IoConfigEvent *>(event);
+ {
+ Mutex::Autolock _l(mAudioFlinger->mLock);
audioConfigChanged_l(ioEvent->event(), ioEvent->param());
- mAudioFlinger->mLock.unlock();
- } break;
- default:
- ALOGE("processConfigEvents() unknown event type %d", event->type());
- break;
+ }
+ } break;
+ default:
+ ALOGE("processConfigEvents() unknown event type %d", event->type());
+ break;
}
delete event;
mLock.lock();
}
- mLock.unlock();
}
void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
@@ -423,6 +439,8 @@ void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
result.append(buffer);
snprintf(buffer, SIZE, "HAL frame count: %d\n", mFrameCount);
result.append(buffer);
+ snprintf(buffer, SIZE, "HAL buffer size: %u bytes\n", mBufferSize);
+ result.append(buffer);
snprintf(buffer, SIZE, "Channel Count: %u\n", mChannelCount);
result.append(buffer);
snprintf(buffer, SIZE, "Channel Mask: 0x%08x\n", mChannelMask);
@@ -682,8 +700,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
int sessionId,
effect_descriptor_t *desc,
int *enabled,
- status_t *status
- )
+ status_t *status)
{
sp<EffectModule> effect;
sp<EffectHandle> handle;
@@ -783,9 +800,7 @@ Exit:
handle.clear();
}
- if (status != NULL) {
- *status = lStatus;
- }
+ *status = lStatus;
return handle;
}
@@ -929,7 +944,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
type_t type)
: ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type),
mNormalFrameCount(0), mMixBuffer(NULL),
- mAllocMixBuffer(NULL), mSuspended(0), mBytesWritten(0),
+ mSuspended(0), mBytesWritten(0),
// mStreamTypes[] initialized in constructor body
mOutput(output),
mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
@@ -985,7 +1000,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
AudioFlinger::PlaybackThread::~PlaybackThread()
{
mAudioFlinger->unregisterWriter(mNBLogWriter);
- delete [] mAllocMixBuffer;
+ delete[] mMixBuffer;
}
void AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
@@ -1075,16 +1090,6 @@ void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>&
}
// Thread virtuals
-status_t AudioFlinger::PlaybackThread::readyToRun()
-{
- status_t status = initCheck();
- if (status == NO_ERROR) {
- ALOGI("AudioFlinger's thread %p ready to run", this);
- } else {
- ALOGE("No working audio driver found.");
- }
- return status;
-}
void AudioFlinger::PlaybackThread::onFirstRef()
{
@@ -1250,8 +1255,12 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
track = TimedTrack::create(this, client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, sessionId);
}
- if (track == 0 || track->getCblk() == NULL || track->name() < 0) {
- lStatus = NO_MEMORY;
+
+ // new Track always returns non-NULL,
+ // but TimedTrack::create() is a factory that could fail by returning NULL
+ lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
+ if (lStatus != NO_ERROR) {
+ track.clear();
goto Exit;
}
@@ -1276,9 +1285,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
lStatus = NO_ERROR;
Exit:
- if (status) {
- *status = lStatus;
- }
+ *status = lStatus;
return track;
}
@@ -1563,7 +1570,8 @@ void AudioFlinger::PlaybackThread::readOutputParameters()
mFormat);
}
mFrameSize = audio_stream_frame_size(&mOutput->stream->common);
- mFrameCount = mOutput->stream->common.get_buffer_size(&mOutput->stream->common) / mFrameSize;
+ mBufferSize = mOutput->stream->common.get_buffer_size(&mOutput->stream->common);
+ mFrameCount = mBufferSize / mFrameSize;
if (mFrameCount & 15) {
ALOGW("HAL output buffer size is %u frames but AudioMixer requires multiples of 16 frames",
mFrameCount);
@@ -1619,11 +1627,11 @@ void AudioFlinger::PlaybackThread::readOutputParameters()
ALOGI("HAL output buffer size %u frames, normal mix buffer size %u frames", mFrameCount,
mNormalFrameCount);
- delete[] mAllocMixBuffer;
- size_t align = (mFrameSize < sizeof(int16_t)) ? sizeof(int16_t) : mFrameSize;
- mAllocMixBuffer = new int8_t[mNormalFrameCount * mFrameSize + align - 1];
- mMixBuffer = (int16_t *) ((((size_t)mAllocMixBuffer + align - 1) / align) * align);
- memset(mMixBuffer, 0, mNormalFrameCount * mFrameSize);
+ delete[] mMixBuffer;
+ size_t normalBufferSize = mNormalFrameCount * mFrameSize;
+ // For historical reasons mMixBuffer is int16_t[], but mFrameSize can be odd (such as 1)
+ mMixBuffer = new int16_t[(normalBufferSize + 1) >> 1];
+ memset(mMixBuffer, 0, normalBufferSize);
// force reconfiguration of effect chains and engines to take new buffer size and audio
// parameters into account
@@ -1757,7 +1765,7 @@ void AudioFlinger::PlaybackThread::threadLoop_removeTracks(
const Vector< sp<Track> >& tracksToRemove)
{
size_t count = tracksToRemove.size();
- if (count) {
+ if (count > 0) {
for (size_t i = 0 ; i < count ; i++) {
const sp<Track>& track = tracksToRemove.itemAt(i);
if (!track->isOutputTrack()) {
@@ -2304,7 +2312,7 @@ if (mType == MIXER) {
void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& tracksToRemove)
{
size_t count = tracksToRemove.size();
- if (count) {
+ if (count > 0) {
for (size_t i=0 ; i<count ; i++) {
const sp<Track>& track = tracksToRemove.itemAt(i);
mActiveTracks.remove(track);
@@ -2679,7 +2687,7 @@ void AudioFlinger::MixerThread::threadLoop_sleepTime()
sleepTime = idleSleepTime;
}
} else if (mBytesWritten != 0 || (mMixerStatus == MIXER_TRACKS_ENABLED)) {
- memset (mMixBuffer, 0, mixBufferSize);
+ memset(mMixBuffer, 0, mixBufferSize);
sleepTime = 0;
ALOGV_IF(mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED),
"anticipated start");
@@ -2905,7 +2913,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
// +1 for rounding and +1 for additional sample needed for interpolation
desiredFrames = (mNormalFrameCount * sr) / mSampleRate + 1 + 1;
// add frames already consumed but not yet released by the resampler
- // because cblk->framesReady() will include these frames
+ // because mAudioTrackServerProxy->framesReady() will include these frames
desiredFrames += mAudioMixer->getUnreleasedFrames(track->name());
// the minimum track buffer size is normally twice the number of frames necessary
// to fill one buffer and the resampler should not leave more than one buffer worth
@@ -3243,6 +3251,7 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
status = BAD_VALUE;
} else {
+ // no need to save value, since it's constant
reconfig = true;
}
}
@@ -3250,6 +3259,7 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
if ((audio_channel_mask_t) value != AUDIO_CHANNEL_OUT_STEREO) {
status = BAD_VALUE;
} else {
+ // no need to save value, since it's constant
reconfig = true;
}
}
@@ -4207,7 +4217,7 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
) :
ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD),
mInput(input), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
- // mRsmpInIndex and mBufferSize set by readInputParameters()
+ // mRsmpInIndex set by readInputParameters()
mReqChannelCount(popcount(channelMask)),
mReqSampleRate(sampleRate)
// mBytesRead is only meaningful while active, and so is cleared in start()
@@ -4235,18 +4245,9 @@ void AudioFlinger::RecordThread::onFirstRef()
run(mName, PRIORITY_URGENT_AUDIO);
}
-status_t AudioFlinger::RecordThread::readyToRun()
-{
- status_t status = initCheck();
- ALOGW_IF(status != NO_ERROR,"RecordThread %p could not initialize", this);
- return status;
-}
-
bool AudioFlinger::RecordThread::threadLoop()
{
AudioBufferProvider::Buffer buffer;
- sp<RecordTrack> activeTrack;
- Vector< sp<EffectChain> > effectChains;
nsecs_t lastWarning = 0;
@@ -4256,21 +4257,34 @@ bool AudioFlinger::RecordThread::threadLoop()
// used to verify we've read at least once before evaluating how many bytes were read
bool readOnce = false;
+ // used to request a deferred sleep, to be executed later while mutex is unlocked
+ bool doSleep = false;
+
// start recording
- while (!exitPending()) {
+ for (;;) {
+ sp<RecordTrack> activeTrack;
+ TrackBase::track_state activeTrackState;
+ Vector< sp<EffectChain> > effectChains;
- processConfigEvents();
+ // sleep with mutex unlocked
+ if (doSleep) {
+ doSleep = false;
+ usleep(kRecordThreadSleepUs);
+ }
{ // scope for mLock
Mutex::Autolock _l(mLock);
- checkForNewParameters_l();
- if (mActiveTrack == 0 && mConfigEvents.isEmpty()) {
+ if (exitPending()) {
+ break;
+ }
+ processConfigEvents_l();
+ // return value 'reconfig' is currently unused
+ bool reconfig = checkForNewParameters_l();
+ // make a stable copy of mActiveTrack
+ activeTrack = mActiveTrack;
+ if (activeTrack == 0) {
standby();
-
- if (exitPending()) {
- break;
- }
-
+ // exitPending() can't become true here
releaseWakeLock_l();
ALOGV("RecordThread: loop stopping");
// go to sleep
@@ -4279,172 +4293,191 @@ bool AudioFlinger::RecordThread::threadLoop()
acquireWakeLock_l();
continue;
}
- if (mActiveTrack != 0) {
- if (mActiveTrack->isTerminated()) {
- removeTrack_l(mActiveTrack);
- mActiveTrack.clear();
- } else if (mActiveTrack->mState == TrackBase::PAUSING) {
- standby();
+
+ if (activeTrack->isTerminated()) {
+ removeTrack_l(activeTrack);
+ mActiveTrack.clear();
+ continue;
+ }
+
+ activeTrackState = activeTrack->mState;
+ switch (activeTrackState) {
+ case TrackBase::PAUSING:
+ standby();
+ mActiveTrack.clear();
+ mStartStopCond.broadcast();
+ doSleep = true;
+ continue;
+
+ case TrackBase::RESUMING:
+ mStandby = false;
+ if (mReqChannelCount != activeTrack->channelCount()) {
mActiveTrack.clear();
mStartStopCond.broadcast();
- } else if (mActiveTrack->mState == TrackBase::RESUMING) {
- if (mReqChannelCount != mActiveTrack->channelCount()) {
+ continue;
+ }
+ if (readOnce) {
+ mStartStopCond.broadcast();
+ // record start succeeds only if first read from audio input succeeds
+ if (mBytesRead < 0) {
mActiveTrack.clear();
- mStartStopCond.broadcast();
- } else if (readOnce) {
- // record start succeeds only if first read from audio input
- // succeeds
- if (mBytesRead >= 0) {
- mActiveTrack->mState = TrackBase::ACTIVE;
- } else {
- mActiveTrack.clear();
- }
- mStartStopCond.broadcast();
+ continue;
}
- mStandby = false;
+ activeTrack->mState = TrackBase::ACTIVE;
}
+ break;
+
+ case TrackBase::ACTIVE:
+ break;
+
+ case TrackBase::IDLE:
+ doSleep = true;
+ continue;
+
+ default:
+ LOG_FATAL("Unexpected activeTrackState %d", activeTrackState);
}
+
lockEffectChains_l(effectChains);
}
- if (mActiveTrack != 0) {
- if (mActiveTrack->mState != TrackBase::ACTIVE &&
- mActiveTrack->mState != TrackBase::RESUMING) {
- unlockEffectChains(effectChains);
- usleep(kRecordThreadSleepUs);
- continue;
- }
- for (size_t i = 0; i < effectChains.size(); i ++) {
- effectChains[i]->process_l();
- }
+ // thread mutex is now unlocked, mActiveTrack unknown, activeTrack != 0, kept, immutable
+ // activeTrack->mState unknown, activeTrackState immutable and is ACTIVE or RESUMING
- buffer.frameCount = mFrameCount;
- status_t status = mActiveTrack->getNextBuffer(&buffer);
- if (status == NO_ERROR) {
- readOnce = true;
- size_t framesOut = buffer.frameCount;
- if (mResampler == NULL) {
- // no resampling
- while (framesOut) {
- size_t framesIn = mFrameCount - mRsmpInIndex;
- if (framesIn) {
- int8_t *src = (int8_t *)mRsmpInBuffer + mRsmpInIndex * mFrameSize;
- int8_t *dst = buffer.i8 + (buffer.frameCount - framesOut) *
- mActiveTrack->mFrameSize;
- if (framesIn > framesOut)
- framesIn = framesOut;
- mRsmpInIndex += framesIn;
- framesOut -= framesIn;
- if (mChannelCount == mReqChannelCount) {
- memcpy(dst, src, framesIn * mFrameSize);
- } else {
- if (mChannelCount == 1) {
- upmix_to_stereo_i16_from_mono_i16((int16_t *)dst,
- (int16_t *)src, framesIn);
- } else {
- downmix_to_mono_i16_from_stereo_i16((int16_t *)dst,
- (int16_t *)src, framesIn);
- }
- }
+ for (size_t i = 0; i < effectChains.size(); i ++) {
+ // thread mutex is not locked, but effect chain is locked
+ effectChains[i]->process_l();
+ }
+
+ buffer.frameCount = mFrameCount;
+ status_t status = activeTrack->getNextBuffer(&buffer);
+ if (status == NO_ERROR) {
+ readOnce = true;
+ size_t framesOut = buffer.frameCount;
+ if (mResampler == NULL) {
+ // no resampling
+ while (framesOut) {
+ size_t framesIn = mFrameCount - mRsmpInIndex;
+ if (framesIn > 0) {
+ int8_t *src = (int8_t *)mRsmpInBuffer + mRsmpInIndex * mFrameSize;
+ int8_t *dst = buffer.i8 + (buffer.frameCount - framesOut) *
+ activeTrack->mFrameSize;
+ if (framesIn > framesOut) {
+ framesIn = framesOut;
}
- if (framesOut && mFrameCount == mRsmpInIndex) {
- void *readInto;
- if (framesOut == mFrameCount && mChannelCount == mReqChannelCount) {
- readInto = buffer.raw;
- framesOut = 0;
+ mRsmpInIndex += framesIn;
+ framesOut -= framesIn;
+ if (mChannelCount == mReqChannelCount) {
+ memcpy(dst, src, framesIn * mFrameSize);
+ } else {
+ if (mChannelCount == 1) {
+ upmix_to_stereo_i16_from_mono_i16((int16_t *)dst,
+ (int16_t *)src, framesIn);
} else {
- readInto = mRsmpInBuffer;
- mRsmpInIndex = 0;
+ downmix_to_mono_i16_from_stereo_i16((int16_t *)dst,
+ (int16_t *)src, framesIn);
}
- mBytesRead = mInput->stream->read(mInput->stream, readInto,
- mBufferSize);
- if (mBytesRead <= 0) {
- if ((mBytesRead < 0) && (mActiveTrack->mState == TrackBase::ACTIVE))
- {
- ALOGE("Error reading audio input");
- // Force input into standby so that it tries to
- // recover at next read attempt
- inputStandBy();
- usleep(kRecordThreadSleepUs);
- }
- mRsmpInIndex = mFrameCount;
- framesOut = 0;
- buffer.frameCount = 0;
+ }
+ }
+ if (framesOut > 0 && mFrameCount == mRsmpInIndex) {
+ void *readInto;
+ if (framesOut == mFrameCount && mChannelCount == mReqChannelCount) {
+ readInto = buffer.raw;
+ framesOut = 0;
+ } else {
+ readInto = mRsmpInBuffer;
+ mRsmpInIndex = 0;
+ }
+ mBytesRead = mInput->stream->read(mInput->stream, readInto,
+ mBufferSize);
+ if (mBytesRead <= 0) {
+ // TODO: verify that it's benign to use a stale track state
+ if ((mBytesRead < 0) && (activeTrackState == TrackBase::ACTIVE))
+ {
+ ALOGE("Error reading audio input");
+ // Force input into standby so that it tries to
+ // recover at next read attempt
+ inputStandBy();
+ doSleep = true;
}
+ mRsmpInIndex = mFrameCount;
+ framesOut = 0;
+ buffer.frameCount = 0;
+ }
#ifdef TEE_SINK
- else if (mTeeSink != 0) {
- (void) mTeeSink->write(readInto,
- mBytesRead >> Format_frameBitShift(mTeeSink->format()));
- }
-#endif
+ else if (mTeeSink != 0) {
+ (void) mTeeSink->write(readInto,
+ mBytesRead >> Format_frameBitShift(mTeeSink->format()));
}
+#endif
}
+ }
+ } else {
+ // resampling
+
+ // resampler accumulates, but we only have one source track
+ memset(mRsmpOutBuffer, 0, framesOut * FCC_2 * sizeof(int32_t));
+ // alter output frame count as if we were expecting stereo samples
+ if (mChannelCount == 1 && mReqChannelCount == 1) {
+ framesOut >>= 1;
+ }
+ mResampler->resample(mRsmpOutBuffer, framesOut,
+ this /* AudioBufferProvider* */);
+ // ditherAndClamp() works as long as all buffers returned by
+ // activeTrack->getNextBuffer() are 32 bit aligned which should be always true.
+ if (mChannelCount == 2 && mReqChannelCount == 1) {
+ // temporarily type pun mRsmpOutBuffer from Q19.12 to int16_t
+ ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut);
+ // the resampler always outputs stereo samples:
+ // do post stereo to mono conversion
+ downmix_to_mono_i16_from_stereo_i16(buffer.i16, (int16_t *)mRsmpOutBuffer,
+ framesOut);
} else {
- // resampling
+ ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut);
+ }
+ // now done with mRsmpOutBuffer
- // resampler accumulates, but we only have one source track
- memset(mRsmpOutBuffer, 0, framesOut * FCC_2 * sizeof(int32_t));
- // alter output frame count as if we were expecting stereo samples
- if (mChannelCount == 1 && mReqChannelCount == 1) {
- framesOut >>= 1;
- }
- mResampler->resample(mRsmpOutBuffer, framesOut,
- this /* AudioBufferProvider* */);
- // ditherAndClamp() works as long as all buffers returned by
- // mActiveTrack->getNextBuffer() are 32 bit aligned which should be always true.
- if (mChannelCount == 2 && mReqChannelCount == 1) {
- // temporarily type pun mRsmpOutBuffer from Q19.12 to int16_t
- ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut);
- // the resampler always outputs stereo samples:
- // do post stereo to mono conversion
- downmix_to_mono_i16_from_stereo_i16(buffer.i16, (int16_t *)mRsmpOutBuffer,
- framesOut);
- } else {
- ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut);
+ }
+ if (mFramestoDrop == 0) {
+ activeTrack->releaseBuffer(&buffer);
+ } else {
+ if (mFramestoDrop > 0) {
+ mFramestoDrop -= buffer.frameCount;
+ if (mFramestoDrop <= 0) {
+ clearSyncStartEvent();
}
- // now done with mRsmpOutBuffer
-
- }
- if (mFramestoDrop == 0) {
- mActiveTrack->releaseBuffer(&buffer);
} else {
- if (mFramestoDrop > 0) {
- mFramestoDrop -= buffer.frameCount;
- if (mFramestoDrop <= 0) {
- clearSyncStartEvent();
- }
- } else {
- mFramestoDrop += buffer.frameCount;
- if (mFramestoDrop >= 0 || mSyncStartEvent == 0 ||
- mSyncStartEvent->isCancelled()) {
- ALOGW("Synced record %s, session %d, trigger session %d",
- (mFramestoDrop >= 0) ? "timed out" : "cancelled",
- mActiveTrack->sessionId(),
- (mSyncStartEvent != 0) ? mSyncStartEvent->triggerSession() : 0);
- clearSyncStartEvent();
- }
+ mFramestoDrop += buffer.frameCount;
+ if (mFramestoDrop >= 0 || mSyncStartEvent == 0 ||
+ mSyncStartEvent->isCancelled()) {
+ ALOGW("Synced record %s, session %d, trigger session %d",
+ (mFramestoDrop >= 0) ? "timed out" : "cancelled",
+ activeTrack->sessionId(),
+ (mSyncStartEvent != 0) ? mSyncStartEvent->triggerSession() : 0);
+ clearSyncStartEvent();
}
}
- mActiveTrack->clearOverflow();
}
- // client isn't retrieving buffers fast enough
- else {
- if (!mActiveTrack->setOverflow()) {
- nsecs_t now = systemTime();
- if ((now - lastWarning) > kWarningThrottleNs) {
- ALOGW("RecordThread: buffer overflow");
- lastWarning = now;
- }
+ activeTrack->clearOverflow();
+ }
+ // client isn't retrieving buffers fast enough
+ else {
+ if (!activeTrack->setOverflow()) {
+ nsecs_t now = systemTime();
+ if ((now - lastWarning) > kWarningThrottleNs) {
+ ALOGW("RecordThread: buffer overflow");
+ lastWarning = now;
}
- // Release the processor for a while before asking for a new buffer.
- // This will give the application more chance to read from the buffer and
- // clear the overflow.
- usleep(kRecordThreadSleepUs);
}
+ // Release the processor for a while before asking for a new buffer.
+ // This will give the application more chance to read from the buffer and
+ // clear the overflow.
+ doSleep = true;
}
+
// enable changes in effect chain
unlockEffectChains(effectChains);
- effectChains.clear();
+ // effectChains doesn't need to be cleared, since it is cleared by destructor at scope end
}
standby();
@@ -4474,7 +4507,7 @@ void AudioFlinger::RecordThread::inputStandBy()
mInput->stream->common.standby(&mInput->stream->common);
}
-sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
+sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
const sp<AudioFlinger::Client>& client,
uint32_t sampleRate,
audio_format_t format,
@@ -4553,8 +4586,9 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createR
track = new RecordTrack(this, client, sampleRate,
format, channelMask, frameCount, sessionId);
- if (track->getCblk() == 0) {
- lStatus = NO_MEMORY;
+ lStatus = track->initCheck();
+ if (lStatus != NO_ERROR) {
+ track.clear();
goto Exit;
}
mTracks.add(track);
@@ -4575,9 +4609,7 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createR
lStatus = NO_ERROR;
Exit:
- if (status) {
- *status = lStatus;
- }
+ *status = lStatus;
return track;
}
@@ -4608,6 +4640,7 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
}
{
+ // This section is a rendezvous between binder thread executing start() and RecordThread
AutoMutex lock(mLock);
if (mActiveTrack != 0) {
if (recordTrack != mActiveTrack.get()) {
@@ -4618,11 +4651,13 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
return status;
}
+ // FIXME why? already set in constructor, 'STARTING_1' would be more accurate
recordTrack->mState = TrackBase::IDLE;
mActiveTrack = recordTrack;
mLock.unlock();
status_t status = AudioSystem::startInput(mId);
mLock.lock();
+ // FIXME should verify that mActiveTrack is still == recordTrack
if (status != NO_ERROR) {
mActiveTrack.clear();
clearSyncStartEvent();
@@ -4633,6 +4668,8 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
if (mResampler != NULL) {
mResampler->reset();
}
+ // FIXME hijacking a playback track state name which was intended for start after pause;
+ // here 'STARTING_2' would be more accurate
mActiveTrack->mState = TrackBase::RESUMING;
// signal thread to start
ALOGV("Signal record thread");
@@ -4643,6 +4680,7 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
status = INVALID_OPERATION;
goto startError;
}
+ // FIXME incorrect usage of wait: no explicit predicate or loop
mStartStopCond.wait(mLock);
if (mActiveTrack == 0) {
ALOGV("Record failed to start");
@@ -4693,11 +4731,13 @@ bool AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
if (recordTrack != mActiveTrack.get() || recordTrack->mState == TrackBase::PAUSING) {
return false;
}
+ // note that threadLoop may still be processing the track at this point [without lock]
recordTrack->mState = TrackBase::PAUSING;
// do not wait for mStartStopCond if exiting
if (exitPending()) {
return true;
}
+ // FIXME incorrect usage of wait: no explicit predicate or loop
mStartStopCond.wait(mLock);
// if we have been restarted, recordTrack == mActiveTrack.get() here
if (exitPending() || recordTrack != mActiveTrack.get()) {
@@ -4833,6 +4873,7 @@ status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer*
// Force input into standby so that it tries to
// recover at next read attempt
inputStandBy();
+ // FIXME an awkward place to sleep, consider using doSleep when this is pulled up
usleep(kRecordThreadSleepUs);
}
buffer->raw = NULL;
@@ -4875,7 +4916,7 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l()
int value;
audio_format_t reqFormat = mFormat;
uint32_t reqSamplingRate = mReqSampleRate;
- uint32_t reqChannelCount = mReqChannelCount;
+ audio_channel_mask_t reqChannelMask = audio_channel_in_mask_from_count(mReqChannelCount);
if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
reqSamplingRate = value;
@@ -4890,8 +4931,13 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l()
}
}
if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
- reqChannelCount = popcount(value);
- reconfig = true;
+ audio_channel_mask_t mask = (audio_channel_mask_t) value;
+ if (mask != AUDIO_CHANNEL_IN_MONO && mask != AUDIO_CHANNEL_IN_STEREO) {
+ status = BAD_VALUE;
+ } else {
+ reqChannelMask = mask;
+ reconfig = true;
+ }
}
if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
// do not accept frame count changes if tracks are open as the track buffer
@@ -4940,6 +4986,7 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l()
}
mAudioSource = (audio_source_t)value;
}
+
if (status == NO_ERROR) {
status = mInput->stream->common.set_parameters(&mInput->stream->common,
keyValuePair.string());
@@ -4956,7 +5003,8 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l()
<= (2 * reqSamplingRate)) &&
popcount(mInput->stream->common.get_channels(&mInput->stream->common))
<= FCC_2 &&
- (reqChannelCount <= FCC_2)) {
+ (reqChannelMask == AUDIO_CHANNEL_IN_MONO ||
+ reqChannelMask == AUDIO_CHANNEL_IN_STEREO)) {
status = NO_ERROR;
}
if (status == NO_ERROR) {
@@ -5033,8 +5081,7 @@ void AudioFlinger::RecordThread::readInputParameters()
mFrameCount = mBufferSize / mFrameSize;
mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount];
- if (mSampleRate != mReqSampleRate && mChannelCount <= FCC_2 && mReqChannelCount <= FCC_2)
- {
+ if (mSampleRate != mReqSampleRate && mChannelCount <= FCC_2 && mReqChannelCount <= FCC_2) {
int channelCount;
// optimization: if mono to mono, use the resampler in stereo to stereo mode to avoid
// stereo to mono post process as the resampler always outputs stereo.
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 3fe470c..7999436 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -36,6 +36,8 @@ public:
audio_devices_t outDevice, audio_devices_t inDevice, type_t type);
virtual ~ThreadBase();
+ virtual status_t readyToRun();
+
void dumpBase(int fd, const Vector<String16>& args);
void dumpEffectChains(int fd, const Vector<String16>& args);
@@ -141,6 +143,7 @@ public:
void sendIoConfigEvent_l(int event, int param = 0);
void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
void processConfigEvents();
+ void processConfigEvents_l();
// see note at declaration of mStandby, mOutDevice and mInDevice
bool standby() const { return mStandby; }
@@ -156,7 +159,7 @@ public:
int sessionId,
effect_descriptor_t *desc,
int *enabled,
- status_t *status);
+ status_t *status /*non-NULL*/);
void disconnectEffect(const sp< EffectModule>& effect,
EffectHandle *handle,
bool unpinIfLast);
@@ -270,6 +273,7 @@ protected:
uint32_t mChannelCount;
size_t mFrameSize;
audio_format_t mFormat;
+ size_t mBufferSize; // HAL buffer size for read() or write()
// Parameter sequence by client: binder thread calling setParameters():
// 1. Lock mLock
@@ -353,7 +357,6 @@ public:
void dump(int fd, const Vector<String16>& args);
// Thread virtuals
- virtual status_t readyToRun();
virtual bool threadLoop();
// RefBase
@@ -419,7 +422,7 @@ public:
int sessionId,
IAudioFlinger::track_flags_t *flags,
pid_t tid,
- status_t *status);
+ status_t *status /*non-NULL*/);
AudioStreamOut* getOutput() const;
AudioStreamOut* clearOutput();
@@ -471,7 +474,6 @@ protected:
size_t mNormalFrameCount; // normal mixer and effects
int16_t* mMixBuffer; // frame size aligned mix buffer
- int8_t* mAllocMixBuffer; // mixer buffer allocation address
// 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
@@ -854,12 +856,12 @@ public:
// Thread virtuals
virtual bool threadLoop();
- virtual status_t readyToRun();
// RefBase
virtual void onFirstRef();
virtual status_t initCheck() const { return (mInput == NULL) ? NO_INIT : NO_ERROR; }
+
sp<AudioFlinger::RecordThread::RecordTrack> createRecordTrack_l(
const sp<AudioFlinger::Client>& client,
uint32_t sampleRate,
@@ -869,7 +871,7 @@ public:
int sessionId,
IAudioFlinger::track_flags_t *flags,
pid_t tid,
- status_t *status);
+ status_t *status /*non-NULL*/);
status_t start(RecordTrack* recordTrack,
AudioSystem::sync_event_t event,
@@ -912,13 +914,13 @@ public:
bool hasFastRecorder() const { return false; }
private:
- void clearSyncStartEvent();
+ void clearSyncStartEvent();
// Enter standby if not already in standby, and set mStandby flag
- void standby();
+ void standby();
// Call the HAL standby method unconditionally, and don't change mStandby flag
- void inputStandBy();
+ void inputStandBy();
AudioStreamIn *mInput;
SortedVector < sp<RecordTrack> > mTracks;
@@ -933,7 +935,6 @@ private:
int32_t *mRsmpOutBuffer;
int16_t *mRsmpInBuffer; // [mFrameCount * mChannelCount]
size_t mRsmpInIndex;
- size_t mBufferSize; // stream buffer size for read()
const uint32_t mReqChannelCount;
const uint32_t mReqSampleRate;
ssize_t mBytesRead;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 523e4b2..00a91b7 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -47,6 +47,7 @@ public:
int sessionId,
bool isOut);
virtual ~TrackBase();
+ virtual status_t initCheck() const { return getCblk() != 0 ? NO_ERROR : NO_MEMORY; }
virtual status_t start(AudioSystem::sync_event_t event,
int triggerSession) = 0;
@@ -76,15 +77,6 @@ protected:
virtual uint32_t sampleRate() const { return mSampleRate; }
- // 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 {
return (mState == STOPPED || mState == FLUSHED);
}
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 6002aa3..7f58300 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -366,6 +366,15 @@ AudioFlinger::PlaybackThread::Track::~Track()
ALOGV("PlaybackThread::Track destructor");
}
+status_t AudioFlinger::PlaybackThread::Track::initCheck() const
+{
+ status_t status = TrackBase::initCheck();
+ if (status == NO_ERROR && mName < 0) {
+ status = NO_MEMORY;
+ }
+ return status;
+}
+
void AudioFlinger::PlaybackThread::Track::destroy()
{
// NOTE: destroyTrack_l() can remove a strong reference to this Track
@@ -985,15 +994,17 @@ status_t AudioFlinger::PlaybackThread::TimedTrack::allocateTimedBuffer(
mTimedMemoryDealer = new MemoryDealer(kTimedBufferHeapSize,
"AudioFlingerTimed");
- if (mTimedMemoryDealer == NULL)
+ if (mTimedMemoryDealer == NULL) {
return NO_MEMORY;
+ }
}
sp<IMemory> newBuffer = mTimedMemoryDealer->allocate(size);
if (newBuffer == NULL) {
newBuffer = mTimedMemoryDealer->allocate(size);
- if (newBuffer == NULL)
+ if (newBuffer == NULL) {
return NO_MEMORY;
+ }
}
*buffer = newBuffer;
@@ -1702,9 +1713,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
{
ALOGV("RecordTrack constructor");
if (mCblk != NULL) {
- mAudioRecordServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
- mFrameSize);
- mServerProxy = mAudioRecordServerProxy;
+ mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, mFrameSize);
}
}