aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJirka Novak <j.novak@netsystem.cz>2019-11-21 15:08:16 +0100
committerRoland Knall <rknall@gmail.com>2019-11-21 16:06:49 +0000
commit37f3c65ca58771daf7292629836652459d1420f4 (patch)
tree64d6a3cdddaff267704a69bdeda78550b260f952
parentc55dd79d2c7e35586a62de197a45ec5a50af620a (diff)
rtp_analysis_dialog.cpp: save any supported codec as .au
Change improves Wireshark ability to save rtp streams. It allows a user to save any supported codec with 8 kHz rate. In real, it means G.711 and G.729 for now. There is no hardcoded codec limitation during save anymore. If code detects unsupported codec or rate during save, it replaces samples with silence and reports it. Therefore any added codec in future will be supported. Note to RTP saving: RTP streams (there can be up to two of them for save) can contain multiple codecs in each direction - some of it can be supported and some unsupported. What should be exported then? Till my patch save do not run and a user received nothing even part of stream was OK/encoded with supported codec. Therefore I managed the code to start with export and do its best. Unknown codec/part is replaced with silence and user is warned after export. Therefore a user will get: a) audio - when all codecs are supported (no warning) b) mix audio/silence - when some codecs are supported (warning) c) only silence - when no codec is supported (warning) BTW same output user sees/gets in RTP player for years. Change-Id: Id938d419f5841af46d2d2d3ddfaf1ec9a0235bcc Reviewed-on: https://code.wireshark.org/review/35105 Petri-Dish: Roland Knall <rknall@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Roland Knall <rknall@gmail.com>
-rw-r--r--docbook/release-notes.adoc1
-rw-r--r--ui/qt/rtp_analysis_dialog.cpp328
-rw-r--r--ui/qt/rtp_analysis_dialog.h26
-rw-r--r--ui/rtp_media.c36
-rw-r--r--ui/rtp_media.h16
5 files changed, 238 insertions, 169 deletions
diff --git a/docbook/release-notes.adoc b/docbook/release-notes.adoc
index fcc4beac15..81f765b0ba 100644
--- a/docbook/release-notes.adoc
+++ b/docbook/release-notes.adoc
@@ -34,6 +34,7 @@ The following features are new (or have been significantly updated)
since version 3.2.0:
* Windows executables and installers are now https://support.microsoft.com/en-us/help/4472027/2019-sha-2-code-signing-support-requirement-for-windows-and-wsus[signed using SHA-2 only].
+* Save RTP stream to .au supports any codec with 8000 Hz rate supported by Wireshark (shown in RTP player). If save of audio is not possible (unsupported codec or rate), silence of same length is saved and warning is shown.
// === Removed Features and Support
diff --git a/ui/qt/rtp_analysis_dialog.cpp b/ui/qt/rtp_analysis_dialog.cpp
index c0878ee3c0..4ca20b6e3d 100644
--- a/ui/qt/rtp_analysis_dialog.cpp
+++ b/ui/qt/rtp_analysis_dialog.cpp
@@ -20,6 +20,8 @@
#include "epan/dissectors/packet-rtp.h"
+#include <ui/rtp_media.h>
+
#include "ui/help_url.h"
#include "ui/simple_dialog.h"
#include <wsutil/utf8_entities.h>
@@ -163,7 +165,7 @@ public:
}
}
- guint32 frameNum() { return frame_num_; }
+ uint32_t frameNum() { return frame_num_; }
bool frameStatus() { return ok_; }
QList<QVariant> rowData() {
@@ -209,10 +211,10 @@ public:
return QTreeWidgetItem::operator <(other);
}
private:
- guint32 frame_num_;
- guint32 sequence_num_;
- guint32 pkt_len_;
- guint32 flags_;
+ uint32_t frame_num_;
+ uint32_t sequence_num_;
+ uint32_t pkt_len_;
+ uint32_t flags_;
double delta_;
double jitter_;
double skew_;
@@ -697,8 +699,8 @@ void RtpAnalysisDialog::resetStatistics()
memset(&fwd_statinfo_.rtp_stats, 0, sizeof(fwd_statinfo_.rtp_stats));
memset(&rev_statinfo_.rtp_stats, 0, sizeof(rev_statinfo_.rtp_stats));
- fwd_statinfo_.rtp_stats.first_packet = TRUE;
- rev_statinfo_.rtp_stats.first_packet = TRUE;
+ fwd_statinfo_.rtp_stats.first_packet = true;
+ rev_statinfo_.rtp_stats.first_packet = true;
fwd_statinfo_.rtp_stats.reg_pt = PT_UNDEFINED;
rev_statinfo_.rtp_stats.reg_pt = PT_UNDEFINED;
@@ -756,10 +758,10 @@ void RtpAnalysisDialog::savePayload(QTemporaryFile *tmpfile, tap_rtp_stat_t *sta
/* Is this the first packet we got in this direction? */
// if (statinfo->flags & STAT_FLAG_FIRST) {
// if (saveinfo->fp == NULL) {
-// saveinfo->saved = FALSE;
+// saveinfo->saved = false;
// saveinfo->error_type = TAP_RTP_FILE_OPEN_ERROR;
// } else {
-// saveinfo->saved = TRUE;
+// saveinfo->saved = true;
// }
// }
@@ -784,7 +786,7 @@ void RtpAnalysisDialog::savePayload(QTemporaryFile *tmpfile, tap_rtp_stat_t *sta
/* If padding bit is set but the padding count is bigger
* then the whole RTP data - error with padding count
*/
- if ((rtpinfo->info_padding_set != FALSE) &&
+ if ((rtpinfo->info_padding_set != false) &&
(rtpinfo->info_padding_count > rtpinfo->info_payload_len))
{
tmpfile->close();
@@ -797,7 +799,7 @@ void RtpAnalysisDialog::savePayload(QTemporaryFile *tmpfile, tap_rtp_stat_t *sta
(rtpinfo->info_payload_type == PT_CN_OLD)) {
} else { /* All other payloads */
const char *data;
- qint64 nchars;
+ int64_t nchars;
tap_rtp_save_data_t save_data;
if (!rtpinfo->info_all_data_present) {
@@ -972,7 +974,7 @@ void RtpAnalysisDialog::updateStatistics()
if (rev_statinfo_.rtp_stats.total_nr) {
stats_tables += QString("<h4>Forward to reverse<br/>start diff %1 s @ %2</h4>")
.arg((rev_statinfo_.rtp_stats.start_time - fwd_statinfo_.rtp_stats.start_time) / 1000.0, 0, 'f', 6)
- .arg((gint64)rev_statinfo_.rtp_stats.first_packet_num - (gint64)fwd_statinfo_.rtp_stats.first_packet_num);
+ .arg((int64_t)rev_statinfo_.rtp_stats.first_packet_num - (int64_t)fwd_statinfo_.rtp_stats.first_packet_num);
}
stats_tables += "</body></html>\n";
@@ -1041,50 +1043,55 @@ void RtpAnalysisDialog::showPlayer()
/* Convert one packet payload to samples in row */
/* It supports G.711 now, but can be extended to any other codecs */
-size_t RtpAnalysisDialog::convert_payload_to_samples(unsigned int payload_type, QTemporaryFile *tempfile, guint8 *pd_out, size_t payload_len)
+size_t RtpAnalysisDialog::convert_payload_to_samples(unsigned int payload_type, QTemporaryFile *tempfile, uint8_t *pd_out, size_t payload_len, struct _GHashTable *decoders_hash)
{
- size_t sample_count;
- char f_rawvalue;
- gint16 sample;
- guint8 pd[4];
-
- if (payload_type == PT_PCMU) {
- /* Output sample count is same as input sample count for G.711 */
- sample_count = payload_len;
- for (size_t i = 0; i < payload_len; i++) {
- tempfile->read((char *)&f_rawvalue, sizeof(f_rawvalue));
- sample = ulaw2linear((unsigned char)f_rawvalue);
- phton16(pd, sample);
- pd_out[2*i] = pd[0];
- pd_out[2*i+1] = pd[1];
- }
- } else if (payload_type == PT_PCMA) {
- /* Output sample count is same as input sample count for G.711 */
- sample_count = payload_len;
- for (size_t i = 0; i < payload_len; i++) {
- tempfile->read((char *)&f_rawvalue, sizeof(f_rawvalue));
- sample = alaw2linear((unsigned char)f_rawvalue);
+ unsigned int channels = 0;
+ unsigned int sample_rate = 0;
+ /* Payload data are in bytes */
+ uint8_t payload_data[2*4000];
+ size_t decoded_bytes;
+ /* Decoded audio is in samples (2 bytes) */
+ SAMPLE *decode_buff = Q_NULLPTR;
+ size_t decoded_samples;
+
+ tempfile->read((char *)payload_data, payload_len);
+ if (PT_UNDF_123 == payload_type) {
+ /* 123 is payload used as silence in ED-137 */
+ return 0;
+ }
+
+ /* Decoder returns count of bytes, but data are samples */
+ decoded_bytes = decode_rtp_packet_payload(payload_type, Q_NULLPTR, payload_data, payload_len, &decode_buff, decoders_hash, &channels, &sample_rate);
+ decoded_samples = decoded_bytes/2;
+
+ if (sample_rate != 8000) {
+ sae_unsupported_codec_ = true;
+ decoded_samples = 0;
+ } else if (decoded_samples > 0) {
+ /* Change byte order to network order */
+ for(size_t i = 0; i < decoded_samples; i++) {
+ SAMPLE sample;
+ uint8_t pd[4];
+
+ sample = decode_buff[i];
phton16(pd, sample);
pd_out[2*i] = pd[0];
pd_out[2*i+1] = pd[1];
}
} else {
- /* Read payload, but ignore it */
- sample_count = 0;
- for (size_t i = 0; i < payload_len; i++) {
- tempfile->read((char *)&f_rawvalue, sizeof(f_rawvalue));
- }
+ sae_unsupported_codec_ = true;
}
+ g_free(decode_buff);
- return sample_count;
+ return decoded_samples;
}
-gboolean RtpAnalysisDialog::saveAudioAUSilence(size_t total_len, QFile *save_file, gboolean *stop_flag)
+bool RtpAnalysisDialog::saveAudioAUSilence(size_t total_len, QFile *save_file, gboolean *stop_flag)
{
- qint64 nchars;
- guint8 pd_out[2*4000];
- gint16 silence;
- guint8 pd[4];
+ int64_t nchars;
+ uint8_t pd_out[2*4000];
+ int16_t silence;
+ uint8_t pd[4];
silence = 0x0000;
phton16(pd, silence);
@@ -1093,36 +1100,43 @@ gboolean RtpAnalysisDialog::saveAudioAUSilence(size_t total_len, QFile *save_fil
/* Fill whole file with silence */
for (size_t i=0; i<total_len; i++) {
if (*stop_flag) {
- return FALSE;
+ sae_stopped_ = true;
+ return false;
}
nchars = save_file->write((const char *)pd_out, 2);
if (nchars < 2) {
- return FALSE;
+ sae_file_error_ = true;
+ return false;
}
}
- return TRUE;
+ return true;
}
-gboolean RtpAnalysisDialog::saveAudioAUUnidir(tap_rtp_stat_t &statinfo, QTemporaryFile *tempfile, QFile *save_file, qint64 header_end, gboolean *stop_flag, gboolean interleave, size_t prefix_silence)
+bool RtpAnalysisDialog::saveAudioAUUnidir(tap_rtp_stat_t &statinfo, QTemporaryFile *tempfile, QFile *save_file, int64_t header_end, gboolean *stop_flag, gboolean interleave, size_t prefix_silence)
{
- qint64 nchars;
- guint8 pd_out[2*4000];
- guint8 pd[4];
+ int64_t nchars;
+ uint8_t pd_out[2*4000];
+ uint8_t pd[4];
tap_rtp_save_data_t save_data;
+ struct _GHashTable *decoders_hash = rtp_decoder_hash_table_new();
while (sizeof(save_data) == tempfile->read((char *)&save_data,sizeof(save_data))) {
size_t sample_count;
if (*stop_flag) {
- return FALSE;
+ sae_stopped_ = true;
+ return false;
}
ui->progressFrame->setValue(int(tempfile->pos() * 100 / tempfile->size()));
- sample_count=convert_payload_to_samples(save_data.payload_type, tempfile ,pd_out, save_data.payload_len);
+ sample_count=convert_payload_to_samples(save_data.payload_type, tempfile , pd_out, save_data.payload_len, decoders_hash);
- if (sample_count > 0) {
+ if (!isSAEOK()) {
+ return false;
+ }
+ if (sample_count > 0 ) {
nchars = 0;
/* Save payload samples with optional interleaving */
for (size_t i = 0; i < sample_count; i++) {
@@ -1136,33 +1150,34 @@ gboolean RtpAnalysisDialog::saveAudioAUUnidir(tap_rtp_stat_t &statinfo, QTempora
nchars += save_file->write((const char *)pd, 2);
}
if ((size_t)nchars < sample_count*2) {
- return FALSE;
+ sae_file_error_ = true;
+ return false;
}
}
}
+ g_hash_table_destroy(decoders_hash);
- return TRUE;
+ return true;
}
-gboolean RtpAnalysisDialog::saveAudioAUBidir(tap_rtp_stat_t &fwd_statinfo, tap_rtp_stat_t &rev_statinfo, QTemporaryFile *fwd_tempfile, QTemporaryFile *rev_tempfile, QFile *save_file, qint64 header_end, gboolean *stop_flag, size_t prefix_silence_fwd, size_t prefix_silence_rev)
+bool RtpAnalysisDialog::saveAudioAUBidir(tap_rtp_stat_t &fwd_statinfo, tap_rtp_stat_t &rev_statinfo, QTemporaryFile *fwd_tempfile, QTemporaryFile *rev_tempfile, QFile *save_file, int64_t header_end, gboolean *stop_flag, size_t prefix_silence_fwd, size_t prefix_silence_rev)
{
- if (! saveAudioAUUnidir(fwd_statinfo, fwd_tempfile, save_file, header_end, stop_flag, TRUE, prefix_silence_fwd))
- {
- return FALSE;
+ if (!saveAudioAUUnidir(fwd_statinfo, fwd_tempfile, save_file, header_end, stop_flag, true, prefix_silence_fwd)) {
+ return false;
}
- if (! saveAudioAUUnidir(rev_statinfo, rev_tempfile, save_file, header_end+2, stop_flag, TRUE, prefix_silence_rev))
- {
- return FALSE;
+
+ if (!saveAudioAUUnidir(rev_statinfo, rev_tempfile, save_file, header_end+2, stop_flag, true, prefix_silence_rev)) {
+ return false;
}
- return TRUE;
+ return true;
}
-gboolean RtpAnalysisDialog::saveAudioAU(StreamDirection direction, QFile *save_file, gboolean *stop_flag, RtpAnalysisDialog::SyncType sync)
+bool RtpAnalysisDialog::saveAudioAU(StreamDirection direction, QFile *save_file, gboolean *stop_flag, RtpAnalysisDialog::SyncType sync)
{
- guint8 pd[4];
- qint64 nchars;
- qint64 header_end;
+ uint8_t pd[4];
+ int64_t nchars;
+ int64_t header_end;
size_t fwd_total_len;
size_t rev_total_len;
size_t total_len;
@@ -1176,28 +1191,38 @@ gboolean RtpAnalysisDialog::saveAudioAU(StreamDirection direction, QFile *save_f
/* the magic word 0x2e736e64 == .snd */
phton32(pd, 0x2e736e64);
nchars = save_file->write((const char *)pd, 4);
- if (nchars != 4)
- return FALSE;
+ if (nchars != 4) {
+ sae_file_error_ = true;
+ return false;
+ }
/* header offset == 24 bytes */
phton32(pd, 24);
nchars = save_file->write((const char *)pd, 4);
- if (nchars != 4)
- return FALSE;
+ if (nchars != 4) {
+ sae_file_error_ = true;
+ return false;
+ }
/* total length; it is permitted to set this to 0xffffffff */
phton32(pd, 0xffffffff);
nchars = save_file->write((const char *)pd, 4);
- if (nchars != 4)
- return FALSE;
+ if (nchars != 4) {
+ sae_file_error_ = true;
+ return false;
+ }
/* encoding format == 16-bit linear PCM */
phton32(pd, 3);
nchars = save_file->write((const char *)pd, 4);
- if (nchars != 4)
- return FALSE;
+ if (nchars != 4) {
+ sae_file_error_ = true;
+ return false;
+ }
/* sample rate == 8000 Hz */
phton32(pd, 8000);
nchars = save_file->write((const char *)pd, 4);
- if (nchars != 4)
- return FALSE;
+ if (nchars != 4) {
+ sae_file_error_ = true;
+ return false;
+ }
/* channels == 1 or == 2 */
switch (direction) {
case dir_forward_: {
@@ -1214,8 +1239,10 @@ gboolean RtpAnalysisDialog::saveAudioAU(StreamDirection direction, QFile *save_f
}
}
nchars = save_file->write((const char *)pd, 4);
- if (nchars != 4)
- return FALSE;
+ if (nchars != 4) {
+ sae_file_error_ = true;
+ return false;
+ }
header_end=save_file->pos();
@@ -1239,7 +1266,8 @@ gboolean RtpAnalysisDialog::saveAudioAU(StreamDirection direction, QFile *save_f
/* Only forward channel */
/* This branch should not be reached ever */
QMessageBox::warning(this, tr("Warning"), tr("Can't synchronize when only one channel is selected"));
- return FALSE;
+ sae_other_error_ = true;
+ return false;
} else {
/* Two channels */
fwd_samples_diff = t_fwd_diff*8000/1000;
@@ -1268,26 +1296,23 @@ gboolean RtpAnalysisDialog::saveAudioAU(StreamDirection direction, QFile *save_f
/* Only forward direction */
case dir_forward_: {
fwd_total_len = guint32_wraparound_diff(fwd_statinfo_.rtp_stats.timestamp, fwd_statinfo_.rtp_stats.first_timestamp) + fwd_statinfo_.rtp_stats.last_payload_len;
- if (! saveAudioAUSilence(fwd_total_len + fwd_samples_diff + bidir_samples_diff, save_file, stop_flag))
- {
- return FALSE;
+ if (!saveAudioAUSilence(fwd_total_len + fwd_samples_diff + bidir_samples_diff, save_file, stop_flag)) {
+ return false;
}
- if (! saveAudioAUUnidir(fwd_statinfo_.rtp_stats, fwd_tempfile_, save_file, header_end, stop_flag, FALSE, fwd_samples_diff + bidir_samples_diff))
- {
- return FALSE;
+ if (!saveAudioAUUnidir(fwd_statinfo_.rtp_stats, fwd_tempfile_, save_file, header_end, stop_flag, false, fwd_samples_diff + bidir_samples_diff)) {
+ return false;
}
break;
}
/* Only reverse direction */
case dir_reverse_: {
rev_total_len = guint32_wraparound_diff(rev_statinfo_.rtp_stats.timestamp, rev_statinfo_.rtp_stats.first_timestamp) + rev_statinfo_.rtp_stats.last_payload_len;
- if (! saveAudioAUSilence(rev_total_len + rev_samples_diff + bidir_samples_diff, save_file, stop_flag))
- {
- return FALSE;
+ if (!saveAudioAUSilence(rev_total_len + rev_samples_diff + bidir_samples_diff, save_file, stop_flag)) {
+ return false;
}
- if (! saveAudioAUUnidir(rev_statinfo_.rtp_stats, rev_tempfile_, save_file, header_end, stop_flag, FALSE, rev_samples_diff + bidir_samples_diff))
- {
- return FALSE;
+
+ if (!saveAudioAUUnidir(rev_statinfo_.rtp_stats, rev_tempfile_, save_file, header_end, stop_flag, false, rev_samples_diff + bidir_samples_diff)) {
+ return false;
}
break;
}
@@ -1296,21 +1321,19 @@ gboolean RtpAnalysisDialog::saveAudioAU(StreamDirection direction, QFile *save_f
fwd_total_len = guint32_wraparound_diff(fwd_statinfo_.rtp_stats.timestamp, fwd_statinfo_.rtp_stats.first_timestamp) + fwd_statinfo_.rtp_stats.last_payload_len;
rev_total_len = guint32_wraparound_diff(rev_statinfo_.rtp_stats.timestamp, rev_statinfo_.rtp_stats.first_timestamp) + rev_statinfo_.rtp_stats.last_payload_len;
total_len = MAX(fwd_total_len + fwd_samples_diff, rev_total_len + rev_samples_diff);
- if (! saveAudioAUSilence((total_len + bidir_samples_diff) * 2, save_file, stop_flag))
- {
- return FALSE;
+ if (!saveAudioAUSilence((total_len + bidir_samples_diff) * 2, save_file, stop_flag)) {
+ return false;
}
- if (! saveAudioAUBidir(fwd_statinfo_.rtp_stats, rev_statinfo_.rtp_stats, fwd_tempfile_, rev_tempfile_, save_file, header_end, stop_flag, fwd_samples_diff + bidir_samples_diff, rev_samples_diff + bidir_samples_diff))
- {
- return FALSE;
+ if (!saveAudioAUBidir(fwd_statinfo_.rtp_stats, rev_statinfo_.rtp_stats, fwd_tempfile_, rev_tempfile_, save_file, header_end, stop_flag, fwd_samples_diff + bidir_samples_diff, rev_samples_diff + bidir_samples_diff)) {
+ return false;
}
}
}
- return TRUE;
+ return true;
}
-gboolean RtpAnalysisDialog::saveAudioRAW(StreamDirection direction, QFile *save_file, gboolean *stop_flag)
+bool RtpAnalysisDialog::saveAudioRAW(StreamDirection direction, QFile *save_file, gboolean *stop_flag)
{
QFile *tempfile;
tap_rtp_save_data_t save_data;
@@ -1327,7 +1350,9 @@ gboolean RtpAnalysisDialog::saveAudioRAW(StreamDirection direction, QFile *save_
break;
}
default: {
- return FALSE;
+ QMessageBox::warning(this, tr("Warning"), tr("None of channels was selected"));
+ sae_other_error_ = true;
+ return false;
}
}
@@ -1336,7 +1361,8 @@ gboolean RtpAnalysisDialog::saveAudioRAW(StreamDirection direction, QFile *save_
char f_rawvalue;
if (*stop_flag) {
- return FALSE;
+ sae_stopped_ = true;
+ return false;
}
ui->progressFrame->setValue(int(tempfile->pos() * 100 / fwd_tempfile_->size()));
@@ -1344,16 +1370,18 @@ gboolean RtpAnalysisDialog::saveAudioRAW(StreamDirection direction, QFile *save_
if (save_data.payload_len > 0) {
for (size_t i = 0; i < save_data.payload_len; i++) {
if (sizeof(f_rawvalue) != tempfile->read((char *)&f_rawvalue, sizeof(f_rawvalue))) {
- return FALSE;
+ sae_file_error_ = true;
+ return false;
}
if (sizeof(f_rawvalue) != save_file->write((char *)&f_rawvalue, sizeof(f_rawvalue))) {
- return FALSE;
+ sae_file_error_ = true;
+ return false;
}
}
}
}
- return TRUE;
+ return true;
}
// rtp_analysis.c:copy_file
@@ -1405,7 +1433,7 @@ void RtpAnalysisDialog::saveAudio(RtpAnalysisDialog::StreamDirection direction,
}
QFile save_file(file_path);
- gboolean stop_flag = FALSE;
+ gboolean stop_flag = false;
save_file.open(QIODevice::WriteOnly);
fwd_tempfile_->seek(0);
@@ -1419,50 +1447,36 @@ void RtpAnalysisDialog::saveAudio(RtpAnalysisDialog::StreamDirection direction,
ui->hintLabel->setText(tr("Saving %1" UTF8_HORIZONTAL_ELLIPSIS).arg(save_file.fileName()));
ui->progressFrame->showProgress(true, true, &stop_flag);
+ clearSAEErrors();
if (save_format == save_audio_au_) { /* au format */
- bool showPayloadWarning = TRUE;
-
- if ((fwd_statinfo_.rtp_stats.clock_rate != 8000) ||
- ((rev_statinfo_.rtp_stats.clock_rate != 0) && (rev_statinfo_.rtp_stats.clock_rate != 8000))
- ) {
- QMessageBox::warning(this, tr("Warning"), tr("Can save audio with 8000 Hz clock rate only"));
- goto copy_file_err;
- }
-
- /* Check for supported codecs */
- if (rtpstream_is_payload_used(&fwd_statinfo_, PT_PCMU)) { showPayloadWarning=FALSE; }
- if (rtpstream_is_payload_used(&fwd_statinfo_, PT_PCMA)) { showPayloadWarning=FALSE; }
- /* ED-137 silence */
- if (rtpstream_is_payload_used(&fwd_statinfo_, PT_UNDF_123)) { showPayloadWarning=FALSE; }
- if (rev_statinfo_.rtp_stats.clock_rate != 0)
- { /* Reverse stream is defined */
- bool showRevPayloadWarning = TRUE;
-
- /* Check for supported codecs */
- if (rtpstream_is_payload_used(&rev_statinfo_, PT_PCMU)) { showRevPayloadWarning=FALSE; }
- if (rtpstream_is_payload_used(&rev_statinfo_, PT_PCMA)) { showRevPayloadWarning=FALSE; }
- /* ED-137 silence */
- if (rtpstream_is_payload_used(&rev_statinfo_, PT_UNDF_123)) { showRevPayloadWarning=FALSE; }
- if (showRevPayloadWarning) { showPayloadWarning=TRUE; }
- }
- /* If unsupported coded is used, warn user */
- if (showPayloadWarning)
- {
- QMessageBox::warning(this, tr("Error"), tr("Can save audio with PCM u-law or A-law encoding only"));
- goto copy_file_err;
- }
-
- if (! saveAudioAU(direction, &save_file, &stop_flag, sync)) {
- goto copy_file_err;
+ if (!saveAudioAU(direction, &save_file, &stop_flag, sync)) {
}
} else if (save_format == save_audio_raw_) { /* raw format */
- if (! saveAudioRAW(direction, &save_file, &stop_flag)) {
- goto copy_file_err;
+ if (!saveAudioRAW(direction, &save_file, &stop_flag)) {
+ }
+ }
+ if (!isSAEOK()) {
+ // Other error was already handled
+ if (!sae_other_error_) {
+ if (sae_stopped_) {
+ QMessageBox::warning(this, tr("Information"), tr("Save was interrupted"));
+ }
+ else if (sae_file_error_) {
+ QMessageBox::warning(this, tr("Error"), tr("Save or read of file was failed during saving"));
+ }
+ else if (sae_unsupported_codec_) {
+ QMessageBox::warning(this, tr("Warning"), tr("Codec is not supported, file is incomplete"));
+ }
+ else if (sae_unsupported_rate_) {
+ QMessageBox::warning(this, tr("Warning"), tr("Codec rate is not supported, file is incomplete"));
+ }
+ else {
+ QMessageBox::warning(this, tr("Warning"), tr("Unknown error occured"));
+ }
}
}
-copy_file_err:
ui->progressFrame->hide();
updateWidgets();
return;
@@ -1569,6 +1583,24 @@ void RtpAnalysisDialog::graphClicked(QMouseEvent *event)
}
}
+void RtpAnalysisDialog::clearSAEErrors()
+{ sae_stopped_ = false;
+ sae_file_error_ = false;
+ sae_unsupported_codec_ = false;
+ sae_unsupported_rate_ = false;
+ sae_other_error_ = false;
+}
+
+bool RtpAnalysisDialog::isSAEOK()
+{ return !(sae_stopped_ ||
+ sae_file_error_ ||
+ sae_unsupported_codec_ ||
+ sae_unsupported_rate_ ||
+ sae_other_error_
+ )
+ ;
+}
+
void RtpAnalysisDialog::findStreams()
{
const gchar filter_text[] = "rtp && rtp.version == 2 && rtp.ssrc && (ip || ipv6)";
@@ -1599,7 +1631,7 @@ void RtpAnalysisDialog::findStreams()
epan_dissect_t edt;
- epan_dissect_init(&edt, cap_file_.capFile()->epan, TRUE, FALSE);
+ epan_dissect_init(&edt, cap_file_.capFile()->epan, true, false);
epan_dissect_prime_with_dfilter(&edt, sfcode);
epan_dissect_prime_with_hfid(&edt, hfid_rtp_ssrc);
epan_dissect_run(&edt, cap_file_.capFile()->cd_t, &cap_file_.capFile()->rec,
@@ -1621,10 +1653,10 @@ void RtpAnalysisDialog::findStreams()
dfilter_free(sfcode);
/* OK, it is an RTP frame. Let's get the IP and port values */
- rtpstream_id_copy_pinfo(&(edt.pi),&(fwd_statinfo_.id),FALSE);
+ rtpstream_id_copy_pinfo(&(edt.pi),&(fwd_statinfo_.id),false);
/* assume the inverse ip/port combination for the reverse direction */
- rtpstream_id_copy_pinfo(&(edt.pi),&(rev_statinfo_.id),TRUE);
+ rtpstream_id_copy_pinfo(&(edt.pi),&(rev_statinfo_.id),true);
/* now we need the SSRC value of the current frame */
GPtrArray *gp = proto_get_finfo_ptr_array(edt.tree, hfid_rtp_ssrc);
diff --git a/ui/qt/rtp_analysis_dialog.h b/ui/qt/rtp_analysis_dialog.h
index 8a843b7df6..903574162f 100644
--- a/ui/qt/rtp_analysis_dialog.h
+++ b/ui/qt/rtp_analysis_dialog.h
@@ -82,6 +82,13 @@ private:
enum StreamDirection { dir_both_, dir_forward_, dir_reverse_ };
enum SyncType { sync_unsync_, sync_sync_stream_, sync_sync_file_ };
+ /* Save Audio Errors */
+ bool sae_stopped_;
+ bool sae_file_error_;
+ bool sae_unsupported_codec_;
+ bool sae_unsupported_rate_;
+ bool sae_other_error_;
+
int num_streams_;
rtpstream_info_t fwd_statinfo_;
@@ -126,19 +133,22 @@ private:
void showPlayer();
- size_t convert_payload_to_samples(unsigned int payload_type, QTemporaryFile *tempfile, guint8 *pd_out, size_t expected_nchars);
- gboolean saveAudioAUSilence(size_t total_len, QFile *save_file, gboolean *stop_flag);
- gboolean saveAudioAUUnidir(tap_rtp_stat_t &statinfo, QTemporaryFile *tempfile, QFile *save_file, qint64 header_end, gboolean *stop_flag, gboolean interleave, size_t prefix_silence);
- gboolean saveAudioAUBidir(tap_rtp_stat_t &fwd_statinfo, tap_rtp_stat_t &rev_statinfo, QTemporaryFile *fwd_tempfile, QTemporaryFile *rev_tempfile, QFile *save_file, qint64 header_end, gboolean *stop_flag, size_t prefix_silence_fwd, size_t prefix_silence_rev);
- gboolean saveAudioAU(StreamDirection direction, QFile *save_file, gboolean *stop_flag, RtpAnalysisDialog::SyncType sync);
- gboolean saveAudioRAW(StreamDirection direction, QFile *save_file, gboolean *stop_flag);
+ size_t convert_payload_to_samples(unsigned int payload_type, QTemporaryFile *tempfile, uint8_t *pd_out, size_t expected_nchars, struct _GHashTable *decoders_hash);
+ bool saveAudioAUSilence(size_t total_len, QFile *save_file, gboolean *stop_flag);
+ bool saveAudioAUUnidir(tap_rtp_stat_t &statinfo, QTemporaryFile *tempfile, QFile *save_file, int64_t header_end, gboolean *stop_flag, gboolean interleave, size_t prefix_silence);
+ bool saveAudioAUBidir(tap_rtp_stat_t &fwd_statinfo, tap_rtp_stat_t &rev_statinfo, QTemporaryFile *fwd_tempfile, QTemporaryFile *rev_tempfile, QFile *save_file, int64_t header_end, gboolean *stop_flag, size_t prefix_silence_fwd, size_t prefix_silence_rev);
+ bool saveAudioAU(StreamDirection direction, QFile *save_file, gboolean *stop_flag, RtpAnalysisDialog::SyncType sync);
+ bool saveAudioRAW(StreamDirection direction, QFile *save_file, gboolean *stop_flag);
void saveAudio(StreamDirection direction, RtpAnalysisDialog::SyncType sync);
void saveCsv(StreamDirection direction);
- guint32 processNode(proto_node *ptree_node, header_field_info *hfinformation, const gchar* proto_field, bool *ok);
- guint32 getIntFromProtoTree(proto_tree *protocol_tree, const gchar *proto_name, const gchar *proto_field, bool *ok);
+ uint32_t processNode(proto_node *ptree_node, header_field_info *hfinformation, const gchar* proto_field, bool *ok);
+ uint32_t getIntFromProtoTree(proto_tree *protocol_tree, const gchar *proto_name, const gchar *proto_field, bool *ok);
bool eventFilter(QObject*, QEvent* event);
+
+ void clearSAEErrors();
+ bool isSAEOK();
};
#endif // RTP_ANALYSIS_DIALOG_H
diff --git a/ui/rtp_media.c b/ui/rtp_media.c
index 6321017ca8..692d2a5948 100644
--- a/ui/rtp_media.c
+++ b/ui/rtp_media.c
@@ -36,21 +36,14 @@ typedef struct _rtp_decoder_t {
*/
size_t
-decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash, unsigned *channels_ptr, unsigned *sample_rate_ptr)
+decode_rtp_packet_payload(guint8 payload_type, const gchar *payload_type_str, guint8 *payload_data, size_t payload_len, SAMPLE **out_buff, GHashTable *decoders_hash, guint *channels_ptr, guint *sample_rate_ptr)
{
- unsigned int payload_type;
const gchar *p;
rtp_decoder_t *decoder;
SAMPLE *tmp_buff = NULL;
size_t tmp_buff_len;
size_t decoded_bytes = 0;
- if ((rp->payload_data == NULL) || (rp->info->info_payload_len == 0) ) {
- return 0;
- }
-
- payload_type = rp->info->info_payload_type;
-
/* Look for registered codecs */
decoder = (rtp_decoder_t *)g_hash_table_lookup(decoders_hash, GUINT_TO_POINTER(payload_type));
if (!decoder) { /* Put either valid or empty decoder into the hash table */
@@ -58,8 +51,8 @@ decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash
decoder->handle = NULL;
decoder->context = NULL;
- if (rp->info->info_payload_type_str && find_codec(rp->info->info_payload_type_str)) {
- p = rp->info->info_payload_type_str;
+ if (payload_type_str && find_codec(payload_type_str)) {
+ p = payload_type_str;
} else {
p = try_val_to_str_ext(payload_type, &rtp_payload_type_short_vals_ext);
}
@@ -73,9 +66,9 @@ decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash
}
if (decoder->handle) { /* Decode with registered codec */
/* if output == NULL and outputSizeBytes == NULL => ask for expected size of the buffer */
- tmp_buff_len = codec_decode(decoder->handle, decoder->context, rp->payload_data, rp->info->info_payload_len, NULL, NULL);
+ tmp_buff_len = codec_decode(decoder->handle, decoder->context, payload_data, payload_len, NULL, NULL);
tmp_buff = (SAMPLE *)g_malloc(tmp_buff_len);
- decoded_bytes = codec_decode(decoder->handle, decoder->context, rp->payload_data, rp->info->info_payload_len, tmp_buff, &tmp_buff_len);
+ decoded_bytes = codec_decode(decoder->handle, decoder->context, payload_data, payload_len, tmp_buff, &tmp_buff_len);
*out_buff = tmp_buff;
if (channels_ptr) {
@@ -94,6 +87,25 @@ decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash
}
/****************************************************************************/
+/*
+ * Return the number of decoded bytes
+ */
+
+size_t
+decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash, guint *channels_ptr, guint *sample_rate_ptr)
+{
+ guint8 payload_type;
+
+ if ((rp->payload_data == NULL) || (rp->info->info_payload_len == 0) ) {
+ return 0;
+ }
+
+ payload_type = rp->info->info_payload_type;
+
+ return decode_rtp_packet_payload(payload_type, rp->info->info_payload_type_str, rp->payload_data, rp->info->info_payload_len, out_buff, decoders_hash, channels_ptr, sample_rate_ptr);
+}
+
+/****************************************************************************/
static void
rtp_decoder_value_destroy(gpointer dec_arg)
{
diff --git a/ui/rtp_media.h b/ui/rtp_media.h
index 00942f5096..94497d18e0 100644
--- a/ui/rtp_media.h
+++ b/ui/rtp_media.h
@@ -48,6 +48,20 @@ typedef struct _rtp_packet {
*/
GHashTable *rtp_decoder_hash_table_new(void);
+/** Decode payload from an RTP packet
+ *
+ * @param payload_type Payload number
+ * @param payload_type_str Payload name, can be NULL
+ * @param payload_data Payload
+ * @param payload_len Length of payload
+ * @param out_buff Output audio samples.
+ * @param decoders_hash Hash table created with rtp_decoder_hash_table_new.
+ * @param channels_ptr If non-NULL, receives the number of channels in the sample.
+ * @param sample_rate_ptr If non-NULL, receives the sample rate.
+ * @return The number of decoded bytes on success, 0 on failure.
+ */
+size_t decode_rtp_packet_payload(guint8 payload_type, const gchar *payload_type_str, guint8 *payload_data, size_t payload_len, SAMPLE **out_buff, GHashTable *decoders_hash, guint *channels_ptr, guint *sample_rate_ptr);
+
/** Decode an RTP packet
*
* @param rp Wrapper for per-packet RTP tap data.
@@ -57,7 +71,7 @@ GHashTable *rtp_decoder_hash_table_new(void);
* @param sample_rate_ptr If non-NULL, receives the sample rate.
* @return The number of decoded bytes on success, 0 on failure.
*/
-size_t decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash, unsigned *channels_ptr, unsigned *sample_rate_ptr);
+size_t decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash, guint *channels_ptr, guint *sample_rate_ptr);
#ifdef __cplusplus
}