* 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
#include <QAudioOutput>
#include <QDir>
#include <QTemporaryFile>
+#include <QVariant>
// To do:
// - Only allow one rtp_stream_info_t per RtpAudioStream?
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
// 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()));
#include <QSet>
#include <QVector>
+class QAudioFormat;
class QAudioOutput;
class QTemporaryFile;
signals:
void startedPlaying();
void processedSecs(double secs);
+ void playbackError(const QString error_msg);
void finishedPlaying();
public slots:
TimingMode timing_mode_;
void writeSilence(int samples);
+ const QString formatDescription(const QAudioFormat & format);
private slots:
void outputStateChanged(QAudio::State new_state);
#include "tango_colors.h"
#include <QAudio>
+#include <QAudioDeviceInfo>
#include <QFrame>
#include <QMenu>
#include <QVBoxLayout>
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*)));
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(
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);
}
ui->playButton->setEnabled(enable_play);
+ ui->outputDeviceComboBox->setEnabled(enable_play);
ui->stopButton->setEnabled(enable_stop);
cur_play_pos_->setVisible(enable_stop);
ui->timingComboBox->setEnabled(enable_timing);
ui->todCheckBox->setEnabled(enable_timing);
+ updateHintLabel();
ui->audioPlot->replot();
}
ui->audioPlot->setFocus();
}
-void RtpPlayerDialog::mouseMoved(QMouseEvent *)
+void RtpPlayerDialog::updateHintLabel()
{
int packet_num = getHoveredPacket();
QString hint = "<small><i>";
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>";
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();
}
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();
class RtpPlayerDialog : public WiresharkDialog
{
Q_OBJECT
+ Q_PROPERTY(QString currentOutputDeviceName READ currentOutputDeviceName CONSTANT)
public:
explicit RtpPlayerDialog(QWidget &parent, CaptureFile &cf);
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();
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);
double getLowestTimestamp();
const QString getHoveredTime();
int getHoveredPacket();
+ const QString currentOutputDeviceName();
#else // QT_MULTIMEDIA_LIB
private:
<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">
</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">
</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">
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>40</width>
- <height>20</height>
+ <width>20</width>
+ <height>10</height>
</size>
</property>
</spacer>
</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>