android的混音是通过AudioMixer来实现的,最近遇到了一个混音的问题,该是好好看看音频的基本知识了。
很早之前就知道音频存储是通过采样来实现的,就是所谓的A/D(Analog-to-Digital Converter与D/A(Digital Analog Converter)
音轨有很多属性如
前三个比较重要,具体去了解一下
看到知乎上有一个回答,感觉挺形象的什么是音频的采样率?采样率和音质有没有关系?
一般的采样率固定在44100HZ(- -就是一秒记44100次),理由是因为人耳听觉范围在20HZ~20KHZ,这样记录能还原最高22.05KHZ的声音。
还有一个采样率48000HZ也比较常见
指每次采样所用的bit数,比如8bit,16bit
从命名来看,android好像用来8bit,16bit跟32bit
就是两个耳机有不同的声音??
一般有单通道(mono) 双通道(stereo)
参考博客园上的一篇博客[Android] 混音器AudioMixer 结合代码分析。
mNormalFrameCount为输入buffer大小??mSampleRate为输出采样率
AudioFlinger::MixerThread::MixerThread(...)
: ...{
...
mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
...
}
在MixerThread的prepareTracks_l会对AudioMixer的参数进行配置,如音量,输入源,混音参数等。
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(...){
...
// 设置输入源 name是引索集合,track是mActiveTracks??
mAudioMixer->setBufferProvider(name, track);
// 启用该启用的音轨并更新状态
mAudioMixer->enable(name);
// 设置左右音量
mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, &vlf);
mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, &vrf);
mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, &vaf);
// 设置混音格式
mAudioMixer->setParameter(name,AudioMixer::TRACK,AudioMixer::FORMAT, (void *)track->format());
// 设置通道数
mAudioMixer->setParameter(name,AudioMixer::TRACK,AudioMixer::CHANNEL_MASK, (void *)(uintptr_t)track->channelMask());
...
// 设置采样率
mAudioMixer->setParameter(name,AudioMixer::RESAMPLE,AudioMixer::SAMPLE_RATE,(void *)(uintptr_t)reqSampleRate);
// 设置播放速率
mAudioMixer->setParameter(name,AudioMixer::TIMESTRETCH,AudioMixer::PLAYBACK_RATE,&playbackRate);
... // mark一下
if (mMixerBufferEnabled && (track->mainBuffer() == mSinkBuffer || track->mainBuffer() == mMixerBuffer)) {
mAudioMixer->setParameter(name,AudioMixer::TRACK,AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
}
// 设置输出
mAudioMixer->setParameter(name,AudioMixer::TRACK,AudioMixer::MAIN_BUFFER, (void *)mMixerBuffer);
...
}
先计算track的flags,然后通过flags来判断要混音的函数
void AudioMixer::process__validate(state_t* state, int64_t pts)
{
...(计算需要invalidate的track)
// 主要通过下列几个参数去判断
bool all16BitsStereoNoResample = true;
bool resampling = false;
bool volumeRamp = false;
uint32_t en = state->enabledTracks;
while (en) { //对所有需要进行混音的track
const int i = 31 - __builtin_clz(en); //取出最高位为1的bit
en &= ~(1<tracks[i]; //取出来track
// 计算flags
uint32_t n = 0;
n |= NEEDS_CHANNEL_1 + t.channelCount - 1; //至少有一个channel需要混音
n |= NEEDS_FORMAT_16; //必须为16bit PCM
n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED; //是否需要重采样
if (t.auxLevel != 0 && t.auxBuffer != NULL) {
n |= NEEDS_AUX_ENABLED;
}
if (t.volumeInc[0]|t.volumeInc[1]) {
volumeRamp = true;
} else if (!t.doesResample() && t.volumeRL == 0) {
n |= NEEDS_MUTE_ENABLED;
}
t.needs = n; //更新track flag
...(通过flags选择混音函数)
//这里调用一次进行混音,后续会在MixerThread的threadLoop_mix内调用
state->hook(state, pts);
...
}
}
就是像搓面把几根面搓成一团
示意图
在android里使用process_xxx函数来实现,几个方法大同小异(不是我说的),举个process__genericResampling当例子。
// generic code with resampling
void AudioMixer::process__genericResampling(state_t* state, int64_t pts)
{
int32_t* const outTemp = state->outputTemp;
size_t numFrames = state->frameCount;
uint32_t e0 = state->enabledTracks;
while (e0) {
...(选出有相同mainBuffer的track集合e1)
int32_t *out = t1.mainBuffer;
memset(outTemp, 0, size);
// 搓面
while (e1) {
const int i = 31 - __builtin_clz(e1);
e1 &= ~(1<tracks[i];
int32_t *aux = NULL;
if (CC_UNLIKELY(t.needs & NEEDS_AUX)) {
aux = t.auxBuffer;
}
// this is a little goofy, on the resampling case we don't
// acquire/release the buffers because it's done by
// the resampler.
if (t.needs & NEEDS_RESAMPLE) {
t.resampler->setPTS(pts);
t.hook(&t, outTemp, numFrames, state->resampleTemp, aux);
} else {...}
}
}
}
真正的采样在这(最终的采样在resample)
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) {
...(设置ramp音量)
} 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);
}
}
}