RTP Stream Analysis: Process more streams than two, audio save removed

This commit is contained in:
j.novak@netsystem.cz 2021-04-07 05:40:09 +00:00 committed by Wireshark GitLab Utility
parent fe7bf413fc
commit 2b072b8e76
11 changed files with 746 additions and 1475 deletions

View File

@ -77,6 +77,7 @@
#include <ui/qt/models/pref_models.h> #include <ui/qt/models/pref_models.h>
#include "rtp_stream_dialog.h" #include "rtp_stream_dialog.h"
#include "voip_calls_dialog.h" #include "voip_calls_dialog.h"
#include "rtp_analysis_dialog.h"
class AccordionFrame; class AccordionFrame;
class ByteViewTab; class ByteViewTab;
@ -250,6 +251,7 @@ private:
QPointer<VoipCallsDialog> voip_calls_dialog_; // Singleton pattern used QPointer<VoipCallsDialog> voip_calls_dialog_; // Singleton pattern used
QPointer<VoipCallsDialog> sip_calls_dialog_; // Singleton pattern used QPointer<VoipCallsDialog> sip_calls_dialog_; // Singleton pattern used
QPointer<RtpPlayerDialog> rtp_player_dialog_; // Singleton pattern used QPointer<RtpPlayerDialog> rtp_player_dialog_; // Singleton pattern used
QPointer<RtpAnalysisDialog> rtp_analysis_dialog_; // Singleton pattern used
void freeze(); void freeze();
void thaw(); void thaw();
@ -312,9 +314,6 @@ signals:
void framesSelected(QList<int>); void framesSelected(QList<int>);
void captureActive(int); void captureActive(int);
void replaceRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void addRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void removeRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void selectRtpStream(rtpstream_id_t *id); void selectRtpStream(rtpstream_id_t *id);
void deselectRtpStream(rtpstream_id_t *id); void deselectRtpStream(rtpstream_id_t *id);
@ -367,6 +366,9 @@ public slots:
void rtpPlayerDialogReplaceRtpStreams(QVector<rtpstream_info_t *> stream_infos); void rtpPlayerDialogReplaceRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *> stream_infos); void rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *> stream_infos); void rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void rtpAnalysisDialogReplaceRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void rtpAnalysisDialogAddRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void rtpAnalysisDialogRemoveRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void rtpStreamsDialogSelectRtpStream(rtpstream_id_t *id); void rtpStreamsDialogSelectRtpStream(rtpstream_id_t *id);
void rtpStreamsDialogDeselectRtpStream(rtpstream_id_t *id); void rtpStreamsDialogDeselectRtpStream(rtpstream_id_t *id);
@ -686,6 +688,7 @@ private slots:
void openTelephonyRtpStreamsDialog(); void openTelephonyRtpStreamsDialog();
void openTelephonyRtpPlayerDialog(); void openTelephonyRtpPlayerDialog();
void openTelephonyVoipCallsDialog(bool all_flows); void openTelephonyVoipCallsDialog(bool all_flows);
void openTelephonyRtpAnalysisDialog();
void on_actionTelephonyVoipCalls_triggered(); void on_actionTelephonyVoipCalls_triggered();
void on_actionTelephonyGsmMapSummary_triggered(); void on_actionTelephonyGsmMapSummary_triggered();
void statCommandLteMacStatistics(const char *arg, void *); void statCommandLteMacStatistics(const char *arg, void *);

View File

