source: trunk/src/3rdparty/phonon/mmf/mediaobject.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 15.7 KB
Line 
1/* This file is part of the KDE project.
2
3Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
5This library is free software: you can redistribute it and/or modify
6it under the terms of the GNU Lesser General Public License as published by
7the Free Software Foundation, either version 2.1 or 3 of the License.
8
9This library is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU Lesser General Public License for more details.
13
14You should have received a copy of the GNU Lesser General Public License
15along with this library. If not, see <http://www.gnu.org/licenses/>.
16
17*/
18
19#include "audiooutput.h"
20#include "audioplayer.h"
21#include "defs.h"
22#include "dummyplayer.h"
23#include "utils.h"
24#include "utils.h"
25
26#ifdef PHONON_MMF_VIDEO_SURFACES
27#include "videoplayer_surface.h"
28#else
29#include "videoplayer_dsa.h"
30#endif
31
32#include "videowidget.h"
33
34#include "mediaobject.h"
35
36#include <QDir>
37#include <QResource>
38#include <QUrl>
39#include <cdbcols.h>
40#include <cdblen.h>
41#include <commdb.h>
42#include <mmf/common/mmfcontrollerframeworkbase.h>
43
44QT_BEGIN_NAMESPACE
45
46using namespace Phonon;
47using namespace Phonon::MMF;
48
49/*! \class MMF::MediaObject
50 \internal
51*/
52
53//-----------------------------------------------------------------------------
54// Constructor / destructor
55//-----------------------------------------------------------------------------
56
57MMF::MediaObject::MediaObject(QObject *parent) : MMF::MediaNode::MediaNode(parent)
58 , m_recognizerOpened(false)
59 , m_nextSourceSet(false)
60 , m_file(0)
61 , m_resource(0)
62{
63 m_player.reset(new DummyPlayer());
64
65 TRACE_CONTEXT(MediaObject::MediaObject, EAudioApi);
66 TRACE_ENTRY_0();
67
68 const int err = m_fileServer.Connect();
69 QT_TRAP_THROWING(User::LeaveIfError(err));
70
71 parent->installEventFilter(this);
72 m_iap = KUseDefaultIap;
73
74 TRACE_EXIT_0();
75}
76
77MMF::MediaObject::~MediaObject()
78{
79 TRACE_CONTEXT(MediaObject::~MediaObject, EAudioApi);
80 TRACE_ENTRY_0();
81
82 parent()->removeEventFilter(this);
83 delete m_resource;
84
85 if (m_file)
86 m_file->Close();
87 delete m_file;
88
89 m_fileServer.Close();
90 m_recognizer.Close();
91
92 TRACE_EXIT_0();
93}
94
95
96//-----------------------------------------------------------------------------
97// Recognizer
98//-----------------------------------------------------------------------------
99
100bool MMF::MediaObject::openRecognizer()
101{
102 TRACE_CONTEXT(MediaObject::openRecognizer, EAudioInternal);
103
104 if (!m_recognizerOpened) {
105 TInt err = m_recognizer.Connect();
106 if (KErrNone != err) {
107 TRACE("RApaLsSession::Connect error %d", err);
108 return false;
109 }
110
111 // This must be called in order to be able to share file handles with
112 // the recognizer server (see fileMediaType function).
113 err = m_fileServer.ShareProtected();
114 if (KErrNone != err) {
115 TRACE("RFs::ShareProtected error %d", err);
116 return false;
117 }
118
119 m_recognizerOpened = true;
120 }
121
122 return true;
123}
124
125MMF::MediaType MMF::MediaObject::fileMediaType
126(const QString& fileName)
127{
128 TRACE_CONTEXT(MediaObject::fileMediaType, EAudioInternal);
129
130 MediaType result = MediaTypeUnknown;
131
132 if (openRecognizer()) {
133 TInt err = openFileHandle(fileName);
134 const QHBufC nativeFileName(QDir::toNativeSeparators(fileName));
135 if (KErrNone == err) {
136 TDataRecognitionResult recognizerResult;
137 err = m_recognizer.RecognizeData(*m_file, recognizerResult);
138 if (KErrNone == err) {
139 const TPtrC mimeType = recognizerResult.iDataType.Des();
140 result = Utils::mimeTypeToMediaType(mimeType);
141 } else {
142 TRACE("RApaLsSession::RecognizeData filename %S error %d", nativeFileName.data(), err);
143 }
144 } else {
145 TRACE("RFile::Open filename %S error %d", nativeFileName.data(), err);
146 }
147 }
148
149 return result;
150}
151
152int MMF::MediaObject::openFileHandle(const QString &fileName)
153{
154 TRACE_CONTEXT(MediaObject::openFileHandle, EAudioInternal);
155 const QHBufC nativeFileName(QDir::toNativeSeparators(fileName));
156 TRACE_ENTRY("filename %S", nativeFileName.data());
157 if (m_file)
158 m_file->Close();
159 delete m_file;
160 m_file = 0;
161 m_file = new RFile;
162 TInt err = m_file->Open(m_fileServer, *nativeFileName, EFileRead | EFileShareReadersOrWriters);
163 return err;
164}
165
166MMF::MediaType MMF::MediaObject::bufferMediaType(const uchar *data, qint64 size)
167{
168 TRACE_CONTEXT(MediaObject::bufferMediaType, EAudioInternal);
169 MediaType result = MediaTypeUnknown;
170 if (openRecognizer()) {
171 TDataRecognitionResult recognizerResult;
172 const TPtrC8 des(data, size);
173 const TInt err = m_recognizer.RecognizeData(KNullDesC, des, recognizerResult);
174 if (KErrNone == err) {
175 const TPtrC mimeType = recognizerResult.iDataType.Des();
176 result = Utils::mimeTypeToMediaType(mimeType);
177 } else {
178 TRACE("RApaLsSession::RecognizeData error %d", err);
179 }
180 }
181 return result;
182}
183
184//-----------------------------------------------------------------------------
185// MediaObjectInterface
186//-----------------------------------------------------------------------------
187
188void MMF::MediaObject::play()
189{
190 m_player->play();
191}
192
193void MMF::MediaObject::pause()
194{
195 m_player->pause();
196}
197
198void MMF::MediaObject::stop()
199{
200 m_player->stop();
201}
202
203void MMF::MediaObject::seek(qint64 ms)
204{
205 m_player->seek(ms);
206
207 if (state() == PausedState or state() == PlayingState) {
208 emit tick(currentTime());
209 }
210}
211
212qint32 MMF::MediaObject::tickInterval() const
213{
214 return m_player->tickInterval();
215}
216
217void MMF::MediaObject::setTickInterval(qint32 interval)
218{
219 m_player->setTickInterval(interval);
220}
221
222bool MMF::MediaObject::hasVideo() const
223{
224 return m_player->hasVideo();
225}
226
227bool MMF::MediaObject::isSeekable() const
228{
229 return m_player->isSeekable();
230}
231
232Phonon::State MMF::MediaObject::state() const
233{
234 return m_player->state();
235}
236
237qint64 MMF::MediaObject::currentTime() const
238{
239 return m_player->currentTime();
240}
241
242QString MMF::MediaObject::errorString() const
243{
244 return m_player->errorString();
245}
246
247Phonon::ErrorType MMF::MediaObject::errorType() const
248{
249 return m_player->errorType();
250}
251
252qint64 MMF::MediaObject::totalTime() const
253{
254 return m_player->totalTime();
255}
256
257MediaSource MMF::MediaObject::source() const
258{
259 return m_source;
260}
261
262void MMF::MediaObject::setSource(const MediaSource &source)
263{
264 switchToSource(source);
265}
266
267void MMF::MediaObject::switchToSource(const MediaSource &source)
268{
269 if (m_file)
270 m_file->Close();
271 delete m_file;
272 m_file = 0;
273
274 delete m_resource;
275 m_resource = 0;
276
277 createPlayer(source);
278 m_source = source;
279 m_player->open();
280 emit currentSourceChanged(m_source);
281}
282
283void MMF::MediaObject::createPlayer(const MediaSource &source)
284{
285 TRACE_CONTEXT(MediaObject::createPlayer, EAudioApi);
286 TRACE_ENTRY("state %d source.type %d", state(), source.type());
287 TRACE_ENTRY("source.type %d", source.type());
288
289 MediaType mediaType = MediaTypeUnknown;
290
291 AbstractPlayer* oldPlayer = m_player.data();
292
293 const bool oldPlayerHasVideo = oldPlayer->hasVideo();
294 const bool oldPlayerSeekable = oldPlayer->isSeekable();
295
296 QString errorMessage;
297
298 // Determine media type
299 switch (source.type()) {
300 case MediaSource::LocalFile:
301 mediaType = fileMediaType(source.fileName());
302 break;
303
304 case MediaSource::Url:
305 {
306 const QUrl url(source.url());
307 if (url.scheme() == QLatin1String("file")) {
308 mediaType = fileMediaType(url.toLocalFile());
309 }
310 else {
311 // Streaming playback is generally not supported by the implementation
312 // of the audio player API, so we use CVideoPlayerUtility for both
313 // audio and video streaming.
314 mediaType = MediaTypeVideo;
315 }
316 }
317 break;
318
319 case MediaSource::Invalid:
320 case MediaSource::Disc:
321 errorMessage = tr("Error opening source: type not supported");
322 break;
323
324 case MediaSource::Stream:
325 {
326 const QString fileName = source.url().toLocalFile();
327 if (fileName.startsWith(QLatin1String(":/")) || fileName.startsWith(QLatin1String("qrc://"))) {
328 Q_ASSERT(!m_resource);
329 m_resource = new QResource(fileName);
330 if (m_resource->isValid()) {
331 if (m_resource->isCompressed())
332 errorMessage = tr("Error opening source: resource is compressed");
333 else
334 mediaType = bufferMediaType(m_resource->data(), m_resource->size());
335 } else {
336 errorMessage = tr("Error opening source: resource not valid");
337 }
338 } else {
339 errorMessage = tr("Error opening source: type not supported");
340 }
341 }
342 break;
343
344 case MediaSource::Empty:
345 TRACE_0("Empty media source");
346 break;
347 }
348
349 if (oldPlayer)
350 oldPlayer->close();
351
352 AbstractPlayer* newPlayer = 0;
353
354 // Construct newPlayer using oldPlayer (if not 0) in order to copy
355 // parameters (volume, prefinishMark, transitionTime) which may have
356 // been set on oldPlayer.
357
358 switch (mediaType) {
359 case MediaTypeUnknown:
360 TRACE_0("Media type could not be determined");
361 newPlayer = new DummyPlayer(oldPlayer);
362 errorMessage = tr("Error opening source: media type could not be determined");
363 break;
364
365 case MediaTypeAudio:
366 newPlayer = new AudioPlayer(this, oldPlayer);
367 break;
368
369 case MediaTypeVideo:
370#ifdef PHONON_MMF_VIDEO_SURFACES
371 newPlayer = SurfaceVideoPlayer::create(this, oldPlayer);
372#else
373 newPlayer = DsaVideoPlayer::create(this, oldPlayer);
374#endif
375 break;
376 }
377
378 if (oldPlayer)
379 emit abstractPlayerChanged(0);
380 m_player.reset(newPlayer);
381 emit abstractPlayerChanged(newPlayer);
382
383 if (oldPlayerHasVideo != hasVideo()) {
384 emit hasVideoChanged(hasVideo());
385 }
386
387 if (oldPlayerSeekable != isSeekable()) {
388 emit seekableChanged(isSeekable());
389 }
390
391 connect(m_player.data(), SIGNAL(totalTimeChanged(qint64)), SIGNAL(totalTimeChanged(qint64)));
392 connect(m_player.data(), SIGNAL(stateChanged(Phonon::State,Phonon::State)), SIGNAL(stateChanged(Phonon::State,Phonon::State)));
393 connect(m_player.data(), SIGNAL(finished()), SIGNAL(finished()));
394 connect(m_player.data(), SIGNAL(bufferStatus(int)), SIGNAL(bufferStatus(int)));
395 connect(m_player.data(), SIGNAL(metaDataChanged(QMultiMap<QString,QString>)), SIGNAL(metaDataChanged(QMultiMap<QString,QString>)));
396 connect(m_player.data(), SIGNAL(aboutToFinish()), SIGNAL(aboutToFinish()));
397 connect(m_player.data(), SIGNAL(prefinishMarkReached(qint32)), SIGNAL(prefinishMarkReached(qint32)));
398 connect(m_player.data(), SIGNAL(prefinishMarkReached(qint32)), SLOT(handlePrefinishMarkReached(qint32)));
399 connect(m_player.data(), SIGNAL(tick(qint64)), SIGNAL(tick(qint64)));
400
401 // We need to call setError() after doing the connects, otherwise the
402 // error won't be received.
403 if (!errorMessage.isEmpty()) {
404 Q_ASSERT(m_player);
405 m_player->setError(errorMessage);
406 }
407
408 TRACE_EXIT_0();
409}
410
411void MMF::MediaObject::setNextSource(const MediaSource &source)
412{
413 m_nextSource = source;
414 m_nextSourceSet = true;
415}
416
417qint32 MMF::MediaObject::prefinishMark() const
418{
419 return m_player->prefinishMark();
420}
421
422void MMF::MediaObject::setPrefinishMark(qint32 mark)
423{
424 m_player->setPrefinishMark(mark);
425}
426
427qint32 MMF::MediaObject::transitionTime() const
428{
429 return m_player->transitionTime();
430}
431
432void MMF::MediaObject::setTransitionTime(qint32 time)
433{
434 m_player->setTransitionTime(time);
435}
436
437void MMF::MediaObject::volumeChanged(qreal volume)
438{
439 m_player->volumeChanged(volume);
440}
441
442RFile* MMF::MediaObject::file() const
443{
444 return m_file;
445}
446
447QResource* MMF::MediaObject::resource() const
448{
449 return m_resource;
450}
451
452//-----------------------------------------------------------------------------
453// MediaNode
454//-----------------------------------------------------------------------------
455
456void MMF::MediaObject::connectMediaObject(MediaObject * /*mediaObject*/)
457{
458 // This function should never be called - see MediaNode::setMediaObject()
459 Q_ASSERT_X(false, Q_FUNC_INFO,
460 "Connection of MediaObject to MediaObject");
461}
462
463void MMF::MediaObject::disconnectMediaObject(MediaObject * /*mediaObject*/)
464{
465 // This function should never be called - see MediaNode::setMediaObject()
466 Q_ASSERT_X(false, Q_FUNC_INFO,
467 "Disconnection of MediaObject from MediaObject");
468}
469
470
471//-----------------------------------------------------------------------------
472// Video output
473//-----------------------------------------------------------------------------
474
475void MMF::MediaObject::setVideoOutput(AbstractVideoOutput* videoOutput)
476{
477 m_player->setVideoOutput(videoOutput);
478}
479
480
481AbstractPlayer *MMF::MediaObject::abstractPlayer() const
482{
483 return m_player.data();
484}
485
486//-----------------------------------------------------------------------------
487// Playlist support
488//-----------------------------------------------------------------------------
489
490void MMF::MediaObject::switchToNextSource()
491{
492 if (m_nextSourceSet) {
493 m_nextSourceSet = false;
494 switchToSource(m_nextSource);
495 play();
496 } else {
497 emit finished();
498 }
499}
500
501//-----------------------------------------------------------------------------
502// IAP support
503//-----------------------------------------------------------------------------
504
505int MMF::MediaObject::currentIAP() const
506{
507 return m_iap;
508}
509
510bool MMF::MediaObject::eventFilter(QObject *watched, QEvent *event)
511{
512 if (event->type() == QEvent::DynamicPropertyChange ) {
513 QDynamicPropertyChangeEvent* dynamicEvent = static_cast<QDynamicPropertyChangeEvent*>(event);
514 if (dynamicEvent->propertyName() == "InternetAccessPointName") {
515 QVariant value = watched->property("InternetAccessPointName");
516 if (value.isValid()) {
517 QString iapName = value.toString();
518 TRAPD(err, setIAPIdFromNameL(iapName));
519 if (err)
520 m_player->setError(tr("Failed to set requested IAP"), err);
521 }
522 }
523 }
524 return false;
525}
526
527void MMF::MediaObject::setIAPIdFromNameL(const QString& iapString)
528{
529 TRACE_CONTEXT(MediaObject::getIapIdFromName, EVideoInternal);
530 TBuf<KCommsDbSvrMaxColumnNameLength> iapDes = qt_QString2TPtrC(iapString);
531 CCommsDatabase *commsDb = CCommsDatabase::NewL(EDatabaseTypeIAP);
532 CleanupStack::PushL(commsDb);
533 commsDb->ShowHiddenRecords();
534 CCommsDbTableView *view = commsDb->OpenTableLC(TPtrC(IAP));
535 for (TInt l = view->GotoFirstRecord(); l != KErrNotFound; l = view->GotoNextRecord()) {
536 TBuf<KCommsDbSvrMaxColumnNameLength> iapName;
537 view->ReadTextL(TPtrC(COMMDB_NAME), iapName);
538 TRACE("found IAP %S", &iapName);
539 if (iapName.CompareF(iapDes) == 0) {
540 TUint32 uiap;
541 view->ReadUintL(TPtrC(COMMDB_ID), uiap);
542 TRACE("matched IAP %S, setting m_iap %d", &iapName, uiap);
543 m_iap = uiap;
544 break;
545 }
546 }
547 CleanupStack::PopAndDestroy(2); // commsDb, view
548}
549
550//-----------------------------------------------------------------------------
551// Other private functions
552//-----------------------------------------------------------------------------
553
554void MMF::MediaObject::handlePrefinishMarkReached(qint32 time)
555{
556 emit tick(time);
557}
558
559
560QT_END_NAMESPACE
561
Note: See TracBrowser for help on using the repository browser.