phonon music player 开发文档

TheMusic Player Example shows how to use Phonon - the multimediaframework that comes with Qt - to create a simple music player. Theplayer can play music files, and provides simple playback control,such as pausing, stopping, and resuming the music.


Theplayer has a button group with the play, pause, and stop buttonsfamiliar from most music players. The top-most slider controls theposition in the media stream, and the bottom slider allows adjustingthe sound volume.

Theuser can use a file dialog to add music files to a table, whichdisplays meta information about the music - such as the title, album,and artist. Each row contains information about a single music file;to play it, the user selects that row and presses the play button.Also, when a row is selected, the files in the table are queued forplayback.

Phononoffers playback of sound using an available audio device, e.g., asound card or an USB headset. For the implementation, we use twoobjects: a MediaObject,which controls the playback, and anAudioOutput,which can output the audio to a sound device. We will explain howthey cooperate when we encounter them in the code. For a high-levelintroduction to Phonon, see its overview.

TheAPI of Phonon is implemented through an intermediate technology oneach supported platform: DirectShow, QuickTime, and GStreamer. Thesound formats supported may therefore vary from system to system. Wedo not in this example try to determine which formats are supported,but let Phonon report an error if the user tries to play anunsupported sound file.

Ourplayer consists of one class, MainWindow,which both constructs the GUI and handles the playback. We will nowgo through the parts of its definition and implementation thatconcerns Phonon.



MainWindowClass Definition

Mostof the API in MainWindow isprivate, as is often the case for classes that representself-contained windows. We list Phonon objects and slots we connectto their signals; we take a closer look at them when we walk throughthe MainWindow implementation.

Phonon::SeekSlider*seekSlider;

Phonon::MediaObject*mediaObject;

Phonon::MediaObject*metaInformationResolver;

Phonon::AudioOutput*audioOutput;

Phonon::VolumeSlider*volumeSlider;

QList<Phonon::MediaSource>sources;

Weuse the SeekSlider tomove the current playback position in the media stream, andtheVolumeSlider controlsthe sound volume. Both of these widgets come ready made with Phonon.We use another MediaObject,metaInformationProvider, to get the meta information from the musicfiles. More on this later.

voidstateChanged(Phonon::State newState, Phonon::State oldState);

voidtick(qint64 time);

voidsourceChanged(const Phonon::MediaSource &source);

voidmetaStateChanged(Phonon::State newState, Phonon::State oldState);

voidaboutToFinish();

voidtableClicked(int row, int column);

The MediaObject informsus of the state of the playback and properties of the media it isplaying back through a series of signals. We connect the signals weneed to slots in MainWindow.ThetableClicked() slotis connected to the table, so that we know when the user requestsplayback of a new music file, by clicking on the table.

MainWindowClass Implementation

The MainWindow classhandles both the user interface and Phonon. We will now take a lookat the code relevant for Phonon. The code required for setting up theGUI is explained elsewhere.

Westart with the constructor:

MainWindow::MainWindow()

{

audioOutput= new Phonon::AudioOutput(Phonon::MusicCategory, this);

mediaObject= new Phonon::MediaObject(this);

metaInformationResolver= new Phonon::MediaObject(this);



mediaObject->setTickInterval(1000);

Westart by instantiating our media and audio output objects. Asmentioned, the media object knows how to playback multimedia (in ourcase sound files) while the audio output can send it to a sounddevice.

Forthe playback to work, the media and audio output objects need to getin contact with each other, so that the media object can send thesound to the audio output. Phonon is a graph based framework, i.e.,its objects are nodes that can be connected by paths. Objects areconnected using the createPath()function,which is part of the Phonon namespace.

Phonon::createPath(mediaObject,audioOutput);

Wealso connect signals of the media object to slots in our MainWindow.We will examine them shortly.

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(metaInformationResolver,SIGNAL(stateChanged(Phonon::State,Phonon::State)),

this,SLOT(metaStateChanged(Phonon::State,Phonon::State)));

connect(mediaObject,SIGNAL(currentSourceChanged(Phonon::MediaSource)),

this,SLOT(sourceChanged(Phonon::MediaSource)));

connect(mediaObject,SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));