@ -3311,12 +3311,6 @@ void MainWindow::openTelephonyRtpPlayerDialog()
connect(rtp_player_dialog_, SIGNAL(goToPacket(int)), connect(rtp_player_dialog_, SIGNAL(goToPacket(int)),
packet_list_, SLOT(goToPacket(int))); packet_list_, SLOT(goToPacket(int)));
connect(this, SIGNAL(replaceRtpStreams(QVector<rtpstream_info_t *>)),
rtp_player_dialog_, SLOT(replaceRtpStreams(QVector<rtpstream_info_t *>)));
connect(this, SIGNAL(addRtpStreams(QVector<rtpstream_info_t *>)),
rtp_player_dialog_, SLOT(addRtpStreams(QVector<rtpstream_info_t *>)));
connect(this, SIGNAL(removeRtpStreams(QVector<rtpstream_info_t *>)),
rtp_player_dialog_, SLOT(removeRtpStreams(QVector<rtpstream_info_t *>)));
} }
rtp_player_dialog_->show(); rtp_player_dialog_->show();
} }
@ -3356,6 +3350,23 @@ void MainWindow::openTelephonyVoipCallsDialog(bool all_flows)
dlg->show(); dlg->show();
} }
void MainWindow::openTelephonyRtpAnalysisDialog()
{
if (!rtp_analysis_dialog_) {
rtp_analysis_dialog_ = new RtpAnalysisDialog(*this, capture_file_);
connect(rtp_analysis_dialog_, SIGNAL(goToPacket(int)),
packet_list_, SLOT(goToPacket(int)));
connect(rtp_analysis_dialog_, SIGNAL(rtpPlayerDialogReplaceRtpStreams(QVector<rtpstream_info_t *>)),
this, SLOT(rtpPlayerDialogReplaceRtpStreams(QVector<rtpstream_info_t *>)));
connect(rtp_analysis_dialog_, SIGNAL(rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *>)),
this, SLOT(rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *>)));
connect(rtp_analysis_dialog_, SIGNAL(rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *>)),
this, SLOT(rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *>)));
}
rtp_analysis_dialog_->show();
}
void MainWindow::on_actionTelephonyVoipCalls_triggered() void MainWindow::on_actionTelephonyVoipCalls_triggered()
{ {
openTelephonyVoipCallsDialog(false); openTelephonyVoipCallsDialog(false);
@ -3447,7 +3458,6 @@ void MainWindow::openTelephonyRtpStreamsDialog()
{ {
if (!rtp_stream_dialog_) { if (!rtp_stream_dialog_) {
rtp_stream_dialog_ = new RtpStreamDialog(*this, capture_file_); rtp_stream_dialog_ = new RtpStreamDialog(*this, capture_file_);
connect(rtp_stream_dialog_, SIGNAL(packetsMarked()), connect(rtp_stream_dialog_, SIGNAL(packetsMarked()),
packet_list_, SLOT(redrawVisiblePackets())); packet_list_, SLOT(redrawVisiblePackets()));
connect(rtp_stream_dialog_, SIGNAL(goToPacket(int)), connect(rtp_stream_dialog_, SIGNAL(goToPacket(int)),
@ -3462,8 +3472,12 @@ void MainWindow::openTelephonyRtpStreamsDialog()
this, SLOT(rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *>))); this, SLOT(rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *>)));
connect(rtp_stream_dialog_, SIGNAL(rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *>)), connect(rtp_stream_dialog_, SIGNAL(rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *>)),
this, SLOT(rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *>))); this, SLOT(rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *>)));
connect(this, SIGNAL(selectRtpStream(rtpstream_id_t *)), rtp_stream_dialog_, SLOT(selectRtpStream(rtpstream_id_t *))); connect(rtp_stream_dialog_, SIGNAL(rtpAnalysisDialogReplaceRtpStreams(QVector<rtpstream_info_t *>)),
connect(this, SIGNAL(deselectRtpStream(rtpstream_id_t *)), rtp_stream_dialog_, SLOT(deselectRtpStream(rtpstream_id_t *))); this, SLOT(rtpAnalysisDialogReplaceRtpStreams(QVector<rtpstream_info_t *>)));
connect(rtp_stream_dialog_, SIGNAL(rtpAnalysisDialogAddRtpStreams(QVector<rtpstream_info_t *>)),
this, SLOT(rtpAnalysisDialogAddRtpStreams(QVector<rtpstream_info_t *>)));
connect(rtp_stream_dialog_, SIGNAL(rtpAnalysisDialogRemoveRtpStreams(QVector<rtpstream_info_t *>)),
this, SLOT(rtpAnalysisDialogRemoveRtpStreams(QVector<rtpstream_info_t *>)));
} }
rtp_stream_dialog_->show(); rtp_stream_dialog_->show();
} }
@ -3475,16 +3489,8 @@ void MainWindow::on_actionTelephonyRtpStreams_triggered()
void MainWindow::on_actionTelephonyRtpStreamAnalysis_triggered() void MainWindow::on_actionTelephonyRtpStreamAnalysis_triggered()
{ {
RtpAnalysisDialog *rtp_analysis_dialog = new RtpAnalysisDialog(*this, capture_file_); openTelephonyRtpAnalysisDialog();
connect(rtp_analysis_dialog, SIGNAL(goToPacket(int)), rtp_analysis_dialog_->findRtpStreams();
packet_list_, SLOT(goToPacket(int)));
connect(rtp_analysis_dialog, SIGNAL(rtpPlayerDialogReplaceRtpStreams(QVector<rtpstream_info_t *>)),
this, SLOT(rtpPlayerDialogReplaceRtpStreams(QVector<rtpstream_info_t *>)));
connect(rtp_analysis_dialog, SIGNAL(rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *>)),
this, SLOT(rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *>)));
connect(rtp_analysis_dialog, SIGNAL(rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *>)),
this, SLOT(rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *>)));
rtp_analysis_dialog->show();
} }
void MainWindow::on_actionTelephonyRTSPPacketCounter_triggered() void MainWindow::on_actionTelephonyRTSPPacketCounter_triggered()
@ -4061,31 +4067,49 @@ void MainWindow::activatePluginIFToolbar(bool)
void MainWindow::rtpPlayerDialogReplaceRtpStreams(QVector<rtpstream_info_t *> stream_infos) void MainWindow::rtpPlayerDialogReplaceRtpStreams(QVector<rtpstream_info_t *> stream_infos)
{ {
openTelephonyRtpPlayerDialog(); openTelephonyRtpPlayerDialog();
emit replaceRtpStreams(stream_infos); rtp_player_dialog_->replaceRtpStreams(stream_infos);
} }
void MainWindow::rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *> stream_infos) void MainWindow::rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *> stream_infos)
{ {
openTelephonyRtpPlayerDialog(); openTelephonyRtpPlayerDialog();
emit addRtpStreams(stream_infos); rtp_player_dialog_->addRtpStreams(stream_infos);
} }
void MainWindow::rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *> stream_infos) void MainWindow::rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *> stream_infos)
{ {
openTelephonyRtpPlayerDialog(); openTelephonyRtpPlayerDialog();
emit removeRtpStreams(stream_infos); rtp_player_dialog_->removeRtpStreams(stream_infos);
}
void MainWindow::rtpAnalysisDialogReplaceRtpStreams(QVector<rtpstream_info_t *> stream_infos)
{
openTelephonyRtpAnalysisDialog();
rtp_analysis_dialog_->replaceRtpStreams(stream_infos);
}
void MainWindow::rtpAnalysisDialogAddRtpStreams(QVector<rtpstream_info_t *> stream_infos)
{
openTelephonyRtpAnalysisDialog();
rtp_analysis_dialog_->addRtpStreams(stream_infos);
}
void MainWindow::rtpAnalysisDialogRemoveRtpStreams(QVector<rtpstream_info_t *> stream_infos)
{
openTelephonyRtpAnalysisDialog();
rtp_analysis_dialog_->removeRtpStreams(stream_infos);
} }
void MainWindow::rtpStreamsDialogSelectRtpStream(rtpstream_id_t *id) void MainWindow::rtpStreamsDialogSelectRtpStream(rtpstream_id_t *id)
{ {
openTelephonyRtpStreamsDialog(); openTelephonyRtpStreamsDialog();
emit selectRtpStream(id); rtp_stream_dialog_->selectRtpStream(id);
} }
void MainWindow::rtpStreamsDialogDeselectRtpStream(rtpstream_id_t *id) void MainWindow::rtpStreamsDialogDeselectRtpStream(rtpstream_id_t *id)
{ {
openTelephonyRtpStreamsDialog(); openTelephonyRtpStreamsDialog();
emit deselectRtpStream(id); rtp_stream_dialog_->deselectRtpStream(id);
} }
#ifdef _MSC_VER #ifdef _MSC_VER

