Streaming Audio with Qt
Article Metadata
Code Example
Tested with
Compatibility
Article
Contents |
Overview
In this article we will discuss how we can play audio and video in Qt using Phonon APIs. This API can also be used to play audio/ video streaming.
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)
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
#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
#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 createMenus() function creates the menu of the application. showHttpView() stops the playback if its playing and set the current index of the streaming list to zero. playStream() set the selected URL and pass it to SetUrl() function and then call the playNow() function of MyPlayerView class.
MyPlayerView Class Definition
#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
#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 sizeHint() method defines the initial size of the widget. The basic handling on getting the stream to play is to construct Phonon::AudioOutput() and Phonon::MediaObject() and linking them together with Phonon::createPath() 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 StopPlay() we stop the currently playing media and then clear the queue. With SetUrl() we set the link to the media source that we want to stream. stateChanged() 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 sourceChanged() function we reset the time of the media playing to zero. setBufferingValue() displays the buffering value in the screen. tick() displays the time in LCD format.
HttpWindow Class Definition
#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
#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();
}
itemSelected() call the PlayFile() function and plays the selected item from the list. PlayFile() fetch the selected item from the list and then emits streamSelected() signal and which calls the playStream() signal, addTestData() crated the list widget of the streaming links.
Source Code
The full example with some example streams is found in: StreamMusicTest.zip




Hi Yucca
--somnathbanik 09:53, 28 April 2011 (UTC)
Contents
Build-errors
Hi! Shouldn't I be able to run this "out-of-the-box" without any compiling errors? I would like to use this as a base for a new application, but would like to test it first.
Thank you
Devnull -
Build errors may arise due to Qt creator handling differently pro files from CarbideDevnull 10:32, 15 March 2012 (EET)
Khadijarss - error of memory
Hello,
when i try to execute this project i get this error : " error of loading file can no connect(dowloading error)" although my device is connecting to the internet.
can you help me to solve this problem :)
thanks in advancekhadijarss 13:24, 22 March 2012 (EET)
Khadijarss - Opening clip failed:Not supported
Hello,
i can execute the example in QT simulator and the media is played correctly but if i try to excute the same example in my device i get this error: "Opening clip failed:Not supported"
my file is a mp3 extention.
Can anyone please send me any link which will help me to solve this error.
Thanks in advancekhadijarss 14:26, 22 March 2012 (EET)
Khadijarss - error "MediaSource::Stream not yet handled"
Hi i tried to create a application with phonon API so as to play music from the server, but i would like to show a progress bar to watch loading state, i try to do that by using Qbuffer and i associate it to my mediaObject but i get this error "MediaSource::Stream not yet handled", i would like to know if there is a function in phonon that return a buffer size.
thanks in advance for your help.khadijarss 13:36, 29 March 2012 (EEST)