diff options
author | Gerald Combs <gerald@wireshark.org> | 2015-10-20 08:31:52 -0700 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2015-10-21 17:52:15 +0000 |
commit | 8682eb49ef9e865be114ac57525628527bad1bd6 (patch) | |
tree | ca29ce58ee792b2b0b01b32ed8d858c9c58624e2 /ui/qt | |
parent | ed27dad41eb2085fa2afb51c6a66a89bd1c64ad4 (diff) |
Split RTP player tapping, decoding, and plotting.
In RtpAudioStream split tapping+decoding into separate member functions.
Store RTP payloads in memory. In RtpPlayerDialog split tapping+plotting.
This more closely resembles what we're doing in the GTK+ UI and paves
the way for jitter support and other changes.
Change-Id: I244c225cec8930545622e6582b7be35ebe45b237
Reviewed-on: https://code.wireshark.org/review/11195
Petri-Dish: Gerald Combs <gerald@wireshark.org>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Diffstat (limited to 'ui/qt')
-rw-r--r-- | ui/qt/rtp_audio_stream.cpp | 242 | ||||
-rw-r--r-- | ui/qt/rtp_audio_stream.h | 7 | ||||
-rw-r--r-- | ui/qt/rtp_player_dialog.cpp | 27 | ||||
-rw-r--r-- | ui/qt/rtp_player_dialog.h | 7 | ||||
-rw-r--r-- | ui/qt/rtp_player_dialog.ui | 2 |
5 files changed, 163 insertions, 122 deletions
diff --git a/ui/qt/rtp_audio_stream.cpp b/ui/qt/rtp_audio_stream.cpp index 68be1ccd4d..0868f5abee 100644 --- a/ui/qt/rtp_audio_stream.cpp +++ b/ui/qt/rtp_audio_stream.cpp @@ -19,7 +19,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "rtp_audio_stream.h" #ifdef QT_MULTIMEDIA_LIB @@ -40,6 +39,9 @@ #include <QDir> #include <QTemporaryFile> +// To do: +// - Only allow one rtp_stream_info_t per RtpAudioStream? + static spx_int16_t default_audio_sample_rate_ = 8000; static const spx_int16_t visual_sample_rate_ = 1000; @@ -77,6 +79,12 @@ RtpAudioStream::RtpAudioStream(QObject *parent, _rtp_stream_info *rtp_stream) : RtpAudioStream::~RtpAudioStream() { + for (int i = 0; i < rtp_packets_.size(); i++) { + rtp_packet_t *rtp_packet = rtp_packets_[i]; + g_free(rtp_packet->info); + g_free(rtp_packet->payload_data); + g_free(rtp_packet); + } g_hash_table_destroy(decoders_hash_); if (audio_resampler_) ws_codec_resampler_destroy (audio_resampler_); ws_codec_resampler_destroy (visual_resampler_); @@ -115,125 +123,27 @@ void RtpAudioStream::addRtpStream(const _rtp_stream_info *rtp_stream) // RTP_STREAM_DEBUG("added %d:%u packets", g_list_length(rtp_stream->rtp_packet_list), rtp_stream->packet_count); rtp_streams_ << rtp_stream; - - double stream_srt = nstime_to_sec(&rtp_stream->start_rel_time); - if (rtp_streams_.length() < 2 || stream_srt > start_rel_time_) { - start_rel_time_ = stop_rel_time_ = stream_srt; - start_abs_offset_ = nstime_to_sec(&rtp_stream->start_fd->abs_ts) - start_rel_time_; - } } -static const int sample_bytes_ = sizeof(SAMPLE) / sizeof(char); -void RtpAudioStream::addRtpPacket(const struct _packet_info *pinfo, const _rtp_info *rtp_info) +void RtpAudioStream::addRtpPacket(const struct _packet_info *pinfo, const struct _rtp_info *rtp_info) { + // gtk/rtp_player.c:decode_rtp_packet if (!rtp_info) return; - // Combination of gtk/rtp_player.c:decode_rtp_stream + decode_rtp_packet - // XXX This is more messy than it should be. - - SAMPLE *decode_buff = NULL; - SAMPLE *resample_buff = NULL; - spx_uint32_t cur_in_rate, visual_out_rate; - char *write_buff; - qint64 write_bytes; - unsigned channels; - unsigned sample_rate; - rtp_packet_t rtp_packet; - - stop_rel_time_ = nstime_to_sec(&pinfo->rel_ts); - ws_codec_resampler_get_rate(visual_resampler_, &cur_in_rate, &visual_out_rate); - - QString payload_name; - if (rtp_info->info_payload_type_str) { - payload_name = rtp_info->info_payload_type_str; - } else { - payload_name = try_val_to_str_ext(rtp_info->info_payload_type, &rtp_payload_type_short_vals_ext); - } - if (!payload_name.isEmpty()) { - payload_names_ << payload_name; - } - - // First, decode the payload. - rtp_packet.info = (_rtp_info *) g_memdup(rtp_info, sizeof(struct _rtp_info)); - rtp_packet.arrive_offset = start_rel_time_; + rtp_packet_t *rtp_packet = g_new0(rtp_packet_t, 1); + rtp_packet->info = (struct _rtp_info *) g_memdup(rtp_info, sizeof(struct _rtp_info)); if (rtp_info->info_all_data_present && (rtp_info->info_payload_len != 0)) { - rtp_packet.payload_data = (guint8 *)g_malloc(rtp_info->info_payload_len); - memcpy(rtp_packet.payload_data, rtp_info->info_data + rtp_info->info_payload_offset, rtp_info->info_payload_len); - } else { - rtp_packet.payload_data = NULL; - } - - //size_t decoded_bytes = - decode_rtp_packet(&rtp_packet, &decode_buff, decoders_hash_, &channels, &sample_rate); - write_buff = (char *) decode_buff; - write_bytes = rtp_info->info_payload_len * sample_bytes_; - - if (tempfile_->pos() == 0) { - // First packet. Let it determine our sample rate. - audio_out_rate_ = sample_rate; - - last_sequence_ = rtp_info->info_seq_num - 1; - - // Prepend silence to match our sibling streams. - int prepend_samples = (start_rel_time_ - global_start_rel_time_) * audio_out_rate_; - if (prepend_samples > 0) { - int prepend_bytes = prepend_samples * sample_bytes_; - char *prepend_buff = (char *) g_malloc(prepend_bytes); - SAMPLE silence = 0; - memccpy(prepend_buff, &silence, prepend_samples, sample_bytes_); - tempfile_->write(prepend_buff, prepend_bytes); - } - } else if (audio_out_rate_ != sample_rate) { - // Resample the audio to match our previous output rate. - if (!audio_resampler_) { - audio_resampler_ = ws_codec_resampler_init(1, sample_rate, audio_out_rate_, 10, NULL); - ws_codec_resampler_skip_zeros(audio_resampler_); - // RTP_STREAM_DEBUG("Started resampling from %u to (out) %u Hz.", sample_rate, audio_out_rate_); - } else { - spx_uint32_t audio_out_rate; - ws_codec_resampler_get_rate(audio_resampler_, &cur_in_rate, &audio_out_rate); - - // Adjust rates if needed. - if (sample_rate != cur_in_rate) { - ws_codec_resampler_set_rate(audio_resampler_, sample_rate, audio_out_rate); - ws_codec_resampler_set_rate(visual_resampler_, sample_rate, visual_out_rate); - // RTP_STREAM_DEBUG("Changed input rate from %u to %u Hz. Out is %u.", cur_in_rate, sample_rate, audio_out_rate_); - } - } - spx_uint32_t in_len = (spx_uint32_t)rtp_info->info_payload_len; - spx_uint32_t out_len = (audio_out_rate_ * (spx_uint32_t)rtp_info->info_payload_len / sample_rate) + (audio_out_rate_ % sample_rate != 0); - resample_buff = (SAMPLE *) g_malloc(out_len * sample_bytes_); - - ws_codec_resampler_process_int(audio_resampler_, 0, decode_buff, &in_len, resample_buff, &out_len); - write_buff = (char *) decode_buff; - write_bytes = out_len * sample_bytes_; - } - - if (rtp_info->info_seq_num != last_sequence_+1) { - out_of_seq_timestamps_.append(stop_rel_time_); - // XXX Add silence to tempfile_ and visual_samples_ + rtp_packet->payload_data = (guint8 *) g_memdup(&(rtp_info->info_data[rtp_info->info_payload_offset]), rtp_info->info_payload_len); } - last_sequence_ = rtp_info->info_seq_num; - // Write the decoded, possibly-resampled audio to our temp file. - tempfile_->write(write_buff, write_bytes); - - // Collect our visual samples. - spx_uint32_t in_len = (spx_uint32_t)rtp_info->info_payload_len; - spx_uint32_t out_len = (visual_out_rate * in_len / sample_rate) + (visual_out_rate % sample_rate != 0); - resample_buff = (SAMPLE *) g_realloc(resample_buff, out_len * sizeof(SAMPLE)); - - ws_codec_resampler_process_int(visual_resampler_, 0, decode_buff, &in_len, resample_buff, &out_len); - for (unsigned i = 0; i < out_len; i++) { - packet_timestamps_[stop_rel_time_ + (double) i / visual_out_rate] = pinfo->fd->num; - if (qAbs(resample_buff[i]) > max_sample_val_) max_sample_val_ = qAbs(resample_buff[i]); - visual_samples_.append(resample_buff[i]); + if (rtp_packets_.size() < 1) { // First packet + start_abs_offset_ = nstime_to_sec(&pinfo->fd->abs_ts) - start_rel_time_; + start_rel_time_ = stop_rel_time_ = nstime_to_sec(&pinfo->rel_ts); } + rtp_packet->frame_num = pinfo->fd->num; + rtp_packet->arrive_offset = nstime_to_sec(&pinfo->rel_ts) - start_rel_time_; - // Finally, write the resampled audio to our temp file and clean up. - g_free(rtp_packet.payload_data); - g_free(decode_buff); - g_free(resample_buff); + rtp_packets_ << rtp_packet; } void RtpAudioStream::reset(double start_rel_time) @@ -256,6 +166,118 @@ void RtpAudioStream::reset(double start_rel_time) tempfile_->seek(0); } +static const int sample_bytes_ = sizeof(SAMPLE) / sizeof(char); +void RtpAudioStream::decode() +{ + // gtk/rtp_player.c:decode_rtp_stream + // XXX This is more messy than it should be. + + SAMPLE *decode_buff = NULL; + gsize resample_buff_len = 0x1000; + SAMPLE *resample_buff = (SAMPLE *) g_malloc(resample_buff_len); + spx_uint32_t cur_in_rate, visual_out_rate; + char *write_buff; + qint64 write_bytes; + unsigned channels; + unsigned sample_rate; + + for (int i = 0; i < rtp_packets_.size(); i++) { + rtp_packet_t *rtp_packet = rtp_packets_[i]; + + stop_rel_time_ = start_rel_time_ + rtp_packet->arrive_offset; + ws_codec_resampler_get_rate(visual_resampler_, &cur_in_rate, &visual_out_rate); + + QString payload_name; + if (rtp_packet->info->info_payload_type_str) { + payload_name = rtp_packet->info->info_payload_type_str; + } else { + payload_name = try_val_to_str_ext(rtp_packet->info->info_payload_type, &rtp_payload_type_short_vals_ext); + } + if (!payload_name.isEmpty()) { + payload_names_ << payload_name; + } + + //size_t decoded_bytes = + decode_rtp_packet(rtp_packet, &decode_buff, decoders_hash_, &channels, &sample_rate); + write_buff = (char *) decode_buff; + write_bytes = rtp_packet->info->info_payload_len * sample_bytes_; + + if (tempfile_->pos() == 0) { + // First packet. Let it determine our sample rate. + audio_out_rate_ = sample_rate; + + last_sequence_ = rtp_packet->info->info_seq_num - 1; + + // Prepend silence to match our sibling streams. + int prepend_samples = (start_rel_time_ - global_start_rel_time_) * audio_out_rate_; + if (prepend_samples > 0) { + int prepend_bytes = prepend_samples * sample_bytes_; + char *prepend_buff = (char *) g_malloc(prepend_bytes); + SAMPLE silence = 0; + memccpy(prepend_buff, &silence, prepend_samples, sample_bytes_); + tempfile_->write(prepend_buff, prepend_bytes); + } + } else if (audio_out_rate_ != sample_rate) { + // Resample the audio to match our previous output rate. + if (!audio_resampler_) { + audio_resampler_ = ws_codec_resampler_init(1, sample_rate, audio_out_rate_, 10, NULL); + ws_codec_resampler_skip_zeros(audio_resampler_); + // RTP_STREAM_DEBUG("Started resampling from %u to (out) %u Hz.", sample_rate, audio_out_rate_); + } else { + spx_uint32_t audio_out_rate; + ws_codec_resampler_get_rate(audio_resampler_, &cur_in_rate, &audio_out_rate); + + // Adjust rates if needed. + if (sample_rate != cur_in_rate) { + ws_codec_resampler_set_rate(audio_resampler_, sample_rate, audio_out_rate); + ws_codec_resampler_set_rate(visual_resampler_, sample_rate, visual_out_rate); + // RTP_STREAM_DEBUG("Changed input rate from %u to %u Hz. Out is %u.", cur_in_rate, sample_rate, audio_out_rate_); + } + } + spx_uint32_t in_len = (spx_uint32_t)rtp_packet->info->info_payload_len; + spx_uint32_t out_len = (audio_out_rate_ * (spx_uint32_t)rtp_packet->info->info_payload_len / sample_rate) + (audio_out_rate_ % sample_rate != 0); + if (out_len * sample_bytes_ > resample_buff_len) { + while ((out_len * sample_bytes_ > resample_buff_len)) + resample_buff_len *= 2; + resample_buff = (SAMPLE *) g_realloc(resample_buff, resample_buff_len); + } + + ws_codec_resampler_process_int(audio_resampler_, 0, decode_buff, &in_len, resample_buff, &out_len); + write_buff = (char *) decode_buff; + write_bytes = out_len * sample_bytes_; + } + + if (rtp_packet->info->info_seq_num != last_sequence_+1) { + out_of_seq_timestamps_.append(stop_rel_time_); + // XXX Add silence to tempfile_ and visual_samples_ + } + last_sequence_ = rtp_packet->info->info_seq_num; + + // Write the decoded, possibly-resampled audio to our temp file. + tempfile_->write(write_buff, write_bytes); + + // Collect our visual samples. + spx_uint32_t in_len = (spx_uint32_t)rtp_packet->info->info_payload_len; + spx_uint32_t out_len = (visual_out_rate * in_len / sample_rate) + (visual_out_rate % sample_rate != 0); + if (out_len * sample_bytes_ > resample_buff_len) { + while ((out_len * sample_bytes_ > resample_buff_len)) + resample_buff_len *= 2; + resample_buff = (SAMPLE *) g_realloc(resample_buff, resample_buff_len); + } + + ws_codec_resampler_process_int(visual_resampler_, 0, decode_buff, &in_len, resample_buff, &out_len); + for (unsigned i = 0; i < out_len; i++) { + packet_timestamps_[stop_rel_time_ + (double) i / visual_out_rate] = rtp_packet->frame_num; + if (qAbs(resample_buff[i]) > max_sample_val_) max_sample_val_ = qAbs(resample_buff[i]); + visual_samples_.append(resample_buff[i]); + } + + // Finally, write the resampled audio to our temp file and clean up. + g_free(decode_buff); + } + g_free(resample_buff); +} + const QStringList RtpAudioStream::payloadNames() const { QStringList payload_names = payload_names_.toList(); diff --git a/ui/qt/rtp_audio_stream.h b/ui/qt/rtp_audio_stream.h index 33c3c469ab..f329870161 100644 --- a/ui/qt/rtp_audio_stream.h +++ b/ui/qt/rtp_audio_stream.h @@ -40,6 +40,7 @@ class QAudioOutput; class QTemporaryFile; +struct _rtp_info; struct _rtp_stream_info; struct _rtp_sample; @@ -54,6 +55,7 @@ public: void addRtpStream(const struct _rtp_stream_info *rtp_stream); void addRtpPacket(const struct _packet_info *pinfo, const struct _rtp_info *rtp_info); void reset(double start_rel_time); + void decode(); double startRelTime() const { return start_rel_time_; } double stopRelTime() const { return stop_rel_time_; } @@ -103,11 +105,15 @@ public slots: void stopPlaying(); private: + // Used to identify unique streams. + // The GTK+ UI also uses the call number + current channel. address src_addr_; quint16 src_port_; address dst_addr_; quint16 dst_port_; quint32 ssrc_; + + QVector<struct _rtp_packet *>rtp_packets_; int last_sequence_; QTemporaryFile *tempfile_; struct _GHashTable *decoders_hash_; @@ -130,7 +136,6 @@ private: private slots: void outputStateChanged(); void outputNotify(); - }; #endif // QT_MULTIMEDIA_LIB diff --git a/ui/qt/rtp_player_dialog.cpp b/ui/qt/rtp_player_dialog.cpp index 6a46d4b240..f25668f486 100644 --- a/ui/qt/rtp_player_dialog.cpp +++ b/ui/qt/rtp_player_dialog.cpp @@ -177,7 +177,16 @@ RtpPlayerDialog::~RtpPlayerDialog() delete ui; } -void RtpPlayerDialog::retapPackets(bool rescale_axes) +void RtpPlayerDialog::retapPackets() +{ + register_tap_listener("rtp", this, NULL, 0, NULL, tapPacket, NULL); + cap_file_.retapPackets(); + remove_tap_listener(this); + + rescanPackets(); +} + +void RtpPlayerDialog::rescanPackets(bool rescale_axes) { int row_count = ui->streamTreeWidget->topLevelItemCount(); // Clear existing graphs and reset stream values @@ -190,10 +199,6 @@ void RtpPlayerDialog::retapPackets(bool rescale_axes) } ui->audioPlot->clearGraphs(); - register_tap_listener("rtp", this, NULL, 0, NULL, tapPacket, NULL); - cap_file_.retapPackets(); - remove_tap_listener(this); - bool show_legend = false; bool relative_timestamps = !ui->todCheckBox->isChecked(); @@ -204,6 +209,8 @@ void RtpPlayerDialog::retapPackets(bool rescale_axes) RtpAudioStream *audio_stream = ti->data(stream_data_col_, Qt::UserRole).value<RtpAudioStream*>(); int y_offset = row_count - row - 1; + audio_stream->decode(); + // Waveform QCPGraph *audio_graph = ui->audioPlot->addGraph(); QPen wf_pen(audio_stream->color()); @@ -215,7 +222,7 @@ void RtpPlayerDialog::retapPackets(bool rescale_axes) audio_graph->setData(audio_stream->visualTimestamps(relative_timestamps), audio_stream->visualSamples(y_offset)); audio_graph->removeFromLegend(); ti->setData(graph_data_col_, Qt::UserRole, QVariant::fromValue<QCPGraph *>(audio_graph)); - // RTP_STREAM_DEBUG("Plotting %s, %d samples", ti->text(src_addr_col_).toUtf8().constData(), audio_graph->data()->keys().length()); + RTP_STREAM_DEBUG("Plotting %s, %d samples", ti->text(src_addr_col_).toUtf8().constData(), audio_graph->data()->keys().length()); QString span_str = QString("%1 - %2 (%3)") .arg(QString::number(audio_stream->startRelTime(), 'g', 3)) @@ -303,7 +310,11 @@ void RtpPlayerDialog::addRtpStream(struct _rtp_stream_info *rtp_stream) } else { start_rel_time_ = qMin(start_rel_time_, start_rel_time); } - // RTP_STREAM_DEBUG("adding stream %s to layout, %u packets, start %u", stream_key.toUtf8().constData(), rtp_stream->packet_count, rtp_stream->start_fd->num); + RTP_STREAM_DEBUG("adding stream %d to layout, %u packets, %u in list, start %u", + ui->streamTreeWidget->topLevelItemCount(), + rtp_stream->packet_count, + g_list_length(rtp_stream->rtp_packet_list), + rtp_stream->start_fd->num); } void RtpPlayerDialog::showEvent(QShowEvent *) @@ -618,7 +629,7 @@ void RtpPlayerDialog::on_todCheckBox_toggled(bool) QCPAxis *x_axis = ui->audioPlot->xAxis; double old_lowest = getLowestTimestamp(); - retapPackets(false); + rescanPackets(false); x_axis->moveRange(getLowestTimestamp() - old_lowest); ui->audioPlot->replot(); } diff --git a/ui/qt/rtp_player_dialog.h b/ui/qt/rtp_player_dialog.h index 4d004b860a..9cb8ed5b9e 100644 --- a/ui/qt/rtp_player_dialog.h +++ b/ui/qt/rtp_player_dialog.h @@ -79,9 +79,12 @@ protected: private slots: /** Retap the capture file, adding RTP packets that match the - * streams added using ::addRtpStream and display the dialog. + * streams added using ::addRtpStream. */ - void retapPackets(bool rescale_axes = true); + void retapPackets(); + /** Clear, decode, and redraw each stream. + */ + void rescanPackets(bool rescale_axes = true); void updateWidgets(); void graphClicked(QMouseEvent *event); void mouseMoved(QMouseEvent *); diff --git a/ui/qt/rtp_player_dialog.ui b/ui/qt/rtp_player_dialog.ui index 728a67e4db..721f3e5bb5 100644 --- a/ui/qt/rtp_player_dialog.ui +++ b/ui/qt/rtp_player_dialog.ui @@ -54,7 +54,7 @@ </column> <column> <property name="text"> - <string>First Packet</string> + <string>Setup Frame</string> </property> </column> <column> |