File diff suppressed because it is too large Load Diff

View File

@ -20,9 +20,12 @@
#include "ui/tap-rtp-common.h" #include "ui/tap-rtp-common.h"
#include "ui/tap-rtp-analysis.h" #include "ui/tap-rtp-analysis.h"
#include <QAbstractButton>
#include <QMenu> #include <QMenu>
#include <QTreeWidget>
#include <QLabel>
#include <QFile> #include <QFile>
#include <QCheckBox>
#include <QHBoxLayout>
#include "wireshark_dialog.h" #include "wireshark_dialog.h"
@ -32,6 +35,26 @@ class RtpAnalysisDialog;
class QCPGraph; class QCPGraph;
class QTemporaryFile; class QTemporaryFile;
class QDialogButtonBox;
typedef struct {
rtpstream_info_t stream;
QVector<double> *time_vals;
QVector<double> *jitter_vals;
QVector<double> *diff_vals;
QVector<double> *delta_vals;
QTreeWidget *tree_widget;
QLabel *statistics_label;
QString *tab_name;
QCPGraph *jitter_graph;
QCPGraph *diff_graph;
QCPGraph *delta_graph;
QHBoxLayout *graphHorizontalLayout;
QCheckBox *stream_checkbox;
QCheckBox *jitter_checkbox;
QCheckBox *diff_checkbox;
QCheckBox *delta_checkbox;
} tab_info_t;
class RtpAnalysisDialog : public WiresharkDialog class RtpAnalysisDialog : public WiresharkDialog
{ {
@ -40,6 +63,24 @@ class RtpAnalysisDialog : public WiresharkDialog
public: public:
explicit RtpAnalysisDialog(QWidget &parent, CaptureFile &cf, rtpstream_info_t *stream_fwd = 0, rtpstream_info_t *stream_rev = 0); explicit RtpAnalysisDialog(QWidget &parent, CaptureFile &cf, rtpstream_info_t *stream_fwd = 0, rtpstream_info_t *stream_rev = 0);
~RtpAnalysisDialog(); ~RtpAnalysisDialog();
/**
* @brief Common routine to add a "Analyze" button to a QDialogButtonBox.
* @param button_box Caller's QDialogButtonBox.
* @return The new "Analyze" button.
*/
static QPushButton *addAnalyzeButton(QDialogButtonBox *button_box, QDialog *dialog);
/** Replace/Add/Remove an RTP streams to analyse.
* Requires array of rtpstream_info_t.
* Each item must have filled items: src_addr, src_port, dest_addr,
* dest_port, ssrc, packet_count, setup_frame_number, and start_rel_time.
*
* @param rtpstream struct with rtpstream info
*/
void replaceRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void addRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void removeRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void findRtpStreams();
signals: signals:
void goToPacket(int packet_num); void goToPacket(int packet_num);
@ -58,102 +99,54 @@ protected slots:
private slots: private slots:
void on_actionGoToPacket_triggered(); void on_actionGoToPacket_triggered();
void on_actionNextProblem_triggered(); void on_actionNextProblem_triggered();
void on_fJitterCheckBox_toggled(bool checked); void on_actionSaveOneCsv_triggered();
void on_fDiffCheckBox_toggled(bool checked); void on_actionSaveAllCsv_triggered();
void on_fDeltaCheckBox_toggled(bool checked);
void on_rJitterCheckBox_toggled(bool checked);
void on_rDiffCheckBox_toggled(bool checked);
void on_rDeltaCheckBox_toggled(bool checked);
void on_actionSaveAudioUnsync_triggered();
void on_actionSaveForwardAudioUnsync_triggered();
void on_actionSaveReverseAudioUnsync_triggered();
void on_actionSaveAudioSyncStream_triggered();
void on_actionSaveForwardAudioSyncStream_triggered();
void on_actionSaveReverseAudioSyncStream_triggered();
void on_actionSaveAudioSyncFile_triggered();
void on_actionSaveForwardAudioSyncFile_triggered();
void on_actionSaveReverseAudioSyncFile_triggered();
void on_actionSaveCsv_triggered();
void on_actionSaveForwardCsv_triggered();
void on_actionSaveReverseCsv_triggered();
void on_actionSaveGraph_triggered(); void on_actionSaveGraph_triggered();
void on_buttonBox_helpRequested(); void on_buttonBox_helpRequested();
void showStreamMenu(QPoint pos); void showStreamMenu(QPoint pos);
void graphClicked(QMouseEvent *event); void graphClicked(QMouseEvent *event);
void closeTab(int index);
void rowCheckboxChanged(int checked);
void singleCheckboxChanged(int checked);
private: private:
Ui::RtpAnalysisDialog *ui; Ui::RtpAnalysisDialog *ui;
enum StreamDirection { dir_both_, dir_forward_, dir_reverse_ }; enum StreamDirection { dir_all_, dir_one_ };
enum SyncType { sync_unsync_, sync_sync_stream_, sync_sync_file_ }; int tab_seq;
/* Save Audio Errors */ QVector<tab_info_t *> tabs_;
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_;
rtpstream_info_t rev_statinfo_;
QPushButton *player_button_; QPushButton *player_button_;
QTemporaryFile *fwd_tempfile_;
QTemporaryFile *rev_tempfile_;
// Graph data for QCustomPlot // Graph data for QCustomPlot
QList<QCPGraph *>graphs_; QList<QCPGraph *>graphs_;
QVector<double> fwd_time_vals_;
QVector<double> fwd_jitter_vals_;
QVector<double> fwd_diff_vals_;
QVector<double> fwd_delta_vals_;
QVector<double> rev_time_vals_;
QVector<double> rev_jitter_vals_;
QVector<double> rev_diff_vals_;
QVector<double> rev_delta_vals_;
rtpstream_tapinfo_t tapinfo_; rtpstream_tapinfo_t tapinfo_;
QString err_str_; QString err_str_;
tap_rtp_error_type_t save_payload_error_;
QMenu stream_ctx_menu_; QMenu stream_ctx_menu_;
QMenu graph_ctx_menu_; QMenu graph_ctx_menu_;
void findStreams();
// Tap callbacks // Tap callbacks
static void tapReset(void *tapinfo_ptr); static void tapReset(void *tapinfo_ptr);
static tap_packet_status tapPacket(void *tapinfo_ptr, packet_info *pinfo, epan_dissect_t *, const void *rtpinfo_ptr); static tap_packet_status tapPacket(void *tapinfo_ptr, packet_info *pinfo, epan_dissect_t *, const void *rtpinfo_ptr);
static void tapDraw(void *tapinfo_ptr); static void tapDraw(void *tapinfo_ptr);
void resetStatistics(); void resetStatistics();
void addPacket(bool forward, packet_info *pinfo, const struct _rtp_info *rtpinfo); void addPacket(tab_info_t *tab, packet_info *pinfo, const struct _rtp_info *rtpinfo);
void savePayload(QTemporaryFile *tmpfile, tap_rtp_stat_t *statinfo, packet_info *pinfo, const struct _rtp_info *rtpinfo);
void updateStatistics(); void updateStatistics();
void updateGraph(); void updateGraph();
void showPlayer(); void saveCsvData(QFile *save_file, QTreeWidget *tree);
size_t convert_payload_to_samples(unsigned int payload_type, const gchar *payload_type_names[256], 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, const gchar *payload_type_names[256], 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, const gchar *fwd_payload_type_names[256], const gchar *rev_payload_type_names[256], 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); void saveCsv(StreamDirection direction);
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); bool eventFilter(QObject*, QEvent* event);
void clearSAEErrors();
bool isSAEOK();
QVector<rtpstream_info_t *>getSelectedRtpStreams(); QVector<rtpstream_info_t *>getSelectedRtpStreams();
int addTabUI(tab_info_t *new_tab);
tab_info_t *getTabInfoForCurrentTab();
void deleteTabInfo(tab_info_t *tab_info);
void clearLayout(QLayout *layout);
}; };
#endif // RTP_ANALYSIS_DIALOG_H #endif // RTP_ANALYSIS_DIALOG_H

