3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
10 #ifndef RTP_PLAYER_DIALOG_H
11 #define RTP_PLAYER_DIALOG_H
17 #include "ui/rtp_stream.h"
19 #include "wireshark_dialog.h"
20 #include "rtp_audio_stream.h"
25 #include <QTreeWidgetItem>
27 #include <ui/qt/widgets/qcustomplot.h>
29 #ifdef QT_MULTIMEDIA_LIB
30 # if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
31 # include <QAudioDevice>
33 # include <QAudioDeviceInfo>
38 class RtpPlayerDialog
;
41 class QCPItemStraightLine
;
42 class QDialogButtonBox
;
46 class QCPAxisTickerDateTime
;
60 save_mode_from_cursor
,
61 save_mode_sync_stream
,
65 class RtpBaseDialog
: public WiresharkDialog
69 explicit RtpBaseDialog(QWidget
&parent
, CaptureFile
&cf
) : WiresharkDialog(parent
, cf
) {}
72 virtual void rtpAnalysisReplace() = 0;
73 virtual void rtpAnalysisAdd() = 0;
74 virtual void rtpAnalysisRemove() = 0;
77 // Singleton by https://refactoring.guru/design-patterns/singleton/cpp/example#example-1
78 class RtpPlayerDialog
: public RtpBaseDialog
81 #ifdef QT_MULTIMEDIA_LIB
82 Q_PROPERTY(QString currentOutputDeviceName READ currentOutputDeviceName
)
89 static RtpPlayerDialog
*openRtpPlayerDialog(QWidget
&parent
, CaptureFile
&cf
, QObject
*packet_list
, bool capture_running
);
92 * Should not be clonnable and assignable
94 RtpPlayerDialog(RtpPlayerDialog
&other
) = delete;
95 void operator=(const RtpPlayerDialog
&) = delete;
98 * @brief Common routine to add a "Play call" button to a QDialogButtonBox.
99 * @param button_box Caller's QDialogButtonBox.
100 * @return The new "Play call" button.
102 static QToolButton
*addPlayerButton(QDialogButtonBox
*button_box
, QDialog
*dialog
);
104 #ifdef QT_MULTIMEDIA_LIB
110 /** Replace/Add/Remove an RTP streams to play.
111 * Requires array of rtpstream_info_t.
112 * Each item must have filled items: src_addr, src_port, dest_addr,
113 * dest_port, ssrc, packet_count, setup_frame_number, and start_rel_time.
115 * @param stream_ids struct with rtpstream info
117 void replaceRtpStreams(QVector
<rtpstream_id_t
*> stream_ids
);
118 void addRtpStreams(QVector
<rtpstream_id_t
*> stream_ids
);
119 void removeRtpStreams(QVector
<rtpstream_id_t
*> stream_ids
);
122 // Tells the packet list to redraw. An alternative might be to add a
123 // cf_packet_marked callback to file.[ch] but that's synchronous and
124 // might incur too much overhead.
125 void packetsMarked();
126 void updateFilter(QString filter
, bool force
= false);
127 void goToPacket(int packet_num
);
128 void rtpAnalysisDialogReplaceRtpStreams(QVector
<rtpstream_id_t
*> stream_infos
);
129 void rtpAnalysisDialogAddRtpStreams(QVector
<rtpstream_id_t
*> stream_infos
);
130 void rtpAnalysisDialogRemoveRtpStreams(QVector
<rtpstream_id_t
*> stream_infos
);
133 void rtpAnalysisReplace();
134 void rtpAnalysisAdd();
135 void rtpAnalysisRemove();
139 explicit RtpPlayerDialog(QWidget
&parent
, CaptureFile
&cf
, bool capture_running
);
140 #ifdef QT_MULTIMEDIA_LIB
143 virtual void showEvent(QShowEvent
*);
144 void contextMenuEvent(QContextMenuEvent
*event
);
145 bool eventFilter(QObject
*obj
, QEvent
*event
);
148 /** Retap the capture file, reading RTP packets that match the
149 * streams added using ::addRtpStream.
152 void captureEvent(CaptureEvent e
);
153 /** Clear, decode, and redraw each stream.
155 void rescanPackets(bool rescale_axes
= false);
156 void createPlot(bool rescale_axes
= false);
157 void updateWidgets();
158 void itemEntered(QTreeWidgetItem
*item
, int column
);
159 void mouseMovePlot(QMouseEvent
*event
);
160 void mouseMoveUpdate();
161 void showGraphContextMenu(const QPoint
&pos
);
162 void graphClicked(QMouseEvent
*event
);
163 void graphDoubleClicked(QMouseEvent
*event
);
164 void plotClicked(QCPAbstractPlottable
*plottable
, int dataIndex
, QMouseEvent
*event
);
165 void updateHintLabel();
168 void playFinished(RtpAudioStream
*stream
, QAudio::Error error
);
170 void setPlayPosition(double secs
);
171 void setPlaybackError(const QString playback_error
);
172 void changeAudioRoutingOnItem(QTreeWidgetItem
*ti
, AudioRouting new_audio_routing
);
173 void changeAudioRouting(AudioRouting new_audio_routing
);
174 void invertAudioMutingOnItem(QTreeWidgetItem
*ti
);
175 void on_playButton_clicked();
176 void on_pauseButton_clicked();
177 void on_stopButton_clicked();
178 void on_actionReset_triggered();
179 void on_actionZoomIn_triggered();
180 void on_actionZoomOut_triggered();
181 void on_actionMoveLeft10_triggered();
182 void on_actionMoveRight10_triggered();
183 void on_actionMoveLeft1_triggered();
184 void on_actionMoveRight1_triggered();
185 void on_actionGoToPacket_triggered();
186 void on_actionGoToSetupPacketPlot_triggered();
187 void on_actionGoToSetupPacketTree_triggered();
188 void on_actionRemoveStream_triggered();
189 void on_actionAudioRoutingP_triggered();
190 void on_actionAudioRoutingL_triggered();
191 void on_actionAudioRoutingLR_triggered();
192 void on_actionAudioRoutingR_triggered();
193 void on_actionAudioRoutingMute_triggered();
194 void on_actionAudioRoutingUnmute_triggered();
195 void on_actionAudioRoutingMuteInvert_triggered();
196 void on_streamTreeWidget_itemSelectionChanged();
197 void on_streamTreeWidget_itemDoubleClicked(QTreeWidgetItem
*item
, const int column
);
198 void on_outputDeviceComboBox_currentTextChanged(const QString
&);
199 void on_outputAudioRate_currentTextChanged(const QString
&);
200 void on_jitterSpinBox_valueChanged(double);
201 void on_timingComboBox_currentIndexChanged(int);
202 void on_todCheckBox_toggled(bool checked
);
203 void on_buttonBox_helpRequested();
204 void on_actionSelectAll_triggered();
205 void on_actionSelectInvert_triggered();
206 void on_actionSelectNone_triggered();
208 void on_actionPlay_triggered();
209 void on_actionStop_triggered();
210 void on_actionSaveAudioFromCursor_triggered();
211 void on_actionSaveAudioSyncStream_triggered();
212 void on_actionSaveAudioSyncFile_triggered();
213 void on_actionSavePayload_triggered();
214 void on_actionSelectInaudible_triggered();
215 void on_actionDeselectInaudible_triggered();
216 void on_actionPrepareFilter_triggered();
217 void on_actionReadCapture_triggered();
219 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
220 void sinkStateChanged();
225 static RtpPlayerDialog
*pinstance_
;
226 static std::mutex init_mutex_
;
227 static std::mutex run_mutex_
;
229 #ifdef QT_MULTIMEDIA_LIB
230 Ui::RtpPlayerDialog
*ui
;
231 QMenu
*graph_ctx_menu_
;
232 QMenu
*list_ctx_menu_
;
233 double first_stream_rel_start_time_
; // Relative start time of first stream
234 double first_stream_abs_start_time_
; // Absolute start time of first stream
235 double first_stream_rel_stop_time_
; // Relative end time of first stream (ued for streams_length_ calculation
236 double streams_length_
; // Difference between start of first stream and end of last stream
237 double start_marker_time_
; // Always relative time to start of the capture
238 double start_marker_time_play_
; // Copy when play started
239 QCPItemStraightLine
*cur_play_pos_
;
240 QCPItemStraightLine
*start_marker_pos_
;
241 QString playback_error_
;
242 QSharedPointer
<QCPAxisTicker
> number_ticker_
;
243 QSharedPointer
<QCPAxisTickerDateTime
> datetime_ticker_
;
244 bool stereo_available_
;
245 QList
<RtpAudioStream
*> playing_streams_
;
246 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
247 QAudioSink
*marker_stream_
;
248 QTimer notify_timer_
;
249 qint64 notify_timer_start_diff_
; // Used to shift play cursor to correct place
251 QAudioOutput
*marker_stream_
;
253 quint32 marker_stream_requested_out_rate_
;
254 QTreeWidgetItem
*last_ti_
;
255 bool listener_removed_
;
256 QPushButton
*read_btn_
;
257 QToolButton
*inaudible_btn_
;
258 QToolButton
*analyze_btn_
;
259 QPushButton
*prepare_btn_
;
260 QPushButton
*export_btn_
;
261 QMultiHash
<unsigned, RtpAudioStream
*> stream_hash_
;
264 bool read_capture_enabled_
;
265 double silence_skipped_time_
;
266 QTimer
*mouse_update_timer_
;
269 // const QString streamKey(const rtpstream_info_t *rtpstream);
270 // const QString streamKey(const packet_info *pinfo, const struct _rtp_info *rtpinfo);
273 // static void tapReset(void *tapinfo_ptr);
274 static tap_packet_status
tapPacket(void *tapinfo_ptr
, packet_info
*pinfo
, epan_dissect_t
*, const void *rtpinfo_ptr
, tap_flags_t flags
);
275 static void tapDraw(void *tapinfo_ptr
);
277 void addPacket(packet_info
*pinfo
, const struct _rtp_info
*rtpinfo
);
278 void zoomXAxis(bool in
);
279 void panXAxis(int x_pixels
);
280 const QString
getFormatedTime(double f_time
);
281 const QString
getFormatedHoveredTime();
282 int getHoveredPacket();
283 QString
currentOutputDeviceName();
284 double getStartPlayMarker();
285 void drawStartPlayMarker();
286 void setStartPlayMarker(double new_time
);
287 void updateStartStopTime(rtpstream_info_t
*rtpstream
, bool is_first
);
288 void formatAudioRouting(QTreeWidgetItem
*ti
, AudioRouting audio_routing
);
289 bool isStereoAvailable();
290 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
291 QAudioSink
*getSilenceAudioOutput();
292 QAudioDevice
getCurrentDeviceInfo();
294 QAudioOutput
*getSilenceAudioOutput();
295 QAudioDeviceInfo
getCurrentDeviceInfo();
297 QTreeWidgetItem
*findItemByCoords(QPoint point
);
298 QTreeWidgetItem
*findItem(QCPAbstractPlottable
*plottable
);
299 void handleItemHighlight(QTreeWidgetItem
*ti
, bool scroll
);
300 void highlightItem(QTreeWidgetItem
*ti
, bool highlight
);
301 void invertSelection();
302 void handleGoToSetupPacket(QTreeWidgetItem
*ti
);
303 void addSingleRtpStream(rtpstream_id_t
*id
);
304 void removeRow(QTreeWidgetItem
*ti
);
305 void fillAudioRateMenu();
306 void cleanupMarkerStream();
308 qint64
saveAudioHeaderAU(QFile
*save_file
, quint32 channels
, unsigned audio_rate
);
309 qint64
saveAudioHeaderWAV(QFile
*save_file
, quint32 channels
, unsigned audio_rate
, qint64 samples
);
310 bool writeAudioSilenceSamples(QFile
*out_file
, qint64 samples
, int stream_count
);
311 bool writeAudioStreamsSamples(QFile
*out_file
, QVector
<RtpAudioStream
*> streams
, bool swap_bytes
);
312 save_audio_t
selectFileAudioFormatAndName(QString
*file_path
);
313 save_payload_t
selectFilePayloadFormatAndName(QString
*file_path
);
314 QVector
<RtpAudioStream
*>getSelectedAudibleNonmutedAudioStreams();
315 void saveAudio(save_mode_t save_mode
);
319 void selectInaudible(bool select
);
320 QVector
<rtpstream_id_t
*>getSelectedRtpStreamIDs();
321 void fillTappedColumns();
323 #else // QT_MULTIMEDIA_LIB
325 Ui::RtpPlayerDialog
*ui
;
326 #endif // QT_MULTIMEDIA_LIB
329 #endif // RTP_PLAYER_DIALOG_H