2016-03-24 25 views
1

私の質問のタイトルがひどい場合は、私に許してください。私の妻はいつも私は物事を表現することがうまくいかないと私に言っています。オーディオをデコードした後にsnd_pcm_writeiをブロックすると奇妙な再生が発生しますか?

別のスレッドで満たされたバッファを読み取るコードを記述しました。バッファには、opusコーデックでエンコードされたオーディオデータが格納されます。 VoIPデータはリモート側から20msずつ受信されます。できるだけ早くオーディオを再生しようとすると、バッファから一度に20ミリ秒分のデータを取り出し、それをデコードして直ちに送信してsnd_pcm_writeiを再生します。

私は、以前にエンコードされたオーディオでsnd_pcm_writeiを使用して他の人がどのようにしているかを確認するためのいくつかの例をGoogleで見てきました。私は多くの運がなかった。

私はミューテックスを待ってエンコーディングを待っていると、オーディオが論理的に「滑らか」であるとは思えません。私は各20msのフレームの間に、音声がスピーカーに送られていない時間のギャップがあると思います。これが不完全なオーディオを作成する可能性があるという私の疑惑は正しいのでしょうか?これに関連し

私のコード:20ミリ秒のチャンクを書き込むまでの時間が正確に20msである場合は、新しいチャンクを書いているとき

while(true) 
{ 
    // We need a positive lock 
    if(!buffer_lock) 
     buffer_lock.lock(); 

    LOG_DEBUG(*logger_) << "After the mutex lock."; 
    LOG_DEBUG(*logger_) << "Buffer size: " << current_audio->buffer_size_; 
    LOG_DEBUG(*logger_) << "Read pointer: " << current_audio->read_pointer_; 

    opus_int32 payload_size; 

    LOG_DEBUG(*logger_) << "calling audioCanDecodeChunk()"; 

    // Now fisticuffs do we have enouffs? 
    if(audioCanDecodeChunk(current_audio, payload_size)) 
    { 
     LOG_DEBUG(*logger_) << "We have enough current_audio buffer."; 

     // Are we dank? 
     if(payload_size<0 or payload_size>MAX_PACKET) 
     { 
      LOG_ERROR(*logger_) << "Decoding error, payload size (" << payload_size << ") is outsize range."; 
      break; // Terminal 
     } 

     // We have enough! 
     // Advance the read pointer 
     current_audio->read_pointer_+= 4; 

     // Copy it out 
     memcpy(payload_buffer, current_audio->buffer_+current_audio->read_pointer_, payload_size); 

     // Release it 
     buffer_lock.unlock(); 

     // Now thingify it 
     int samples_decoded = opus_decode(opus_decoder_, 
       (const unsigned char *)payload_buffer, 
       payload_size, 
       (opus_int16 *)pcm_buffer, 
       MAX_FRAME_SIZE, 
       0); 

     // How did we do? 
     if(samples_decoded<0) 
     { 
      // What hap? 
      LOG_ERROR(*logger_) << "Error decoding samples: " << opus_strerror(samples_decoded); 
      break; 
     } 
     else 
     { 
      // Now we have our PCM! 
      int bytes_decoded = current_audio->recording_.channels*sizeof(opus_int16)*samples_decoded; 

      LOG_DEBUG(*logger_) << "We have decoded " << bytes_decoded << " bytes payload: " << payload_size; 

      // Now write 
      if((error = snd_pcm_writei(playback_handle_, pcm_buffer, samples_decoded))!=samples_decoded) 
      { 
       LOG_ERROR(*logger_) << "snd_pcm_writei error: " << snd_strerror(error); 
      } 
     } 

     // Advance pointer 
     current_audio->read_pointer_+= payload_size; 

    } // If we don't have enough let it slide and unlock 
    else if(current_audio->done_) // Were we issued a flush? 
    { 
     LOG_DEBUG(*logger_) << "We are done."; 

     // We are done with this loop 
     break; 
    } 
    else 
    { 
     // Wait for it (an update) 
     LOG_DEBUG(*logger_) << "Before wait_buffer wait. Done: " << (current_audio->done_ ? "true" : "false") << 
      "Size: " << current_audio->buffer_size_ 
      << ", Read: " << current_audio->read_pointer_; 
     current_audio->wait_buffer_.wait(buffer_lock); 
     LOG_DEBUG(*logger_) << "After wait_buffer wait"; 
    } 

} // End while(true) 
+0

PCMデバイスのバッファが20ミリ秒を超えていますか? –

+0

はい。なぜ私がこれをやっているのか言及しなかったのかもしれません。私は私の質問も編集します。これは、データが一度に20ms受信されるVoIPタイプのアプリケーション用です。だから私はできるだけ早くそれを再生しようとしています。 –

+0

送信者の時計とデバイスの時計は同期していませんか? –

答えて

2

は、その後、デバイスのバッファが空になります。最小の遅延でさえも、アンダーランが発生します。

アンダーラングを防ぐには、バッファを可能な限りフルに保つ必要があります。つまり、最初はチャンク間を待たずに入力する必要があります。

送信者のクロックがデバイスのクロックより速く実行されると、ストリームは最終的にアンダーランします。これは、クロック差を測定し、送信者の送信レートを変更するか、データを動的に再サンプリングすることによって回避できます。

関連する問題