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