View File

@ -16,123 +16,11 @@
<layout class="QVBoxLayout" name="verticalLayout_3"> <layout class="QVBoxLayout" name="verticalLayout_3">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="statisticsLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:medium; font-weight:600;&quot;&gt;Forward&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-size:medium; font-weight:600;&quot;&gt;Reverse&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item> <item>
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>0</number>
</property> </property>
<widget class="QTreeWidget" name="forwardTreeWidget">
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<attribute name="title">
<string>Forward</string>
</attribute>
<column>
<property name="text">
<string>Packet</string>
</property>
</column>
<column>
<property name="text">
<string>Sequence</string>
</property>
</column>
<column>
<property name="text">
<string>Delta (ms)</string>
</property>
</column>
<column>
<property name="text">
<string>Jitter (ms)</string>
</property>
</column>
<column>
<property name="text">
<string>Skew</string>
</property>
</column>
<column>
<property name="text">
<string>Bandwidth</string>
</property>
</column>
<column>
<property name="text">
<string>Marker</string>
</property>
</column>
<column>
<property name="text">
<string>Status</string>
</property>
</column>
</widget>
<widget class="QTreeWidget" name="reverseTreeWidget">
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="title">
<string>Reverse</string>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
<widget class="QWidget" name="graphTab"> <widget class="QWidget" name="graphTab">
<attribute name="title"> <attribute name="title">
<string>Graph</string> <string>Graph</string>
@ -141,152 +29,6 @@
<item> <item>
<widget class="QCustomPlot" name="streamGraph" native="true"/> <widget class="QCustomPlot" name="streamGraph" native="true"/>
</item> </item>
<item>
<layout class="QHBoxLayout" name="forwardHorizontalLayout" stretch="0,0,0,0,0,1">
<item>
<widget class="QCheckBox" name="fJitterCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show or hide forward jitter values.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Forward Jitter</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="fDiffCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show or hide forward difference values.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Forward Difference</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="fDeltaCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show or hide forward delta values.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Forward Delta</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="reverseHorizontalLayout" stretch="0,0,0,0,0,1">
<item>
<widget class="QCheckBox" name="rJitterCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show or hide reverse jitter values.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Reverse Jitter</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="rDiffCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show or hide reverse difference values.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Reverse Difference</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="rDeltaCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show or hide reverse delta values.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Reverse Delta</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
@ -336,52 +78,28 @@
<string>Open export menu</string> <string>Open export menu</string>
</property> </property>
</action> </action>
<action name="actionSaveAudioUnsync">
<property name="text">
<string>Unsynchronized Forward and Reverse Audio</string>
</property>
<property name="toolTip">
<string>Save the unsynchronized audio data for both channels.</string>
</property>
</action>
<action name="actionSaveForwardAudioUnsync">
<property name="text">
<string>Unsynchronized Forward Stream Audio</string>
</property>
<property name="toolTip">
<string>Save the unsynchronized forward stream audio data.</string>
</property>
</action>
<action name="actionSaveReverseAudioUnsync">
<property name="text">
<string>Unsynchronized Reverse Stream Audio</string>
</property>
<property name="toolTip">
<string>Save the unsynchronized reverse stream audio data.</string>
</property>
</action>
<action name="actionSaveCsv"> <action name="actionSaveCsv">
<property name="text"> <property name="text">
<string>CSV</string> <string>CSV</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Save both tables as CSV.</string> <string>Save tables as CSV.</string>
</property> </property>
</action> </action>
<action name="actionSaveForwardCsv"> <action name="actionSaveOneCsv">
<property name="text"> <property name="text">
<string>Forward Stream CSV</string> <string>Current Tab Stream CSV</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Save the forward table as CSV.</string> <string>Save the table on the current tab as CSV.</string>
</property> </property>
</action> </action>
<action name="actionSaveReverseCsv"> <action name="actionSaveAllCsv">
<property name="text"> <property name="text">
<string>Reverse Stream CSV</string> <string>All Tab Streams CSV</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Save the reverse table as CSV.</string> <string>Save the table from all tabs as CSV.</string>
</property> </property>
</action> </action>
<action name="actionSaveGraph"> <action name="actionSaveGraph">
@ -414,54 +132,6 @@
<string>N</string> <string>N</string>
</property> </property>
</action> </action>
<action name="actionSaveAudioSyncStream">
<property name="text">
<string>Stream Synchronized Forward and Reverse Audio</string>
</property>
<property name="toolTip">
<string>Save the audio data for both channels synchronized to start of earlier stream.</string>
</property>
</action>
<action name="actionSaveForwardAudioSyncStream">
<property name="text">
<string>Stream Synchronized Forward Stream Audio</string>
</property>
<property name="toolTip">
<string>Save the forward stream audio data synchronized to start of earlier stream.</string>
</property>
</action>
<action name="actionSaveReverseAudioSyncStream">
<property name="text">
<string>Stream Synchronized Reverse Stream Audio</string>
</property>
<property name="toolTip">
<string>Save the reverse stream audio data synchronized to start of earlier stream.</string>
</property>
</action>
<action name="actionSaveAudioSyncFile">
<property name="text">
<string>File Synchronized Forward and Reverse Audio</string>
</property>
<property name="toolTip">
<string>Save the audio data for both channels synchronized to start of file.</string>
</property>
</action>
<action name="actionSaveForwardAudioSyncFile">
<property name="text">
<string>File Synchronized Forward Stream Audio</string>
</property>
<property name="toolTip">
<string>Save the forward stream audio data synchronized to start of file.</string>
</property>
</action>
<action name="actionSaveReverseAudioSyncFile">
<property name="text">
<string>File Synchronized Reverse Stream Audio</string>
</property>
<property name="toolTip">
<string>Save the reverse stream audio data synchronized to start of file.</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View File

