1. 程式人生 > >[RK3288][Android6.0] Audio中的單聲道到雙聲道的轉換處理過程

[RK3288][Android6.0] Audio中的單聲道到雙聲道的轉換處理過程

Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92

播放音樂是單聲道,硬體用的是雙聲道。

AudioFlinger::PlaybackThread::Track::Track ->
 thread->getTrackName_l ->
 AudioMixer::getTrackName ->
  t->channelCount = audio_channel_count_from_out_mask(channelMask)
  t->channelMask = channelMask;
  t->prepareForDownmix

status_t AudioMixer::track_t::prepareForDownmix()
{
......
    // MONO_HACK Only remix (upmix or downmix) if the track and mixer/device channel masks
    // are not the same and not handled internally, as mono -> stereo currently is.
    if (channelMask == mMixerChannelMask
            || (channelMask ==
AUDIO_CHANNEL_OUT_MONO && mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO)) { return NO_ERROR; } ...... // Effect downmixer does not accept the channel conversion. Let's use our remixer. RemixBufferProvider* pRbp = new RemixBufferProvider(channelMask, mMixerChannelMask, mMixerInFormat, kCopyBufferFrameCount); ...
... }

prepareForDownmix()有兩種情況下會直接返回:
1.資料來源channel和mix channel一樣時,那麼肯定不需要轉換
2.當資料來源是單聲道時,也不轉換,直接返回,它是一個特例,其實後面會處理。
否則會通過RemixBufferProvider這個類來實現input channel到output channel的轉換。

那麼單聲道的處理在哪裡呢?

void AudioMixer::process__validate(state_t* state, int64_t pts)
{
......
  if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
    //第一個引數結果為TRACKTYPE_NORESAMPLEMONO
    t.hook = getTrackHook(
            (t.mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO  // TODO: MONO_HACK
                    && t.channelMask == AUDIO_CHANNEL_OUT_MONO)
                ? TRACKTYPE_NORESAMPLEMONO : TRACKTYPE_NORESAMPLE,
            t.mMixerChannelCount,
            t.mMixerInFormat, t.mMixerFormat);
    all16BitsStereoNoResample = false;
   }
......
}
AudioMixer::hook_t AudioMixer::getTrackHook(int trackType, uint32_t channelCount,
        audio_format_t mixerInFormat, audio_format_t mixerOutFormat __unused)
{
......
 switch (trackType) {
......
    case TRACKTYPE_NORESAMPLEMONO:
        switch (mixerInFormat) {
        case AUDIO_FORMAT_PCM_FLOAT:
            return (AudioMixer::hook_t)
                    track__NoResample<MIXTYPE_MONOEXPAND, float, float, int32_t>;
        case AUDIO_FORMAT_PCM_16_BIT:
            //16bit的情況
            return (AudioMixer::hook_t)
                    track__NoResample<MIXTYPE_MONOEXPAND, int32_t, int16_t, int32_t>;
        default:
            LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
            break;
        }
  }
......
}

t.hook對應的處理函式是track__NoResample(),在process__genericNoResampling()中呼叫:

void AudioMixer::process__genericNoResampling(state_t* state, int64_t pts)
{
......
    if (inFrames > 0) {
        t.hook(&t, outTemp + (BLOCKSIZE - outFrames) * t.mMixerChannelCount,
                inFrames, state->resampleTemp, aux);
        t.frameCount -= inFrames;
        outFrames -= inFrames;
        if (CC_UNLIKELY(aux != NULL)) {
            aux += inFrames;
        }
    }
......
}

track__NoResample()是個模板函式。

template <int MIXTYPE, typename TO, typename TI, typename TA>
void AudioMixer::track__NoResample(track_t* t, TO* out, size_t frameCount,
        TO* temp __unused, TA* aux)
{
    ALOGVV("track__NoResample\n");
    const TI *in = static_cast<const TI *>(t->in);

    volumeMix<MIXTYPE, is_same<TI, float>::value, true>(
            out, frameCount, in, aux, t->needsRamp(), t);

    // MIXTYPE_MONOEXPAND reads a single input channel and expands to NCHAN output channels.
    // MIXTYPE_MULTI reads NCHAN input channels and places to NCHAN output channels.
    in += (MIXTYPE == MIXTYPE_MONOEXPAND) ? frameCount : frameCount * t->mMixerChannelCount;
    t->in = in;
}

註釋說得很明白了,將單聲道轉換成NCHAN聲道,這裡的NCHAN是2,也就是轉換成立體聲。