forked from osmocom/wireshark
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:
parent
c70ab1a122
commit
18bec424fb
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue