src/3rdparty/phonon/mmf/abstractmediaplayer.cpp
branchRCL_3
changeset 4 3b1da2848fc7
parent 3 41300fa6a67c
child 14 c0432d11811c
equal deleted inserted replaced
3:41300fa6a67c 4:3b1da2848fc7
    18 
    18 
    19 #include <QUrl>
    19 #include <QUrl>
    20 
    20 
    21 #include "abstractmediaplayer.h"
    21 #include "abstractmediaplayer.h"
    22 #include "defs.h"
    22 #include "defs.h"
       
    23 #include "mediaobject.h"
    23 #include "utils.h"
    24 #include "utils.h"
    24 
    25 
    25 QT_BEGIN_NAMESPACE
    26 QT_BEGIN_NAMESPACE
    26 
    27 
    27 using namespace Phonon;
    28 using namespace Phonon;
    34 //-----------------------------------------------------------------------------
    35 //-----------------------------------------------------------------------------
    35 // Constants
    36 // Constants
    36 //-----------------------------------------------------------------------------
    37 //-----------------------------------------------------------------------------
    37 
    38 
    38 const int       NullMaxVolume = -1;
    39 const int       NullMaxVolume = -1;
       
    40 const int       BufferStatusTimerInterval = 100; // ms
    39 
    41 
    40 
    42 
    41 //-----------------------------------------------------------------------------
    43 //-----------------------------------------------------------------------------
    42 // Constructor / destructor
    44 // Constructor / destructor
    43 //-----------------------------------------------------------------------------
    45 //-----------------------------------------------------------------------------
    44 
    46 
    45 MMF::AbstractMediaPlayer::AbstractMediaPlayer() :
    47 MMF::AbstractMediaPlayer::AbstractMediaPlayer
    46             m_playPending(false)
    48     (MediaObject *parent, const AbstractPlayer *player)
    47         ,   m_tickTimer(new QTimer(this))
    49         :   AbstractPlayer(player)
       
    50         ,   m_parent(parent)
       
    51         ,   m_playPending(false)
       
    52         ,   m_positionTimer(new QTimer(this))
       
    53         ,   m_bufferStatusTimer(new QTimer(this))
    48         ,   m_mmfMaxVolume(NullMaxVolume)
    54         ,   m_mmfMaxVolume(NullMaxVolume)
    49 {
    55         ,   m_prefinishMarkSent(false)
    50     connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick()));
    56         ,   m_aboutToFinishSent(false)
    51 }
    57 {
    52 
    58     connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick()));
    53 MMF::AbstractMediaPlayer::AbstractMediaPlayer(const AbstractPlayer& player) :
    59     connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick()));
    54         AbstractPlayer(player)
       
    55         ,   m_playPending(false)
       
    56         ,   m_tickTimer(new QTimer(this))
       
    57         ,   m_mmfMaxVolume(NullMaxVolume)
       
    58 {
       
    59     connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick()));
       
    60 }
    60 }
    61 
    61 
    62 //-----------------------------------------------------------------------------
    62 //-----------------------------------------------------------------------------
    63 // MediaObjectInterface
    63 // MediaObjectInterface
    64 //-----------------------------------------------------------------------------
    64 //-----------------------------------------------------------------------------
    68     TRACE_CONTEXT(AbstractMediaPlayer::play, EAudioApi);
    68     TRACE_CONTEXT(AbstractMediaPlayer::play, EAudioApi);
    69     TRACE_ENTRY("state %d", privateState());
    69     TRACE_ENTRY("state %d", privateState());
    70 
    70 
    71     switch (privateState()) {
    71     switch (privateState()) {
    72     case GroundState:
    72     case GroundState:
    73         setError(NormalError);
    73         setError(tr("Not ready to play"));
    74         break;
    74         break;
    75 
    75 
    76     case LoadingState:
    76     case LoadingState:
    77         m_playPending = true;
    77         m_playPending = true;
    78         break;
    78         break;
    79 
    79 
    80     case StoppedState:
    80     case StoppedState:
    81     case PausedState:
    81     case PausedState:
    82         doPlay();
    82         doPlay();
    83         startTickTimer();
    83         startPositionTimer();
    84         changeState(PlayingState);
    84         changeState(PlayingState);
    85         break;
    85         break;
    86 
    86 
    87     case PlayingState:
    87     case PlayingState:
    88     case BufferingState:
    88     case BufferingState:
   102 {
   102 {
   103     TRACE_CONTEXT(AbstractMediaPlayer::pause, EAudioApi);
   103     TRACE_CONTEXT(AbstractMediaPlayer::pause, EAudioApi);
   104     TRACE_ENTRY("state %d", privateState());
   104     TRACE_ENTRY("state %d", privateState());
   105 
   105 
   106     m_playPending = false;
   106     m_playPending = false;
       
   107     stopTimers();
   107 
   108 
   108     switch (privateState()) {
   109     switch (privateState()) {
   109     case GroundState:
   110     case GroundState:
   110     case LoadingState:
   111     case LoadingState:
   111     case PausedState:
   112     case PausedState:
       
   113     case StoppedState:
   112         // Do nothing
   114         // Do nothing
   113         break;
   115         break;
   114 
   116 
   115     case StoppedState:
       
   116     case PlayingState:
   117     case PlayingState:
       
   118     case BufferingState:
       
   119         changeState(PausedState);
       
   120         // Fall through
   117     case ErrorState:
   121     case ErrorState:
   118     case BufferingState:
       
   119         doPause();
   122         doPause();
   120         stopTickTimer();
       
   121         changeState(PausedState);
       
   122         break;
   123         break;
   123 
   124 
   124         // Protection against adding new states and forgetting to update this switch
   125         // Protection against adding new states and forgetting to update this switch
   125     default:
   126     default:
   126         TRACE_PANIC(InvalidStatePanic);
   127         TRACE_PANIC(InvalidStatePanic);
   133 {
   134 {
   134     TRACE_CONTEXT(AbstractMediaPlayer::stop, EAudioApi);
   135     TRACE_CONTEXT(AbstractMediaPlayer::stop, EAudioApi);
   135     TRACE_ENTRY("state %d", privateState());
   136     TRACE_ENTRY("state %d", privateState());
   136 
   137 
   137     m_playPending = false;
   138     m_playPending = false;
       
   139     stopTimers();
   138 
   140 
   139     switch (privateState()) {
   141     switch (privateState()) {
   140     case GroundState:
   142     case GroundState:
   141     case LoadingState:
   143     case LoadingState:
   142     case StoppedState:
   144     case StoppedState:
   146 
   148 
   147     case PlayingState:
   149     case PlayingState:
   148     case BufferingState:
   150     case BufferingState:
   149     case PausedState:
   151     case PausedState:
   150         doStop();
   152         doStop();
   151         stopTickTimer();
       
   152         changeState(StoppedState);
   153         changeState(StoppedState);
   153         break;
   154         break;
   154 
   155 
   155         // Protection against adding new states and forgetting to update this switch
   156         // Protection against adding new states and forgetting to update this switch
   156     default:
   157     default:
   171     case StoppedState:
   172     case StoppedState:
   172     case PausedState:
   173     case PausedState:
   173     case PlayingState:
   174     case PlayingState:
   174     case LoadingState:
   175     case LoadingState:
   175     {
   176     {
   176         const bool tickTimerWasRunning = m_tickTimer->isActive();
   177         bool wasPlaying = false;
   177         stopTickTimer();
   178         if (state() == PlayingState) {
       
   179             stopPositionTimer();
       
   180             doPause();
       
   181             wasPlaying = true;
       
   182         }
   178 
   183 
   179         doSeek(ms);
   184         doSeek(ms);
   180 
   185         resetMarksIfRewound();
   181         if (tickTimerWasRunning) {
   186 
   182             startTickTimer();
   187         if(wasPlaying && state() != ErrorState) {
   183         }
   188             doPlay();
       
   189             startPositionTimer();
       
   190         }
       
   191 
   184         break;
   192         break;
   185     }
   193     }
   186     case BufferingState:
   194     case BufferingState:
   187     // Fallthrough
   195     // Fallthrough
   188     case ErrorState:
   196     case ErrorState:
   201 void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval)
   209 void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval)
   202 {
   210 {
   203     TRACE_CONTEXT(AbstractMediaPlayer::doSetTickInterval, EAudioApi);
   211     TRACE_CONTEXT(AbstractMediaPlayer::doSetTickInterval, EAudioApi);
   204     TRACE_ENTRY("state %d m_interval %d interval %d", privateState(), tickInterval(), interval);
   212     TRACE_ENTRY("state %d m_interval %d interval %d", privateState(), tickInterval(), interval);
   205 
   213 
   206     m_tickTimer->setInterval(interval);
   214     m_positionTimer->setInterval(interval);
   207 
   215 
   208     TRACE_EXIT_0();
   216     TRACE_EXIT_0();
   209 }
   217 }
   210 
   218 
   211 MediaSource MMF::AbstractMediaPlayer::source() const
   219 void MMF::AbstractMediaPlayer::open(const MediaSource &source, RFile& file)
   212 {
       
   213     return m_source;
       
   214 }
       
   215 
       
   216 void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& file)
       
   217 {
   220 {
   218     TRACE_CONTEXT(AbstractMediaPlayer::setFileSource, EAudioApi);
   221     TRACE_CONTEXT(AbstractMediaPlayer::setFileSource, EAudioApi);
   219     TRACE_ENTRY("state %d source.type %d", privateState(), source.type());
   222     TRACE_ENTRY("state %d source.type %d", privateState(), source.type());
   220 
   223 
   221     close();
   224     close();
   222     changeState(GroundState);
   225     changeState(GroundState);
   223 
   226 
   224     // TODO: is it correct to assign even if the media type is not supported in
       
   225     // the switch statement below?
       
   226     m_source = source;
       
   227 
       
   228     TInt symbianErr = KErrNone;
   227     TInt symbianErr = KErrNone;
   229 
   228     QString errorMessage;
   230     switch (m_source.type()) {
   229 
       
   230     switch (source.type()) {
   231     case MediaSource::LocalFile: {
   231     case MediaSource::LocalFile: {
   232         symbianErr = openFile(file);
   232         symbianErr = openFile(file);
       
   233         if (KErrNone != symbianErr)
       
   234             errorMessage = tr("Error opening file");
   233         break;
   235         break;
   234     }
   236     }
   235 
   237 
   236     case MediaSource::Url: {
   238     case MediaSource::Url: {
   237         const QUrl url(source.url());
   239         const QUrl url(source.url());
   238 
   240 
   239         if (url.scheme() == QLatin1String("file")) {
   241         if (url.scheme() == QLatin1String("file")) {
   240             symbianErr = openFile(file);
   242             symbianErr = openFile(file);
   241         }
   243             if (KErrNone != symbianErr)
   242         else {
   244                 errorMessage = tr("Error opening file");
   243             TRACE_0("Source type not supported");
   245         } else {
   244             // TODO: support network URLs
   246             symbianErr = openUrl(url.toString());
   245             symbianErr = KErrNotSupported;
   247             if (KErrNone != symbianErr)
   246         }
   248                 errorMessage = tr("Error opening URL");
   247 
   249         }
   248         break;
   250 
   249     }
   251         break;
   250 
   252     }
   251     case MediaSource::Invalid:
   253 
   252     case MediaSource::Disc:
   254     // Other source types are handled in MediaObject::createPlayer
   253     case MediaSource::Stream:
   255 
   254         TRACE_0("Source type not supported");
   256     // Protection against adding new media types and forgetting to update this switch
   255         symbianErr = KErrNotSupported;
       
   256         break;
       
   257 
       
   258     case MediaSource::Empty:
       
   259         TRACE_0("Empty source - doing nothing");
       
   260         TRACE_EXIT_0();
       
   261         return;
       
   262 
       
   263         // Protection against adding new media types and forgetting to update this switch
       
   264     default:
   257     default:
   265         TRACE_PANIC(InvalidMediaTypePanic);
   258         TRACE_PANIC(InvalidMediaTypePanic);
   266     }
   259     }
   267 
   260 
   268     if (KErrNone == symbianErr) {
   261     if (errorMessage.isEmpty()) {
   269         changeState(LoadingState);
   262         changeState(LoadingState);
   270     } else {
   263     } else {
   271         TRACE("error %d", symbianErr)
   264         if (symbianErr)
   272         setError(NormalError);
   265             setError(errorMessage, symbianErr);
       
   266         else
       
   267             setError(errorMessage);
   273     }
   268     }
   274 
   269 
   275     TRACE_EXIT_0();
   270     TRACE_EXIT_0();
   276 }
   271 }
   277 
       
   278 void MMF::AbstractMediaPlayer::setNextSource(const MediaSource &source)
       
   279 {
       
   280     TRACE_CONTEXT(AbstractMediaPlayer::setNextSource, EAudioApi);
       
   281     TRACE_ENTRY("state %d", privateState());
       
   282 
       
   283     // TODO: handle 'next source'
       
   284 
       
   285     m_nextSource = source;
       
   286     Q_UNUSED(source);
       
   287 
       
   288     TRACE_EXIT_0();
       
   289 }
       
   290 
       
   291 
   272 
   292 void MMF::AbstractMediaPlayer::volumeChanged(qreal volume)
   273 void MMF::AbstractMediaPlayer::volumeChanged(qreal volume)
   293 {
   274 {
   294     TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal);
   275     TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal);
   295     TRACE_ENTRY("state %d", privateState());
   276     TRACE_ENTRY("state %d", privateState());
   298     doVolumeChanged();
   279     doVolumeChanged();
   299 
   280 
   300     TRACE_EXIT_0();
   281     TRACE_EXIT_0();
   301 }
   282 }
   302 
   283 
       
   284 //-----------------------------------------------------------------------------
       
   285 // Private functions
       
   286 //-----------------------------------------------------------------------------
       
   287 
       
   288 void MMF::AbstractMediaPlayer::startPositionTimer()
       
   289 {
       
   290     m_positionTimer->start(tickInterval());
       
   291 }
       
   292 
       
   293 void MMF::AbstractMediaPlayer::stopPositionTimer()
       
   294 {
       
   295     m_positionTimer->stop();
       
   296 }
       
   297 
       
   298 void MMF::AbstractMediaPlayer::startBufferStatusTimer()
       
   299 {
       
   300     m_bufferStatusTimer->start(BufferStatusTimerInterval);
       
   301 }
       
   302 
       
   303 void MMF::AbstractMediaPlayer::stopBufferStatusTimer()
       
   304 {
       
   305     m_bufferStatusTimer->stop();
       
   306 }
       
   307 
       
   308 void MMF::AbstractMediaPlayer::stopTimers()
       
   309 {
       
   310     stopPositionTimer();
       
   311     stopBufferStatusTimer();
       
   312 }
   303 
   313 
   304 void MMF::AbstractMediaPlayer::doVolumeChanged()
   314 void MMF::AbstractMediaPlayer::doVolumeChanged()
   305 {
   315 {
   306     switch (privateState()) {
   316     switch (privateState()) {
   307     case GroundState:
   317     case GroundState:
   316     case BufferingState: {
   326     case BufferingState: {
   317         const qreal volume = (m_volume * m_mmfMaxVolume) + 0.5;
   327         const qreal volume = (m_volume * m_mmfMaxVolume) + 0.5;
   318         const int err = setDeviceVolume(volume);
   328         const int err = setDeviceVolume(volume);
   319 
   329 
   320         if (KErrNone != err) {
   330         if (KErrNone != err) {
   321             setError(NormalError);
   331             setError(tr("Setting volume failed"), err);
   322         }
   332         }
   323         break;
   333         break;
   324     }
   334     }
   325 
   335 
   326     // Protection against adding new states and forgetting to update this
   336     // Protection against adding new states and forgetting to update this
   328     default:
   338     default:
   329         Utils::panic(InvalidStatePanic);
   339         Utils::panic(InvalidStatePanic);
   330     }
   340     }
   331 }
   341 }
   332 
   342 
   333 
       
   334 //-----------------------------------------------------------------------------
   343 //-----------------------------------------------------------------------------
   335 // Protected functions
   344 // Protected functions
   336 //-----------------------------------------------------------------------------
   345 //-----------------------------------------------------------------------------
   337 
   346 
   338 void MMF::AbstractMediaPlayer::startTickTimer()
   347 void MMF::AbstractMediaPlayer::bufferingStarted()
   339 {
   348 {
   340     m_tickTimer->start(tickInterval());
   349     m_stateBeforeBuffering = privateState();
   341 }
   350     changeState(BufferingState);
   342 
   351     bufferStatusTick();
   343 void MMF::AbstractMediaPlayer::stopTickTimer()
   352     startBufferStatusTimer();
   344 {
   353 }
   345     m_tickTimer->stop();
   354 
       
   355 void MMF::AbstractMediaPlayer::bufferingComplete()
       
   356 {
       
   357     stopBufferStatusTimer();
       
   358     emit MMF::AbstractPlayer::bufferStatus(100);
       
   359     changeState(m_stateBeforeBuffering);
   346 }
   360 }
   347 
   361 
   348 void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume)
   362 void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume)
   349 {
   363 {
   350     m_mmfMaxVolume = mmfMaxVolume;
   364     m_mmfMaxVolume = mmfMaxVolume;
   351     doVolumeChanged();
   365     doVolumeChanged();
   352 }
   366 }
   353 
   367 
       
   368 void MMF::AbstractMediaPlayer::playbackComplete(int error)
       
   369 {
       
   370     stopTimers();
       
   371 
       
   372     if (KErrNone == error) {
       
   373         changeState(StoppedState);
       
   374 
       
   375         // MediaObject::switchToNextSource deletes the current player, so we
       
   376         // call it via delayed slot invokation to ensure that this object does
       
   377         // not get deleted during execution of a member function.
       
   378         QMetaObject::invokeMethod(m_parent, "switchToNextSource", Qt::QueuedConnection);
       
   379     }
       
   380     else {
       
   381         setError(tr("Playback complete"), error);
       
   382     }
       
   383 }
       
   384 
   354 qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in)
   385 qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in)
   355 {
   386 {
   356     return in.Int64() / 1000;
   387     return in.Int64() / 1000;
   357 }
   388 }
   358 
   389 
   359 //-----------------------------------------------------------------------------
   390 //-----------------------------------------------------------------------------
   360 // Slots
   391 // Slots
   361 //-----------------------------------------------------------------------------
   392 //-----------------------------------------------------------------------------
   362 
   393 
   363 void MMF::AbstractMediaPlayer::tick()
   394 void MMF::AbstractMediaPlayer::positionTick()
   364 {
   395 {
   365     // For the MWC compiler, we need to qualify the base class.
   396     emitMarksIfReached();
   366     emit MMF::AbstractPlayer::tick(currentTime());
   397 
       
   398     const qint64 current = currentTime();
       
   399     emit MMF::AbstractPlayer::tick(current);
       
   400 }
       
   401 
       
   402 void MMF::AbstractMediaPlayer::emitMarksIfReached()
       
   403 {
       
   404     const qint64 current = currentTime();
       
   405     const qint64 total = totalTime();
       
   406     const qint64 remaining = total - current;
       
   407 
       
   408     if (prefinishMark() && !m_prefinishMarkSent) {
       
   409         if (remaining < (prefinishMark() + tickInterval()/2)) {
       
   410             m_prefinishMarkSent = true;
       
   411             emit prefinishMarkReached(remaining);
       
   412         }
       
   413     }
       
   414 
       
   415     if (!m_aboutToFinishSent) {
       
   416         if (remaining < tickInterval()) {
       
   417             m_aboutToFinishSent = true;
       
   418             emit aboutToFinish();
       
   419         }
       
   420     }
       
   421 }
       
   422 
       
   423 void MMF::AbstractMediaPlayer::resetMarksIfRewound()
       
   424 {
       
   425     const qint64 current = currentTime();
       
   426     const qint64 total = totalTime();
       
   427     const qint64 remaining = total - current;
       
   428 
       
   429     if (prefinishMark() && m_prefinishMarkSent)
       
   430         if (remaining >= (prefinishMark() + tickInterval()/2))
       
   431             m_prefinishMarkSent = false;
       
   432 
       
   433     if (m_aboutToFinishSent)
       
   434         if (remaining >= tickInterval())
       
   435             m_aboutToFinishSent = false;
       
   436 }
       
   437 
       
   438 void MMF::AbstractMediaPlayer::bufferStatusTick()
       
   439 {
       
   440     emit MMF::AbstractPlayer::bufferStatus(bufferStatus());
   367 }
   441 }
   368 
   442 
   369 void MMF::AbstractMediaPlayer::changeState(PrivateState newState)
   443 void MMF::AbstractMediaPlayer::changeState(PrivateState newState)
   370 {
   444 {
   371     TRACE_CONTEXT(AbstractMediaPlayer::changeState, EAudioInternal);
   445     TRACE_CONTEXT(AbstractMediaPlayer::changeState, EAudioInternal);