1
/* This file is part of the KDE project.
3
Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
5
This library is free software: you can redistribute it and/or modify
6
it under the terms of the GNU Lesser General Public License as published by
7
the Free Software Foundation, either version 2.1 or 3 of the License.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU Lesser General Public License for more details.
14
You should have received a copy of the GNU Lesser General Public License
15
along with this library. If not, see <http://www.gnu.org/licenses/>.
19
#include "audiooutput.h"
20
#include "audioplayer.h"
22
#include "dummyplayer.h"
26
#ifdef PHONON_MMF_VIDEO_SURFACES
27
#include "videoplayer_surface.h"
29
#include "videoplayer_dsa.h"
32
#include "videowidget.h"
34
#include "mediaobject.h"
42
using namespace Phonon;
43
using namespace Phonon::MMF;
45
/*! \class MMF::MediaObject
49
//-----------------------------------------------------------------------------
50
// Constructor / destructor
51
//-----------------------------------------------------------------------------
53
MMF::MediaObject::MediaObject(QObject *parent) : MMF::MediaNode::MediaNode(parent)
54
, m_recognizerOpened(false)
55
, m_nextSourceSet(false)
59
m_player.reset(new DummyPlayer());
61
TRACE_CONTEXT(MediaObject::MediaObject, EAudioApi);
69
MMF::MediaObject::~MediaObject()
71
TRACE_CONTEXT(MediaObject::~MediaObject, EAudioApi);
87
//-----------------------------------------------------------------------------
89
//-----------------------------------------------------------------------------
91
bool MMF::MediaObject::openRecognizer()
93
TRACE_CONTEXT(MediaObject::openRecognizer, EAudioInternal);
95
if (!m_recognizerOpened) {
96
TInt err = m_recognizer.Connect();
97
if (KErrNone != err) {
98
TRACE("RApaLsSession::Connect error %d", err);
102
err = m_fileServer.Connect();
103
if (KErrNone != err) {
104
TRACE("RFs::Connect error %d", err);
108
// This must be called in order to be able to share file handles with
109
// the recognizer server (see fileMediaType function).
110
err = m_fileServer.ShareProtected();
111
if (KErrNone != err) {
112
TRACE("RFs::ShareProtected error %d", err);
116
m_recognizerOpened = true;
122
MMF::MediaType MMF::MediaObject::fileMediaType
123
(const QString& fileName)
125
TRACE_CONTEXT(MediaObject::fileMediaType, EAudioInternal);
127
MediaType result = MediaTypeUnknown;
129
if (openRecognizer()) {
131
const QHBufC fileNameSymbian(QDir::toNativeSeparators(fileName));
135
TInt err = m_file->Open(m_fileServer, *fileNameSymbian, EFileRead | EFileShareReadersOnly);
137
if (KErrNone == err) {
138
TDataRecognitionResult recognizerResult;
139
err = m_recognizer.RecognizeData(*m_file, recognizerResult);
140
if (KErrNone == err) {
141
const TPtrC mimeType = recognizerResult.iDataType.Des();
142
result = Utils::mimeTypeToMediaType(mimeType);
144
TRACE("RApaLsSession::RecognizeData filename %S error %d", fileNameSymbian.data(), err);
147
TRACE("RFile::Open filename %S error %d", fileNameSymbian.data(), err);
154
MMF::MediaType MMF::MediaObject::bufferMediaType(const uchar *data, qint64 size)
156
TRACE_CONTEXT(MediaObject::bufferMediaType, EAudioInternal);
157
MediaType result = MediaTypeUnknown;
158
if (openRecognizer()) {
159
TDataRecognitionResult recognizerResult;
160
const TPtrC8 des(data, size);
161
const TInt err = m_recognizer.RecognizeData(des, recognizerResult);
162
if (KErrNone == err) {
163
const TPtrC mimeType = recognizerResult.iDataType.Des();
164
result = Utils::mimeTypeToMediaType(mimeType);
166
TRACE("RApaLsSession::RecognizeData error %d", err);
172
//-----------------------------------------------------------------------------
173
// MediaObjectInterface
174
//-----------------------------------------------------------------------------
176
void MMF::MediaObject::play()
181
void MMF::MediaObject::pause()
186
void MMF::MediaObject::stop()
191
void MMF::MediaObject::seek(qint64 ms)
195
if (state() == PausedState or state() == PlayingState) {
196
emit tick(currentTime());
200
qint32 MMF::MediaObject::tickInterval() const
202
return m_player->tickInterval();
205
void MMF::MediaObject::setTickInterval(qint32 interval)
207
m_player->setTickInterval(interval);
210
bool MMF::MediaObject::hasVideo() const
212
return m_player->hasVideo();
215
bool MMF::MediaObject::isSeekable() const
217
return m_player->isSeekable();
220
Phonon::State MMF::MediaObject::state() const
222
return m_player->state();
225
qint64 MMF::MediaObject::currentTime() const
227
return m_player->currentTime();
230
QString MMF::MediaObject::errorString() const
232
return m_player->errorString();
235
Phonon::ErrorType MMF::MediaObject::errorType() const
237
return m_player->errorType();
240
qint64 MMF::MediaObject::totalTime() const
242
return m_player->totalTime();
245
MediaSource MMF::MediaObject::source() const
250
void MMF::MediaObject::setSource(const MediaSource &source)
252
switchToSource(source);
255
void MMF::MediaObject::switchToSource(const MediaSource &source)
265
createPlayer(source);
268
emit currentSourceChanged(m_source);
271
void MMF::MediaObject::createPlayer(const MediaSource &source)
273
TRACE_CONTEXT(MediaObject::createPlayer, EAudioApi);
274
TRACE_ENTRY("state %d source.type %d", state(), source.type());
275
TRACE_ENTRY("source.type %d", source.type());
277
MediaType mediaType = MediaTypeUnknown;
279
AbstractPlayer* oldPlayer = m_player.data();
281
const bool oldPlayerHasVideo = oldPlayer->hasVideo();
282
const bool oldPlayerSeekable = oldPlayer->isSeekable();
284
QString errorMessage;
286
// Determine media type
287
switch (source.type()) {
288
case MediaSource::LocalFile:
289
mediaType = fileMediaType(source.fileName());
292
case MediaSource::Url:
294
const QUrl url(source.url());
295
if (url.scheme() == QLatin1String("file")) {
296
mediaType = fileMediaType(url.toLocalFile());
299
// Streaming playback is generally not supported by the implementation
300
// of the audio player API, so we use CVideoPlayerUtility for both
301
// audio and video streaming.
302
mediaType = MediaTypeVideo;
307
case MediaSource::Invalid:
308
case MediaSource::Disc:
309
errorMessage = tr("Error opening source: type not supported");
312
case MediaSource::Stream:
314
const QString fileName = source.url().toLocalFile();
315
if (fileName.startsWith(QLatin1String(":/")) || fileName.startsWith(QLatin1String("qrc://"))) {
316
Q_ASSERT(!m_resource);
317
m_resource = new QResource(fileName);
318
if (m_resource->isValid()) {
319
if (m_resource->isCompressed())
320
errorMessage = tr("Error opening source: resource is compressed");
322
mediaType = bufferMediaType(m_resource->data(), m_resource->size());
324
errorMessage = tr("Error opening source: resource not valid");
327
errorMessage = tr("Error opening source: type not supported");
332
case MediaSource::Empty:
333
TRACE_0("Empty media source");
340
AbstractPlayer* newPlayer = 0;
342
// Construct newPlayer using oldPlayer (if not 0) in order to copy
343
// parameters (volume, prefinishMark, transitionTime) which may have
344
// been set on oldPlayer.
347
case MediaTypeUnknown:
348
TRACE_0("Media type could not be determined");
349
newPlayer = new DummyPlayer(oldPlayer);
350
errorMessage = tr("Error opening source: media type could not be determined");
354
newPlayer = new AudioPlayer(this, oldPlayer);
358
#ifdef PHONON_MMF_VIDEO_SURFACES
359
newPlayer = SurfaceVideoPlayer::create(this, oldPlayer);
361
newPlayer = DsaVideoPlayer::create(this, oldPlayer);
367
emit abstractPlayerChanged(0);
368
m_player.reset(newPlayer);
369
emit abstractPlayerChanged(newPlayer);
371
if (oldPlayerHasVideo != hasVideo()) {
372
emit hasVideoChanged(hasVideo());
375
if (oldPlayerSeekable != isSeekable()) {
376
emit seekableChanged(isSeekable());
379
connect(m_player.data(), SIGNAL(totalTimeChanged(qint64)), SIGNAL(totalTimeChanged(qint64)));
380
connect(m_player.data(), SIGNAL(stateChanged(Phonon::State,Phonon::State)), SIGNAL(stateChanged(Phonon::State,Phonon::State)));
381
connect(m_player.data(), SIGNAL(finished()), SIGNAL(finished()));
382
connect(m_player.data(), SIGNAL(bufferStatus(int)), SIGNAL(bufferStatus(int)));
383
connect(m_player.data(), SIGNAL(metaDataChanged(QMultiMap<QString,QString>)), SIGNAL(metaDataChanged(QMultiMap<QString,QString>)));
384
connect(m_player.data(), SIGNAL(aboutToFinish()), SIGNAL(aboutToFinish()));
385
connect(m_player.data(), SIGNAL(prefinishMarkReached(qint32)), SIGNAL(prefinishMarkReached(qint32)));
386
connect(m_player.data(), SIGNAL(prefinishMarkReached(qint32)), SLOT(handlePrefinishMarkReached(qint32)));
387
connect(m_player.data(), SIGNAL(tick(qint64)), SIGNAL(tick(qint64)));
389
// We need to call setError() after doing the connects, otherwise the
390
// error won't be received.
391
if (!errorMessage.isEmpty()) {
393
m_player->setError(errorMessage);
399
void MMF::MediaObject::setNextSource(const MediaSource &source)
401
m_nextSource = source;
402
m_nextSourceSet = true;
405
qint32 MMF::MediaObject::prefinishMark() const
407
return m_player->prefinishMark();
410
void MMF::MediaObject::setPrefinishMark(qint32 mark)
412
m_player->setPrefinishMark(mark);
415
qint32 MMF::MediaObject::transitionTime() const
417
return m_player->transitionTime();
420
void MMF::MediaObject::setTransitionTime(qint32 time)
422
m_player->setTransitionTime(time);
425
void MMF::MediaObject::volumeChanged(qreal volume)
427
m_player->volumeChanged(volume);
430
RFile* MMF::MediaObject::file() const
435
QResource* MMF::MediaObject::resource() const
440
//-----------------------------------------------------------------------------
442
//-----------------------------------------------------------------------------
444
void MMF::MediaObject::connectMediaObject(MediaObject * /*mediaObject*/)
446
// This function should never be called - see MediaNode::setMediaObject()
447
Q_ASSERT_X(false, Q_FUNC_INFO,
448
"Connection of MediaObject to MediaObject");
451
void MMF::MediaObject::disconnectMediaObject(MediaObject * /*mediaObject*/)
453
// This function should never be called - see MediaNode::setMediaObject()
454
Q_ASSERT_X(false, Q_FUNC_INFO,
455
"Disconnection of MediaObject from MediaObject");
459
//-----------------------------------------------------------------------------
461
//-----------------------------------------------------------------------------
463
void MMF::MediaObject::setVideoOutput(AbstractVideoOutput* videoOutput)
465
m_player->setVideoOutput(videoOutput);
469
AbstractPlayer *MMF::MediaObject::abstractPlayer() const
471
return m_player.data();
474
//-----------------------------------------------------------------------------
476
//-----------------------------------------------------------------------------
478
void MMF::MediaObject::switchToNextSource()
480
if (m_nextSourceSet) {
481
m_nextSourceSet = false;
482
switchToSource(m_nextSource);
489
//-----------------------------------------------------------------------------
490
// Other private functions
491
//-----------------------------------------------------------------------------
493
void MMF::MediaObject::handlePrefinishMarkReached(qint32 time)