Finally,we call private helper functions to set up the GUI.The setupUi() functioncontains code for setting up the seek , and volume slider. We move onto setupUi():

voidMainWindow::setupUi()

{

...

seekSlider= new Phonon::SeekSlider(this);

seekSlider->setMediaObject(mediaObject);



volumeSlider= new Phonon::VolumeSlider(this);

volumeSlider->setAudioOutput(audioOutput);

Aftercreating the widgets, they must be supplied withthe MediaObject and AudioOutput objectsthey should control.

Inthe setupActions(),we connect the actions for the play, pause, and stop tool buttons, toslots of the media object.

connect(playAction,SIGNAL(triggered()), mediaObject, SLOT(play()));

connect(pauseAction,SIGNAL(triggered()), mediaObject, SLOT(pause()) );

connect(stopAction,SIGNAL(triggered()), mediaObject, SLOT(stop()));

Wemove on to the slots of MainWindow,starting with addFiles():

voidMainWindow::addFiles()

{

QStringListfiles = QFileDialog::getOpenFileNames(this, tr("Select MusicFiles"),

QDesktopServices::storageLocation(QDesktopServices::MusicLocation));



if(files.isEmpty())

return;



intindex = sources.size();

foreach(QString string, files) {

Phonon::MediaSourcesource(string);



sources.append(source);

}

if(!sources.isEmpty())

metaInformationResolver->setCurrentSource(sources.at(index));



}

Inthe addFiles() slot,we add files selected by the user to the sources list.We then set the first source selected onthe metaInformationProvider MediaObject,which will send a state changed signal when the meta information isresolved; we have this signal connected tothe metaStateChanged() slot.

Themedia object informs us of state changes by sendingthe stateChanged() signal.ThestateChanged() slotis connected to this signal.

voidMainWindow::stateChanged(Phonon::State newState, Phonon::State /*oldState */)

{

switch(newState) {

casePhonon::ErrorState:

if(mediaObject->errorType() == Phonon::FatalError) {

QMessageBox::warning(this,tr("Fatal Error"),

mediaObject->errorString());

}else {

QMessageBox::warning(this,tr("Error"),

mediaObject->errorString());

}

break;

The errorString() functiongives a description of the error that is suitable for users of aPhonon application. The two values of the ErrorState enumhelps us determine whether it is possible to try to play the samefile again.

casePhonon::PlayingState:

playAction->setEnabled(false);

pauseAction->setEnabled(true);

stopAction->setEnabled(true);

break;

casePhonon::StoppedState:

stopAction->setEnabled(false);

playAction->setEnabled(true);

pauseAction->setEnabled(false);

timeLcd->display("00:00");

break;

casePhonon::PausedState:

pauseAction->setEnabled(false);

stopAction->setEnabled(true);

playAction->setEnabled(true);

break;

Weupdate the GUI when the playback state changes, i.e., when it starts,pauses, stops, or resumes.

Themedia object will report other state changes, as defined bythe State enum.

The tick() slotis connected to a MediaObject signalwhich is emitted when the playback position changes:

voidMainWindow::tick(qint64 time)

{

QTimedisplayTime(0, (time / 60000) % 60, (time / 1000) % 60);



timeLcd->display(displayTime.toString("mm:ss"));

}

The time isgiven in milliseconds.

Whenthe table is clicked on with the mouse, tableClick() isinvoked:

voidMainWindow::tableClicked(int row, int /*column */)

{

boolwasPlaying = mediaObject->state() == Phonon::PlayingState;



mediaObject->stop();

mediaObject->clearQueue();



if(row >= sources.size())

return;



mediaObject->setCurrentSource(sources[row]);



if(wasPlaying)

mediaObject->play();

else

mediaObject->stop();

}

Sincewe stop the media object, we first check whether it is currentlyplaying. row containsthe row in the table that was clicked upon; the indicesof sources followsthe table, so we can simply use row tofind the new source.

voidMainWindow::sourceChanged(const Phonon::MediaSource &source)

{

musicTable->selectRow(sources.indexOf(source));

timeLcd->display("00:00");

}

Whenthe media source changes, we simply need to select the correspondingrow in the table.

voidMainWindow::metaStateChanged(Phonon::State newState, Phonon::State /*oldState */)

{

if(newState == Phonon::ErrorState) {

QMessageBox::warning(this,tr("Error opening files"),

metaInformationResolver->errorString());

while(!sources.isEmpty() &&

!(sources.takeLast()== metaInformationResolver->currentSource())) {} /*loop */;

return;

}



if(newState != Phonon::StoppedState && newState !=Phonon::PausedState)

return;



if(metaInformationResolver->currentSource().type() ==Phonon::MediaSource::Invalid)

return;



QMap<QString,QString> metaData = metaInformationResolver->metaData();



QStringtitle = metaData.value("TITLE");

if(title == "")

title= metaInformationResolver->currentSource().fileName();



QTableWidgetItem*titleItem = new QTableWidgetItem(title);

titleItem->setFlags(titleItem->flags()^ Qt::ItemIsEditable);

QTableWidgetItem*artistItem = new QTableWidgetItem(metaData.value("ARTIST"));

artistItem->setFlags(artistItem->flags()^ Qt::ItemIsEditable);

QTableWidgetItem*albumItem = new QTableWidgetItem(metaData.value("ALBUM"));

albumItem->setFlags(albumItem->flags()^ Qt::ItemIsEditable);

QTableWidgetItem*yearItem = new QTableWidgetItem(metaData.value("DATE"));

yearItem->setFlags(yearItem->flags()^ Qt::ItemIsEditable);

When metaStateChanged() isinvoked, metaInformationProvider hasresolved the meta data for its current source. A MediaObject willdo this before entering StoppedState.Note that we could also have used the metaDataChanged() signalfor this purpose.

Someof the meta data is then chosen to be displayed in the music table. Afile might not contain the meta data requested, in which case anempty string is returned.

if(musicTable->selectedItems().isEmpty()) {

musicTable->selectRow(0);

mediaObject->setCurrentSource(metaInformationResolver->currentSource());

}



Phonon::MediaSourcesource = metaInformationResolver->currentSource();

intindex = sources.indexOf(metaInformationResolver->currentSource())+ 1;

if(sources.size() > index) {

metaInformationResolver->setCurrentSource(sources.at(index));

}

else{

musicTable->resizeColumnsToContents();

if(musicTable->columnWidth(0) > 300)

musicTable->setColumnWidth(0,300);

}

}

Ifwe have media sources in sources ofwhich meta information is not resolved, we set a new source onthe metaInformationProvider,which will invoke metaStateChanged() again.

Wemove on to the aboutToFinish() slot:

voidMainWindow::aboutToFinish()

{

intindex = sources.indexOf(mediaObject->currentSource()) + 1;

if(sources.size() > index) {

mediaObject->enqueue(sources.at(index));

}

}

Whena file is finished playing, the Music Player will move on and playthe next file in the table. This slot is connected tothe MediaObject's aboutToFinish() signal,which is guaranteed to be emitted while there is still time toenqueue another file for playback.

Themain() function.

Phononrequires that the application has a name; it is setwith setApplicationName().This is because D-Bus, which is used by Phonon on Linux systems,demands this.

intmain(int argv, char **args)

{

QApplicationapp(argv, args);

app.setApplicationName("MusicPlayer");

app.setQuitOnLastWindowClosed(true);



MainWindowwindow;

window.show();



returnapp.exec();

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值