1 /* rtp_audio_frame.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9 
10 #include "rtp_audio_stream.h"
11 
12 #ifdef QT_MULTIMEDIA_LIB
13 
14 #ifdef HAVE_SPEEXDSP
15 #include <speex/speex_resampler.h>
16 #else
17 #include "../../speexdsp/speex_resampler.h"
18 #endif /* HAVE_SPEEXDSP */
19 
20 #include <epan/rtp_pt.h>
21 #include <epan/to_str.h>
22 
23 #include <epan/dissectors/packet-rtp.h>
24 
25 #include <ui/rtp_media.h>
26 #include <ui/rtp_stream.h>
27 #include <ui/tap-rtp-common.h>
28 
29 #include <wsutil/nstime.h>
30 
31 #include <ui/qt/utils/rtp_audio_routing_filter.h>
32 #include <ui/qt/utils/rtp_audio_file.h>
33 
34 #include <QAudioFormat>
35 #include <QAudioOutput>
36 #include <QVariant>
37 #include <QTimer>
38 
39 // To do:
40 // - Only allow one rtpstream_info_t per RtpAudioStream?
41 
42 static const spx_int16_t visual_sample_rate_ = 1000;
43 
RtpAudioStream(QObject * parent,rtpstream_id_t * id,bool stereo_required)44 RtpAudioStream::RtpAudioStream(QObject *parent, rtpstream_id_t *id, bool stereo_required) :
45     QObject(parent)
46     , first_packet_(true)
47     , decoders_hash_(rtp_decoder_hash_table_new())
48     , global_start_rel_time_(0.0)
49     , start_abs_offset_(0.0)
50     , start_rel_time_(0.0)
51     , stop_rel_time_(0.0)
52     , stereo_required_(stereo_required)
53     , first_sample_rate_(0)
54     , audio_out_rate_(0)
55     , audio_requested_out_rate_(0)
56     , audio_resampler_(0)
57     , audio_output_(NULL)
58     , max_sample_val_(1)
59     , max_sample_val_used_(1)
60     , color_(0)
61     , jitter_buffer_size_(50)
62     , timing_mode_(RtpAudioStream::JitterBuffer)
63     , start_play_time_(0)
64 {
65     rtpstream_id_copy(id, &id_);
66     memset(&rtpstream_, 0, sizeof(rtpstream_));
67     rtpstream_id_copy(&id_, &rtpstream_.id);
68 
69     // Rates will be set later, we just init visual resampler
70     visual_resampler_ = speex_resampler_init(1, visual_sample_rate_,
71                                                 visual_sample_rate_, SPEEX_RESAMPLER_QUALITY_MIN, NULL);
72 
73     try {
74         // RtpAudioFile is ready for writing Frames
75         audio_file_ = new RtpAudioFile(prefs.gui_rtp_player_use_disk1, prefs.gui_rtp_player_use_disk2);
76     } catch (...) {
77         speex_resampler_destroy(visual_resampler_);
78         rtpstream_info_free_data(&rtpstream_);
79         rtpstream_id_free(&id_);
80         throw -1;
81     }
82 
83     // RTP_STREAM_DEBUG("Writing to %s", tempname.toUtf8().constData());
84 }
85 
~RtpAudioStream()86 RtpAudioStream::~RtpAudioStream()
87 {
88     for (int i = 0; i < rtp_packets_.size(); i++) {
89         rtp_packet_t *rtp_packet = rtp_packets_[i];
90         g_free(rtp_packet->info);
91         g_free(rtp_packet->payload_data);
92         g_free(rtp_packet);
93     }
94     g_hash_table_destroy(decoders_hash_);
95     if (audio_resampler_) speex_resampler_destroy(audio_resampler_);
96     speex_resampler_destroy(visual_resampler_);
97     rtpstream_info_free_data(&rtpstream_);
98     rtpstream_id_free(&id_);
99     if (audio_file_) delete audio_file_;
100     // temp_file_ is released by audio_output_
101     if (audio_output_) delete audio_output_;
102 }
103 
isMatch(const rtpstream_id_t * id) const104 bool RtpAudioStream::isMatch(const rtpstream_id_t *id) const
105 {
106     if (id
107         && rtpstream_id_equal(&id_, id, RTPSTREAM_ID_EQUAL_SSRC))
108         return true;
109     return false;
110 }
111 
isMatch(const _packet_info * pinfo,const _rtp_info * rtp_info) const112 bool RtpAudioStream::isMatch(const _packet_info *pinfo, const _rtp_info *rtp_info) const
113 {
114     if (pinfo && rtp_info
115         && rtpstream_id_equal_pinfo_rtp_info(&id_, pinfo, rtp_info))
116         return true;
117     return false;
118 }
119 
addRtpPacket(const struct _packet_info * pinfo,const struct _rtp_info * rtp_info)120 void RtpAudioStream::addRtpPacket(const struct _packet_info *pinfo, const struct _rtp_info *rtp_info)
121 {
122     if (!rtp_info) return;
123 
124     if (first_packet_) {
125         rtpstream_info_analyse_init(&rtpstream_, pinfo, rtp_info);
126         first_packet_ = false;
127     }
128     rtpstream_info_analyse_process(&rtpstream_, pinfo, rtp_info);
129 
130     rtp_packet_t *rtp_packet = g_new0(rtp_packet_t, 1);
131     rtp_packet->info = (struct _rtp_info *) g_memdup2(rtp_info, sizeof(struct _rtp_info));
132     if (rtp_info->info_all_data_present && (rtp_info->info_payload_len != 0)) {
133         rtp_packet->payload_data = (guint8 *) g_memdup2(&(rtp_info->info_data[rtp_info->info_payload_offset]),
134           rtp_info->info_payload_len);
135     }
136 
137     if (rtp_packets_.size() < 1) { // First packet
138         start_abs_offset_ = nstime_to_sec(&pinfo->abs_ts) - start_rel_time_;
139         start_rel_time_ = stop_rel_time_ = nstime_to_sec(&pinfo->rel_ts);
140     }
141     rtp_packet->frame_num = pinfo->num;
142     rtp_packet->arrive_offset = nstime_to_sec(&pinfo->rel_ts) - start_rel_time_;
143 
144     rtp_packets_ << rtp_packet;
145 }
146 
clearPackets()147 void RtpAudioStream::clearPackets()
148 {
149     for (int i = 0; i < rtp_packets_.size(); i++) {
150         rtp_packet_t *rtp_packet = rtp_packets_[i];
151         g_free(rtp_packet->info);
152         g_free(rtp_packet->payload_data);
153         g_free(rtp_packet);
154     }
155     rtp_packets_.clear();
156     rtpstream_info_free_data(&rtpstream_);
157     memset(&rtpstream_, 0, sizeof(rtpstream_));
158     rtpstream_id_copy(&id_, &rtpstream_.id);
159     first_packet_ = true;
160 }
161 
reset(double global_start_time)162 void RtpAudioStream::reset(double global_start_time)
163 {
164     global_start_rel_time_ = global_start_time;
165     stop_rel_time_ = start_rel_time_;
166     audio_out_rate_ = 0;
167     max_sample_val_ = 1;
168     packet_timestamps_.clear();
169     visual_samples_.clear();
170     out_of_seq_timestamps_.clear();
171     jitter_drop_timestamps_.clear();
172 }
173 
getAudioRouting()174 AudioRouting RtpAudioStream::getAudioRouting()
175 {
176     return audio_routing_;
177 }
178 
setAudioRouting(AudioRouting audio_routing)179 void RtpAudioStream::setAudioRouting(AudioRouting audio_routing)
180 {
181     audio_routing_ = audio_routing;
182 }
183 
decode(QAudioDeviceInfo out_device)184 void RtpAudioStream::decode(QAudioDeviceInfo out_device)
185 {
186     if (rtp_packets_.size() < 1) return;
187 
188     if (audio_resampler_) {
189         speex_resampler_reset_mem(audio_resampler_);
190     }
191     audio_file_->setFrameWriteStage();
192     decodeAudio(out_device);
193 
194     // Skip silence at begin of the stream
195     audio_file_->setFrameReadStage(prepend_samples_);
196 
197     speex_resampler_reset_mem(visual_resampler_);
198     decodeVisual();
199     audio_file_->setDataReadStage();
200 }
201 
202 // Side effect: it creates and initiates resampler if needed
calculateAudioOutRate(QAudioDeviceInfo out_device,unsigned int sample_rate,unsigned int requested_out_rate)203 quint32 RtpAudioStream::calculateAudioOutRate(QAudioDeviceInfo out_device, unsigned int sample_rate, unsigned int requested_out_rate)
204 {
205     quint32 out_rate;
206 
207     // Use the first non-zero rate we find. Ajust it to match
208     // our audio hardware.
209     QAudioFormat format;
210     format.setSampleRate(sample_rate);
211     format.setSampleSize(SAMPLE_BYTES * 8); // bits
212     format.setSampleType(QAudioFormat::SignedInt);
213     if (stereo_required_) {
214         format.setChannelCount(2);
215     } else {
216         format.setChannelCount(1);
217     }
218     format.setCodec("audio/pcm");
219 
220     if (!out_device.isFormatSupported(format) &&
221         (requested_out_rate==0)
222        ) {
223         out_rate = out_device.nearestFormat(format).sampleRate();
224         audio_resampler_ = speex_resampler_init(1, sample_rate, out_rate, 10, NULL);
225         RTP_STREAM_DEBUG("Started resampling from %u to (out) %u Hz.", sample_rate, out_rate);
226     } else {
227         if ((requested_out_rate!=0) &&
228             (requested_out_rate != sample_rate)
229            ) {
230             out_rate = requested_out_rate;
231             audio_resampler_ = speex_resampler_init(1, sample_rate, out_rate, 10, NULL);
232             RTP_STREAM_DEBUG("Started resampling from %u to (out) %u Hz.", sample_rate, out_rate);
233         } else {
234             out_rate = sample_rate;
235         }
236     }
237 
238     RTP_STREAM_DEBUG("Audio sample rate is %u", out_rate);
239 
240     return out_rate;
241 }
242 
decodeAudio(QAudioDeviceInfo out_device)243 void RtpAudioStream::decodeAudio(QAudioDeviceInfo out_device)
244 {
245     // XXX This is more messy than it should be.
246 
247     gint32 resample_buff_bytes = 0x1000;
248     SAMPLE *resample_buff = (SAMPLE *) g_malloc(resample_buff_bytes);
249     char *write_buff = NULL;
250     qint64 write_bytes = 0;
251     unsigned int channels = 0;
252     unsigned int sample_rate = 0;
253     guint32 last_sequence = 0;
254     guint32 last_sequence_w = 0;  // Last sequence number we wrote data
255 
256     double rtp_time_prev = 0.0;
257     double arrive_time_prev = 0.0;
258     double pack_period = 0.0;
259     double start_time = 0.0;
260     double start_rtp_time = 0.0;
261     guint64 start_timestamp = 0;
262 
263     size_t decoded_bytes_prev = 0;
264 
265     for (int cur_packet = 0; cur_packet < rtp_packets_.size(); cur_packet++) {
266         SAMPLE *decode_buff = NULL;
267         // TODO: Update a progress bar here.
268         rtp_packet_t *rtp_packet = rtp_packets_[cur_packet];
269 
270         stop_rel_time_ = start_rel_time_ + rtp_packet->arrive_offset;
271 
272         QString payload_name;
273         if (rtp_packet->info->info_payload_type_str) {
274             payload_name = rtp_packet->info->info_payload_type_str;
275         } else {
276             payload_name = try_val_to_str_ext(rtp_packet->info->info_payload_type, &rtp_payload_type_short_vals_ext);
277         }
278         if (!payload_name.isEmpty()) {
279             payload_names_ << payload_name;
280         }
281 
282         if (cur_packet < 1) { // First packet
283             start_timestamp = rtp_packet->info->info_extended_timestamp;
284             start_rtp_time = 0;
285             rtp_time_prev = 0;
286             last_sequence = rtp_packet->info->info_extended_seq_num - 1;
287         }
288 
289         size_t decoded_bytes = decode_rtp_packet(rtp_packet, &decode_buff, decoders_hash_, &channels, &sample_rate);
290 
291         unsigned rtp_clock_rate = sample_rate;
292         if (rtp_packet->info->info_payload_type == PT_G722) {
293             // G.722 sample rate is 16kHz, but RTP clock rate is 8kHz
294             // for historic reasons.
295             rtp_clock_rate = 8000;
296         }
297 
298         // Length 2 for PT_PCM mean silence packet probably, ignore
299         if (decoded_bytes == 0 || sample_rate == 0 ||
300             ((rtp_packet->info->info_payload_type == PT_PCMU ||
301               rtp_packet->info->info_payload_type == PT_PCMA
302              ) && (decoded_bytes == 2)
303             )
304            ) {
305             // We didn't decode anything. Clean up and prep for
306             // the next packet.
307             last_sequence = rtp_packet->info->info_extended_seq_num;
308             g_free(decode_buff);
309             continue;
310         }
311 
312         if (audio_out_rate_ == 0) {
313             first_sample_rate_ = sample_rate;
314 
315             // We calculate audio_out_rate just for first sample_rate.
316             // All later are just resampled to it.
317             // Side effect: it creates and initiates resampler if needed
318             audio_out_rate_ = calculateAudioOutRate(out_device, sample_rate, audio_requested_out_rate_);
319 
320             // Calculate count of prepend samples for the stream
321             // The earliest stream starts at 0.
322             // Note: Order of operations and separation to two formulas is
323             // important.
324             // When joined, calculated incorrectly - probably caused by
325             // conversions between int/double
326             prepend_samples_ = (start_rel_time_ - global_start_rel_time_) * sample_rate;
327             prepend_samples_ = prepend_samples_ * audio_out_rate_ / sample_rate;
328 
329             // Prepend silence to match our sibling streams.
330             if ((prepend_samples_ > 0) && (audio_out_rate_ != 0)) {
331                 audio_file_->frameWriteSilence(rtp_packet->frame_num, prepend_samples_);
332             }
333         }
334 
335         if (rtp_packet->info->info_extended_seq_num != last_sequence+1) {
336             out_of_seq_timestamps_.append(stop_rel_time_);
337         }
338         last_sequence = rtp_packet->info->info_extended_seq_num;
339 
340         double rtp_time = (double)(rtp_packet->info->info_extended_timestamp-start_timestamp)/rtp_clock_rate - start_rtp_time;
341         double arrive_time;
342         if (timing_mode_ == RtpTimestamp) {
343             arrive_time = rtp_time;
344         } else {
345             arrive_time = rtp_packet->arrive_offset - start_time;
346         }
347 
348         double diff = qAbs(arrive_time - rtp_time);
349         if (diff*1000 > jitter_buffer_size_ && timing_mode_ != Uninterrupted) {
350             // rtp_player.c:628
351 
352             jitter_drop_timestamps_.append(stop_rel_time_);
353             RTP_STREAM_DEBUG("Packet drop by jitter buffer exceeded %f > %d", diff*1000, jitter_buffer_size_);
354 
355             /* if there was a silence period (more than two packetization
356              * period) resync the source */
357             if ((rtp_time - rtp_time_prev) > pack_period*2) {
358                 qint64 silence_samples;
359                 RTP_STREAM_DEBUG("Resync...");
360 
361                 silence_samples = (qint64)((arrive_time - arrive_time_prev)*sample_rate - decoded_bytes_prev / SAMPLE_BYTES);
362                 silence_samples = silence_samples * audio_out_rate_ / sample_rate;
363                 silence_timestamps_.append(stop_rel_time_);
364                 // Timestamp shift can make silence calculation negative
365                 if ((silence_samples > 0) && (audio_out_rate_ != 0)) {
366                     audio_file_->frameWriteSilence(rtp_packet->frame_num, silence_samples);
367                 }
368 
369                 decoded_bytes_prev = 0;
370                 start_timestamp = rtp_packet->info->info_extended_timestamp;
371                 start_rtp_time = 0;
372                 start_time = rtp_packet->arrive_offset;
373                 rtp_time_prev = 0;
374             }
375 
376         } else {
377             // rtp_player.c:664
378             /* Add silence if it is necessary */
379             qint64 silence_samples;
380 
381             if (timing_mode_ == Uninterrupted) {
382                 silence_samples = 0;
383             } else {
384                 silence_samples = (int)((rtp_time - rtp_time_prev)*sample_rate - decoded_bytes_prev / SAMPLE_BYTES);
385                 silence_samples = silence_samples * audio_out_rate_ / sample_rate;
386             }
387 
388             if (silence_samples != 0) {
389                 wrong_timestamp_timestamps_.append(stop_rel_time_);
390             }
391 
392             if (silence_samples > 0) {
393                 silence_timestamps_.append(stop_rel_time_);
394                 if ((silence_samples > 0) && (audio_out_rate_ != 0)) {
395                     audio_file_->frameWriteSilence(rtp_packet->frame_num, silence_samples);
396                 }
397             }
398 
399             // XXX rtp_player.c:696 adds audio here.
400             rtp_time_prev = rtp_time;
401             pack_period = (double) decoded_bytes / SAMPLE_BYTES / sample_rate;
402             decoded_bytes_prev = decoded_bytes;
403             arrive_time_prev = arrive_time;
404         }
405 
406         // Prepare samples to write
407         write_buff = (char *) decode_buff;
408         write_bytes = decoded_bytes;
409 
410         if (audio_out_rate_ != sample_rate) {
411             // Resample the audio to match output rate.
412             // Buffer is in SAMPLEs
413             spx_uint32_t in_len = (spx_uint32_t) (write_bytes / SAMPLE_BYTES);
414             // Output is audio_out_rate_/sample_rate bigger than input
415             spx_uint32_t out_len = (spx_uint32_t) ((guint64)in_len * audio_out_rate_ / sample_rate);
416             resample_buff = resizeBufferIfNeeded(resample_buff, &resample_buff_bytes, out_len * SAMPLE_BYTES);
417 
418             speex_resampler_process_int(audio_resampler_, 0, decode_buff, &in_len, resample_buff, &out_len);
419 
420             write_buff = (char *) resample_buff;
421             write_bytes = out_len * SAMPLE_BYTES;
422         }
423 
424         // We should write only newer data to avoid duplicates in replay
425         if (last_sequence_w < last_sequence) {
426             // Write the decoded, possibly-resampled audio to our temp file.
427             audio_file_->frameWriteSamples(rtp_packet->frame_num, write_buff, write_bytes);
428             last_sequence_w = last_sequence;
429         }
430 
431         g_free(decode_buff);
432     }
433     g_free(resample_buff);
434 }
435 
436 // We preallocate buffer, 320 samples is enough for most scenarios
437 #define VISUAL_BUFF_LEN (320)
438 #define VISUAL_BUFF_BYTES (SAMPLE_BYTES * VISUAL_BUFF_LEN)
decodeVisual()439 void RtpAudioStream::decodeVisual()
440 {
441     spx_uint32_t read_len = 0;
442     gint32 read_buff_bytes = VISUAL_BUFF_BYTES;
443     SAMPLE *read_buff = (SAMPLE *) g_malloc(read_buff_bytes);
444     gint32 resample_buff_bytes = VISUAL_BUFF_BYTES;
445     SAMPLE *resample_buff = (SAMPLE *) g_malloc(resample_buff_bytes);
446     unsigned int sample_no = 0;
447     spx_uint32_t out_len;
448     guint32 frame_num;
449     rtp_frame_type type;
450 
451     speex_resampler_set_rate(visual_resampler_, audio_out_rate_, visual_sample_rate_);
452 
453     // Loop over every frame record
454     // readFrameSamples() maintains size of buffer for us
455     while (audio_file_->readFrameSamples(&read_buff_bytes, &read_buff, &read_len, &frame_num, &type)) {
456         out_len = (spx_uint32_t)(((guint64)read_len * visual_sample_rate_ ) / audio_out_rate_);
457 
458         if (type == RTP_FRAME_AUDIO) {
459             // We resample only audio samples
460             resample_buff = resizeBufferIfNeeded(resample_buff, &resample_buff_bytes, out_len * SAMPLE_BYTES);
461 
462             // Resample
463             speex_resampler_process_int(visual_resampler_, 0, read_buff, &read_len, resample_buff, &out_len);
464 
465             // Create timestamp and visual sample
466             for (unsigned i = 0; i < out_len; i++) {
467                 double time = start_rel_time_ + (double) sample_no / visual_sample_rate_;
468                 packet_timestamps_[time] = frame_num;
469                 if (qAbs(resample_buff[i]) > max_sample_val_) max_sample_val_ = qAbs(resample_buff[i]);
470                 visual_samples_.append(resample_buff[i]);
471                 sample_no++;
472             }
473         } else {
474             // Insert end of line mark
475             double time = start_rel_time_ + (double) sample_no / visual_sample_rate_;
476             packet_timestamps_[time] = frame_num;
477             visual_samples_.append(SAMPLE_NaN);
478             sample_no += out_len;
479         }
480     }
481 
482     max_sample_val_used_ = max_sample_val_;
483     g_free(resample_buff);
484     g_free(read_buff);
485 }
486 
payloadNames() const487 const QStringList RtpAudioStream::payloadNames() const
488 {
489     QStringList payload_names = payload_names_.values();
490     payload_names.sort();
491     return payload_names;
492 }
493 
visualTimestamps(bool relative)494 const QVector<double> RtpAudioStream::visualTimestamps(bool relative)
495 {
496     QVector<double> ts_keys = packet_timestamps_.keys().toVector();
497     if (relative) return ts_keys;
498 
499     QVector<double> adj_timestamps;
500     for (int i = 0; i < ts_keys.size(); i++) {
501         adj_timestamps.append(ts_keys[i] + start_abs_offset_ - start_rel_time_);
502     }
503     return adj_timestamps;
504 }
505 
506 // Scale the height of the waveform to global scale (max_sample_val_used_)
507 // and adjust its Y offset so that they overlap slightly (stack_offset_).
508 static const double stack_offset_ = G_MAXINT16 / 3;
visualSamples(int y_offset)509 const QVector<double> RtpAudioStream::visualSamples(int y_offset)
510 {
511     QVector<double> adj_samples;
512     double scaled_offset = y_offset * stack_offset_;
513     for (int i = 0; i < visual_samples_.size(); i++) {
514         if (SAMPLE_NaN != visual_samples_[i]) {
515             adj_samples.append(((double)visual_samples_[i] * G_MAXINT16 / max_sample_val_used_) + scaled_offset);
516         } else {
517             // Convert to break in graph line
518             adj_samples.append(qQNaN());
519         }
520     }
521     return adj_samples;
522 }
523 
outOfSequenceTimestamps(bool relative)524 const QVector<double> RtpAudioStream::outOfSequenceTimestamps(bool relative)
525 {
526     if (relative) return out_of_seq_timestamps_;
527 
528     QVector<double> adj_timestamps;
529     for (int i = 0; i < out_of_seq_timestamps_.size(); i++) {
530         adj_timestamps.append(out_of_seq_timestamps_[i] + start_abs_offset_ - start_rel_time_);
531     }
532     return adj_timestamps;
533 }
534 
outOfSequenceSamples(int y_offset)535 const QVector<double> RtpAudioStream::outOfSequenceSamples(int y_offset)
536 {
537     QVector<double> adj_samples;
538     double scaled_offset = y_offset * stack_offset_;  // XXX Should be different for seq, jitter, wrong & silence
539     for (int i = 0; i < out_of_seq_timestamps_.size(); i++) {
540         adj_samples.append(scaled_offset);
541     }
542     return adj_samples;
543 }
544 
jitterDroppedTimestamps(bool relative)545 const QVector<double> RtpAudioStream::jitterDroppedTimestamps(bool relative)
546 {
547     if (relative) return jitter_drop_timestamps_;
548 
549     QVector<double> adj_timestamps;
550     for (int i = 0; i < jitter_drop_timestamps_.size(); i++) {
551         adj_timestamps.append(jitter_drop_timestamps_[i] + start_abs_offset_ - start_rel_time_);
552     }
553     return adj_timestamps;
554 }
555 
jitterDroppedSamples(int y_offset)556 const QVector<double> RtpAudioStream::jitterDroppedSamples(int y_offset)
557 {
558     QVector<double> adj_samples;
559     double scaled_offset = y_offset * stack_offset_; // XXX Should be different for seq, jitter, wrong & silence
560     for (int i = 0; i < jitter_drop_timestamps_.size(); i++) {
561         adj_samples.append(scaled_offset);
562     }
563     return adj_samples;
564 }
565 
wrongTimestampTimestamps(bool relative)566 const QVector<double> RtpAudioStream::wrongTimestampTimestamps(bool relative)
567 {
568     if (relative) return wrong_timestamp_timestamps_;
569 
570     QVector<double> adj_timestamps;
571     for (int i = 0; i < wrong_timestamp_timestamps_.size(); i++) {
572         adj_timestamps.append(wrong_timestamp_timestamps_[i] + start_abs_offset_ - start_rel_time_);
573     }
574     return adj_timestamps;
575 }
576 
wrongTimestampSamples(int y_offset)577 const QVector<double> RtpAudioStream::wrongTimestampSamples(int y_offset)
578 {
579     QVector<double> adj_samples;
580     double scaled_offset = y_offset * stack_offset_; // XXX Should be different for seq, jitter, wrong & silence
581     for (int i = 0; i < wrong_timestamp_timestamps_.size(); i++) {
582         adj_samples.append(scaled_offset);
583     }
584     return adj_samples;
585 }
586 
insertedSilenceTimestamps(bool relative)587 const QVector<double> RtpAudioStream::insertedSilenceTimestamps(bool relative)
588 {
589     if (relative) return silence_timestamps_;
590 
591     QVector<double> adj_timestamps;
592     for (int i = 0; i < silence_timestamps_.size(); i++) {
593         adj_timestamps.append(silence_timestamps_[i] + start_abs_offset_ - start_rel_time_);
594     }
595     return adj_timestamps;
596 }
597 
insertedSilenceSamples(int y_offset)598 const QVector<double> RtpAudioStream::insertedSilenceSamples(int y_offset)
599 {
600     QVector<double> adj_samples;
601     double scaled_offset = y_offset * stack_offset_;  // XXX Should be different for seq, jitter, wrong & silence
602     for (int i = 0; i < silence_timestamps_.size(); i++) {
603         adj_samples.append(scaled_offset);
604     }
605     return adj_samples;
606 }
607 
nearestPacket(double timestamp,bool is_relative)608 quint32 RtpAudioStream::nearestPacket(double timestamp, bool is_relative)
609 {
610     if (packet_timestamps_.keys().count() < 1) return 0;
611 
612     if (!is_relative) timestamp -= start_abs_offset_;
613     QMap<double, quint32>::const_iterator it = packet_timestamps_.lowerBound(timestamp);
614     if (it == packet_timestamps_.end()) return 0;
615     return it.value();
616 }
617 
outputState() const618 QAudio::State RtpAudioStream::outputState() const
619 {
620     if (!audio_output_) return QAudio::IdleState;
621     return audio_output_->state();
622 }
623 
formatDescription(const QAudioFormat & format)624 const QString RtpAudioStream::formatDescription(const QAudioFormat &format)
625 {
626     QString fmt_descr = QString("%1 Hz, ").arg(format.sampleRate());
627     switch (format.sampleType()) {
628     case QAudioFormat::SignedInt:
629         fmt_descr += "Int";
630         break;
631     case QAudioFormat::UnSignedInt:
632         fmt_descr += "UInt";
633         break;
634     case QAudioFormat::Float:
635         fmt_descr += "Float";
636         break;
637     default:
638         fmt_descr += "Unknown";
639         break;
640     }
641     fmt_descr += QString::number(format.sampleSize());
642     fmt_descr += format.byteOrder() == QAudioFormat::BigEndian ? "BE" : "LE";
643 
644     return fmt_descr;
645 }
646 
getIDAsQString()647 QString RtpAudioStream::getIDAsQString()
648 {
649     gchar *src_addr_str = address_to_display(NULL, &id_.src_addr);
650     gchar *dst_addr_str = address_to_display(NULL, &id_.dst_addr);
651     QString str = QString("%1:%2 - %3:%4 %5")
652         .arg(src_addr_str)
653         .arg(id_.src_port)
654         .arg(dst_addr_str)
655         .arg(id_.dst_port)
656         .arg(QString("0x%1").arg(id_.ssrc, 0, 16));
657     wmem_free(NULL, src_addr_str);
658     wmem_free(NULL, dst_addr_str);
659 
660     return str;
661 }
662 
prepareForPlay(QAudioDeviceInfo out_device)663 bool RtpAudioStream::prepareForPlay(QAudioDeviceInfo out_device)
664 {
665     qint64 start_pos;
666     qint64 size;
667 
668     if (audio_routing_.isMuted())
669         return false;
670 
671     if (audio_output_)
672         return false;
673 
674     if (audio_out_rate_ == 0) {
675         /* It is observed, but is not an error
676         QString error = tr("RTP stream (%1) is empty or codec is unsupported.")
677             .arg(getIDAsQString());
678 
679         emit playbackError(error);
680         */
681         return false;
682     }
683 
684     QAudioFormat format;
685     format.setSampleRate(audio_out_rate_);
686     format.setSampleSize(SAMPLE_BYTES * 8); // bits
687     format.setSampleType(QAudioFormat::SignedInt);
688     if (stereo_required_) {
689         format.setChannelCount(2);
690     } else {
691         format.setChannelCount(1);
692     }
693     format.setCodec("audio/pcm");
694 
695     // RTP_STREAM_DEBUG("playing %s %d samples @ %u Hz",
696     //                 sample_file_->fileName().toUtf8().constData(),
697     //                 (int) sample_file_->size(), audio_out_rate_);
698 
699     if (!out_device.isFormatSupported(format)) {
700         QString playback_error = tr("%1 does not support PCM at %2. Preferred format is %3")
701                 .arg(out_device.deviceName())
702                 .arg(formatDescription(format))
703                 .arg(formatDescription(out_device.nearestFormat(format)));
704         emit playbackError(playback_error);
705     }
706 
707     start_pos = (qint64)(start_play_time_ * SAMPLE_BYTES * audio_out_rate_);
708     // Round to SAMPLE_BYTES boundary
709     start_pos = (start_pos / SAMPLE_BYTES) * SAMPLE_BYTES;
710     size = audio_file_->sampleFileSize();
711     if (stereo_required_) {
712         // There is 2x more samples for stereo
713         start_pos *= 2;
714         size *= 2;
715     }
716     if (start_pos < size) {
717         audio_file_->setDataReadStage();
718         temp_file_ = new AudioRoutingFilter(audio_file_, stereo_required_, audio_routing_);
719         temp_file_->seek(start_pos);
720         if (audio_output_) delete audio_output_;
721         audio_output_ = new QAudioOutput(out_device, format, this);
722         connect(audio_output_, SIGNAL(stateChanged(QAudio::State)), this, SLOT(outputStateChanged(QAudio::State)));
723         return true;
724     } else {
725         // Report stopped audio if start position is later than stream ends
726         outputStateChanged(QAudio::StoppedState);
727         return false;
728     }
729 
730     return false;
731 }
732 
startPlaying()733 void RtpAudioStream::startPlaying()
734 {
735    audio_output_->start(temp_file_);
736    // QTBUG-6548 StoppedState is not always emitted on error, force a cleanup
737    // in case playback fails immediately.
738    if (audio_output_ && audio_output_->state() == QAudio::StoppedState) {
739        outputStateChanged(QAudio::StoppedState);
740    }
741 }
742 
pausePlaying()743 void RtpAudioStream::pausePlaying()
744 {
745     if (audio_routing_.isMuted())
746         return;
747 
748     if (audio_output_) {
749         if (QAudio::ActiveState == audio_output_->state()) {
750             audio_output_->suspend();
751         } else if (QAudio::SuspendedState == audio_output_->state()) {
752             audio_output_->resume();
753         }
754     }
755 }
756 
stopPlaying()757 void RtpAudioStream::stopPlaying()
758 {
759     if (audio_routing_.isMuted())
760         return;
761 
762     if (audio_output_) {
763         if (audio_output_->state() == QAudio::StoppedState) {
764             // Looks like "delayed" QTBUG-6548
765             // It may happen that stream is stopped, but no signal emited
766             // Probably triggered by some issue in sound system which is not
767             // handled by Qt correctly
768             outputStateChanged(QAudio::StoppedState);
769         } else {
770             audio_output_->stop();
771         }
772     }
773 }
774 
seekPlaying(qint64 samples _U_)775 void RtpAudioStream::seekPlaying(qint64 samples _U_)
776 {
777     if (audio_routing_.isMuted())
778         return;
779 
780     if (audio_output_) {
781         audio_output_->suspend();
782         audio_file_->seekSample(samples);
783         audio_output_->resume();
784     }
785 }
786 
outputStateChanged(QAudio::State new_state)787 void RtpAudioStream::outputStateChanged(QAudio::State new_state)
788 {
789     if (!audio_output_) return;
790 
791     // On some platforms including macOS and Windows, the stateChanged signal
792     // is emitted while a QMutexLocker is active. As a result we shouldn't
793     // delete audio_output_ here.
794     switch (new_state) {
795     case QAudio::StoppedState:
796         {
797             // RTP_STREAM_DEBUG("stopped %f", audio_output_->processedUSecs() / 100000.0);
798             // Detach from parent (RtpAudioStream) to prevent deleteLater
799             // from being run during destruction of this class.
800             QAudio::Error error = audio_output_->error();
801 
802             audio_output_->setParent(0);
803             audio_output_->disconnect();
804             audio_output_->deleteLater();
805             audio_output_ = NULL;
806             emit finishedPlaying(this, error);
807             break;
808         }
809     case QAudio::IdleState:
810         // Workaround for Qt behaving on some platforms with some soundcards:
811         // When ->stop() is called from outputStateChanged(),
812         // internalQMutexLock is locked and application hangs.
813         // We can stop the stream later.
814         QTimer::singleShot(0, this, SLOT(delayedStopStream()));
815 
816         break;
817     default:
818         break;
819     }
820 }
821 
delayedStopStream()822 void RtpAudioStream::delayedStopStream()
823 {
824     audio_output_->stop();
825 }
826 
resizeBufferIfNeeded(SAMPLE * buff,gint32 * buff_bytes,qint64 requested_size)827 SAMPLE *RtpAudioStream::resizeBufferIfNeeded(SAMPLE *buff, gint32 *buff_bytes, qint64 requested_size)
828 {
829     if (requested_size > *buff_bytes) {
830         while ((requested_size > *buff_bytes))
831             *buff_bytes *= 2;
832         buff = (SAMPLE *) g_realloc(buff, *buff_bytes);
833     }
834 
835     return buff;
836 }
837 
seekSample(qint64 samples)838 void RtpAudioStream::seekSample(qint64 samples)
839 {
840     audio_file_->seekSample(samples);
841 }
842 
readSample(SAMPLE * sample)843 qint64 RtpAudioStream::readSample(SAMPLE *sample)
844 {
845     return audio_file_->readSample(sample);
846 }
847 
savePayload(QIODevice * file)848 bool RtpAudioStream::savePayload(QIODevice *file)
849 {
850     for (int cur_packet = 0; cur_packet < rtp_packets_.size(); cur_packet++) {
851         // TODO: Update a progress bar here.
852         rtp_packet_t *rtp_packet = rtp_packets_[cur_packet];
853 
854         if ((rtp_packet->info->info_payload_type != PT_CN) &&
855             (rtp_packet->info->info_payload_type != PT_CN_OLD)) {
856             // All other payloads
857             int64_t nchars;
858 
859             if (rtp_packet->payload_data && (rtp_packet->info->info_payload_len > 0)) {
860                 nchars = file->write((char *)rtp_packet->payload_data, rtp_packet->info->info_payload_len);
861                 if (nchars != rtp_packet->info->info_payload_len) {
862                     return false;
863                 }
864             }
865         }
866     }
867 
868     return true;
869 }
870 
871 
872 #endif // QT_MULTIMEDIA_LIB
873