@ -14,6 +14,7 @@
#ifdef QT_MULTIMEDIA_LIB #ifdef QT_MULTIMEDIA_LIB
#include <epan/dissectors/packet-rtp.h> #include <epan/dissectors/packet-rtp.h>
#include <epan/to_str.h>
#include <wsutil/report_message.h> #include <wsutil/report_message.h>
#include <wsutil/utf8_entities.h> #include <wsutil/utf8_entities.h>

View File

@ -62,7 +62,6 @@ public:
* @param button_box Caller's QDialogButtonBox. * @param button_box Caller's QDialogButtonBox.
* @return The new "Play call" button. * @return The new "Play call" button.
*/ */
// XXX We might want to move this to qt_ui_utils.
static QPushButton *addPlayerButton(QDialogButtonBox *button_box, QDialog *dialog); static QPushButton *addPlayerButton(QDialogButtonBox *button_box, QDialog *dialog);
#ifdef QT_MULTIMEDIA_LIB #ifdef QT_MULTIMEDIA_LIB
@ -73,7 +72,6 @@ public:
void setMarkers(); void setMarkers();
public slots:
/** Replace/Add/Remove an RTP streams to play. /** Replace/Add/Remove an RTP streams to play.
* Requires array of rtpstream_info_t. * Requires array of rtpstream_info_t.
* Each item must have filled items: src_addr, src_port, dest_addr, * Each item must have filled items: src_addr, src_port, dest_addr,

View File

@ -273,8 +273,7 @@ RtpStreamDialog::RtpStreamDialog(QWidget &parent, CaptureFile &cf) :
// this? Perhaps you should volunteer to maintain this code! // this? Perhaps you should volunteer to maintain this code!
find_reverse_button_ = ui->buttonBox->addButton(ui->actionFindReverse->text(), QDialogButtonBox::ActionRole); find_reverse_button_ = ui->buttonBox->addButton(ui->actionFindReverse->text(), QDialogButtonBox::ActionRole);
find_reverse_button_->setToolTip(ui->actionFindReverse->toolTip()); find_reverse_button_->setToolTip(ui->actionFindReverse->toolTip());
analyze_button_ = ui->buttonBox->addButton(ui->actionAnalyze->text(), QDialogButtonBox::ActionRole); analyze_button_ = RtpAnalysisDialog::addAnalyzeButton(ui->buttonBox, this);
analyze_button_->setToolTip(ui->actionAnalyze->toolTip());
prepare_button_ = ui->buttonBox->addButton(ui->actionPrepareFilter->text(), QDialogButtonBox::ActionRole); prepare_button_ = ui->buttonBox->addButton(ui->actionPrepareFilter->text(), QDialogButtonBox::ActionRole);
prepare_button_->setToolTip(ui->actionPrepareFilter->toolTip()); prepare_button_->setToolTip(ui->actionPrepareFilter->toolTip());
player_button_ = RtpPlayerDialog::addPlayerButton(ui->buttonBox, this); player_button_ = RtpPlayerDialog::addPlayerButton(ui->buttonBox, this);
@ -619,26 +618,6 @@ void RtpStreamDialog::showStreamMenu(QPoint pos)
ctx_menu_.popup(ui->streamTreeWidget->viewport()->mapToGlobal(pos)); ctx_menu_.popup(ui->streamTreeWidget->viewport()->mapToGlobal(pos));
} }
void RtpStreamDialog::on_actionAnalyze_triggered()
{
rtpstream_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 = new RtpAnalysisDialog(*this, cap_file_, stream_a, stream_b);
connect(rtp_analysis_dialog, SIGNAL(goToPacket(int)), this, SIGNAL(goToPacket(int)));
rtp_analysis_dialog->show();
}
void RtpStreamDialog::on_actionCopyAsCsv_triggered() void RtpStreamDialog::on_actionCopyAsCsv_triggered()
{ {
QString csv; QString csv;
@ -807,8 +786,6 @@ void RtpStreamDialog::on_buttonBox_clicked(QAbstractButton *button)
on_actionPrepareFilter_triggered(); on_actionPrepareFilter_triggered();
} else if (button == export_button_) { } else if (button == export_button_) {
on_actionExportAsRtpDump_triggered(); on_actionExportAsRtpDump_triggered();
} else if (button == analyze_button_) {
on_actionAnalyze_triggered();
} }
} }
@ -891,6 +868,27 @@ void RtpStreamDialog::rtpPlayerRemove()
emit rtpPlayerDialogRemoveRtpStreams(getSelectedRtpStreams()); emit rtpPlayerDialogRemoveRtpStreams(getSelectedRtpStreams());
} }
void RtpStreamDialog::rtpAnalysisReplace()
{
if (ui->streamTreeWidget->selectedItems().count() < 1) return;
emit rtpAnalysisDialogReplaceRtpStreams(getSelectedRtpStreams());
}
void RtpStreamDialog::rtpAnalysisAdd()
{
if (ui->streamTreeWidget->selectedItems().count() < 1) return;
emit rtpAnalysisDialogAddRtpStreams(getSelectedRtpStreams());
}
void RtpStreamDialog::rtpAnalysisRemove()
{
if (ui->streamTreeWidget->selectedItems().count() < 1) return;
emit rtpAnalysisDialogRemoveRtpStreams(getSelectedRtpStreams());
}
void RtpStreamDialog::displayFilterSuccess(bool success) void RtpStreamDialog::displayFilterSuccess(bool success)
{ {
if (success && ui->displayFilterCheckBox->isChecked()) { if (success && ui->displayFilterCheckBox->isChecked()) {

View File

@ -29,6 +29,8 @@ class RtpStreamDialog : public WiresharkDialog
public: public:
explicit RtpStreamDialog(QWidget &parent, CaptureFile &cf); explicit RtpStreamDialog(QWidget &parent, CaptureFile &cf);
~RtpStreamDialog(); ~RtpStreamDialog();
void selectRtpStream(rtpstream_id_t *id);
void deselectRtpStream(rtpstream_id_t *id);
signals: signals:
// Tells the packet list to redraw. An alternative might be to add a // Tells the packet list to redraw. An alternative might be to add a
@ -40,14 +42,18 @@ signals:
void rtpPlayerDialogReplaceRtpStreams(QVector<rtpstream_info_t *> stream_infos); void rtpPlayerDialogReplaceRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *> stream_infos); void rtpPlayerDialogAddRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *> stream_infos); void rtpPlayerDialogRemoveRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void rtpAnalysisDialogReplaceRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void rtpAnalysisDialogAddRtpStreams(QVector<rtpstream_info_t *> stream_infos);
void rtpAnalysisDialogRemoveRtpStreams(QVector<rtpstream_info_t *> stream_infos);
public slots: public slots:
void selectRtpStream(rtpstream_id_t *id);
void deselectRtpStream(rtpstream_id_t *id);
void displayFilterSuccess(bool success); void displayFilterSuccess(bool success);
void rtpPlayerReplace(); void rtpPlayerReplace();
void rtpPlayerAdd(); void rtpPlayerAdd();
void rtpPlayerRemove(); void rtpPlayerRemove();
void rtpAnalysisReplace();
void rtpAnalysisAdd();
void rtpAnalysisRemove();
protected: protected:
bool eventFilter(QObject *obj, QEvent *event); bool eventFilter(QObject *obj, QEvent *event);
@ -94,7 +100,6 @@ private slots:
void on_buttonBox_helpRequested(); void on_buttonBox_helpRequested();
void on_buttonBox_clicked(QAbstractButton *button); void on_buttonBox_clicked(QAbstractButton *button);
void on_actionExportAsRtpDump_triggered(); void on_actionExportAsRtpDump_triggered();
void on_actionAnalyze_triggered();
void captureEvent(CaptureEvent e); void captureEvent(CaptureEvent e);
void on_displayFilterCheckBox_toggled(bool checked); void on_displayFilterCheckBox_toggled(bool checked);
void on_todCheckBox_toggled(bool checked); void on_todCheckBox_toggled(bool checked);

View File

@ -46,6 +46,7 @@
#include <QFontMetrics> #include <QFontMetrics>
#include <QMap> #include <QMap>
#include <QPainter> #include <QPainter>
#include <QPainterPath>
#include <QStyle> #include <QStyle>
#include <QStyleOption> #include <QStyleOption>
@ -170,6 +171,78 @@ QIcon StockIcon::colorIcon(const QRgb bg_color, const QRgb fg_color, const QStri
return color_icon; return color_icon;
} }
// Create a triangle icon filled with the specified color.
QIcon StockIcon::colorIconTriangle(const QRgb bg_color, const QRgb fg_color)
{
QList<int> sizes = QList<int>() << 12 << 16 << 24 << 32 << 48;
QIcon color_icon;
foreach (int size, sizes) {
QPixmap pm(size, size);
QPainter painter(&pm);
QPainterPath triangle;
pm.fill();
painter.fillRect(0, 0, size-1, size-1, Qt::transparent);
painter.setPen(fg_color);
painter.setBrush(QColor(bg_color));
triangle.moveTo(0, size-1);
triangle.lineTo(size-1, size-1);
triangle.lineTo((size-1)/2, 0);
triangle.closeSubpath();
painter.fillPath(triangle, QColor(bg_color));
color_icon.addPixmap(pm);
}
return color_icon;
}
// Create a cross icon filled with the specified color.
QIcon StockIcon::colorIconCross(const QRgb bg_color, const QRgb fg_color)
{
QList<int> sizes = QList<int>() << 12 << 16 << 24 << 32 << 48;
QIcon color_icon;
foreach (int size, sizes) {
QPixmap pm(size, size);
QPainter painter(&pm);
QPainterPath cross;
pm.fill();
painter.fillRect(0, 0, size-1, size-1, Qt::transparent);
painter.setPen(QPen(QBrush(bg_color), 3));
painter.setBrush(QColor(fg_color));
cross.moveTo(0, 0);
cross.lineTo(size-1, size-1);
cross.moveTo(0, size-1);
cross.lineTo(size-1, 0);
painter.drawPath(cross);
color_icon.addPixmap(pm);
}
return color_icon;
}
// Create a circle icon filled with the specified color.
QIcon StockIcon::colorIconCircle(const QRgb bg_color, const QRgb fg_color)
{
QList<int> sizes = QList<int>() << 12 << 16 << 24 << 32 << 48;
QIcon color_icon;
foreach (int size, sizes) {
QPixmap pm(size, size);
QPainter painter(&pm);
QRect border(2, 2, size - 3, size - 3);
pm.fill();
painter.fillRect(0, 0, size-1, size-1, Qt::transparent);
painter.setPen(QPen(QBrush(bg_color), 3));
painter.setBrush(QColor(fg_color));
painter.setBrush(QColor(bg_color));
painter.drawEllipse(border);
color_icon.addPixmap(pm);
}
return color_icon;
}
void StockIcon::fillIconNameMap() void StockIcon::fillIconNameMap()
{ {
// Note that some of Qt's standard pixmaps are awful. We shouldn't add an // Note that some of Qt's standard pixmaps are awful. We shouldn't add an

View File

@ -29,6 +29,9 @@ public:
explicit StockIcon(const QString icon_name); explicit StockIcon(const QString icon_name);
static QIcon colorIcon(const QRgb bg_color, const QRgb fg_color, const QString glyph = QString()); static QIcon colorIcon(const QRgb bg_color, const QRgb fg_color, const QString glyph = QString());
static QIcon colorIconTriangle(const QRgb bg_color, const QRgb fg_color);
static QIcon colorIconCross(const QRgb bg_color, const QRgb fg_color);
static QIcon colorIconCircle(const QRgb bg_color, const QRgb fg_color);
private: private:
void fillIconNameMap(); void fillIconNameMap();