From 1640acce5ca8f49c5655edffa2a1108048c5a414 Mon Sep 17 00:00:00 2001 From: Ruth Sadler Date: Tue, 11 Jan 2011 10:32:46 +0000 Subject: Allow IAP to be selected in Phonon MMF backend The Phonon API does not provide any way for the client to specify which network connection should be used for streaming playback. If the application already has a connection open, using a bearer other than the default (e.g. using WiFi when the device default is GPRS), it may be desirable to use it for streaming, rather than allowing the Phonon backend to open a second connection on the default bearer. This patch adds a custom property on the Phonon::MediaObject, called InternetAccessPointName. The client can specify the IAP which Phonon should use by setting this property. Note that support for this property is only provided in the Phonon MMF backend. Task-number: QTBUG-11436 Reviewed-by: Gareth Stockwell --- demos/qmediaplayer/mediaplayer.cpp | 43 ++++++ demos/qmediaplayer/mediaplayer.h | 6 + demos/qmediaplayer/qmediaplayer.pro | 2 + dist/changes-4.7.2 | 7 + src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 11 +- src/3rdparty/phonon/mmf/abstractmediaplayer.h | 2 +- src/3rdparty/phonon/mmf/abstractvideoplayer.cpp | 4 +- src/3rdparty/phonon/mmf/abstractvideoplayer.h | 2 +- src/3rdparty/phonon/mmf/audioplayer.cpp | 2 +- src/3rdparty/phonon/mmf/audioplayer.h | 2 +- src/3rdparty/phonon/mmf/download.cpp | 9 +- src/3rdparty/phonon/mmf/download.h | 4 +- src/3rdparty/phonon/mmf/mediaobject.cpp | 57 +++++++- src/3rdparty/phonon/mmf/mediaobject.h | 7 + src/plugins/phonon/mmf/mmf.pro | 3 + tests/auto/mediaobject/mediaobject.pro | 2 + tests/auto/mediaobject/tst_mediaobject.cpp | 187 ++++++++++++++++++++++++ 17 files changed, 336 insertions(+), 14 deletions(-) diff --git a/demos/qmediaplayer/mediaplayer.cpp b/demos/qmediaplayer/mediaplayer.cpp index 126031e..68752a0 100644 --- a/demos/qmediaplayer/mediaplayer.cpp +++ b/demos/qmediaplayer/mediaplayer.cpp @@ -46,6 +46,11 @@ #include "mediaplayer.h" #include "ui_settings.h" +#ifdef Q_OS_SYMBIAN +#include +#include +#include +#endif MediaVideoWidget::MediaVideoWidget(MediaPlayer *player, QWidget *parent) : Phonon::VideoWidget(parent), m_player(player), m_action(this) @@ -269,6 +274,10 @@ MediaPlayer::MediaPlayer() : fileMenu = new QMenu(this); QAction *openFileAction = fileMenu->addAction(tr("Open &File...")); QAction *openUrlAction = fileMenu->addAction(tr("Open &Location...")); +#ifdef Q_OS_SYMBIAN + QAction *selectIAPAction = fileMenu->addAction(tr("Select &IAP...")); + connect(selectIAPAction, SIGNAL(triggered(bool)), this, SLOT(selectIAP())); +#endif QAction *const openLinkAction = fileMenu->addAction(tr("Open &RAM File...")); connect(openLinkAction, SIGNAL(triggered(bool)), this, SLOT(openRamFile())); @@ -949,3 +958,37 @@ void MediaPlayer::hasVideoChanged(bool bHasVideo) m_videoWindow.setVisible(bHasVideo); m_fullScreenAction->setEnabled(bHasVideo); } + +#ifdef Q_OS_SYMBIAN +void MediaPlayer::selectIAP() +{ + TRAPD(err, selectIAPL()); + if (KErrNone != err) + QMessageBox::warning(this, "Phonon Mediaplayer", "Error selecting IAP", QMessageBox::Close); +} + +void MediaPlayer::selectIAPL() +{ + QVariant currentIAPValue = m_MediaObject.property("InternetAccessPointName"); + QString currentIAPString = currentIAPValue.toString(); + bool ok = false; + CCommsDatabase *commsDb = CCommsDatabase::NewL(EDatabaseTypeIAP); + CleanupStack::PushL(commsDb); + commsDb->ShowHiddenRecords(); + CCommsDbTableView* view = commsDb->OpenTableLC(TPtrC(IAP)); + QStringList items; + TInt currentIAP = 0; + for (TInt l = view->GotoFirstRecord(), i = 0; l != KErrNotFound; l = view->GotoNextRecord(), i++) { + TBuf iapName; + view->ReadTextL(TPtrC(COMMDB_NAME), iapName); + QString iapString = QString::fromUtf16(iapName.Ptr(), iapName.Length()); + items << iapString; + if (iapString == currentIAPString) + currentIAP = i; + } + currentIAPString = QInputDialog::getItem(this, tr("Select Access Point"), tr("Select Access Point"), items, currentIAP, false, &ok); + if (ok) + m_MediaObject.setProperty("InternetAccessPointName", currentIAPString); + CleanupStack::PopAndDestroy(2); //commsDB, view +} +#endif diff --git a/demos/qmediaplayer/mediaplayer.h b/demos/qmediaplayer/mediaplayer.h index 7803321..7ddb7ae 100644 --- a/demos/qmediaplayer/mediaplayer.h +++ b/demos/qmediaplayer/mediaplayer.h @@ -141,12 +141,18 @@ private slots: void showContextMenu(const QPoint& point); void bufferStatus(int percent); void openUrl(); +#ifdef Q_OS_SYMBIAN + void selectIAP(); +#endif void openRamFile(); void configureEffect(); void hasVideoChanged(bool); private: bool playPauseForDialog(); +#ifdef Q_OS_SYMBIAN + void selectIAPL(); +#endif QIcon playIcon; QIcon pauseIcon; diff --git a/demos/qmediaplayer/qmediaplayer.pro b/demos/qmediaplayer/qmediaplayer.pro index 9407a81..d283ec8 100644 --- a/demos/qmediaplayer/qmediaplayer.pro +++ b/demos/qmediaplayer/qmediaplayer.pro @@ -33,5 +33,7 @@ symbian { include($$QT_SOURCE_TREE/demos/symbianpkgrules.pri) + LIBS += -lCommDb + TARGET.CAPABILITY="NetworkServices" } diff --git a/dist/changes-4.7.2 b/dist/changes-4.7.2 index a18a237..d443d88 100644 --- a/dist/changes-4.7.2 +++ b/dist/changes-4.7.2 @@ -126,6 +126,13 @@ Qt for Mac OS X - +Qt for Symbian +-------------- + + - Phonon MMF backend + * [QTBUG-11436] Added a MediaObject property which allows the client to + specify which Internet Access Point should be used for streaming. + Qt for Embedded Linux --------------------- diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index dfc5840..4f7caff 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -23,6 +23,9 @@ along with this library. If not, see . #include "defs.h" #include "mediaobject.h" #include "utils.h" +#include +#include +#include QT_BEGIN_NAMESPACE @@ -267,11 +270,15 @@ void MMF::AbstractMediaPlayer::open() this, SLOT(downloadLengthChanged(qint64))); connect(m_download, SIGNAL(stateChanged(Download::State)), this, SLOT(downloadStateChanged(Download::State))); - m_download->start(); + int iap = m_parent->currentIAP(); + TRACE("HTTP Url: Using IAP %d", iap); + m_download->start(iap); } #endif else { - symbianErr = openUrl(url.toString()); + int iap = m_parent->currentIAP(); + TRACE("Using IAP %d", iap); + symbianErr = openUrl(url.toString(), iap); if (KErrNone != symbianErr) errorMessage = tr("Error opening URL"); } diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index c3b4528..df0a42f 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -75,7 +75,7 @@ protected: virtual int setDeviceVolume(int mmfVolume) = 0; virtual int openFile(const QString &fileName) = 0; virtual int openFile(RFile& file) = 0; - virtual int openUrl(const QString& url) = 0; + virtual int openUrl(const QString& url, int iap) = 0; virtual int openDescriptor(const TDesC8 &des) = 0; virtual int bufferStatus() const = 0; virtual void doClose() = 0; diff --git a/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp b/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp index 1ab5bae..ad4ee83 100644 --- a/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp @@ -146,9 +146,9 @@ int MMF::AbstractVideoPlayer::openFile(RFile &file) return err; } -int MMF::AbstractVideoPlayer::openUrl(const QString &url) +int MMF::AbstractVideoPlayer::openUrl(const QString &url, int iap) { - TRAPD(err, m_player->OpenUrlL(qt_QString2TPtrC(url))); + TRAPD(err, m_player->OpenUrlL(qt_QString2TPtrC(url), iap)); return err; } diff --git a/src/3rdparty/phonon/mmf/abstractvideoplayer.h b/src/3rdparty/phonon/mmf/abstractvideoplayer.h index 3bc5c7c..21446d2 100644 --- a/src/3rdparty/phonon/mmf/abstractvideoplayer.h +++ b/src/3rdparty/phonon/mmf/abstractvideoplayer.h @@ -66,7 +66,7 @@ public: virtual int setDeviceVolume(int mmfVolume); virtual int openFile(const QString &fileName); virtual int openFile(RFile &file); - virtual int openUrl(const QString &url); + virtual int openUrl(const QString &url, int iap); virtual int openDescriptor(const TDesC8 &des); virtual int bufferStatus() const; virtual void doClose(); diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index dc5c800..2ae6a3d 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -134,7 +134,7 @@ int MMF::AudioPlayer::openFile(RFile& file) return err; } -int MMF::AudioPlayer::openUrl(const QString& /*url*/) +int MMF::AudioPlayer::openUrl(const QString& /*url*/, int /*iap*/) { // Streaming playback is generally not supported by the implementation // of the audio player API, so we use CVideoPlayerUtility for both diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index cf4f6d5..e963c26 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -67,7 +67,7 @@ typedef CMdaAudioPlayerUtility NativePlayer; virtual int setDeviceVolume(int mmfVolume); virtual int openFile(const QString &fileName); virtual int openFile(RFile& file); - virtual int openUrl(const QString& url); + virtual int openUrl(const QString& url, int iap); virtual int openDescriptor(const TDesC8 &des); virtual int bufferStatus() const; virtual void doClose(); diff --git a/src/3rdparty/phonon/mmf/download.cpp b/src/3rdparty/phonon/mmf/download.cpp index 7b80e4a..de65811 100644 --- a/src/3rdparty/phonon/mmf/download.cpp +++ b/src/3rdparty/phonon/mmf/download.cpp @@ -20,6 +20,7 @@ along with this library. If not, see . #include "utils.h" #include #include +#include QT_BEGIN_NAMESPACE @@ -43,7 +44,7 @@ DownloadPrivate::~DownloadPrivate() m_downloadManager.Close(); } -bool DownloadPrivate::start() +bool DownloadPrivate::start(int iap) { TRACE_CONTEXT(DownloadPrivate::start, EVideoApi); Q_ASSERT(!m_download); @@ -54,6 +55,8 @@ bool DownloadPrivate::start() TRACE("connect err %d", err); if (KErrNone == err) { // Start download + if (KUseDefaultIap != iap) + m_downloadManager.SetIntAttribute(EDlMgrIap, iap); QHBufC url(m_parent->sourceUrl().toString()); TPtr8 url8 = url->Des().Collapse(); TRAP(err, m_download = &m_downloadManager.CreateDownloadL(url8)); @@ -140,12 +143,12 @@ const QString &Download::targetFileName() const return m_targetFileName; } -void Download::start() +void Download::start(int iap) { TRACE_CONTEXT(Download::start, EVideoApi); TRACE_ENTRY_0(); Q_ASSERT(Idle == m_state); - const bool ok = m_private->start(); + const bool ok = m_private->start(iap); setState(ok ? Initializing : Error); TRACE_EXIT_0(); } diff --git a/src/3rdparty/phonon/mmf/download.h b/src/3rdparty/phonon/mmf/download.h index bda7963..2ce54a8 100644 --- a/src/3rdparty/phonon/mmf/download.h +++ b/src/3rdparty/phonon/mmf/download.h @@ -43,7 +43,7 @@ class DownloadPrivate : public QObject public: DownloadPrivate(Download *parent); ~DownloadPrivate(); - bool start(); + bool start(int iap); void resume(); signals: void error(); @@ -69,7 +69,7 @@ public: ~Download(); const QUrl &sourceUrl() const; const QString &targetFileName() const; - void start(); + void start(int iap); void resume(); enum State { diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index 2c7a7ef..9da94ee 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -36,6 +36,10 @@ along with this library. If not, see . #include #include #include +#include +#include +#include +#include QT_BEGIN_NAMESPACE @@ -64,7 +68,8 @@ MMF::MediaObject::MediaObject(QObject *parent) : MMF::MediaNode::MediaNode(paren const int err = m_fileServer.Connect(); QT_TRAP_THROWING(User::LeaveIfError(err)); - Q_UNUSED(parent); + parent->installEventFilter(this); + m_iap = KUseDefaultIap; TRACE_EXIT_0(); } @@ -74,6 +79,7 @@ MMF::MediaObject::~MediaObject() TRACE_CONTEXT(MediaObject::~MediaObject, EAudioApi); TRACE_ENTRY_0(); + parent()->removeEventFilter(this); delete m_resource; if (m_file) @@ -493,6 +499,55 @@ void MMF::MediaObject::switchToNextSource() } //----------------------------------------------------------------------------- +// IAP support +//----------------------------------------------------------------------------- + +int MMF::MediaObject::currentIAP() const +{ + return m_iap; +} + +bool MMF::MediaObject::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::DynamicPropertyChange ) { + QDynamicPropertyChangeEvent* dynamicEvent = static_cast(event); + if (dynamicEvent->propertyName() == "InternetAccessPointName") { + QVariant value = watched->property("InternetAccessPointName"); + if (value.isValid()) { + QString iapName = value.toString(); + TRAPD(err, setIAPIdFromNameL(iapName)); + if (err) + m_player->setError(tr("Failed to set requested IAP"), err); + } + } + } + return false; +} + +void MMF::MediaObject::setIAPIdFromNameL(const QString& iapString) +{ + TRACE_CONTEXT(MediaObject::getIapIdFromName, EVideoInternal); + TBuf iapDes = qt_QString2TPtrC(iapString); + CCommsDatabase *commsDb = CCommsDatabase::NewL(EDatabaseTypeIAP); + CleanupStack::PushL(commsDb); + commsDb->ShowHiddenRecords(); + CCommsDbTableView *view = commsDb->OpenTableLC(TPtrC(IAP)); + for (TInt l = view->GotoFirstRecord(); l != KErrNotFound; l = view->GotoNextRecord()) { + TBuf iapName; + view->ReadTextL(TPtrC(COMMDB_NAME), iapName); + TRACE("found IAP %S", &iapName); + if (iapName.CompareF(iapDes) == 0) { + TUint32 uiap; + view->ReadUintL(TPtrC(COMMDB_ID), uiap); + TRACE("matched IAP %S, setting m_iap %d", &iapName, uiap); + m_iap = uiap; + break; + } + } + CleanupStack::PopAndDestroy(2); // commsDb, view +} + +//----------------------------------------------------------------------------- // Other private functions //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index 5d785fb..0ed70ff 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -23,6 +23,7 @@ along with this library. If not, see . #include #include #include +#include // For recognizer #include @@ -92,6 +93,7 @@ public: int openFileHandle(const QString &fileName); RFile* file() const; QResource* resource() const; + int currentIAP() const; public Q_SLOTS: void volumeChanged(qreal volume); @@ -113,6 +115,9 @@ Q_SIGNALS: void finished(); void tick(qint64 time); +protected: + bool eventFilter(QObject *watched, QEvent *event); + private Q_SLOTS: void handlePrefinishMarkReached(qint32); @@ -120,6 +125,7 @@ private: void switchToSource(const MediaSource &source); void createPlayer(const MediaSource &source); bool openRecognizer(); + void setIAPIdFromNameL(const QString& iapString); // Audio / video media type recognition MediaType fileMediaType(const QString& fileName); @@ -143,6 +149,7 @@ private: QResource* m_resource; QScopedPointer m_player; + int m_iap; }; } diff --git a/src/plugins/phonon/mmf/mmf.pro b/src/plugins/phonon/mmf/mmf.pro index 5d7b61d..de00c9e 100644 --- a/src/plugins/phonon/mmf/mmf.pro +++ b/src/plugins/phonon/mmf/mmf.pro @@ -127,6 +127,9 @@ symbian { # These are for effects. LIBS += -lAudioEqualizerEffect -lBassBoostEffect -lDistanceAttenuationEffect -lDopplerbase -lEffectBase -lEnvironmentalReverbEffect -lListenerDopplerEffect -lListenerLocationEffect -lListenerOrientationEffect -lLocationBase -lLoudnessEffect -lOrientationBase -lSourceDopplerEffect -lSourceLocationEffect -lSourceOrientationEffect -lStereoWideningEffect + # This is to allow IAP to be specified + LIBS += -lCommDb + # This is needed for having the .qtplugin file properly created on Symbian. QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/phonon_backend diff --git a/tests/auto/mediaobject/mediaobject.pro b/tests/auto/mediaobject/mediaobject.pro index e887df4..1fc76a2 100755 --- a/tests/auto/mediaobject/mediaobject.pro +++ b/tests/auto/mediaobject/mediaobject.pro @@ -18,5 +18,7 @@ symbian:{ addFiles.sources = media/test.sdp addFiles.path = media DEPLOYMENT += addFiles + LIBS += -lCommDb -lconnmon + TARGET.CAPABILITY += "NetworkServices" } diff --git a/tests/auto/mediaobject/tst_mediaobject.cpp b/tests/auto/mediaobject/tst_mediaobject.cpp index 5decbe2..a4ee3ba 100644 --- a/tests/auto/mediaobject/tst_mediaobject.cpp +++ b/tests/auto/mediaobject/tst_mediaobject.cpp @@ -101,6 +101,70 @@ const qint64 ALLOWED_TIME_FOR_SEEKING = 1000; // 1s const qint64 SEEKING_TOLERANCE = 0; #endif //Q_OS_WINCE +#ifdef Q_OS_SYMBIAN +#include +#include +#include +#include + +const QString KDefaultIAP = QLatin1String("default"); +const QString KInvalidIAP = QLatin1String("invalid IAP"); + +class CConnectionObserver : public CBase, public MConnectionMonitorObserver +{ +public: + static CConnectionObserver* NewL() + { + CConnectionObserver* self = new (ELeave) CConnectionObserver(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + QString currentIAP() + { + return m_currentIAPName; + } + ~CConnectionObserver() + { + m_connMon.Close(); + } +private: + CConnectionObserver() + { + } + void ConstructL() + { + m_connMon.ConnectL(); + m_connMon.NotifyEventL(*this); + } + void EventL (const CConnMonEventBase &aConnEvent) + { + TInt event = aConnEvent.EventType(); + TUint connId = aConnEvent.ConnectionId(); + TRequestStatus status; + switch (event) { + case EConnMonCreateConnection: { + TBuf iapName; + m_connMon.GetStringAttribute(connId, 0, KIAPName, iapName, status); + User::WaitForRequest(status); + m_currentIAPName = QString(reinterpret_cast(iapName.Ptr()), iapName.Length()); + qDebug() << "A new connection created using: " << m_currentIAPName; + break; + } + default: + break; + } + } + +private: + RConnectionMonitor m_connMon; + QString m_currentIAPName; +}; + +#endif + + class tst_MediaObject : public QObject { Q_OBJECT @@ -140,6 +204,8 @@ class tst_MediaObject : public QObject void pauseToPlay(); void pauseToStop(); void playSDP(); + void playUrl_data(); + void playUrl(); void testPrefinishMark(); void testSeek(); @@ -161,6 +227,10 @@ class tst_MediaObject : public QObject Phonon::MediaObject *m_media; QSignalSpy *m_stateChangedSignalSpy; QString m_tmpFileName; +#ifdef Q_OS_SYMBIAN + CConnectionObserver *m_iapConnectionObserver; + QString getValidIAPL(); +#endif //Q_OS_SYMBIAN static void copyMediaFile(const QString &original, const QString &name, @@ -451,6 +521,10 @@ void tst_MediaObject::initTestCase() QCOMPARE(m_media->outputPaths().size(), 1); QCOMPARE(audioOutput->inputPaths().size(), 1); +#ifdef Q_OS_SYMBIAN + TRAP_IGNORE(m_iapConnectionObserver = CConnectionObserver::NewL()); +#endif //Q_OS_SYMBIAN + } void tst_MediaObject::checkForDefaults() @@ -586,6 +660,115 @@ void tst_MediaObject::playSDP() #endif } +/*! + Attempt to play from an RTSP link, and, on Symbian, to specify the IAP that + should be used to connect to the network. This test requires the unit under test + to have a default internet connection that will support streaming media, and ideally + one other internet connection that will also support streaming. + */ +void tst_MediaObject::playUrl_data() +{ + QTest::addColumn("url"); + QTest::addColumn("iap"); + + QUrl rtspLink("rtsp://v1.cache8.c.youtube.com/CjgLENy73wIaLwnoDBCE7tF7fxMYESARFEIJbXYtZ29vZ2xlSARSB3Jlc3VsdHNgpbWqq7L7je5KDA==/0/0/0/video.3gp"); + QUrl httpLink("http://www.theflute.co.uk/media/BachCPE_SonataAmin_1.wma"); + + QTest::newRow("default_IAP_rtsp") << rtspLink << KDefaultIAP; + QTest::newRow("invalid_IAP_rtsp") << rtspLink << KInvalidIAP; + //don't test HTTP link with invalid or default IAP as it will prompt the user + +#ifdef Q_OS_SYMBIAN + //Add tests with a valid IAP if we can get one from CommsDB + QString validIAP; + TRAPD(err, validIAP = getValidIAPL()); + if (KErrNone == err) { + QTest::newRow("valid_IAP_rtsp") << rtspLink << validIAP; + QTest::newRow("valid_IAP_http") << httpLink << validIAP; + } +#endif //Q_OS_SYMBIAN +} + +#ifdef Q_OS_SYMBIAN +QString tst_MediaObject::getValidIAPL() +{ + CCommsDatabase* commsDb = CCommsDatabase::NewL(EDatabaseTypeIAP); + CleanupStack::PushL(commsDb); + commsDb->ShowHiddenRecords(); + CCommsDbTableView* view = commsDb->OpenTableLC(TPtrC(IAP)); + QString validIAP; + TBool found = EFalse; + TInt record = view->GotoFirstRecord(); + while (KErrNotFound != record) { + TBuf iapName; + view->ReadTextL(TPtrC(COMMDB_NAME), iapName); + validIAP = QString::fromUtf16(iapName.Ptr(),iapName.Length()); + //We don't want the "Easy WLAN" IAP as it will try and prompt the user + if ("Easy WLAN" != validIAP) { + qDebug() << "playUrl_data() adding a valid IAP test: " << validIAP; + found = ETrue; + break; + } + record = view->GotoNextRecord(); + } + CleanupStack::PopAndDestroy(2); + if (!found) + User::Leave(KErrNotFound); + return validIAP; +} +#endif //Q_OS_SYMBIAN + +void tst_MediaObject::playUrl() +{ + QFETCH(QUrl, url); + QFETCH(QString, iap); + MediaObject media(this); + + //Create a proper media path for video and audio + VideoWidget videoOutput; + Path path = createPath(&media, &videoOutput); + QVERIFY(path.isValid()); + AudioOutput audioOutput(Phonon::MusicCategory, this); + path = createPath(&media, &audioOutput); + QVERIFY(path.isValid()); + +#ifdef Q_OS_SYMBIAN + //The Symbian backend allows the IAP used for streaming connections to be specified + //by the application, using the "InternetAccessPointName" property. + if (KDefaultIAP != iap) + media.setProperty("InternetAccessPointName", iap); +#endif //Q_OS_SYMBIAN + media.setCurrentSource(Phonon::MediaSource(url)); + QVERIFY(media.state() != Phonon::ErrorState); + + //we use a long 30s timeout here as it can take a long time for the streaming source to + //be sucessfully prepared depending on the network. + if (media.state() != Phonon::StoppedState) + QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 30000); + QCOMPARE(media.state(), Phonon::StoppedState); + + media.play(); + if (media.state() != Phonon::PlayingState) + QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 15000); + QCOMPARE(media.state(), Phonon::PlayingState); + + //sleep and allow some of the stream to be played + QTest::qSleep(10000); + +#ifdef Q_OS_SYMBIAN + // Verify that the specified IAP is actually being used when we're not doing negative tests + if ((KDefaultIAP == iap || KInvalidIAP == iap) == false) { + if (m_iapConnectionObserver) + QCOMPARE(iap,m_iapConnectionObserver->currentIAP()); + } +#endif //Q_OS_SYMBIAN + + media.stop(); + if (media.state() != Phonon::StoppedState) + QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 15000); + QCOMPARE(media.state(), Phonon::StoppedState); +} + void tst_MediaObject::testPrefinishMark() { const qint32 requestedPrefinishMarkTime = 2000; @@ -937,6 +1120,10 @@ void tst_MediaObject::cleanupTestCase() if (!m_tmpFileName.isNull()) { QVERIFY(QFile::remove(m_tmpFileName)); } +#ifdef Q_OS_SYMBIAN + if (m_iapConnectionObserver) + delete m_iapConnectionObserver; +#endif //Q_OS_SYMBIAN } void tst_MediaObject::_testOneSeek(qint64 seekTo) -- cgit v0.12 From b58eb0419f9f724af5d9baf8bbce4e0f1e2f3f8b Mon Sep 17 00:00:00 2001 From: Ruth Sadler Date: Tue, 11 Jan 2011 10:57:41 +0000 Subject: Fixed resource leak in Phonon MMF backend Task-number: QTBUG-16513 Reviewed-by: Gareth Stockwell --- src/3rdparty/phonon/mmf/download.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/3rdparty/phonon/mmf/download.cpp b/src/3rdparty/phonon/mmf/download.cpp index de65811..f074d7f 100644 --- a/src/3rdparty/phonon/mmf/download.cpp +++ b/src/3rdparty/phonon/mmf/download.cpp @@ -40,6 +40,8 @@ DownloadPrivate::DownloadPrivate(Download *parent) DownloadPrivate::~DownloadPrivate() { + if (m_download) + m_download->Delete(); m_downloadManager.Disconnect(); m_downloadManager.Close(); } -- cgit v0.12 From a601a45f7fbff6df2b39990d0e1dbd00542b9819 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 11 Jan 2011 12:48:38 +0200 Subject: Allow use of command line parameters with RApaLsSession::StartApp. When a Symbian application is launched using RApaLsSession::StartApp, command line parameters can be given with CApaCommandLine::SetTailEndL and will now be correctly interpreted by Qt applications as command line parameters. There are a couple of limitations: 1) The parameters given with CApaCommandLine::SetTailEndL will not be available in main method's argv array; they can be accessed via QCoreApplication::arguments function. 2) CApaCommandLine::SetTailEndL does support any arbitrary binary data as parameter, but only 8-bit string data gets parsed properly into QCoreApplication::arguments. For other kind of tail data, you need to subclass QS60MainAppUi and implement ProcessCommandParametersL callback. Task-number: QTBUG-15987 Reviewed-by: axis --- mkspecs/common/symbian/symbian.conf | 4 +-- src/corelib/kernel/qcoreapplication.cpp | 64 ++++++++++++++++++++++++++++++++- src/corelib/kernel/qcoreapplication_p.h | 10 ++++-- src/corelib/kernel/qcorecmdlineargs_p.h | 13 ++++--- src/gui/kernel/qapplication_s60.cpp | 29 ++++++++------- 5 files changed, 95 insertions(+), 25 deletions(-) diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index 00cf0d7..ab94cfb 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -66,8 +66,8 @@ QMAKE_LINK_OBJECT_MAX = QMAKE_LINK_OBJECT_SCRIPT= QMAKE_LIBS = -llibc -llibm -leuser -llibdl -QMAKE_LIBS_CORE = $$QMAKE_LIBS -lefsrv -lhal -lbafl -QMAKE_LIBS_GUI = $$QMAKE_LIBS_CORE -lfbscli -lbitgdi -lgdi -lws32 -lapgrfx -lcone -leikcore -lmediaclientaudio -lapparc -lcentralrepository +QMAKE_LIBS_CORE = $$QMAKE_LIBS -lefsrv -lhal -lbafl -lapparc +QMAKE_LIBS_GUI = $$QMAKE_LIBS_CORE -lfbscli -lbitgdi -lgdi -lws32 -lapgrfx -lcone -leikcore -lmediaclientaudio -lcentralrepository QMAKE_LIBS_NETWORK = QMAKE_LIBS_EGL = -llibEGL QMAKE_LIBS_OPENGL = -llibGLESv2 diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index b445a50..381be34 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -71,6 +71,7 @@ # include # include "qeventdispatcher_symbian_p.h" # include "private/qcore_symbian_p.h" +# include #elif defined(Q_OS_UNIX) # if !defined(QT_NO_GLIB) # include "qeventdispatcher_glib_p.h" @@ -115,7 +116,58 @@ private: #ifdef Q_OS_SYMBIAN typedef TDriveNumber (*SystemDriveFunc)(RFs&); -static SystemDriveFunc PtrGetSystemDrive=0; +static SystemDriveFunc PtrGetSystemDrive = 0; +static CApaCommandLine* apaCommandLine = 0; +static char *apaTail = 0; +static QVector *apaArgv = 0; + +static void qt_cleanup_apa_cmd_line() +{ + delete apaCommandLine; + apaCommandLine = 0; + delete apaArgv; + apaArgv = 0; + delete apaTail; + apaTail = 0; +} + +static inline void qt_init_symbian_apa_arguments(int &argc, char **&argv) +{ + // If app is launched via CApaCommandLine::StartApp(), normal arguments only contain + // application name. + if (argc == 1) { + CApaCommandLine* commandLine = QCoreApplicationPrivate::symbianCommandLine(); + if(commandLine) { + TPtrC8 apaCmdLine = commandLine->TailEnd(); + int tailLen = apaCmdLine.Length(); + if (tailLen) { + apaTail = reinterpret_cast(qMalloc(tailLen + 1)); + qMemCopy(apaTail, reinterpret_cast(apaCmdLine.Ptr()), tailLen); + apaTail[tailLen] = '\0'; + apaArgv = new QVector(8); + // Reuse windows command line parsing + *apaArgv = qWinCmdLine(apaTail, tailLen, argc); + apaArgv->insert(0, argv[0]); + argc++; + argv = apaArgv->data(); + } + } + } +} + +CApaCommandLine* QCoreApplicationPrivate::symbianCommandLine() +{ + // Getting of Apa command line needs to be static as it can only be called successfully + // once per process. + if (!apaCommandLine) { + TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(apaCommandLine); + if (err == KErrNone) { + qAddPostRoutine(qt_cleanup_apa_cmd_line); + } + } + return apaCommandLine; +} + #endif #if defined(Q_WS_WIN) || defined(Q_WS_MAC) @@ -274,6 +326,10 @@ QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv) } QCoreApplicationPrivate::is_app_closing = false; +#ifdef Q_OS_SYMBIAN + qt_init_symbian_apa_arguments(argc, argv); +#endif + #ifdef Q_OS_UNIX qt_application_thread_id = QThread::currentThreadId(); #endif @@ -2056,6 +2112,12 @@ char **QCoreApplication::argv() As a result of this, the string given by arguments().at(0) might not be the program name on Windows, depending on how the application was started. + For Symbian applications started with \c RApaLsSession::StartApp one can specify + arguments using \c CApaCommandLine::SetTailEndL function. Such arguments are only + available via this method; they will not be passed to \c main function. Also note + that only 8-bit string data set with \c CApaCommandLine::SetTailEndL is supported + by this function. + \sa applicationFilePath() */ diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index d06fb51..703c825 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -65,8 +65,11 @@ QT_BEGIN_NAMESPACE typedef QList QTranslatorList; -#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_SYSTEMLOCALE) +#if defined(Q_OS_SYMBIAN) +# if !defined(QT_NO_SYSTEMLOCALE) class QEnvironmentChangeNotifier; +# endif +class CApaCommandLine; #endif class QAbstractEventDispatcher; @@ -116,9 +119,12 @@ public: bool aboutToQuitEmitted; QString cachedApplicationDirPath; QString cachedApplicationFilePath; -#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_SYSTEMLOCALE) +#if defined(Q_OS_SYMBIAN) +# if !defined(QT_NO_SYSTEMLOCALE) QScopedPointer environmentChangeNotifier; void symbianInit(); +# endif + static CApaCommandLine* symbianCommandLine(); #endif static bool isTranslatorInstalled(QTranslator *translator); diff --git a/src/corelib/kernel/qcorecmdlineargs_p.h b/src/corelib/kernel/qcorecmdlineargs_p.h index fd1d202..cdde782 100644 --- a/src/corelib/kernel/qcorecmdlineargs_p.h +++ b/src/corelib/kernel/qcorecmdlineargs_p.h @@ -58,11 +58,13 @@ QT_BEGIN_NAMESPACE -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) QT_BEGIN_INCLUDE_NAMESPACE #include "QtCore/qvector.h" -#include "qt_windows.h" +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) +# include "qt_windows.h" +#endif QT_END_INCLUDE_NAMESPACE // template implementation of the parsing algorithm @@ -130,6 +132,7 @@ static QVector qWinCmdLine(Char *cmdParam, int length, int &argc) return argv; } +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) static inline QStringList qWinCmdArgs(QString cmdLine) // not const-ref: this might be modified { QStringList args; @@ -150,8 +153,8 @@ static inline QStringList qCmdLineArgs(int argc, char *argv[]) QString cmdLine = QString::fromWCharArray(GetCommandLine()); return qWinCmdArgs(cmdLine); } - -#else // !Q_OS_WIN +#endif +#else // !Q_OS_WIN || !Q_OS_SYMBIAN static inline QStringList qCmdLineArgs(int argc, char *argv[]) { @@ -161,7 +164,7 @@ static inline QStringList qCmdLineArgs(int argc, char *argv[]) return args; } -#endif // Q_OS_WIN +#endif // Q_OS_WIN || Q_OS_SYMBIAN QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 4793437..789f198 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1431,21 +1431,20 @@ void qt_init(QApplicationPrivate * /* priv */, int) // The S60 framework has not been initialized. We need to do it. TApaApplicationFactory factory(S60->s60ApplicationFactory ? S60->s60ApplicationFactory : newS60Application); - CApaCommandLine* commandLine = 0; - TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine); - // After this construction, CEikonEnv will be available from CEikonEnv::Static(). - // (much like our qApp). - QtEikonEnv* coe = new QtEikonEnv; - //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there. - if(err == KErrNone) - TRAP(err, coe->ConstructAppFromCommandLineL(factory,*commandLine)); - delete commandLine; - if(err != KErrNone) { - qWarning() << "qt_init: Eikon application construct failed (" - << err - << "), maybe missing resource file on S60 3.1?"; - delete coe; - qt_symbian_throwIfError(err); + CApaCommandLine* commandLine = q_check_ptr(QCoreApplicationPrivate::symbianCommandLine()); + if (commandLine) { + // After this construction, CEikonEnv will be available from CEikonEnv::Static(). + // (much like our qApp). + QtEikonEnv* coe = new QtEikonEnv; + //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there. + TRAPD(err, coe->ConstructAppFromCommandLineL(factory, *commandLine)); + if(err != KErrNone) { + qWarning() << "qt_init: Eikon application construct failed (" + << err + << "), maybe missing resource file on S60 3.1?"; + delete coe; + qt_symbian_throwIfError(err); + } } S60->s60InstalledTrapHandler = User::SetTrapHandler(origTrapHandler); -- cgit v0.12 From 99f500838e4eaba9d99c3ea2cd6b4fc5efe0b8b4 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 11 Jan 2011 16:56:23 +0200 Subject: Remove sqlite3_selfsigned.sis as it is no longer usable or needed. Selfsigned qt.sis no longer installs on top of sqlite3_selfsigned.sis as patching embedded sises and dependencies was removed from patch_capabilities.pl script. However, since the regular sqlite3.sis is nowadays signed for all three Symbian manufacturers that Qt supports, there is no more need to have a self-signed sqlite3.sis in the first place, so it is removed to reduce confusion. Task-number: QTBUG-16576 Reviewed-by: axis --- src/s60installs/s60installs.pro | 3 +-- src/s60installs/sqlite3_selfsigned.sis | Bin 285088 -> 0 bytes 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 src/s60installs/sqlite3_selfsigned.sis diff --git a/src/s60installs/s60installs.pro b/src/s60installs/s60installs.pro index be7ed97..3b705ad 100644 --- a/src/s60installs/s60installs.pro +++ b/src/s60installs/s60installs.pro @@ -16,8 +16,7 @@ symbian: { # It is also expected that devices newer than those based on S60 5.0 all have sqlite3.dll. contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2)|contains(S60_VERSION, 5.0) { BLD_INF_RULES.prj_exports += \ - "sqlite3.sis /epoc32/data/qt/sis/sqlite3.sis" \ - "sqlite3_selfsigned.sis /epoc32/data/qt/sis/sqlite3_selfsigned.sis" + "sqlite3.sis /epoc32/data/qt/sis/sqlite3.sis" symbian-abld|symbian-sbsv2 { sqlitedeployment = \ "; Deploy sqlite onto phone that does not have it already" \ diff --git a/src/s60installs/sqlite3_selfsigned.sis b/src/s60installs/sqlite3_selfsigned.sis deleted file mode 100644 index a025ac5..0000000 Binary files a/src/s60installs/sqlite3_selfsigned.sis and /dev/null differ -- cgit v0.12 From e49868217e29f13dba28a2fe199d82268655b9fb Mon Sep 17 00:00:00 2001 From: Jani Hautakangas Date: Tue, 11 Jan 2011 15:26:22 +0200 Subject: Fix qglthreads test crash on Symbian Use less GPU memory to make tests pass and skip threaded rendering since eventually tries to access main RWindow from secondary thread, which is not allowed on Symbian Task-number: QTBUG-13525 Reviewed-by: TRUSTME --- tests/auto/qglthreads/tst_qglthreads.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/auto/qglthreads/tst_qglthreads.cpp b/tests/auto/qglthreads/tst_qglthreads.cpp index 50152d1..0bcc4f6 100644 --- a/tests/auto/qglthreads/tst_qglthreads.cpp +++ b/tests/auto/qglthreads/tst_qglthreads.cpp @@ -51,9 +51,13 @@ #ifdef Q_OS_SYMBIAN #include // for usleep +#define RUNNING_TIME 2000 // save GPU mem by running shorter time. +#else +#define RUNNING_TIME 5000 #endif -#define RUNNING_TIME 5000 + + tst_QGLThreads::tst_QGLThreads(QObject *parent) : QObject(parent) @@ -205,7 +209,15 @@ public: QTime time; time.start(); while (time.elapsed() < RUNNING_TIME) { - QImage image(400, 300, QImage::Format_RGB32); + int width = 400; + int height = 300; +#ifdef Q_OS_SYMBIAN + // GPU mem is very scarce resource on Symbian currently. + // That's why we create only small textures. + width = 50; + height = 20; +#else + QImage image(width, height, QImage::Format_RGB32); QPainter p(&image); p.fillRect(image.rect(), QColor(rand() % 256, rand() % 256, rand() % 256)); p.setPen(Qt::red); @@ -434,6 +446,10 @@ void tst_QGLThreads::renderInThread() QSKIP("OpenGL threading tests are currently disabled on mac as they were causing reboots", SkipAll); #endif +#ifdef Q_OS_SYMBIAN + QSKIP("OpenGL threading tests are disabled on Symbian as accessing RWindow from a secondary thread is not supported", SkipAll); +#endif + QFETCH(bool, resize); QFETCH(bool, update); -- cgit v0.12 From ff5a772b77cd52099ce7000a348d21e7c2fe3f2e Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 12 Jan 2011 10:58:06 +0200 Subject: Fix corelib def files. Added symbianCommandLine function to corelib def files. Task-number: QTBUG-15987 Reviewed-by: TrustMe --- src/s60installs/bwins/QtCoreu.def | 1 + src/s60installs/eabi/QtCoreu.def | 1 + 2 files changed, 2 insertions(+) diff --git a/src/s60installs/bwins/QtCoreu.def b/src/s60installs/bwins/QtCoreu.def index 6ecb403..872142d 100644 --- a/src/s60installs/bwins/QtCoreu.def +++ b/src/s60installs/bwins/QtCoreu.def @@ -4486,4 +4486,5 @@ EXPORTS ?objectNameChanged@QAbstractDeclarativeData@@2P6AXPAV1@PAVQObject@@@ZA @ 4485 NONAME ; void (*QAbstractDeclarativeData::objectNameChanged)(class QAbstractDeclarativeData *, class QObject *) ?queueDeferredActiveObjectsCompletion@QEventDispatcherSymbian@@QAEXXZ @ 4486 NONAME ; void QEventDispatcherSymbian::queueDeferredActiveObjectsCompletion(void) ?reactivateDeferredActiveObjects@QEventDispatcherSymbian@@UAEXXZ @ 4487 NONAME ; void QEventDispatcherSymbian::reactivateDeferredActiveObjects(void) + ?symbianCommandLine@QCoreApplicationPrivate@@SAPAVCApaCommandLine@@XZ @ 4488 NONAME ; class CApaCommandLine * QCoreApplicationPrivate::symbianCommandLine(void) diff --git a/src/s60installs/eabi/QtCoreu.def b/src/s60installs/eabi/QtCoreu.def index aefbe1f..5815b28 100644 --- a/src/s60installs/eabi/QtCoreu.def +++ b/src/s60installs/eabi/QtCoreu.def @@ -3714,4 +3714,5 @@ EXPORTS _Z26qt_symbian_SetupThreadHeapiR24SStdEpocThreadCreateInfo @ 3713 NONAME _ZN24QAbstractDeclarativeData17objectNameChangedE @ 3714 NONAME DATA 4 _ZN23QEventDispatcherSymbian36queueDeferredActiveObjectsCompletionEv @ 3715 NONAME + _ZN23QCoreApplicationPrivate18symbianCommandLineEv @ 3716 NONAME -- cgit v0.12 From 124ad6e903767fae510e0c2f0aba4029564a95c8 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Wed, 12 Jan 2011 13:55:17 +0000 Subject: Fixed build failure on platforms other than Symbian Reviewed-by: Ruth Sadler --- tests/auto/mediaobject/tst_mediaobject.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/auto/mediaobject/tst_mediaobject.cpp b/tests/auto/mediaobject/tst_mediaobject.cpp index a4ee3ba..b29a6db 100644 --- a/tests/auto/mediaobject/tst_mediaobject.cpp +++ b/tests/auto/mediaobject/tst_mediaobject.cpp @@ -669,16 +669,17 @@ void tst_MediaObject::playSDP() void tst_MediaObject::playUrl_data() { QTest::addColumn("url"); +#ifdef Q_OS_SYMBIAN QTest::addColumn("iap"); +#endif //Q_OS_SYMBIAN QUrl rtspLink("rtsp://v1.cache8.c.youtube.com/CjgLENy73wIaLwnoDBCE7tF7fxMYESARFEIJbXYtZ29vZ2xlSARSB3Jlc3VsdHNgpbWqq7L7je5KDA==/0/0/0/video.3gp"); QUrl httpLink("http://www.theflute.co.uk/media/BachCPE_SonataAmin_1.wma"); +#ifdef Q_OS_SYMBIAN QTest::newRow("default_IAP_rtsp") << rtspLink << KDefaultIAP; QTest::newRow("invalid_IAP_rtsp") << rtspLink << KInvalidIAP; //don't test HTTP link with invalid or default IAP as it will prompt the user - -#ifdef Q_OS_SYMBIAN //Add tests with a valid IAP if we can get one from CommsDB QString validIAP; TRAPD(err, validIAP = getValidIAPL()); @@ -686,6 +687,9 @@ void tst_MediaObject::playUrl_data() QTest::newRow("valid_IAP_rtsp") << rtspLink << validIAP; QTest::newRow("valid_IAP_http") << httpLink << validIAP; } +#else + QTest::newRow("default_IAP_rtsp") << rtspLink; + QTest::newRow("invalid_IAP_rtsp") << rtspLink; #endif //Q_OS_SYMBIAN } @@ -721,7 +725,9 @@ QString tst_MediaObject::getValidIAPL() void tst_MediaObject::playUrl() { QFETCH(QUrl, url); +#ifdef Q_OS_SYMBIAN QFETCH(QString, iap); +#endif MediaObject media(this); //Create a proper media path for video and audio -- cgit v0.12