Verzeihen Sie mir, wenn mein Fragetitel schrecklich ist. Meine Frau sagt mir immer, ich bin nicht gut darin, Dinge zu formulieren.Ruft eine Blockierung snd_pcm_writei nach dem Decodieren von Audio seltsame Wiedergabe auf?
Ich habe einen Code geschrieben, der einen Puffer liest, der von einem anderen Thread gefüllt wird. Der Puffer ist mit Audiodaten gefüllt, die durch den Opus-Codec codiert sind. VoIP-Daten werden von der Gegenseite jeweils zu 20ms empfangen. Bei einem Versuch, Audio so schnell wie möglich in einer Schleife abzuspielen, nehme ich 20ms Daten zu einer bestimmten Zeit aus dem Puffer und decide sie dann und sende sie dann direkt zum Abspielen auf snd_pcm_wreitei.
Ich habe auf Google nach einigen Beispielen zur Verwendung von snd_pcm_writei mit zuvor codiertem Audio gesucht, um zu sehen, wie andere es tun. Ich hatte nicht viel Glück.
Mein Gedanke ist, wenn ich auf einen Mutex warte und auf die Kodierung warte, kann ich logisch nicht sehen, dass der Ton "glatt" ist. Ich könnte mir vorstellen, dass es zwischen jedem 20ms-Frame Zeitlücken gibt, in denen kein Audio an die Lautsprecher gesendet wird. Ist mein Verdacht richtig, dass dies wahrscheinlich zu fehlerhaften Audiodaten führen wird?
Mein Code diesbezüglich:
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)
Der PCM-Puffer ist größer als 20 ms, oder? –
Ja. Ich habe möglicherweise nicht erwähnt, warum ich das tat. Ich werde meine Frage auch bearbeiten. Es ist für eine Anwendung vom Typ VoIP, bei der Daten 20 ms gleichzeitig empfangen werden. Also versuche ich es so schnell wie möglich zu spielen. –
Also die Uhr des Senders und die Uhr des Gerätes sind nicht synchronisiert? –