46 |
46 |
47 MMF::AbstractMediaPlayer::AbstractMediaPlayer |
47 MMF::AbstractMediaPlayer::AbstractMediaPlayer |
48 (MediaObject *parent, const AbstractPlayer *player) |
48 (MediaObject *parent, const AbstractPlayer *player) |
49 : AbstractPlayer(player) |
49 : AbstractPlayer(player) |
50 , m_parent(parent) |
50 , m_parent(parent) |
51 , m_playPending(false) |
51 , m_pending(NothingPending) |
52 , m_positionTimer(new QTimer(this)) |
52 , m_positionTimer(new QTimer(this)) |
53 , m_bufferStatusTimer(new QTimer(this)) |
53 , m_bufferStatusTimer(new QTimer(this)) |
54 , m_mmfMaxVolume(NullMaxVolume) |
54 , m_mmfMaxVolume(NullMaxVolume) |
55 , m_prefinishMarkSent(false) |
55 , m_prefinishMarkSent(false) |
56 , m_aboutToFinishSent(false) |
56 , m_aboutToFinishSent(false) |
101 void MMF::AbstractMediaPlayer::pause() |
99 void MMF::AbstractMediaPlayer::pause() |
102 { |
100 { |
103 TRACE_CONTEXT(AbstractMediaPlayer::pause, EAudioApi); |
101 TRACE_CONTEXT(AbstractMediaPlayer::pause, EAudioApi); |
104 TRACE_ENTRY("state %d", privateState()); |
102 TRACE_ENTRY("state %d", privateState()); |
105 |
103 |
106 m_playPending = false; |
|
107 stopTimers(); |
104 stopTimers(); |
108 |
105 |
109 switch (privateState()) { |
106 switch (privateState()) { |
110 case GroundState: |
107 case GroundState: |
111 case LoadingState: |
108 case LoadingState: |
|
109 case StoppedState: |
|
110 setPending(PausePending); |
|
111 break; |
|
112 |
112 case PausedState: |
113 case PausedState: |
113 case StoppedState: |
|
114 // Do nothing |
114 // Do nothing |
115 break; |
115 break; |
116 |
116 |
117 case PlayingState: |
117 case PlayingState: |
118 case BufferingState: |
118 case BufferingState: |
133 void MMF::AbstractMediaPlayer::stop() |
133 void MMF::AbstractMediaPlayer::stop() |
134 { |
134 { |
135 TRACE_CONTEXT(AbstractMediaPlayer::stop, EAudioApi); |
135 TRACE_CONTEXT(AbstractMediaPlayer::stop, EAudioApi); |
136 TRACE_ENTRY("state %d", privateState()); |
136 TRACE_ENTRY("state %d", privateState()); |
137 |
137 |
138 m_playPending = false; |
138 setPending(NothingPending); |
139 stopTimers(); |
139 stopTimers(); |
140 |
140 |
141 switch (privateState()) { |
141 switch (privateState()) { |
142 case GroundState: |
142 case GroundState: |
143 case LoadingState: |
143 case LoadingState: |
363 { |
363 { |
364 m_mmfMaxVolume = mmfMaxVolume; |
364 m_mmfMaxVolume = mmfMaxVolume; |
365 doVolumeChanged(); |
365 doVolumeChanged(); |
366 } |
366 } |
367 |
367 |
|
368 void MMF::AbstractMediaPlayer::loadingComplete(int error) |
|
369 { |
|
370 Q_ASSERT(Phonon::LoadingState == state()); |
|
371 |
|
372 if (KErrNone == error) { |
|
373 updateMetaData(); |
|
374 changeState(StoppedState); |
|
375 } else { |
|
376 setError(tr("Loading clip failed"), error); |
|
377 } |
|
378 } |
|
379 |
368 void MMF::AbstractMediaPlayer::playbackComplete(int error) |
380 void MMF::AbstractMediaPlayer::playbackComplete(int error) |
369 { |
381 { |
370 stopTimers(); |
382 stopTimers(); |
371 |
383 |
|
384 if (KErrNone == error && !m_aboutToFinishSent) { |
|
385 const qint64 total = totalTime(); |
|
386 emit MMF::AbstractPlayer::tick(total); |
|
387 m_aboutToFinishSent = true; |
|
388 emit aboutToFinish(); |
|
389 } |
|
390 |
372 if (KErrNone == error) { |
391 if (KErrNone == error) { |
373 changeState(StoppedState); |
392 changeState(PausedState); |
374 |
393 |
375 // MediaObject::switchToNextSource deletes the current player, so we |
394 // MediaObject::switchToNextSource deletes the current player, so we |
376 // call it via delayed slot invokation to ensure that this object does |
395 // call it via delayed slot invokation to ensure that this object does |
377 // not get deleted during execution of a member function. |
396 // not get deleted during execution of a member function. |
378 QMetaObject::invokeMethod(m_parent, "switchToNextSource", Qt::QueuedConnection); |
397 QMetaObject::invokeMethod(m_parent, "switchToNextSource", Qt::QueuedConnection); |
379 } |
398 } |
380 else { |
399 else { |
381 setError(tr("Playback complete"), error); |
400 setError(tr("Playback complete"), error); |
|
401 emit finished(); |
382 } |
402 } |
383 } |
403 } |
384 |
404 |
385 qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in) |
405 qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in) |
386 { |
406 { |
391 // Slots |
411 // Slots |
392 //----------------------------------------------------------------------------- |
412 //----------------------------------------------------------------------------- |
393 |
413 |
394 void MMF::AbstractMediaPlayer::positionTick() |
414 void MMF::AbstractMediaPlayer::positionTick() |
395 { |
415 { |
396 emitMarksIfReached(); |
|
397 |
|
398 const qint64 current = currentTime(); |
416 const qint64 current = currentTime(); |
|
417 emitMarksIfReached(current); |
399 emit MMF::AbstractPlayer::tick(current); |
418 emit MMF::AbstractPlayer::tick(current); |
400 } |
419 } |
401 |
420 |
402 void MMF::AbstractMediaPlayer::emitMarksIfReached() |
421 void MMF::AbstractMediaPlayer::emitMarksIfReached(qint64 current) |
403 { |
422 { |
404 const qint64 current = currentTime(); |
|
405 const qint64 total = totalTime(); |
423 const qint64 total = totalTime(); |
406 const qint64 remaining = total - current; |
424 const qint64 remaining = total - current; |
407 |
425 |
408 if (prefinishMark() && !m_prefinishMarkSent) { |
426 if (prefinishMark() && !m_prefinishMarkSent) { |
409 if (remaining < (prefinishMark() + tickInterval()/2)) { |
427 if (remaining < (prefinishMark() + tickInterval()/2)) { |
433 if (m_aboutToFinishSent) |
451 if (m_aboutToFinishSent) |
434 if (remaining >= tickInterval()) |
452 if (remaining >= tickInterval()) |
435 m_aboutToFinishSent = false; |
453 m_aboutToFinishSent = false; |
436 } |
454 } |
437 |
455 |
|
456 void MMF::AbstractMediaPlayer::setPending(Pending pending) |
|
457 { |
|
458 const Phonon::State oldState = state(); |
|
459 m_pending = pending; |
|
460 const Phonon::State newState = state(); |
|
461 if (newState != oldState) |
|
462 emit stateChanged(newState, oldState); |
|
463 } |
|
464 |
|
465 void MMF::AbstractMediaPlayer::startPlayback() |
|
466 { |
|
467 doPlay(); |
|
468 startPositionTimer(); |
|
469 changeState(PlayingState); |
|
470 } |
|
471 |
438 void MMF::AbstractMediaPlayer::bufferStatusTick() |
472 void MMF::AbstractMediaPlayer::bufferStatusTick() |
439 { |
473 { |
440 emit MMF::AbstractPlayer::bufferStatus(bufferStatus()); |
474 emit MMF::AbstractPlayer::bufferStatus(bufferStatus()); |
|
475 } |
|
476 |
|
477 Phonon::State MMF::AbstractMediaPlayer::phononState(PrivateState state) const |
|
478 { |
|
479 Phonon::State result = AbstractPlayer::phononState(state); |
|
480 |
|
481 if (PausePending == m_pending) { |
|
482 Q_ASSERT(Phonon::StoppedState == result || Phonon::LoadingState == result); |
|
483 result = Phonon::PausedState; |
|
484 } |
|
485 |
|
486 return result; |
441 } |
487 } |
442 |
488 |
443 void MMF::AbstractMediaPlayer::changeState(PrivateState newState) |
489 void MMF::AbstractMediaPlayer::changeState(PrivateState newState) |
444 { |
490 { |
445 TRACE_CONTEXT(AbstractMediaPlayer::changeState, EAudioInternal); |
491 TRACE_CONTEXT(AbstractMediaPlayer::changeState, EAudioInternal); |
446 |
492 |
447 const Phonon::State oldPhononState = phononState(privateState()); |
493 const Phonon::State oldPhononState = phononState(privateState()); |
448 const Phonon::State newPhononState = phononState(newState); |
494 const Phonon::State newPhononState = phononState(newState); |
449 |
495 |
450 // TODO: add some invariants to check that the transition is valid |
|
451 AbstractPlayer::changeState(newState); |
|
452 |
|
453 if (LoadingState == oldPhononState && StoppedState == newPhononState) { |
496 if (LoadingState == oldPhononState && StoppedState == newPhononState) { |
454 // Ensure initial volume is set on MMF API before starting playback |
497 switch (m_pending) { |
455 doVolumeChanged(); |
498 case NothingPending: |
456 |
499 AbstractPlayer::changeState(newState); |
457 // Check whether play() was called while clip was being loaded. If so, |
500 break; |
458 // playback should be started now |
501 |
459 if (m_playPending) { |
502 case PlayPending: |
460 TRACE_0("play was called while loading; starting playback now"); |
503 changeState(PlayingState); // necessary in order to apply initial volume |
461 m_playPending = false; |
504 doVolumeChanged(); |
462 play(); |
505 startPlayback(); |
463 } |
506 break; |
|
507 |
|
508 case PausePending: |
|
509 AbstractPlayer::changeState(PausedState); |
|
510 break; |
|
511 } |
|
512 |
|
513 setPending(NothingPending); |
|
514 } else { |
|
515 AbstractPlayer::changeState(newState); |
464 } |
516 } |
465 } |
517 } |
466 |
518 |
467 void MMF::AbstractMediaPlayer::updateMetaData() |
519 void MMF::AbstractMediaPlayer::updateMetaData() |
468 { |
520 { |