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>
This commit is contained in:
parent
263fea9723
commit
d59653f8d5
|
@ -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
|
||||
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,12 +153,39 @@
|
|||
</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">
|
||||
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue