我正在尝试构建一个最小的循环音频
Microphone -> Portaudio -> buffer -> Speex encoder -> Speex decoder -> buffer -> Portaudio -> Headphones
如果没有 Speex,我可以使用 Portaudio 获取音频并在耳机中播放。插入 Speex 编码器/解码器会中断循环音频。根据 Speex 的要求,我将 Portaudio 设置为将音频缓冲区保存为一种short int*
类型。下面是主循环列表:
#define SAMPLE_RATE (44100)
#define PA_SAMPLE_TYPE paInt16
[...]
// initializes Speex
// sets speex_nb_mode for narrow band coding
speex_bits_init(&bits);
enc_state = speex_encoder_init(&speex_nb_mode);
dec_state = speex_decoder_init(&speex_nb_mode);
// gets frame size in samples
int samplesPerFrameEncoder = 0, samplesPerFrameDecoder = 0;
speex_encoder_ctl(enc_state, SPEEX_GET_FRAME_SIZE,
&samplesPerFrameEncoder);
speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE,
&samplesPerFrameDecoder);
if (samplesPerFrameDecoder != samplesPerFrameEncoder)
throw "Samples per frame between decoder and encoder differ";
// sets quality [0-10]
int quality = 10;
speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &quality);
// open a Portaudio stream
error = Pa_OpenStream(&pStream, // reference to pointer to stream variable
&inputParameters, // reference to input stream properties
&outputParameters, // reference to output stream properties
SAMPLE_RATE, // chosen sample rate
FRAMES_PER_BUFFER, // block granularity for audio sample
// flags for streaming process. In this case we stream
// audio sample that never go out of range so we do not
// clip them
paClipOff,
// no callback, use blocking API, input is passed directly
// to output
NULL,
// no callback, so no callback userData
NULL);
endOnError(pStream, error, pAudioSample);
// starts audio processing
error = Pa_StartStream(pStream);
endOnError(pStream, error, pAudioSample);
char* pSpeexEncodedSample = NULL;
int nbBytes = 0;
while (1)
{
// TODO decodes audio sample from speex array
if (nbBytes != 0)
{
CLEAR(pAudioSample);
speex_bits_read_from(&bits, pSpeexEncodedSample, nbBytes);
speex_decode_int(dec_state, &bits, (short*) pAudioSample);
// writes audio sample to output stream
error = Pa_WriteStream(pStream, // pointer to stream variable
pAudioSample, // pointer to audio sample
FRAMES_PER_BUFFER // block granularity for audio sample
);
}
// reads audio sample from input stream
error = Pa_ReadStream(pStream, // pointer to stream variable
pAudioSample, // pointer to audio sample
FRAMES_PER_BUFFER // block granularity for audio sample
);
// TODO codes audio sample to speex array
speex_bits_reset(&bits);
speex_encode_int(enc_state, (short*) pAudioSample, &bits);
int bytesRequired = speex_bits_nbytes(&bits);
if (pSpeexEncodedSample != NULL)
{
free(pSpeexEncodedSample);
pSpeexEncodedSample = NULL;
}
pSpeexEncodedSample = (char*) malloc(
bytesRequired * sizeof(char));
nbBytes = speex_bits_write(&bits, pSpeexEncodedSample,
bytesRequired);
}
[...]
谢谢