Permalink
Browse files

Make RAOP server properly handle any size of decoded audio packets.

The system as-is would only play the first 352 decoded frames.
Following 86f5fd8, remove this limitation.

Also, be more leniant when dropping expired audio frames. I was suffering lots of dumped audio packets error. Now playback is almost perfect
  • Loading branch information...
1 parent 2d365d6 commit 1b24a764a43abe3683d04610ad516421e3116260 @jyavenard jyavenard committed Apr 5, 2012
Showing with 40 additions and 25 deletions.
  1. +31 −24 mythtv/libs/libmythtv/mythraopconnection.cpp
  2. +9 −1 mythtv/libs/libmythtv/mythraopconnection.h
@@ -30,7 +30,7 @@ MythRAOPConnection::MythRAOPConnection(QObject *parent, QTcpSocket *socket,
m_dataPort(port), m_dataSocket(NULL),
m_clientControlSocket(NULL), m_clientControlPort(0),
m_audio(NULL), m_codec(NULL), m_codeccontext(NULL),
- m_sampleRate(DEFAULT_SAMPLE_RATE), m_allowVolumeControl(true),
+ m_sampleRate(DEFAULT_SAMPLE_RATE), m_queueLength(0), m_allowVolumeControl(true),
m_seenPacket(false), m_lastPacketSequence(0), m_lastPacketTimestamp(0),
m_lastSyncTime(0), m_lastSyncTimestamp(0), m_lastLatency(0), m_latencyAudio(0),
m_latencyQueued(0), m_latencyCounter(0), m_avSync(0), m_audioTimer(NULL)
@@ -212,6 +212,8 @@ void MythRAOPConnection::udpDataReady(QByteArray buf, QHostAddress peer,
memcpy(decrypted_data + aeslen, data_in + aeslen, len - aeslen);
AVPacket tmp_pkt;
+ AVCodecContext *ctx = m_codeccontext;
+
av_init_packet(&tmp_pkt);
tmp_pkt.data = decrypted_data;
tmp_pkt.size = len;
@@ -220,41 +222,39 @@ void MythRAOPConnection::udpDataReady(QByteArray buf, QHostAddress peer,
{
int decoded_data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
int16_t *samples = (int16_t *)av_mallocz(AVCODEC_MAX_AUDIO_FRAME_SIZE);
- int used = avcodec_decode_audio3(m_codeccontext, samples,
- &decoded_data_size, &tmp_pkt);
+ int ret = avcodec_decode_audio3(ctx, samples,
+ &decoded_data_size, &tmp_pkt);
- if (used < 0)
+ if (ret < 0)
{
LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error decoding audio"));
break;
}
if (decoded_data_size > 0)
{
- int frames = decoded_data_size / 4;
-
- if (frames != 352)
- {
- LOG(VB_GENERAL, LOG_WARNING,
- LOC + QString("Decoded %1 frames (not 352)") .arg(frames));
- }
+ int frames = (ctx->channels <= 0 || decoded_data_size < 0) ? -1 :
+ decoded_data_size /
+ (ctx->channels * av_get_bits_per_sample_fmt(ctx->sample_fmt)>>3);
+ AudioFrame aframe;
+ aframe.samples = samples;
+ aframe.frames = frames;
+ aframe.size = decoded_data_size;
if (m_audioQueue.contains(this_timestamp))
LOG(VB_GENERAL, LOG_WARNING,
LOC + "Duplicate packet timestamp.");
- m_audioQueue.insert(this_timestamp, samples);
+ m_audioQueue.insert(this_timestamp, aframe);
+ m_queueLength += aframe.frames;
+ ProcessAudio(timenow);
this_timestamp += (frames * 1000) / m_sampleRate;
}
- tmp_pkt.data += used;
- tmp_pkt.size -= used;
+ tmp_pkt.data += ret;
+ tmp_pkt.size -= ret;
}
-
- // N.B. Unless playback is really messed up, this should only pass through
- // properly sequenced packets
- ProcessAudio(timenow);
}
uint64_t MythRAOPConnection::FramesToMs(uint64_t timestamp)
@@ -345,14 +345,16 @@ void MythRAOPConnection::ProcessSyncPacket(const QByteArray &buf, uint64_t timen
int MythRAOPConnection::ExpireAudio(uint64_t timestamp)
{
int res = 0;
- QMutableMapIterator<uint64_t,int16_t*> it(m_audioQueue);
+ QMutableMapIterator<uint64_t,AudioFrame> it(m_audioQueue);
while (it.hasNext())
{
it.next();
if (it.key() < timestamp)
{
- av_freep((void *)&(it.value()));
+ AudioFrame frame = it.value();
+ av_free((void *)frame.samples);
m_audioQueue.remove(it.key());
+ m_queueLength -= frame.frames;
res++;
}
}
@@ -370,28 +372,33 @@ void MythRAOPConnection::ProcessAudio(uint64_t timenow)
uint64_t updatedsync = m_lastSyncTimestamp + (timenow - m_lastSyncTime);
// expire anything that is late
- int dumped = ExpireAudio(updatedsync);
+ int dumped = ExpireAudio(m_lastSyncTimestamp-m_lastLatency);
+
if (dumped > 0)
{
LOG(VB_GENERAL, LOG_INFO, LOC + QString("Dumped %1 audio packets")
.arg(dumped));
}
int64_t avsync = (int64_t)(m_audio->GetAudiotime() - (int64_t)updatedsync);
- uint64_t queue_length = FramesToMs(m_audioQueue.size() * 352);
+ uint64_t queue_length = FramesToMs(m_queueLength);
uint64_t ideal_ts = updatedsync - queue_length - avsync + m_lastLatency;
m_avSync += avsync;
m_latencyAudio += m_audio->GetAudioBufferedTime();;
m_latencyQueued += queue_length;
m_latencyCounter++;
- QMapIterator<uint64_t,int16_t*> it(m_audioQueue);
+ QMapIterator<uint64_t,AudioFrame> it(m_audioQueue);
while (it.hasNext())
{
it.next();
if (it.key() < ideal_ts)
- m_audio->AddData(it.value(), 1408 /* FIXME */, it.key(), 352);
+ {
+ AudioFrame aframe = it.value();
+ m_audio->AddData((char *)aframe.samples, aframe.size,
+ it.key(), aframe.frames);
+ }
}
ExpireAudio(ideal_ts);
@@ -91,7 +91,15 @@ class MythRAOPConnection : public QObject
AVCodecContext *m_codeccontext;
QList<int> m_audioFormat;
int m_sampleRate;
- QMap<uint64_t, int16_t*> m_audioQueue;
+ typedef struct
+ {
+ int16_t *samples;
+ uint32_t frames;
+ uint32_t size;
+ } AudioFrame;
+
+ QMap<uint64_t, AudioFrame> m_audioQueue;
+ uint32_t m_queueLength;
bool m_allowVolumeControl;
// audio/packet sync
bool m_seenPacket;

0 comments on commit 1b24a76

Please sign in to comment.