diff options
author | Gerald Combs <gerald@wireshark.org> | 2016-12-02 15:52:02 -0800 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2016-12-06 22:36:55 +0000 |
commit | d59653f8d52efbf3ab32f95043cd718965e57406 (patch) | |
tree | 14e868a73180a3eccbed1d3715bb64a2c92f6928 | |
parent | 263fea9723ea3487c0d98b0720ab2d656f780fe1 (diff) | |
download | wireshark-d59653f8d52efbf3ab32f95043cd718965e57406.tar.gz |
Qt: Make the RTP player output device selectable.
Add a combobox for selecting the output device and populate it with our
available devices. Let the user know if our output format isn't
supported.
Ping-Bug: 13105
Change-Id: I299c7d0f191bb66d93896338036000e2c377781f
Reviewed-on: https://code.wireshark.org/review/19046
Petri-Dish: Gerald Combs <gerald@wireshark.org>
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Gerald Combs <gerald@wireshark.org>
-rw-r--r-- | docbook/release-notes.asciidoc | 1 | ||||
-rw-r--r-- | ui/qt/rtp_audio_stream.cpp | 42 | ||||
-rw-r--r-- | ui/qt/rtp_audio_stream.h | 3 | ||||
-rw-r--r-- | ui/qt/rtp_player_dialog.cpp | 33 | ||||
-rw-r--r-- | ui/qt/rtp_player_dialog.h | 6 | ||||
-rw-r--r-- | ui/qt/rtp_player_dialog.ui | 54 |
6 files changed, 128 insertions, 11 deletions
diff --git a/docbook/release-notes.asciidoc b/docbook/release-notes.asciidoc index 83745f4bf1..1507cf2052 100644 --- a/docbook/release-notes.asciidoc +++ b/docbook/release-notes.asciidoc @@ -39,6 +39,7 @@ since version 2.2.0: * Wireshark can now go fullscreen to have more room for packets. * TShark can now export objects like the other GUI interfaces. * Support for G.722 and G.726 codecs in the RTP Player (via the Spandsp library). +* You can now choose the output device when playing RTP streams. //=== Removed Dissectors diff --git a/ui/qt/rtp_audio_stream.cpp b/ui/qt/rtp_audio_stream.cpp index 798d73fcbe..fee1ebc391 100644 --- a/ui/qt/rtp_audio_stream.cpp +++ b/ui/qt/rtp_audio_stream.cpp @@ -42,6 +42,7 @@ #include <QAudioOutput> #include <QDir> #include <QTemporaryFile> +#include <QVariant> // To do: // - Only allow one rtp_stream_info_t per RtpAudioStream? @@ -521,10 +522,41 @@ QAudio::State RtpAudioStream::outputState() const return audio_output_->state(); } +const QString RtpAudioStream::formatDescription(const QAudioFormat &format) +{ + QString fmt_descr = QString("%1 Hz, ").arg(format.sampleRate()); + switch (format.sampleType()) { + case QAudioFormat::SignedInt: + fmt_descr += "Int"; + break; + case QAudioFormat::UnSignedInt: + fmt_descr += "UInt"; + break; + case QAudioFormat::Float: + fmt_descr += "Float"; + break; + default: + fmt_descr += "Unknown"; + break; + } + fmt_descr += QString::number(format.sampleSize()); + fmt_descr += format.byteOrder() == QAudioFormat::BigEndian ? "BE" : "LE"; + + return fmt_descr; +} + void RtpAudioStream::startPlaying() { if (audio_output_) return; + QAudioDeviceInfo cur_out_device = QAudioDeviceInfo::defaultOutputDevice(); + QString cur_out_name = parent()->property("currentOutputDeviceName").toString(); + foreach (QAudioDeviceInfo out_device, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { + if (cur_out_name == out_device.deviceName()) { + cur_out_device = out_device; + } + } + QAudioFormat format; format.setSampleRate(audio_out_rate_); format.setSampleSize(sample_bytes_ * 8); // bits @@ -536,7 +568,15 @@ void RtpAudioStream::startPlaying() // tempfile_->fileName().toUtf8().constData(), // (int) tempfile_->size(), audio_out_rate_); - audio_output_ = new QAudioOutput(format, this); + if (!cur_out_device.isFormatSupported(format)) { + QString playback_error = tr("%1 does not support PCM at %2. Preferred format is %3") + .arg(cur_out_device.deviceName()) + .arg(formatDescription(format)) + .arg(formatDescription(cur_out_device.nearestFormat(format))); + emit playbackError(playback_error); + } + + audio_output_ = new QAudioOutput(cur_out_device, format, this); audio_output_->setNotifyInterval(65); // ~15 fps connect(audio_output_, SIGNAL(stateChanged(QAudio::State)), this, SLOT(outputStateChanged(QAudio::State))); connect(audio_output_, SIGNAL(notify()), this, SLOT(outputNotify())); diff --git a/ui/qt/rtp_audio_stream.h b/ui/qt/rtp_audio_stream.h index e60e5e7ebe..d4cfa22290 100644 --- a/ui/qt/rtp_audio_stream.h +++ b/ui/qt/rtp_audio_stream.h @@ -37,6 +37,7 @@ #include <QSet> #include <QVector> +class QAudioFormat; class QAudioOutput; class QTemporaryFile; @@ -142,6 +143,7 @@ public: signals: void startedPlaying(); void processedSecs(double secs); + void playbackError(const QString error_msg); void finishedPlaying(); public slots: @@ -183,6 +185,7 @@ private: TimingMode timing_mode_; void writeSilence(int samples); + const QString formatDescription(const QAudioFormat & format); private slots: void outputStateChanged(QAudio::State new_state); diff --git a/ui/qt/rtp_player_dialog.cpp b/ui/qt/rtp_player_dialog.cpp index 743685c307..35274cb3f0 100644 --- a/ui/qt/rtp_player_dialog.cpp +++ b/ui/qt/rtp_player_dialog.cpp @@ -35,6 +35,7 @@ #include "tango_colors.h" #include <QAudio> +#include <QAudioDeviceInfo> #include <QFrame> #include <QMenu> #include <QVBoxLayout> @@ -134,7 +135,7 @@ RtpPlayerDialog::RtpPlayerDialog(QWidget &parent, CaptureFile &cf) : ctx_menu_->addAction(ui->actionCrosshairs); connect(ui->audioPlot, SIGNAL(mouseMove(QMouseEvent*)), - this, SLOT(mouseMoved(QMouseEvent*))); + this, SLOT(updateHintLabel())); connect(ui->audioPlot, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(graphClicked(QMouseEvent*))); @@ -150,6 +151,21 @@ RtpPlayerDialog::RtpPlayerDialog(QWidget &parent, CaptureFile &cf) : ui->playButton->setIcon(StockIcon("media-playback-start")); ui->stopButton->setIcon(StockIcon("media-playback-stop")); + QString default_out_name = QAudioDeviceInfo::defaultOutputDevice().deviceName(); + foreach (QAudioDeviceInfo out_device, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { + QString out_name = out_device.deviceName(); + ui->outputDeviceComboBox->addItem(out_name); + if (out_name == default_out_name) { + ui->outputDeviceComboBox->setCurrentText(out_name); + } + } + if (ui->outputDeviceComboBox->count() < 1) { + ui->outputDeviceComboBox->setEnabled(false); + ui->playButton->setEnabled(false); + ui->stopButton->setEnabled(false); + ui->outputDeviceComboBox->addItem(tr("No devices available")); + } + ui->audioPlot->setMouseTracking(true); ui->audioPlot->setEnabled(true); ui->audioPlot->setInteractions( @@ -379,6 +395,7 @@ void RtpPlayerDialog::addRtpStream(struct _rtp_stream_info *rtp_stream) connect(audio_stream, SIGNAL(startedPlaying()), this, SLOT(updateWidgets())); connect(audio_stream, SIGNAL(finishedPlaying()), this, SLOT(updateWidgets())); + connect(audio_stream, SIGNAL(playbackError(QString)), this, SLOT(setPlaybackError(QString))); connect(audio_stream, SIGNAL(processedSecs(double)), this, SLOT(setPlayPosition(double))); } audio_stream->addRtpStream(rtp_stream); @@ -473,6 +490,7 @@ void RtpPlayerDialog::updateWidgets() } ui->playButton->setEnabled(enable_play); + ui->outputDeviceComboBox->setEnabled(enable_play); ui->stopButton->setEnabled(enable_stop); cur_play_pos_->setVisible(enable_stop); @@ -480,6 +498,7 @@ void RtpPlayerDialog::updateWidgets() ui->timingComboBox->setEnabled(enable_timing); ui->todCheckBox->setEnabled(enable_timing); + updateHintLabel(); ui->audioPlot->replot(); } @@ -492,7 +511,7 @@ void RtpPlayerDialog::graphClicked(QMouseEvent *event) ui->audioPlot->setFocus(); } -void RtpPlayerDialog::mouseMoved(QMouseEvent *) +void RtpPlayerDialog::updateHintLabel() { int packet_num = getHoveredPacket(); QString hint = "<small><i>"; @@ -501,6 +520,8 @@ void RtpPlayerDialog::mouseMoved(QMouseEvent *) hint += tr("%1. Press \"G\" to go to packet %2") .arg(getHoveredTime()) .arg(packet_num); + } else if (!playback_error_.isEmpty()) { + hint += playback_error_; } hint += "</i></small>"; @@ -603,6 +624,7 @@ void RtpPlayerDialog::on_playButton_clicked() cur_play_pos_->point1->setCoords(left, 0.0); cur_play_pos_->point2->setCoords(left, 1.0); cur_play_pos_->setVisible(true); + playback_error_.clear(); ui->audioPlot->replot(); } @@ -709,6 +731,13 @@ int RtpPlayerDialog::getHoveredPacket() return audio_stream->nearestPacket(ts, !ui->todCheckBox->isChecked()); } +// Used by RtpAudioStreams to initialize QAudioOutput. We could alternatively +// pass the corresponding QAudioDeviceInfo directly. +const QString RtpPlayerDialog::currentOutputDeviceName() +{ + return ui->outputDeviceComboBox->currentText(); +} + void RtpPlayerDialog::on_jitterSpinBox_valueChanged(double) { rescanPackets(); diff --git a/ui/qt/rtp_player_dialog.h b/ui/qt/rtp_player_dialog.h index e6e1a428be..0067c6f3e9 100644 --- a/ui/qt/rtp_player_dialog.h +++ b/ui/qt/rtp_player_dialog.h @@ -46,6 +46,7 @@ class RtpAudioStream; class RtpPlayerDialog : public WiresharkDialog { Q_OBJECT + Q_PROPERTY(QString currentOutputDeviceName READ currentOutputDeviceName CONSTANT) public: explicit RtpPlayerDialog(QWidget &parent, CaptureFile &cf); @@ -92,10 +93,11 @@ private slots: void rescanPackets(bool rescale_axes = false); void updateWidgets(); void graphClicked(QMouseEvent *event); - void mouseMoved(QMouseEvent *); + void updateHintLabel(); void resetXAxis(); void setPlayPosition(double secs); + void setPlaybackError(const QString playback_error) { playback_error_ = playback_error; } void on_playButton_clicked(); void on_stopButton_clicked(); void on_actionReset_triggered(); @@ -117,6 +119,7 @@ private: QMenu *ctx_menu_; double start_rel_time_; QCPItemStraightLine *cur_play_pos_; + QString playback_error_; // const QString streamKey(const struct _rtp_stream_info *rtp_stream); // const QString streamKey(const packet_info *pinfo, const struct _rtp_info *rtpinfo); @@ -132,6 +135,7 @@ private: double getLowestTimestamp(); const QString getHoveredTime(); int getHoveredPacket(); + const QString currentOutputDeviceName(); #else // QT_MULTIMEDIA_LIB private: diff --git a/ui/qt/rtp_player_dialog.ui b/ui/qt/rtp_player_dialog.ui index fd5d2420c2..d0a5005336 100644 --- a/ui/qt/rtp_player_dialog.ui +++ b/ui/qt/rtp_player_dialog.ui @@ -6,14 +6,14 @@ <rect> <x>0</x> <y>0</y> - <width>708</width> - <height>400</height> + <width>750</width> + <height>600</height> </rect> </property> <property name="windowTitle"> <string>RTP Player</string> </property> - <layout class="QVBoxLayout" name="verticalLayout" stretch="1,0,0,0"> + <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QSplitter" name="splitter"> <property name="orientation"> @@ -118,7 +118,7 @@ </widget> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0,0,0,0,0,1,0"> + <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0,0,1"> <item> <widget class="QToolButton" name="playButton"> <property name="text"> @@ -153,13 +153,40 @@ </property> <property name="sizeHint" stdset="0"> <size> - <width>40</width> + <width>20</width> <height>10</height> </size> </property> </spacer> </item> <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Output Device:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="outputDeviceComboBox"/> + </item> + <item> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,0,0,0,0,0,1"> + <item> <widget class="QLabel" name="label"> <property name="toolTip"> <string><html><head/><body><p><br/></p></body></html></string> @@ -241,8 +268,8 @@ </property> <property name="sizeHint" stdset="0"> <size> - <width>40</width> - <height>20</height> + <width>20</width> + <height>10</height> </size> </property> </spacer> @@ -257,6 +284,19 @@ </property> </widget> </item> + <item> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>48</width> + <height>24</height> + </size> + </property> + </spacer> + </item> </layout> </item> <item> |