AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l( Vector< sp<Track> > *tracksToRemove) { mAudioMixer->setParameter( name, AudioMixer::RESAMPLE, AudioMixer::SAMPLE_RATE, (void *)(uintptr_t)reqSampleRate); } void AudioMixer::setParameter(int name, int target, int param, void *value) { name -= TRACK0; ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); track_t& track = mState.tracks[name]; int valueInt = static_cast<int>(reinterpret_cast<uintptr_t>(value)); int32_t *valueBuf = reinterpret_cast<int32_t*>(value); switch (target) { ...... case RESAMPLE: switch (param) { case SAMPLE_RATE: ALOG_ASSERT(valueInt > 0, "bad sample rate %d", valueInt); if (track.setResampler(uint32_t(valueInt), mSampleRate)) { ALOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)", uint32_t(valueInt)); invalidateState(1 << name); } break; case RESET: track.resetResampler(); invalidateState(1 << name); break; case REMOVE: delete track.resampler; track.resampler = NULL; track.sampleRate = mSampleRate; invalidateState(1 << name); break; default: LOG_ALWAYS_FATAL("setParameter resample: bad param %d", param); } break; ...... default: LOG_ALWAYS_FATAL("setParameter: bad target %d", target); } } bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSampleRate) { if (trackSampleRate != devSampleRate || resampler != NULL) { if (sampleRate != trackSampleRate) { sampleRate = trackSampleRate; if (resampler == NULL) { ALOGV("Creating resampler from track %d Hz to device %d Hz", trackSampleRate, devSampleRate); AudioResampler::src_quality quality; // force lowest quality level resampler if use case isn't music or video // FIXME this is flawed for dynamic sample rates, as we choose the resampler // quality level based on the initial ratio, but that could change later. // Should have a way to distinguish tracks with static ratios vs. dynamic ratios. if (!((trackSampleRate == 44100 && devSampleRate == 48000) || (trackSampleRate == 48000 && devSampleRate == 44100))) { quality = AudioResampler::DYN_LOW_QUALITY; } else { quality = AudioResampler::DEFAULT_QUALITY; } // TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer // but if none exists, it is the channel count (1 for mono). const int resamplerChannelCount = downmixerBufferProvider != NULL ? mMixerChannelCount : channelCount; ALOGVV("Creating resampler:" " format(%#x) channels(%d) devSampleRate(%u) quality(%d)\n", mMixerInFormat, resamplerChannelCount, devSampleRate, quality); resampler = AudioResampler::create( mMixerInFormat, resamplerChannelCount, devSampleRate, quality); resampler->setLocalTimeFreq(sLocalTimeFreq); } return true; } } return false; } void AudioFlinger::MixerThread::threadLoop_mix() { // obtain the presentation timestamp of the next output buffer int64_t pts; status_t status = INVALID_OPERATION; if (mNormalSink != 0) { status = mNormalSink->getNextWriteTimestamp(&pts); } else { status = mOutputSink->getNextWriteTimestamp(&pts); } if (status != NO_ERROR) { pts = AudioBufferProvider::kInvalidPTS; } // mix buffers... mAudioMixer->process(pts); mCurrentWriteLength = mSinkBufferSize; // increase sleep time progressively when application underrun condition clears. // Only increase sleep time if the mixer is ready for two consecutive times to avoid // that a steady state of alternating ready/not ready conditions keeps the sleep time // such that we would underrun the audio HAL. if ((sleepTime == 0) && (sleepTimeShift > 0)) { sleepTimeShift--; } sleepTime = 0; standbyTime = systemTime() + standbyDelay; //TODO: delay standby when effects have a tail } <pre name="code" class="cpp">void AudioMixer::process(int64_t pts) { mState.hook(&mState, pts); }
bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSampleRate) { if (trackSampleRate != devSampleRate || resampler != NULL) { if (sampleRate != trackSampleRate) { sampleRate = trackSampleRate; if (resampler == NULL) { ALOGV("Creating resampler from track %d Hz to device %d Hz", trackSampleRate, devSampleRate); AudioResampler::src_quality quality; // force lowest quality level resampler if use case isn't music or video // FIXME this is flawed for dynamic sample rates, as we choose the resampler // quality level based on the initial ratio, but that could change later. // Should have a way to distinguish tracks with static ratios vs. dynamic ratios. if (!((trackSampleRate == 44100 && devSampleRate == 48000) || (trackSampleRate == 48000 && devSampleRate == 44100))) { quality = AudioResampler::DYN_LOW_QUALITY; } else { quality = AudioResampler::DEFAULT_QUALITY; } // TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer // but if none exists, it is the channel count (1 for mono). const int resamplerChannelCount = downmixerBufferProvider != NULL ? mMixerChannelCount : channelCount; ALOGVV("Creating resampler:" " format(%#x) channels(%d) devSampleRate(%u) quality(%d)\n", mMixerInFormat, resamplerChannelCount, devSampleRate, quality); resampler = AudioResampler::create( mMixerInFormat, resamplerChannelCount, devSampleRate, quality); resampler->setLocalTimeFreq(sLocalTimeFreq); } return true; } } return false; }
void AudioMixer::process__validate(state_t* state, int64_t pts) { ALOGW_IF(!state->needsChanged, "in process__validate() but nothing's invalid"); uint32_t changed = state->needsChanged; state->needsChanged = 0; // clear the validation flag // recompute which tracks are enabled / disabled uint32_t enabled = 0; uint32_t disabled = 0; while (changed) { const int i = 31 - __builtin_clz(changed); const uint32_t mask = 1<<i; changed &= ~mask; track_t& t = state->tracks[i]; (t.enabled ? enabled : disabled) |= mask; } state->enabledTracks &= ~disabled; state->enabledTracks |= enabled; // compute everything we need... int countActiveTracks = 0; // TODO: fix all16BitsStereNoResample logic to // either properly handle muted tracks (it should ignore them) // or remove altogether as an obsolete optimization. bool all16BitsStereoNoResample = true; bool resampling = false; bool volumeRamp = false; uint32_t en = state->enabledTracks; while (en) { const int i = 31 - __builtin_clz(en); en &= ~(1<<i); countActiveTracks++; track_t& t = state->tracks[i]; uint32_t n = 0; // FIXME can overflow (mask is only 3 bits) n |= NEEDS_CHANNEL_1 + t.channelCount - 1; if (t.doesResample()) { n |= NEEDS_RESAMPLE; } if (t.auxLevel != 0 && t.auxBuffer != NULL) { n |= NEEDS_AUX; } if (t.volumeInc[0]|t.volumeInc[1]) { volumeRamp = true; } else if (!t.doesResample() && t.volumeRL == 0) { n |= NEEDS_MUTE; } t.needs = n; if (n & NEEDS_MUTE) { t.hook = track__nop; } else { if (n & NEEDS_AUX) { all16BitsStereoNoResample = false; } if (n & NEEDS_RESAMPLE) { all16BitsStereoNoResample = false; resampling = true; t.hook = getTrackHook(TRACKTYPE_RESAMPLE, t.mMixerChannelCount, t.mMixerInFormat, t.mMixerFormat); ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2, "Track %d needs downmix + resample", i); } else { if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){ t.hook = getTrackHook( t.mMixerChannelCount == 2 // TODO: MONO_HACK. ? TRACKTYPE_NORESAMPLEMONO : TRACKTYPE_NORESAMPLE, t.mMixerChannelCount, t.mMixerInFormat, t.mMixerFormat); all16BitsStereoNoResample = false; } if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2){ t.hook = getTrackHook(TRACKTYPE_NORESAMPLE, t.mMixerChannelCount, t.mMixerInFormat, t.mMixerFormat); ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2, "Track %d needs downmix", i); } } } } // select the processing hooks state->hook = process__nop; if (countActiveTracks > 0) { if (resampling) { if (!state->outputTemp) { state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount]; } if (!state->resampleTemp) { state->resampleTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount]; } state->hook = process__genericResampling; } else { if (state->outputTemp) { delete [] state->outputTemp; state->outputTemp = NULL; } if (state->resampleTemp) { delete [] state->resampleTemp; state->resampleTemp = NULL; } state->hook = process__genericNoResampling; if (all16BitsStereoNoResample && !volumeRamp) { if (countActiveTracks == 1) { const int i = 31 - __builtin_clz(state->enabledTracks); track_t& t = state->tracks[i]; if ((t.needs & NEEDS_MUTE) == 0) { // The check prevents a muted track from acquiring a process hook. // // This is dangerous if the track is MONO as that requires // special case handling due to implicit channel duplication. // Stereo or Multichannel should actually be fine here. state->hook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK, t.mMixerChannelCount, t.mMixerInFormat, t.mMixerFormat); } } } } } ALOGV("mixer configuration change: %d activeTracks (%08x) " "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d", countActiveTracks, state->enabledTracks, all16BitsStereoNoResample, resampling, volumeRamp); state->hook(state, pts); // Now that the volume ramp has been done, set optimal state and // track hooks for subsequent mixer process 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) { t.needs |= NEEDS_MUTE; t.hook = track__nop; } else { allMuted = false; } } if (allMuted) { state->hook = process__nop; } else if (all16BitsStereoNoResample) { if (countActiveTracks == 1) { const int i = 31 - __builtin_clz(state->enabledTracks); track_t& t = state->tracks[i]; // Muted single tracks handled by allMuted above. state->hook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK, t.mMixerChannelCount, t.mMixerInFormat, t.mMixerFormat); } } } }
void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux) { ALOGVV("track__genericResample\n"); t->resampler->setSampleRate(t->sampleRate); // ramp gain - resample to temp buffer and scale/mix in 2nd step if (aux != NULL) { // always resample with unity gain when sending to auxiliary buffer to be able // to apply send level after resampling t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); memset(temp, 0, outFrameCount * t->mMixerChannelCount * sizeof(int32_t)); t->resampler->resample(temp, outFrameCount, t->bufferProvider); if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { volumeRampStereo(t, out, outFrameCount, temp, aux); } else { volumeStereo(t, out, outFrameCount, temp, aux); } } else { if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); t->resampler->resample(temp, outFrameCount, t->bufferProvider); volumeRampStereo(t, out, outFrameCount, temp, aux); } // constant gain else { t->resampler->setVolume(t->mVolume[0], t->mVolume[1]); t->resampler->resample(out, outFrameCount, t->bufferProvider); } } }