3

Speex のエンコード/デコード手順をバイパスすると、生のオーディオ出力は正しくなります。私が望むのは、録音コールバックからキャプチャされたバッファ全体がエンコード、デコードされ、再生ループに送り返されることです。私が確信していないいくつかの項目は次のとおりです。

  1. enc_buffer と dec_buffer に割り当てるサイズ
  2. speex_bits_read_from(SpeexBits* bits,char* bytes,int len) で指定する長さ
  3. int speex_bits_write(SpeexBits* bits,char* bytes,int max_len) で指定する最大サイズ

これが私のspeexコーデックの初期化です:

#define SAMPLE_RATE 8000
#define MAX_FRAMES 100
#define FRAME_SIZE 160

enc_state = speex_encoder_init(&speex_nb_mode);
dec_state = speex_decoder_init(&speex_nb_mode);

spx_int32_t tmp;
tmp=5;
speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &tmp);
tmp=1;
speex_encoder_ctl(enc_state, SPEEX_SET_COMPLEXITY, &tmp);

speex_encoder_ctl(enc_state, SPEEX_GET_FRAME_SIZE, &enc_frame_size );
speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE, &dec_frame_size );

tmp = SAMPLE_RATE;

speex_encoder_ctl(enc_state, SPEEX_SET_SAMPLING_RATE, &tmp);
speex_decoder_ctl(dec_state, SPEEX_SET_SAMPLING_RATE, &tmp);

speex_bits_init(&enc_bits);
speex_bits_init(&dec_bits);

//Unsure of this allocation size
enc_buffer = (char*)malloc(sizeof(char)*enc_frame_size*MAX_FRAMES);
dec_buffer = (spx_int16_t*)malloc(sizeof(spx_int16_t)*dec_frame_size*MAX_FRAMES);

私のエンコード/デコード方法:

-(char*)encodeAudioBuffer:(spx_int16_t*)audioBuffer withByteSize:(int)numberOfFrames andWriteSizeTo:(int*)inSize{
    speex_bits_reset(&enc_bits);
    speex_encode_int(enc_state, audioBuffer, &enc_bits);

    //Unsure of this third argument. 'numberOfFrames' is the stored number of input frames from my recording callback.
    *inSize = speex_bits_write(&enc_bits, enc_buffer, numberOfFrames*enc_frame_size);

    return enc_buffer;
}
-(spx_int16_t*)decodeSpeexBits:(char*)encodedAudio  withEncodedSize:(int)encodedSize andDecodedSize:(int)decodedSize{

    //Unsure of this third argument.  'encodedSize' is the number written to *inSize in the encode method
    speex_bits_read_from(&dec_bits, encodedAudio, encodedSize*dec_frame_size);

    speex_decode_int(dec_state, &dec_bits, dec_buffer);
    return dec_buffer;
}

そして、それらは次のように呼び出されます。

- (void)encodeBufferList:(AudioBufferList*)bufferList withNumberOfFrames:(int)numberOfFrames{
    AudioBuffer sourceBuffer = bufferList->mBuffers[0];
    int speexSize = 0;
    char* encodedAudio = [speexCodec encodeAudioBuffer:(spx_int16_t*)sourceBuffer.mData withByteSize:numberOfFrames andWriteSizeTo:&speexSize];
    spx_int16_t* decodedAudio = [speexCodec decodeSpeexBits:encodedAudio withEncodedSize:speexSize andDecodedSize:sourceBuffer.mDataByteSize];
    memcpy(audioBuffer.mData, sourceBuffer.mData, numberOfFrames * sizeof(SInt32));
}

ここで、「bufferList」は、録音/再生コールバックから返されたものです。バッファが適切に満たされていることを誰かが確認できますか? ここで報告された同様の問題を見ましたが、コードのどこで間違っている可能性があるかを確認できませんでした。

static OSStatus recordingCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
{
    AudioBuffer buffer;
    OSStatus status;
    AudioStreamer *input = (__bridge AudioStreamer*) inRefCon;

    buffer.mDataByteSize = inNumberFrames * sizeof(SInt16);
    buffer.mNumberChannels = 1;
    buffer.mData = malloc( inNumberFrames * sizeof(SInt16));

    AudioBufferList bufferList;
    bufferList.mNumberBuffers = 1;
    bufferList.mBuffers[0] = buffer;

    status = AudioUnitRender([input rioAUInstance], ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);
    [input encodeBufferList:&bufferList withNumberOfFrames:inNumberFrames];
    return noErr;
}

static OSStatus playbackCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
{
    AudioStreamer* input = (__bridge AudioStreamer*)inRefCon;
    UInt32 size = MIN(ioData->mBuffers[0].mDataByteSize, [input audioBuffer].mDataByteSize);
    memcpy(ioData->mBuffers[0].mData, input.audioBuffer.mData, size);
    return noErr;
}

エンコード/デコードによって生成されるノイズは、そのままでは粒状の静的なヒスノイズですが、完全にランダムな情報ではありません。マイクに息を吹き込むと、ノイズの背後で聞こえます。

この問題を解決するための助けをいただければ幸いです。すべてが整理されたら、おそらくそれについてブログを書くことになるでしょう。多くの人が、このコーデックを設定するさまざまな些細な問題に遭遇しているようです。

4

2 に答える 2

1

したがって、これはエンコード/デコード関数の問題でした。一度に 1 フレームしか処理していないように見えるため、複数のフレームにわたって speex_encode_int を呼び出す必要があり、次にそれらを次のようにエンコード バッファーに書き込みます。

-(char*)encodeAudioBuffer:(spx_int16_t*)audioBuffer withNumberOfFrames:(int)numberOfFrames andWriteSizeTo:(int*)inSize{
    speex_bits_reset(&enc_bits);
    for(int i = 0; i < numberOfFrames; ++i){
        speex_encode_int(enc_state, audioBuffer+i, &enc_bits);
    }
    *inSize = speex_bits_write(&enc_bits, enc_buffer, numberOfFrames);
    return enc_buffer;
}

デコードの場合も同様に、エンコードされたバッファから speex_bits_read_from し、各フレームの dec_bits を繰り返し、デコードされたバッファに書き込みます。

-(spx_int16_t*)decodeSpeexBits:(char*)encodedAudio  withEncodedSize:(int)encodedSize andNumberOfFrames:(int)numberOfFrames{
    speex_bits_read_from(&dec_bits, encodedAudio, encodedSize);
    for(int i = 0; i < numberOfFrames; ++i){
        speex_decode_int(dec_state, &dec_bits, dec_buffer+i);
    }
    return dec_buffer;
}

これはまだかなり遅いです。浮動小数点計算ではなく固定小数点計算を使用するように Speex ライブラリを構成した後でも、オーディオ ループよりも低速で実行されます (新しい種類の途切れが発生します)。これをより速く実行する方法についての手がかりはありますか?

于 2013-02-07T17:57:21.420 に答える
0

両方のループで、オーディオ バッファーを渡していますが、フレーム サイズを考慮していません。

for(int i = 0; i < numberOfFrames; ++i){
    speex_encode_int(enc_state, audioBuffer+i, &enc_bits);
}

それは次のようになります。

for(int i = 0; i < numberOfFrames; ++i){
    speex_encode_int(enc_state, audioBuffer + (i * enc_frame_size), &enc_bits);
}

それが役立つことを願っています。

于 2013-02-09T16:28:42.703 に答える