Streaming Audio with Qt
Overview[edit | edit source]
File:Streaming1.png File:Streaming2.png
We will create a Live Audio Streaming application. This application consists of three classes
HttpWindow : Creates a list of Live Streaming Links, and when user clicks on any of those links it calls the play function
MyMusicTest : This class is responsible for creating the UI of the application and playing the file when its being selected by the user.
MyPlayerView : In this class we clear the previous listed audio files (if any) and then starts playing the current one.
Project configuration file (.Pro file)[edit | edit source]
Add the lib and capabilities in the .pro file
...
QT += core \
gui \
xml \
network \
phonon
...
symbian: {
TARGET.CAPABILITY = ReadUSerData \
WriteUserData \
NetworkServices \
LocalServices
}
MyMusicTest Class Definition[edit | edit source]
- ifndef MYMUSICTEST_H
- define MYMUSICTEST_H
- include <QtGui/QMainWindow>
- include <QStackedWidget>
- include <QAction>
- include <QMenuBar>
- include "MyPlayer.h"
#include "HTTP_window.h"
class MyMusicTest : public QMainWindow
{
Q_OBJECT
public:
MyMusicTest(QWidget *parent = 0);
~MyMusicTest();
private slots:
void about();
void playStream(QString);
void showHttpView();
private:
void createMenus(const bool httpView);
private:
QStackedWidget* mStackedWidget;
MyPlayerView* mMyPlayerView;
HttpWindow* mHttpWindow;
QAction* mAboutAction;
QAction* mExitAction;
QAction* mBackAction;
};
- endif // MYMUSICTEST_H
MyMusicTest Class Implementation[edit | edit source]
- include <QMessageBox>
- include <QDesktopServices>
- include <QFileDialog>
- include <QUrl>
- include "MyMusicTest.h"
MyMusicTest::MyMusicTest(QWidget *parent): QMainWindow(parent)
{
setWindowTitle("My Music Player");
mStackedWidget = new QStackedWidget;
setCentralWidget(mStackedWidget);
mHttpWindow = new HttpWindow();
mStackedWidget->addWidget(mHttpWindow);
mMyPlayerView = new MyPlayerView;
mStackedWidget->addWidget(mMyPlayerView);
mStackedWidget->setCurrentIndex(0);
mAboutAction = new QAction(tr("About"), this);
mExitAction = new QAction(tr("Exit"), this);
mBackAction = new QAction(tr("Back"), this);
connect(mHttpWindow, SIGNAL(streamSelected(QString)), this, SLOT(playStream(QString)));
connect(mMyPlayerView, SIGNAL(backButtonPressed()), this, SLOT(showHttpView()));
connect(mExitAction, SIGNAL(triggered()), this, SLOT(close()));
connect(mAboutAction, SIGNAL(triggered()), this, SLOT(about()));
connect(mBackAction, SIGNAL(triggered()), this, SLOT(showHttpView()));
createMenus(true);
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
MyMusicTest::~MyMusicTest()
{
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyMusicTest::createMenus(const bool httpView)
{
QList<QAction*> actList = menuBar()->actions();
for(int i=0; i < actList.count(); i++){
menuBar()->removeAction(actList.at(i));
}
if(httpView){
menuBar()->addAction(mAboutAction);
menuBar()->addAction(mExitAction);
}else{
menuBar()->addAction(mBackAction);
}
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyMusicTest::showHttpView()
{
mMyPlayerView->StopPlay();
mStackedWidget->setCurrentIndex(0);
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyMusicTest::playStream(QString stream)
{
mStackedWidget->setCurrentIndex(1);
createMenus(false);
QUrl url(stream);
mMyPlayerView->SetUrl(url);
mMyPlayerView->playNow();
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyMusicTest::about()
{
QMessageBox::information(this, tr("About stream example"),
tr("This Music Player example shows how to use Phonon for streaming audio."
"work in progress..."));
}
The 76ytuiytuityutyutututyutyutyu function creates the menu of the application. 76ytuiytuityutyutututyutyutyu stops the playback if its playing and set the current index of the streaming list to zero. 76ytuiytuityutyutututyutyutyu set the selected URL and pass it to 76ytuiytuityutyutututyutyutyu function and then call the 76ytuiytuityutyutututyutyutyu function of MyPlayerView class.
MyPlayerView Class Definition[edit | edit source]
- ifndef MYPLAYER_H_
- define MYPLAYER_H_
- include <QWidget>
#include <phonon/audiooutput.h>
#include <phonon/VideoWidget.h>
#include <phonon/seekslider.h>
#include <phonon/mediaobject.h>
#include <phonon/volumeslider.h>
#include <phonon/backendcapabilities.h>
#include <QList>
#include <QLabel>
#include <QPushButton>
class QAction;
class QTableWidget;
class QLCDNumber;
class MyPlayerView : public QWidget
{
Q_OBJECT
public:
MyPlayerView();
QSize sizeHint() const {
return QSize(500, 300);
}
public slots:
void playNow();
void StopPlay();
void SetFile(const QString& file);
void SetUrl(const QUrl &url);
void stateChanged(Phonon::State newState, Phonon::State oldState);
void sourceChanged(const Phonon::MediaSource &source);
void aboutToFinish();
void setBufferingValue(int value);
void tick(qint64 time);
signals:
void backButtonPressed();
private:
void setupUi();
private:
Phonon::MediaObject* mediaObject;
Phonon::AudioOutput* audioOutput;
Phonon::MediaSource source;
Phonon::VideoWidget* videoWidget;
QLabel* mStatusLabel;
QLabel* mStatusTitle;
QAction* playAction;
QAction* pauseAction;
QAction* stopAction;
QLCDNumber* timeLcd;
Phonon::VolumeSlider* volumeSlider;
QWidget* dummy;
};
- endif /* MYPLAYER_H_ */
MyPlayerView Class Implementation[edit | edit source]
- include <QtGui>
#include "MyPlayer.h"
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
MyPlayerView::MyPlayerView()
{
audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
mediaObject = new Phonon::MediaObject(this);
mediaObject->setTickInterval(1000);
connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
connect(mediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)),this, SLOT(stateChanged(Phonon::State,Phonon::State)));
connect(mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)),this, SLOT(sourceChanged(Phonon::MediaSource)));
connect(mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));
connect(mediaObject, SIGNAL(bufferStatus(int)), this, SLOT(setBufferingValue(int)));
Phonon::createPath(mediaObject, audioOutput);
playAction = new QAction(style()->standardIcon(QStyle::SP_MediaPlay), tr("Play"), this);
playAction->setDisabled(true);
pauseAction = new QAction(style()->standardIcon(QStyle::SP_MediaPause), tr("Pause"), this);
pauseAction->setDisabled(true);
stopAction = new QAction(style()->standardIcon(QStyle::SP_MediaStop), tr("Stop"), this);
stopAction->setDisabled(true);
connect(playAction, SIGNAL(triggered()), mediaObject, SLOT(play()));
connect(pauseAction, SIGNAL(triggered()), mediaObject, SLOT(pause()) );
connect(stopAction, SIGNAL(triggered()), mediaObject, SLOT(stop()));
setupUi();
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyPlayerView::SetFile(const QString& file)
{
source = Phonon::MediaSource(file);
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyPlayerView::StopPlay()
{
mediaObject->stop();
mediaObject->clearQueue();
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyPlayerView::SetUrl(const QUrl &url)
{
source = Phonon::MediaSource(url);
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyPlayerView::playNow()
{
mediaObject->stop();
mediaObject->clearQueue();
mediaObject->setCurrentSource(source);
mediaObject->play();
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyPlayerView::stateChanged(Phonon::State newState, Phonon::State /* oldState */)
{
switch (newState) {
case Phonon::ErrorState:
if(mediaObject){
if (mediaObject->errorType() == Phonon::FatalError) {
QMessageBox::warning(this, tr("Fatal Error"),
mediaObject->errorString());
} else {
QMessageBox::warning(this, tr("Error"),
mediaObject->errorString());
}
}else{
QMessageBox::warning(this, tr("Error"),tr("Media is NULL"));
}
break;
case Phonon::PlayingState:
mStatusLabel->setText("PlayingState");
playAction->setEnabled(false);
pauseAction->setEnabled(true);
stopAction->setEnabled(true);
break;
case Phonon::StoppedState:
mStatusLabel->setText("StoppedState");
stopAction->setEnabled(false);
playAction->setEnabled(true);
pauseAction->setEnabled(false);
timeLcd->display("00:00");
break;
case Phonon::PausedState:
mStatusLabel->setText("PausedState");
pauseAction->setEnabled(false);
stopAction->setEnabled(true);
playAction->setEnabled(true);
break;
case Phonon::BufferingState:
mStatusLabel->setText("BufferingState");
break;
default:
break;
}
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyPlayerView::setBufferingValue(int value)
{
QString statt = "Buffering: " + QString::number(value);
mStatusLabel->setText(statt);
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyPlayerView::sourceChanged(const Phonon::MediaSource& /*source*/)
{
mStatusLabel->setText("sourceChanged");
timeLcd->display("00:00");
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyPlayerView::tick(qint64 time)
{
QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
timeLcd->display(displayTime.toString("mm:ss"));
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyPlayerView::aboutToFinish()
{
emit backButtonPressed();
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void MyPlayerView::setupUi()
{
mStatusTitle = new QLabel(tr("Status:"));
mStatusLabel = new QLabel();
dummy = new QWidget();
dummy->setDisabled(true);
videoWidget = new Phonon::VideoWidget(dummy);
Phonon::createPath(mediaObject, videoWidget);
QHBoxLayout *topLayout1 = new QHBoxLayout;
topLayout1->addWidget(mStatusTitle);
topLayout1->addWidget(mStatusLabel);
QToolBar *bar = new QToolBar;
bar->addAction(playAction);
bar->addAction(pauseAction);
bar->addAction(stopAction);
QPalette palette;
palette.setBrush(QPalette::Light, Qt::darkGray);
timeLcd = new QLCDNumber;
timeLcd->setPalette(palette);
volumeSlider = new Phonon::VolumeSlider(this);
volumeSlider->setAudioOutput(audioOutput);
volumeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(topLayout1);
mainLayout->addWidget(bar);
mainLayout->addWidget(volumeSlider);
mainLayout->addWidget(timeLcd);
setLayout(mainLayout);
}
The 76ytuiytuityutyutututyutyutyu method defines the initial size of the widget. The basic handling on getting the stream to play is to construct 76ytuiytuityutyutututyutyutyu and 76ytuiytuityutyutututyutyutyu and linking them together with 76ytuiytuityutyutututyutyutyu function call
audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
mediaObject = new Phonon::MediaObject(this);
Phonon::createPath(mediaObject, audioOutput);
The {{Icode|playNow()} function first stop the playing media file, clear the queue, set the current selected source or media and finally starts playing the media object. Which after the file/stream can be played by giving the filename/stream-Url to the media object as a media source and then simply calling play for the media object.
source = Phonon::MediaSource(url);
mediaObject->setCurrentSource(source);
mediaObject->play();
This works fine for file playing, for streams this would most often cause memory violation error, caused by the fact that the streaming back-end implementation often requires Video widget to be also set for the media object. For normal audio streaming the video UI would be unwanted feature, thus to ignore it, you can simply construct it with a parent widget that is disabled:
dummy = new QWidget();
dummy->setDisabled(true);
videoWidget = new Phonon::VideoWidget(dummy);
Phonon::createPath(mediaObject, videoWidget);
This way you can play audio parts from all supported video and audio streams. In 76ytuiytuityutyutututyutyutyu we stop the currently playing media and then clear the queue. With 76ytuiytuityutyutututyutyutyu we set the link to the media source that we want to stream. 76ytuiytuityutyutututyutyutyu helps us to check the status of the Phonon Media Playback, from this we can know whether the audio is playing, stopped, pushed, buffering or even there is any error in the file or not. In 76ytuiytuityutyutututyutyutyu function we reset the time of the media playing to zero. 76ytuiytuityutyutututyutyutyu displays the buffering value in the screen. 76ytuiytuityutyutututyutyutyu displays the time in LCD format.
HttpWindow Class Definition[edit | edit source]
- ifndef MYHTTPWINDOW_H_
- define MYHTTPWINDOW_H_
- include <QWidget>
- include <QLabel>
- include <QLineEdit>
- include <QHttp>
- include <QFile>
- include <QProgressDialog>
- include <QListWidget>
- include <QPushButton>
struct MyDataItem
{
QString audio;
QString title;
};
class HttpWindow : public QWidget
{
Q_OBJECT
public:
HttpWindow();
public slots:
void itemSelected(QListWidgetItem *item);
void PlayFile();
signals:
void streamSelected(QString);
private:
void addTestData();
private:
QList<MyDataItem> items;
QListWidget* listWidget;
QPushButton* pushBut;
};
- endif /* MYHTTPWINDOW_H_ */
HttpWindow Class Implementation[edit | edit source]
- include <QtGui>
#include <QtNetwork>
- include <QDomDocument>
- include <QDomElement>
- include <QDomNodeList>
#include "HTTP_window.h"
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
HttpWindow::HttpWindow()
{
listWidget = new QListWidget(this);
connect(listWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(itemSelected(QListWidgetItem*)));
pushBut = new QPushButton("Play", this);
connect(pushBut, SIGNAL(pressed()),SLOT(PlayFile()));
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(listWidget);
mainLayout->addWidget(pushBut);
setLayout(mainLayout);
addTestData();
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void HttpWindow::addTestData()
{
//Clear items
listWidget->clear();
items.clear();
MyDataItem newIttem1;
newIttem1.audio = "rtsp://rm.bbc.co.uk/radio2/r2online_id.rm";
newIttem1.title = "rtsp: r2online_id.rm";
items.append(newIttem1);
MyDataItem newIttem5;
newIttem5.audio = "rtsp://rmv8.bbc.net.uk:554/radio1coyopa/radio_1_-_friday_1900.ra";
newIttem5.title = "rtsp: radio_1_-_friday_1900.ra";
items.append(newIttem5);
MyDataItem newIttem3;
newIttem3.audio = "mms://213.92.19.13/m2o";
newIttem3.title = "mms: m2o";
items.append(newIttem3);
MyDataItem newIttem4;
newIttem4.audio = "http://od.netro.ca/netrostream113/voice_demo.wma";
newIttem4.title = "http: voice_demo.wma";
items.append(newIttem4);
MyDataItem newIttem2;
newIttem2.audio = "rtsp://qt2.netro.ca/princess_54.3gp";
newIttem2.title = "rtsp: princess_54.3gp";
items.append(newIttem2);
for(int i=0; i< items.count(); i++){
listWidget->addItem(items[i].title);
}
}
/*
- --------------------------------------------------------------
- --------------------------------------------------------------
- /
void HttpWindow::PlayFile()
{
int selIndex = listWidget->currentRow();
if(selIndex >= 0 && selIndex < items.count()){
emit streamSelected(items[selIndex].audio);
}
}
/*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
void HttpWindow::itemSelected(QListWidgetItem *item)
{
PlayFile();
}
76ytuiytuityutyutututyutyutyu call the 76ytuiytuityutyutututyutyutyu function and plays the selected item from the list. 76ytuiytuityutyutututyutyutyu fetch the selected item from the list and then emits 76ytuiytuityutyutututyutyutyu signal and which calls the 76ytuiytuityutyutututyutyutyu signal, 76ytuiytuityutyutututyutyutyu crated the list widget of the streaming links.
Source Code[edit | edit source]
The full example with some example streams is found in: StreamMusicTest.zip