summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2016-12-02 15:52:02 -0800
committerGerald Combs <gerald@wireshark.org>2016-12-06 22:36:55 +0000
commitd59653f8d52efbf3ab32f95043cd718965e57406 (patch)
tree14e868a73180a3eccbed1d3715bb64a2c92f6928
parent263fea9723ea3487c0d98b0720ab2d656f780fe1 (diff)
downloadwireshark-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.asciidoc1
-rw-r--r--ui/qt/rtp_audio_stream.cpp42
-rw-r--r--ui/qt/rtp_audio_stream.h3
-rw-r--r--ui/qt/rtp_player_dialog.cpp33
-rw-r--r--ui/qt/rtp_player_dialog.h6
-rw-r--r--ui/qt/rtp_player_dialog.ui54
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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>