Qt: Wire up the RTP Streams "Analyze" button.

Change-Id: I0ad5d689b6c05fd3f98ba3304a5d99297db2bd6c
Reviewed-on: https://code.wireshark.org/review/11198
Petri-Dish: Gerald Combs <gerald@wireshark.org>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Gerald Combs <gerald@wireshark.org>
This commit is contained in:
Gerald Combs 2015-10-08 12:52:32 -07:00
parent c70ab1a122
commit 18bec424fb
4 changed files with 269 additions and 175 deletions

View File

@ -242,17 +242,20 @@ enum {
num_graphs_
};
RtpAnalysisDialog::RtpAnalysisDialog(QWidget &parent, CaptureFile &cf) :
RtpAnalysisDialog::RtpAnalysisDialog(QWidget &parent, CaptureFile &cf, struct _rtp_stream_info *stream_fwd, struct _rtp_stream_info *stream_rev) :
WiresharkDialog(parent, cf),
ui(new Ui::RtpAnalysisDialog),
port_src_fwd_(0),
port_dst_fwd_(0),
ssrc_fwd_(0),
stream_fwd_(0),
packet_count_fwd_(0),
setup_frame_number_fwd_(0),
port_src_rev_(0),
port_dst_rev_(0),
ssrc_rev_(0),
stream_rev_(0)
packet_count_rev_(0),
setup_frame_number_rev_(0),
num_streams_(0)
{
ui->setupUi(this);
setWindowSubtitle(tr("RTP Stream Analysis"));
@ -298,6 +301,8 @@ RtpAnalysisDialog::RtpAnalysisDialog(QWidget &parent, CaptureFile &cf) :
memset(&dst_fwd_, 0, sizeof(address));
memset(&src_rev_, 0, sizeof(address));
memset(&dst_rev_, 0, sizeof(address));
nstime_set_zero(&start_rel_time_fwd_);
nstime_set_zero(&start_rel_time_rev_);
QList<QCheckBox *> graph_cbs = QList<QCheckBox *>()
<< ui->fJitterCheckBox << ui->fDiffCheckBox << ui->fDeltaCheckBox
@ -342,108 +347,39 @@ RtpAnalysisDialog::RtpAnalysisDialog(QWidget &parent, CaptureFile &cf) :
save_menu->addAction(ui->actionSaveGraph);
ui->buttonBox->button(QDialogButtonBox::Save)->setMenu(save_menu);
const gchar *filter_text = "rtp && rtp.version && rtp.ssrc";
dfilter_t *sfcode;
gchar *err_msg;
if (!dfilter_compile(filter_text, &sfcode, &err_msg)) {
QMessageBox::warning(this, tr("No RTP packets found"), QString("%1").arg(err_msg));
g_free(err_msg);
close();
}
if (!cap_file_.capFile() || !cap_file_.capFile()->current_frame) close();
frame_data *fdata = cap_file_.capFile()->current_frame;
if (!cf_read_record(cap_file_.capFile(), fdata)) close();
epan_dissect_t edt;
epan_dissect_init(&edt, cap_file_.capFile()->epan, TRUE, FALSE);
epan_dissect_prime_dfilter(&edt, sfcode);
epan_dissect_run(&edt, cap_file_.capFile()->cd_t, &cap_file_.capFile()->phdr,
frame_tvbuff_new_buffer(fdata, &cap_file_.capFile()->buf), fdata, NULL);
// This shouldn't happen (the menu item should be disabled) but check anyway
if (!dfilter_apply_edt(sfcode, &edt)) {
epan_dissect_cleanup(&edt);
dfilter_free(sfcode);
err_str_ = tr("Please select an RTP packet");
updateWidgets();
return;
}
dfilter_free(sfcode);
/* OK, it is an RTP frame. Let's get the IP and port values */
COPY_ADDRESS(&(src_fwd_), &(edt.pi.src));
COPY_ADDRESS(&(dst_fwd_), &(edt.pi.dst));
port_src_fwd_ = edt.pi.srcport;
port_dst_fwd_ = edt.pi.destport;
/* assume the inverse ip/port combination for the reverse direction */
COPY_ADDRESS(&(src_rev_), &(edt.pi.dst));
COPY_ADDRESS(&(dst_rev_), &(edt.pi.src));
port_src_rev_ = edt.pi.destport;
port_dst_rev_ = edt.pi.srcport;
/* Check if it is RTP Version 2 */
unsigned int version_fwd;
bool ok;
version_fwd = getIntFromProtoTree(edt.tree, "rtp", "rtp.version", &ok);
if (!ok || version_fwd != 2) {
err_str_ = tr("RTP version %1 found. Only version 2 is supported.").arg(version_fwd);
updateWidgets();
return;
}
/* now we need the SSRC value of the current frame */
ssrc_fwd_ = getIntFromProtoTree(edt.tree, "rtp", "rtp.ssrc", &ok);
if (!ok) {
err_str_ = tr("SSRC value not found.");
updateWidgets();
return;
}
/* Register the tap listener */
memset(&tapinfo_, 0, sizeof(rtpstream_tapinfo_t));
tapinfo_.tap_data = this;
tapinfo_.mode = TAP_ANALYSE;
// register_tap_listener_rtp_stream(&tapinfo_, NULL);
/* Scan for RTP streams (redissect all packets) */
rtpstream_scan(&tapinfo_, cap_file_.capFile(), NULL);
num_streams_ = 0;
for (GList *strinfo_list = g_list_first(tapinfo_.strinfo_list); strinfo_list; strinfo_list = g_list_next(strinfo_list)) {
rtp_stream_info_t * strinfo = (rtp_stream_info_t*)(strinfo_list->data);
if (ADDRESSES_EQUAL(&(strinfo->src_addr), &(src_fwd_))
&& (strinfo->src_port == port_src_fwd_)
&& (ADDRESSES_EQUAL(&(strinfo->dest_addr), &(dst_fwd_)))
&& (strinfo->dest_port == port_dst_fwd_))
{
++num_streams_;
stream_fwd_ = strinfo;
}
if (ADDRESSES_EQUAL(&(strinfo->src_addr), &(src_rev_))
&& (strinfo->src_port == port_src_rev_)
&& (ADDRESSES_EQUAL(&(strinfo->dest_addr), &(dst_rev_)))
&& (strinfo->dest_port == port_dst_rev_))
{
++num_streams_;
if (ssrc_rev_ == 0) {
ssrc_rev_ = strinfo->ssrc;
stream_rev_ = strinfo;
}
if (stream_fwd) { // XXX What if stream_fwd == 0 && stream_rev != 0?
copy_address(&src_fwd_, &(stream_fwd->src_addr));
port_src_fwd_ = stream_fwd->src_port;
copy_address(&dst_fwd_, &(stream_fwd->dest_addr));
port_dst_fwd_ = stream_fwd->dest_port;
ssrc_fwd_ = stream_fwd->ssrc;
packet_count_fwd_ = stream_fwd->packet_count;
setup_frame_number_fwd_ = stream_fwd->setup_frame_number;
nstime_copy(&start_rel_time_fwd_, &stream_fwd->start_rel_time);
num_streams_++;
if (stream_rev) {
copy_address(&src_rev_, &(stream_rev->src_addr));
port_src_rev_ = stream_rev->src_port;
copy_address(&dst_rev_, &(stream_rev->dest_addr));
port_dst_rev_ = stream_rev->dest_port;
ssrc_rev_ = stream_rev->ssrc;
packet_count_rev_ = stream_rev->packet_count;
setup_frame_number_rev_ = stream_rev->setup_frame_number;
nstime_copy(&start_rel_time_rev_, &stream_rev->start_rel_time);
num_streams_++;
}
} else {
findStreams();
}
if (num_streams_ < 1) {
err_str_ = tr("No streams found.");
}
registerTapListener("rtp", this, NULL, 0, tapReset, tapPacket, tapDraw);
cap_file_.retapPackets();
removeTapListeners();
connect(ui->tabWidget, SIGNAL(currentChanged(int)),
this, SLOT(updateWidgets()));
connect(ui->forwardTreeWidget, SIGNAL(itemSelectionChanged()),
@ -454,10 +390,6 @@ RtpAnalysisDialog::RtpAnalysisDialog(QWidget &parent, CaptureFile &cf) :
this, SLOT(updateWidgets()));
updateWidgets();
registerTapListener("rtp", this, NULL, 0, tapReset, tapPacket, tapDraw);
cap_file_.retapPackets();
removeTapListeners();
updateStatistics();
}
@ -507,7 +439,7 @@ void RtpAnalysisDialog::updateWidgets()
ui->actionSaveReverseCsv->setEnabled(enable_save_rev_csv);
#if defined(QT_MULTIMEDIA_LIB)
player_button_->setEnabled(stream_fwd_ != 0);
player_button_->setEnabled(num_streams_ > 0);
#else
player_button_->setEnabled(false);
player_button_->setText(tr("No Audio"));
@ -705,18 +637,18 @@ gboolean RtpAnalysisDialog::tapPacket(void *tapinfo_ptr, packet_info *pinfo, epa
return FALSE;
/* is it the forward direction? */
else if (rtp_analysis_dialog->ssrc_fwd_ == rtpinfo->info_sync_src
&& (CMP_ADDRESS(&(rtp_analysis_dialog->src_fwd_), &(pinfo->src)) == 0)
&& (cmp_address(&(rtp_analysis_dialog->src_fwd_), &(pinfo->src)) == 0)
&& (rtp_analysis_dialog->port_src_fwd_ == pinfo->srcport)
&& (CMP_ADDRESS(&(rtp_analysis_dialog->dst_fwd_), &(pinfo->dst)) == 0)
&& (cmp_address(&(rtp_analysis_dialog->dst_fwd_), &(pinfo->dst)) == 0)
&& (rtp_analysis_dialog->port_dst_fwd_ == pinfo->destport)) {
rtp_analysis_dialog->addPacket(true, pinfo, rtpinfo);
}
/* is it the reversed direction? */
else if (rtp_analysis_dialog->ssrc_rev_ == rtpinfo->info_sync_src
&& (CMP_ADDRESS(&(rtp_analysis_dialog->src_rev_), &(pinfo->src)) == 0)
&& (cmp_address(&(rtp_analysis_dialog->src_rev_), &(pinfo->src)) == 0)
&& (rtp_analysis_dialog->port_src_rev_ == pinfo->srcport)
&& (CMP_ADDRESS(&(rtp_analysis_dialog->dst_rev_), &(pinfo->dst)) == 0)
&& (cmp_address(&(rtp_analysis_dialog->dst_rev_), &(pinfo->dst)) == 0)
&& (rtp_analysis_dialog->port_dst_rev_ == pinfo->destport)) {
rtp_analysis_dialog->addPacket(false, pinfo, rtpinfo);
@ -1048,12 +980,35 @@ void RtpAnalysisDialog::updateGraph()
void RtpAnalysisDialog::showPlayer()
{
#ifdef QT_MULTIMEDIA_LIB
if (!stream_fwd_) return;
if (num_streams_ < 1) return;
RtpPlayerDialog rtp_player_dialog(*this, cap_file_);
rtp_stream_info_t stream_info;
rtp_player_dialog.addRtpStream(stream_fwd_);
if (stream_rev_) rtp_player_dialog.addRtpStream(stream_rev_);
// XXX We might want to create an "rtp_stream_id_t" struct with only
// addresses, ports & SSRC.
memset(&stream_info, 0, sizeof(stream_info));
copy_address(&(stream_info.src_addr), &src_fwd_);
stream_info.src_port = port_src_fwd_;
copy_address(&(stream_info.dest_addr), &dst_fwd_);
stream_info.dest_port = port_dst_fwd_;
stream_info.ssrc = ssrc_fwd_;
stream_info.packet_count = packet_count_fwd_;
stream_info.setup_frame_number = setup_frame_number_fwd_;
nstime_copy(&stream_info.start_rel_time, &start_rel_time_fwd_);
rtp_player_dialog.addRtpStream(&stream_info);
if (num_streams_ > 1) {
copy_address(&(stream_info.src_addr), &src_rev_);
stream_info.src_port = port_src_rev_;
copy_address(&(stream_info.dest_addr), &dst_rev_);
stream_info.dest_port = port_dst_rev_;
stream_info.ssrc = ssrc_rev_;
stream_info.packet_count = packet_count_rev_;
stream_info.setup_frame_number = setup_frame_number_rev_;
rtp_player_dialog.addRtpStream(&stream_info);
nstime_copy(&stream_info.start_rel_time, &start_rel_time_rev_);
}
connect(&rtp_player_dialog, SIGNAL(goToPacket(int)), this, SIGNAL(goToPacket(int)));
@ -1505,6 +1460,110 @@ void RtpAnalysisDialog::graphClicked(QMouseEvent *event)
}
}
void RtpAnalysisDialog::findStreams()
{
const gchar *filter_text = "rtp && rtp.version && rtp.ssrc";
dfilter_t *sfcode;
gchar *err_msg;
if (!dfilter_compile(filter_text, &sfcode, &err_msg)) {
QMessageBox::warning(this, tr("No RTP packets found"), QString("%1").arg(err_msg));
g_free(err_msg);
close();
}
if (!cap_file_.capFile() || !cap_file_.capFile()->current_frame) close();
frame_data *fdata = cap_file_.capFile()->current_frame;
if (!cf_read_record(cap_file_.capFile(), fdata)) close();
epan_dissect_t edt;
epan_dissect_init(&edt, cap_file_.capFile()->epan, TRUE, FALSE);
epan_dissect_prime_dfilter(&edt, sfcode);
epan_dissect_run(&edt, cap_file_.capFile()->cd_t, &cap_file_.capFile()->phdr,
frame_tvbuff_new_buffer(fdata, &cap_file_.capFile()->buf), fdata, NULL);
// This shouldn't happen (the menu item should be disabled) but check anyway
if (!dfilter_apply_edt(sfcode, &edt)) {
epan_dissect_cleanup(&edt);
dfilter_free(sfcode);
err_str_ = tr("Please select an RTP packet");
updateWidgets();
return;
}
dfilter_free(sfcode);
/* OK, it is an RTP frame. Let's get the IP and port values */
copy_address(&(src_fwd_), &(edt.pi.src));
copy_address(&(dst_fwd_), &(edt.pi.dst));
port_src_fwd_ = edt.pi.srcport;
port_dst_fwd_ = edt.pi.destport;
/* assume the inverse ip/port combination for the reverse direction */
copy_address(&(src_rev_), &(edt.pi.dst));
copy_address(&(dst_rev_), &(edt.pi.src));
port_src_rev_ = edt.pi.destport;
port_dst_rev_ = edt.pi.srcport;
/* Check if it is RTP Version 2 */
unsigned int version_fwd;
bool ok;
version_fwd = getIntFromProtoTree(edt.tree, "rtp", "rtp.version", &ok);
if (!ok || version_fwd != 2) {
err_str_ = tr("RTP version %1 found. Only version 2 is supported.").arg(version_fwd);
updateWidgets();
return;
}
/* now we need the SSRC value of the current frame */
ssrc_fwd_ = getIntFromProtoTree(edt.tree, "rtp", "rtp.ssrc", &ok);
if (!ok) {
err_str_ = tr("SSRC value not found.");
updateWidgets();
return;
}
/* Register the tap listener */
memset(&tapinfo_, 0, sizeof(rtpstream_tapinfo_t));
tapinfo_.tap_data = this;
tapinfo_.mode = TAP_ANALYSE;
// register_tap_listener_rtp_stream(&tapinfo_, NULL);
/* Scan for RTP streams (redissect all packets) */
rtpstream_scan(&tapinfo_, cap_file_.capFile(), NULL);
for (GList *strinfo_list = g_list_first(tapinfo_.strinfo_list); strinfo_list; strinfo_list = g_list_next(strinfo_list)) {
rtp_stream_info_t * strinfo = (rtp_stream_info_t*)(strinfo_list->data);
if (ADDRESSES_EQUAL(&(strinfo->src_addr), &(src_fwd_))
&& (strinfo->src_port == port_src_fwd_)
&& (ADDRESSES_EQUAL(&(strinfo->dest_addr), &(dst_fwd_)))
&& (strinfo->dest_port == port_dst_fwd_))
{
packet_count_fwd_ = strinfo->packet_count;
setup_frame_number_fwd_ = strinfo->setup_frame_number;
nstime_copy(&start_rel_time_fwd_, &strinfo->start_rel_time);
num_streams_++;
}
if (ADDRESSES_EQUAL(&(strinfo->src_addr), &(src_rev_))
&& (strinfo->src_port == port_src_rev_)
&& (ADDRESSES_EQUAL(&(strinfo->dest_addr), &(dst_rev_)))
&& (strinfo->dest_port == port_dst_rev_))
{
packet_count_rev_ = strinfo->packet_count;
setup_frame_number_rev_ = strinfo->setup_frame_number;
nstime_copy(&start_rel_time_rev_, &strinfo->start_rel_time);
num_streams_++;
if (ssrc_rev_ == 0) {
ssrc_rev_ = strinfo->ssrc;
}
}
}
}
void RtpAnalysisDialog::showStreamMenu(QPoint pos)
{
QTreeWidget *cur_tree = qobject_cast<QTreeWidget *>(ui->tabWidget->currentWidget());

View File

@ -48,7 +48,7 @@ class RtpAnalysisDialog : public WiresharkDialog
Q_OBJECT
public:
explicit RtpAnalysisDialog(QWidget &parent, CaptureFile &cf);
explicit RtpAnalysisDialog(QWidget &parent, CaptureFile &cf, struct _rtp_stream_info *stream_fwd = 0, struct _rtp_stream_info *stream_rev = 0);
~RtpAnalysisDialog();
signals:
@ -82,19 +82,26 @@ private:
Ui::RtpAnalysisDialog *ui;
enum StreamDirection { dir_both_, dir_forward_, dir_reverse_ };
// XXX These are copied to and from rtp_stream_info_t structs. Should
// we just have a pair of those instead?
address src_fwd_;
guint32 port_src_fwd_;
address dst_fwd_;
guint32 port_dst_fwd_;
guint32 ssrc_fwd_;
struct _rtp_stream_info *stream_fwd_;
guint32 packet_count_fwd_;
guint32 setup_frame_number_fwd_;
nstime_t start_rel_time_fwd_;
address src_rev_;
guint32 port_src_rev_;
address dst_rev_;
guint32 port_dst_rev_;
guint32 ssrc_rev_;
struct _rtp_stream_info *stream_rev_;
guint32 packet_count_rev_;
guint32 setup_frame_number_rev_;
nstime_t start_rel_time_rev_;
int num_streams_;
tap_rtp_stat_t fwd_statinfo_;
@ -123,6 +130,8 @@ private:
QMenu stream_ctx_menu_;
QMenu graph_ctx_menu_;
void findStreams();
// Tap callbacks
static void tapReset(void *tapinfo_ptr);
static gboolean tapPacket(void *tapinfo_ptr, packet_info *pinfo, epan_dissect_t *, const void *rtpinfo_ptr);

View File

@ -63,6 +63,8 @@ public:
/** Add an RTP stream to play.
* MUST be called before exec().
* Requires src_addr, src_port, dest_addr, dest_port, ssrc, packet_count,
* setup_frame_number, and start_rel_time.
*
* @param rtp_stream struct with rtp_stream info
*/

View File

@ -30,6 +30,7 @@
#include <wsutil/utf8_entities.h>
#include "qt_ui_utils.h"
#include "rtp_analysis_dialog.h"
#include "wireshark_application.h"
#include <QAction>
@ -79,42 +80,45 @@ const int max_jitter_col_ = 9;
const int mean_jitter_col_ = 10;
const int status_col_ = 11;
Q_DECLARE_METATYPE(rtp_stream_info_t*)
enum { rtp_stream_type_ = 1000 };
class RtpStreamTreeWidgetItem : public QTreeWidgetItem
{
public:
RtpStreamTreeWidgetItem(QTreeWidget *tree, rtp_stream_info_t *stream_info) : QTreeWidgetItem(tree) {
setData(0, Qt::UserRole, qVariantFromValue(stream_info));
RtpStreamTreeWidgetItem(QTreeWidget *tree, rtp_stream_info_t *stream_info) :
QTreeWidgetItem(tree, rtp_stream_type_),
stream_info_(stream_info)
{
drawData();
}
rtp_stream_info_t *streamInfo() const { return stream_info_; }
void drawData() {
rtp_stream_info_t *stream_info = data(0, Qt::UserRole).value<rtp_stream_info_t*>();
if (!stream_info) {
if (!stream_info_) {
return;
}
setText(src_addr_col_, address_to_display_qstring(&stream_info->src_addr));
setText(src_port_col_, QString::number(stream_info->src_port));
setText(dst_addr_col_, address_to_display_qstring(&stream_info->dest_addr));
setText(dst_port_col_, QString::number(stream_info->dest_port));
setText(ssrc_col_, QString("0x%1").arg(stream_info->ssrc, 0, 16));
setText(src_addr_col_, address_to_display_qstring(&stream_info_->src_addr));
setText(src_port_col_, QString::number(stream_info_->src_port));
setText(dst_addr_col_, address_to_display_qstring(&stream_info_->dest_addr));
setText(dst_port_col_, QString::number(stream_info_->dest_port));
setText(ssrc_col_, QString("0x%1").arg(stream_info_->ssrc, 0, 16));
if (stream_info->payload_type_name != NULL) {
setText(payload_col_, stream_info->payload_type_name);
if (stream_info_->payload_type_name != NULL) {
setText(payload_col_, stream_info_->payload_type_name);
} else {
setText(payload_col_, val_ext_to_qstring(stream_info->payload_type,
setText(payload_col_, val_ext_to_qstring(stream_info_->payload_type,
&rtp_payload_type_short_vals_ext,
"Unknown (%u)"));
}
setText(packets_col_, QString::number(stream_info->packet_count));
setText(packets_col_, QString::number(stream_info_->packet_count));
guint32 expected;
double pct_loss;
expected = (stream_info->rtp_stats.stop_seq_nr + stream_info->rtp_stats.cycles*65536)
- stream_info->rtp_stats.start_seq_nr + 1;
lost_ = expected - stream_info->rtp_stats.total_nr;
expected = (stream_info_->rtp_stats.stop_seq_nr + stream_info_->rtp_stats.cycles*65536)
- stream_info_->rtp_stats.start_seq_nr + 1;
lost_ = expected - stream_info_->rtp_stats.total_nr;
if (expected) {
pct_loss = (double)(lost_*100.0)/(double)expected;
} else {
@ -122,11 +126,11 @@ public:
}
setText(lost_col_, QObject::tr("%1 (%L2%)").arg(lost_).arg(QString::number(pct_loss, 'f', 1)));
setText(max_delta_col_, QString::number(stream_info->rtp_stats.max_delta, 'f', 3)); // This is RTP. Do we need nanoseconds?
setText(max_jitter_col_, QString::number(stream_info->rtp_stats.max_jitter, 'f', 3));
setText(mean_jitter_col_, QString::number(stream_info->rtp_stats.mean_jitter, 'f', 3));
setText(max_delta_col_, QString::number(stream_info_->rtp_stats.max_delta, 'f', 3)); // This is RTP. Do we need nanoseconds?
setText(max_jitter_col_, QString::number(stream_info_->rtp_stats.max_jitter, 'f', 3));
setText(mean_jitter_col_, QString::number(stream_info_->rtp_stats.mean_jitter, 'f', 3));
if (stream_info->problem) {
if (stream_info_->problem) {
setText(status_col_, UTF8_BULLET);
setTextAlignment(status_col_, Qt::AlignCenter);
for (int i = 0; i < columnCount(); i++) {
@ -137,8 +141,7 @@ public:
}
// Return a QString, int, double, or invalid QVariant representing the raw column data.
QVariant colData(int col) const {
rtp_stream_info_t *stream_info = data(0, Qt::UserRole).value<rtp_stream_info_t*>();
if (!stream_info) {
if (!stream_info_) {
return QVariant();
}
@ -148,23 +151,23 @@ public:
case payload_col_: // XXX Return numeric value?
return text(col);
case src_port_col_:
return stream_info->src_port;
return stream_info_->src_port;
case dst_port_col_:
return stream_info->dest_port;
return stream_info_->dest_port;
case ssrc_col_:
return stream_info->ssrc;
return stream_info_->ssrc;
case packets_col_:
return stream_info->packet_count;
return stream_info_->packet_count;
case lost_col_:
return lost_;
case max_delta_col_:
return stream_info->rtp_stats.max_delta;
return stream_info_->rtp_stats.max_delta;
case max_jitter_col_:
return stream_info->rtp_stats.max_jitter;
return stream_info_->rtp_stats.max_jitter;
case mean_jitter_col_:
return stream_info->rtp_stats.mean_jitter;
return stream_info_->rtp_stats.mean_jitter;
case status_col_:
return stream_info->problem ? "Problem" : "";
return stream_info_->problem ? "Problem" : "";
default:
break;
}
@ -173,36 +176,32 @@ public:
bool operator< (const QTreeWidgetItem &other) const
{
rtp_stream_info_t *this_stream_info = data(0, Qt::UserRole).value<rtp_stream_info_t*>();
rtp_stream_info_t *other_stream_info = other.data(0, Qt::UserRole).value<rtp_stream_info_t*>();
if (!this_stream_info || !other_stream_info) {
return false;
}
if (other.type() != rtp_stream_type_) return QTreeWidgetItem::operator <(other);
const RtpStreamTreeWidgetItem &other_rstwi = dynamic_cast<const RtpStreamTreeWidgetItem&>(other);
switch (treeWidget()->sortColumn()) {
case src_addr_col_:
return cmp_address(&(this_stream_info->src_addr), &(other_stream_info->src_addr)) < 0;
return cmp_address(&(stream_info_->src_addr), &(other_rstwi.stream_info_->src_addr)) < 0;
case src_port_col_:
return this_stream_info->src_port < other_stream_info->src_port;
return stream_info_->src_port < other_rstwi.stream_info_->src_port;
case dst_addr_col_:
return cmp_address(&(this_stream_info->dest_addr), &(other_stream_info->dest_addr)) < 0;
return cmp_address(&(stream_info_->dest_addr), &(other_rstwi.stream_info_->dest_addr)) < 0;
case dst_port_col_:
return this_stream_info->dest_port < other_stream_info->dest_port;
return stream_info_->dest_port < other_rstwi.stream_info_->dest_port;
case ssrc_col_:
return this_stream_info->ssrc < other_stream_info->ssrc;
return stream_info_->ssrc < other_rstwi.stream_info_->ssrc;
case payload_col_:
return this_stream_info->payload_type < other_stream_info->payload_type; // XXX Compare payload_type_name instead?
return stream_info_->payload_type < other_rstwi.stream_info_->payload_type; // XXX Compare payload_type_name instead?
case packets_col_:
return this_stream_info->packet_count < other_stream_info->packet_count;
return stream_info_->packet_count < other_rstwi.stream_info_->packet_count;
case lost_col_:
return lost_ < other_rstwi.lost_;
case max_delta_col_:
return this_stream_info->rtp_stats.max_delta < other_stream_info->rtp_stats.max_delta;
return stream_info_->rtp_stats.max_delta < other_rstwi.stream_info_->rtp_stats.max_delta;
case max_jitter_col_:
return this_stream_info->rtp_stats.max_jitter < other_stream_info->rtp_stats.max_jitter;
return stream_info_->rtp_stats.max_jitter < other_rstwi.stream_info_->rtp_stats.max_jitter;
case mean_jitter_col_:
return this_stream_info->rtp_stats.mean_jitter < other_stream_info->rtp_stats.mean_jitter;
return stream_info_->rtp_stats.mean_jitter < other_rstwi.stream_info_->rtp_stats.mean_jitter;
default:
break;
}
@ -212,6 +211,7 @@ public:
}
private:
rtp_stream_info_t *stream_info_;
guint32 lost_;
};
@ -387,9 +387,9 @@ void RtpStreamDialog::updateWidgets()
if (selected) {
int tot_packets = 0;
foreach(QTreeWidgetItem *ti, ui->streamTreeWidget->selectedItems()) {
rtp_stream_info_t *stream_info = ti->data(0, Qt::UserRole).value<rtp_stream_info_t *>();
if (stream_info) {
tot_packets += stream_info->packet_count;
RtpStreamTreeWidgetItem *rsti = static_cast<RtpStreamTreeWidgetItem*>(ti);
if (rsti->streamInfo()) {
tot_packets += rsti->streamInfo()->packet_count;
}
}
hint += tr(", %1 selected, %2 total packets")
@ -408,7 +408,7 @@ void RtpStreamDialog::updateWidgets()
prepare_button_->setEnabled(enable);
export_button_->setEnabled(enable);
copy_button_->setEnabled(has_data);
analyze_button_->setEnabled(false); // XXX No dialog
analyze_button_->setEnabled(selected);
ui->actionFindReverse->setEnabled(enable);
ui->actionGoToSetup->setEnabled(enable);
@ -417,7 +417,7 @@ void RtpStreamDialog::updateWidgets()
ui->actionExportAsRtpDump->setEnabled(enable);
ui->actionCopyAsCsv->setEnabled(has_data);
ui->actionCopyAsYaml->setEnabled(has_data);
ui->actionAnalyze->setEnabled(false); // XXX No dialog
ui->actionAnalyze->setEnabled(selected);
}
QList<QVariant> RtpStreamDialog::streamRowData(int row) const
@ -454,7 +454,21 @@ void RtpStreamDialog::showStreamMenu(QPoint pos)
void RtpStreamDialog::on_actionAnalyze_triggered()
{
rtp_stream_info_t *stream_a, *stream_b = NULL;
QTreeWidgetItem *ti = ui->streamTreeWidget->selectedItems()[0];
RtpStreamTreeWidgetItem *rsti = static_cast<RtpStreamTreeWidgetItem*>(ti);
stream_a = rsti->streamInfo();
if (ui->streamTreeWidget->selectedItems().count() > 1) {
ti = ui->streamTreeWidget->selectedItems()[1];
rsti = static_cast<RtpStreamTreeWidgetItem*>(ti);
stream_b = rsti->streamInfo();
}
if (stream_a == NULL && stream_b == NULL) return;
RtpAnalysisDialog rtp_analysis_dialog(*this, cap_file_, stream_a, stream_b);
rtp_analysis_dialog.exec();
}
void RtpStreamDialog::on_actionCopyAsCsv_triggered()
@ -497,7 +511,8 @@ void RtpStreamDialog::on_actionExportAsRtpDump_triggered()
// XXX If the user selected multiple frames is this the one we actually want?
QTreeWidgetItem *ti = ui->streamTreeWidget->selectedItems()[0];
rtp_stream_info_t *stream_info = ti->data(0, Qt::UserRole).value<rtp_stream_info_t *>();
RtpStreamTreeWidgetItem *rsti = static_cast<RtpStreamTreeWidgetItem*>(ti);
rtp_stream_info_t *stream_info = rsti->streamInfo();
if (stream_info) {
QString file_name;
QDir path(wsApp->lastOpenDir());
@ -527,7 +542,8 @@ void RtpStreamDialog::on_actionFindReverse_triggered()
// Gather up our selected streams...
QList<rtp_stream_info_t *> selected_streams;
foreach(QTreeWidgetItem *ti, ui->streamTreeWidget->selectedItems()) {
rtp_stream_info_t *stream_info = ti->data(0, Qt::UserRole).value<rtp_stream_info_t *>();
RtpStreamTreeWidgetItem *rsti = static_cast<RtpStreamTreeWidgetItem*>(ti);
rtp_stream_info_t *stream_info = rsti->streamInfo();
if (stream_info) {
selected_streams << stream_info;
}
@ -536,10 +552,11 @@ void RtpStreamDialog::on_actionFindReverse_triggered()
// ...and compare them to our unselected streams.
QTreeWidgetItemIterator iter(ui->streamTreeWidget, QTreeWidgetItemIterator::Unselected);
while (*iter) {
rtp_stream_info_t *stream = (*iter)->data(0, Qt::UserRole).value<rtp_stream_info_t*>();
if (stream) {
RtpStreamTreeWidgetItem *rsti = static_cast<RtpStreamTreeWidgetItem*>(*iter);
rtp_stream_info_t *stream_info = rsti->streamInfo();
if (stream_info) {
foreach (rtp_stream_info_t *fwd_stream, selected_streams) {
if (rtp_stream_info_is_reverse(fwd_stream, stream)) {
if (rtp_stream_info_is_reverse(fwd_stream, stream_info)) {
(*iter)->setSelected(true);
}
}
@ -553,7 +570,8 @@ void RtpStreamDialog::on_actionGoToSetup_triggered()
if (ui->streamTreeWidget->selectedItems().count() < 1) return;
// XXX If the user selected multiple frames is this the one we actually want?
QTreeWidgetItem *ti = ui->streamTreeWidget->selectedItems()[0];
rtp_stream_info_t *stream_info = ti->data(0, Qt::UserRole).value<rtp_stream_info_t *>();
RtpStreamTreeWidgetItem *rsti = static_cast<RtpStreamTreeWidgetItem*>(ti);
rtp_stream_info_t *stream_info = rsti->streamInfo();
if (stream_info) {
emit goToPacket(stream_info->setup_frame_number);
}
@ -564,9 +582,14 @@ void RtpStreamDialog::on_actionMarkPackets_triggered()
if (ui->streamTreeWidget->selectedItems().count() < 1) return;
rtp_stream_info_t *stream_a, *stream_b = NULL;
stream_a = ui->streamTreeWidget->selectedItems()[0]->data(0, Qt::UserRole).value<rtp_stream_info_t*>();
if (ui->streamTreeWidget->selectedItems().count() > 1)
stream_b = ui->streamTreeWidget->selectedItems()[1]->data(0, Qt::UserRole).value<rtp_stream_info_t*>();
QTreeWidgetItem *ti = ui->streamTreeWidget->selectedItems()[0];
RtpStreamTreeWidgetItem *rsti = static_cast<RtpStreamTreeWidgetItem*>(ti);
stream_a = rsti->streamInfo();
if (ui->streamTreeWidget->selectedItems().count() > 1) {
ti = ui->streamTreeWidget->selectedItems()[1];
rsti = static_cast<RtpStreamTreeWidgetItem*>(ti);
stream_b = rsti->streamInfo();
}
if (stream_a == NULL && stream_b == NULL) return;
@ -583,7 +606,8 @@ void RtpStreamDialog::on_actionPrepareFilter_triggered()
// Gather up our selected streams...
QStringList stream_filters;
foreach(QTreeWidgetItem *ti, ui->streamTreeWidget->selectedItems()) {
rtp_stream_info_t *stream_info = ti->data(0, Qt::UserRole).value<rtp_stream_info_t *>();
RtpStreamTreeWidgetItem *rsti = static_cast<RtpStreamTreeWidgetItem*>(ti);
rtp_stream_info_t *stream_info = rsti->streamInfo();
if (stream_info) {
QString ip_proto = stream_info->src_addr.type == AT_IPv6 ? "ipv6" : "ip";
stream_filters << QString("(%1.src==%2 && udp.srcport==%3 && %1.dst==%4 && udp.dstport==%5 && rtp.ssrc==0x%6)")
@ -619,7 +643,7 @@ void RtpStreamDialog::on_buttonBox_clicked(QAbstractButton *button)
} else if (button == export_button_) {
on_actionExportAsRtpDump_triggered();
} else if (button == analyze_button_) {
on_actionAnalyze_triggered();
}
}