2016-03-24 15 views
1

Soru başlığım korkunçsa beni affet. Karım her zaman bana bir şeyler söylemede iyi olmadığımı söylüyor.Ses kodlarının çözülmesinden sonra bir snd_pcm_writei engellenmesi garip oynatmaya neden olur mu?

Başka bir iş parçacığı tarafından doldurulan bir arabellek okuyan bir kod yazdım. Tampon, opus codec tarafından kodlanan ses verileriyle doldurulur. VoIP verileri bir seferde 20ms uzak taraftan alınır. Sesi mümkün olduğu kadar çabuk çalmak için, bir döngüde, arabellek dışında bir anda 20 ms veri alır ve sonra kodu çözer, sonra snd_pcm_writei'de oynatmak için doğrudan gönderirim.

Başkalarının bunu nasıl yaptığını görmek için önceden kodlanmış ses içeren snd_pcm_writei kullanımıyla ilgili bazı örnekler için Google'da etrafa baktım. Çok şansım olmadı.

Düşüncem şu ki, eğer bir muteks üzerinde bekliyorum ve kodlamayı beklerken sesin "düzgün" olduğunu mantıksal olarak göremiyorum. Her 20ms frame arasında, hoparlörlere sesin gönderilmediği zaman aralıkları olduğunu hayal ediyorum. Şüphelerim, bunun muhtemelen kusurlu ses oluşturacağını düzeltir mi? Buna ilişkin

Kodum: yazma 20-ms parçalar arasındaki zaman tam 20 ms, yeni bir yığın yazarken sonra cihazın tampon boş olacaktır ise

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 aygıtının arabelleği 20 ms'den daha büyük değil mi? –

+0

Evet. Bunu neden yaptığımı söyleyemedim. Sorumu da düzenlerim. Verilerin bir seferde 20 ms alındığı bir VoIP tipi uygulama içindir. Bu yüzden sadece en kısa zamanda oynamaya çalışıyorum. –

+0

Böylece gönderenin saati ve cihazın saati senkronize edilmiyor mu? –

cevap

2

. En küçük gecikme bile daha sonra bir alt kata neden olur.

Underrung'ları önlemek için arabayı olabildiğince doldurabilmeniz gerekir. Bu, başlangıçta, parçalar arasında beklemeden doldurmanız gerektiği anlamına gelir.

Göndericinin saati aygıt saatinden daha hızlı çalıştığında, akış eninde sonunda azalır. Bu, saat farkını ölçerek ve gönderenin iletim hızını değiştirerek veya verileri dinamik olarak yeniden örnekleyerek önlenebilir.

İlgili konular