diff options
27 files changed, 460 insertions, 43 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 <cdbcols.h> +#include <cdblen.h> +#include <commdb.h> +#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<KCommsDbSvrMaxColumnNameLength> 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/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/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 <http://www.gnu.org/licenses/>. #include "defs.h" #include "mediaobject.h" #include "utils.h" +#include <cdbcols.h> +#include <cdblen.h> +#include <commdb.h> 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..f074d7f 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 <http://www.gnu.org/licenses/>. #include "utils.h" #include <QtCore/QDir> #include <QtCore/private/qcore_symbian_p.h> +#include <mmf/common/mmfcontrollerframeworkbase.h> QT_BEGIN_NAMESPACE @@ -39,11 +40,13 @@ DownloadPrivate::DownloadPrivate(Download *parent) DownloadPrivate::~DownloadPrivate() { + if (m_download) + m_download->Delete(); m_downloadManager.Disconnect(); m_downloadManager.Close(); } -bool DownloadPrivate::start() +bool DownloadPrivate::start(int iap) { TRACE_CONTEXT(DownloadPrivate::start, EVideoApi); Q_ASSERT(!m_download); @@ -54,6 +57,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 +145,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 <http://www.gnu.org/licenses/>. #include <QDir> #include <QResource> #include <QUrl> +#include <cdbcols.h> +#include <cdblen.h> +#include <commdb.h> +#include <mmf/common/mmfcontrollerframeworkbase.h> 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<QDynamicPropertyChangeEvent*>(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<KCommsDbSvrMaxColumnNameLength> 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<KCommsDbSvrMaxColumnNameLength> 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 <http://www.gnu.org/licenses/>. #include <phonon/mediaobjectinterface.h> #include <QScopedPointer> #include <QTimer> +#include <QString> // For recognizer #include <apgcli.h> @@ -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<AbstractPlayer> m_player; + int m_iap; }; } 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 <e32ldr.h> # include "qeventdispatcher_symbian_p.h" # include "private/qcore_symbian_p.h" +# include <apacmdln.h> #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<char *> *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<char *>(qMalloc(tailLen + 1)); + qMemCopy(apaTail, reinterpret_cast<const char *>(apaCmdLine.Ptr()), tailLen); + apaTail[tailLen] = '\0'; + apaArgv = new QVector<char *>(8); + // Reuse windows command line parsing + *apaArgv = qWinCmdLine<char>(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<QTranslator*> 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<QEnvironmentChangeNotifier> 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<Char*> 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); 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/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 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 Binary files differdeleted file mode 100644 index a025ac5..0000000 --- a/src/s60installs/sqlite3_selfsigned.sis +++ /dev/null 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..b29a6db 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 <cdbcols.h> +#include <cdblen.h> +#include <commdb.h> +#include <rconnmon.h> + +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<KCommsDbSvrMaxColumnNameLength> iapName; + m_connMon.GetStringAttribute(connId, 0, KIAPName, iapName, status); + User::WaitForRequest(status); + m_currentIAPName = QString(reinterpret_cast<const QChar *>(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,121 @@ 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<QUrl>("url"); +#ifdef Q_OS_SYMBIAN + QTest::addColumn<QString>("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 + //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; + } +#else + QTest::newRow("default_IAP_rtsp") << rtspLink; + QTest::newRow("invalid_IAP_rtsp") << rtspLink; +#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<KCommsDbSvrMaxColumnNameLength> 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); +#ifdef Q_OS_SYMBIAN + QFETCH(QString, iap); +#endif + 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 +1126,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) 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 <unistd.h> // 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); |