~ci-train-bot/qtubuntu-media/qtubuntu-media-ubuntu-xenial-landing-035

« back to all changes in this revision

Viewing changes to src/aal/aalmediaplayerservice.cpp

  • Committer: Alfonso Sanchez-Beato
  • Date: 2015-09-02 08:02:08 UTC
  • mfrom: (83.1.2 qtubuntu-media)
  • Revision ID: alfonso.sanchez-beato@canonical.com-20150902080208-tsxsb1ixf7qph5fm
[ Jim Hodapp ]
Added background playlist support connecting qtmultimedia with media-hub.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
#include "aalmediaplayercontrol.h"
18
18
#include "aalmediaplayerservice.h"
19
19
#include "aalmetadatareadercontrol.h"
 
20
#include "aalmediaplaylistcontrol.h"
 
21
#include "aalmediaplaylistprovider.h"
 
22
#include "aalutility.h"
 
23
 
 
24
#include <qmediaplaylistcontrol_p.h>
20
25
 
21
26
#include <core/media/service.h>
22
27
#include <core/media/track_list.h>
24
29
#include <errno.h>
25
30
 
26
31
#include <QAbstractVideoSurface>
 
32
#include <QGuiApplication>
27
33
#include <QTimerEvent>
28
34
#include <QThread>
29
35
 
30
36
#include <qtubuntu_media_signals.h>
31
37
 
 
38
// Uncomment to re-enable media-hub Player session detach/reattach functionality
 
39
//#define DO_PLAYER_ATTACH_DETACH
 
40
 
32
41
// Defined in aalvideorenderercontrol.h
33
42
#ifdef MEASURE_PERFORMANCE
34
43
#include <QDateTime>
56
65
    m_hubPlayerSession(NULL),
57
66
    m_playbackStatusChangedConnection(the_void.connect([](){})),
58
67
    m_errorConnection(the_void.connect([](){})),
 
68
    m_endOfStreamConnection(the_void.connect([](){})),
59
69
    m_mediaPlayerControl(nullptr),
60
70
    m_videoOutput(nullptr),
61
 
    m_metaDataReaderControl(nullptr),
 
71
    m_mediaPlaylistControl(nullptr),
 
72
    m_mediaPlaylistProvider(nullptr),
62
73
    m_videoOutputReady(false),
63
74
    m_firstPlayback(true),
64
75
    m_cachedDuration(0),
65
 
    m_mediaPlaylist(NULL)
 
76
    m_mediaPlaylist(NULL),
 
77
    m_doReattachSession(false)
66
78
#ifdef MEASURE_PERFORMANCE
67
79
     , m_lastFrameDecodeStart(0)
68
80
     , m_currentFrameDecodeStart(0)
72
84
{
73
85
    m_hubService = media::Service::Client::instance();
74
86
 
 
87
    // As core::Connection doesn't allow us to start with a disconnected connection
 
88
    // instance we have to connect it first with a dummy signal and then disconnect
 
89
    // it again. If we don't do this connect_signals() will never be able to attach
 
90
    // to the relevant signals.
 
91
    m_endOfStreamConnection.disconnect();
 
92
 
75
93
    if (!newMediaPlayer())
76
94
        qWarning() << "Failed to create a new media player backend. Video playback will not function." << endl;
77
95
 
83
101
 
84
102
    createMediaPlayerControl();
85
103
    createVideoRendererControl();
86
 
    createMetaDataReaderControl();
87
104
 
88
105
    m_playbackStatusChangedConnection = m_hubPlayerSession->playback_status_changed().connect(
89
106
        [this](const media::Player::PlaybackStatus &status) {
93
110
 
94
111
    m_errorConnection = m_hubPlayerSession->error().connect(
95
112
            std::bind(&AalMediaPlayerService::onError, this, _1));
 
113
 
 
114
    connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &AalMediaPlayerService::onApplicationStateChanged);
96
115
}
97
116
 
98
117
AalMediaPlayerService::~AalMediaPlayerService()
100
119
    m_errorConnection.disconnect();
101
120
    m_playbackStatusChangedConnection.disconnect();
102
121
 
103
 
    deleteMediaPlayerControl();
104
 
    if (isVideoSource())
 
122
    if (m_videoOutput)
105
123
        deleteVideoRendererControl();
106
124
 
107
 
    deleteMetaDataReaderControl();
 
125
    if (m_mediaPlaylistControl)
 
126
        deletePlaylistControl();
 
127
 
 
128
    if (m_mediaPlayerControl)
 
129
        deleteMediaPlayerControl();
 
130
 
 
131
    if (m_hubPlayerSession)
 
132
        destroyPlayerSession();
108
133
}
109
134
 
110
135
QMediaControl *AalMediaPlayerService::requestControl(const char *name)
125
150
        return m_videoOutput;
126
151
    }
127
152
 
128
 
    if (qstrcmp(name, QMetaDataReaderControl_iid) == 0)
 
153
    if (qstrcmp(name, QMediaPlaylistControl_iid) == 0)
129
154
    {
130
 
        if (not m_metaDataReaderControl)
131
 
            createMetaDataReaderControl();
132
 
 
133
 
        return m_metaDataReaderControl;
 
155
        if (not m_mediaPlaylistControl)
 
156
            createPlaylistControl();
 
157
 
 
158
        // Pass on the media-hub Player object to the playlist control
 
159
        if (m_hubPlayerSession)
 
160
            m_mediaPlaylistControl->setPlayerSession(m_hubPlayerSession);
 
161
 
 
162
        return m_mediaPlaylistControl;
134
163
    }
135
164
 
136
165
    return NULL;
138
167
 
139
168
void AalMediaPlayerService::releaseControl(QMediaControl *control)
140
169
{
141
 
    if (control == m_mediaPlayerControl)
142
 
        deleteMediaPlayerControl();
143
 
    else if (control == m_videoOutput)
 
170
    if (control == m_videoOutput)
144
171
        deleteVideoRendererControl();
145
 
    else if (control == m_metaDataReaderControl)
146
 
        deleteMetaDataReaderControl();
147
 
    else
148
 
        delete control;
149
172
}
150
173
 
151
174
bool AalMediaPlayerService::newMediaPlayer()
168
191
        return false;
169
192
    }
170
193
 
 
194
    try {
 
195
        // Get the player session UUID so we can suspend/restore our session when the ApplicationState
 
196
        // changes
 
197
        m_sessionUuid = m_hubPlayerSession->uuid();
 
198
    } catch (const std::runtime_error &e) {
 
199
        qWarning() << "Failed to retrieve the current player's uuid: " << e.what() << endl;
 
200
        return false;
 
201
    }
 
202
 
171
203
    return true;
172
204
}
173
205
 
261
293
    qDebug() << "Setting media to: " << url;
262
294
    const media::Track::UriType uri(url.url().toStdString());
263
295
    try {
264
 
        m_hubPlayerSession->open_uri(uri);
 
296
        if (m_mediaPlaylistProvider != NULL)
 
297
            m_mediaPlaylistProvider->addMedia(QMediaContent(url));
 
298
        else
 
299
            m_hubPlayerSession->open_uri(uri);
265
300
    }
266
301
    catch (const std::runtime_error &e) {
267
302
        qWarning() << "Failed to open media " << url << ": " << e.what();
272
307
        m_videoOutput->setupSurface();
273
308
}
274
309
 
 
310
void AalMediaPlayerService::setMedia(const QMediaContent &media)
 
311
{
 
312
    if (m_hubPlayerSession == NULL)
 
313
    {
 
314
        qWarning() << "Cannot open media without a valid media-hub player session";
 
315
        return;
 
316
    }
 
317
    if (m_mediaPlaylistProvider == NULL)
 
318
    {
 
319
        qWarning() << "Cannot open media without a valid QMediaPlaylistProvider instance";
 
320
        return;
 
321
    }
 
322
    if (media.isNull())
 
323
    {
 
324
        qWarning() << "Failed to set media source, media must be set." << endl;
 
325
        return;
 
326
    }
 
327
 
 
328
    qDebug() << "Setting media to: " << AalUtility::unescape(media);
 
329
    try {
 
330
        m_mediaPlaylistProvider->addMedia(media);
 
331
    }
 
332
    catch (const std::runtime_error &e) {
 
333
        qWarning() << "Failed to open media " << AalUtility::unescape(media) << ": " << e.what();
 
334
        return;
 
335
    }
 
336
 
 
337
    if (isVideoSource())
 
338
        m_videoOutput->setupSurface();
 
339
}
 
340
 
275
341
void AalMediaPlayerService::play()
276
342
{
277
343
    qDebug() << Q_FUNC_INFO;
480
546
        return;
481
547
 
482
548
    m_mediaPlayerControl = new AalMediaPlayerControl(this);
483
 
    m_hubPlayerSession->end_of_stream().connect([this]()
484
 
    {
485
 
        m_firstPlayback = false;
486
 
        Q_EMIT playbackComplete();
487
 
    });
 
549
    connect_signals();
488
550
}
489
551
 
490
552
void AalMediaPlayerService::createVideoRendererControl()
495
557
    m_videoOutput = new AalVideoRendererControl(this);
496
558
}
497
559
 
498
 
void AalMediaPlayerService::createMetaDataReaderControl()
 
560
void AalMediaPlayerService::createPlaylistControl()
499
561
{
500
562
    qDebug() << Q_FUNC_INFO;
501
 
 
502
 
    m_metaDataReaderControl = new AalMetaDataReaderControl(this);
503
 
 
504
 
    if (m_mediaPlayerControl == nullptr)
505
 
        qDebug() << "m_mediaPlayerControl is NULL, can't connect mediaChanged signal";
506
 
 
507
 
    connect(m_mediaPlayerControl, SIGNAL(mediaChanged(QMediaContent)),
508
 
            m_metaDataReaderControl, SLOT(onMediaChanged(QMediaContent)));
 
563
    m_mediaPlaylistControl = new AalMediaPlaylistControl(this);
 
564
    m_mediaPlaylistProvider = new AalMediaPlaylistProvider(this);
 
565
    m_mediaPlaylistControl->setPlaylistProvider(m_mediaPlaylistProvider);
509
566
}
510
567
 
511
568
void AalMediaPlayerService::deleteMediaPlayerControl()
512
569
{
513
 
    if (m_hubPlayerSession == NULL)
514
 
        return;
515
 
 
516
 
    delete m_mediaPlayerControl;
517
 
    m_mediaPlayerControl = NULL;
 
570
    qDebug() << Q_FUNC_INFO;
 
571
 
 
572
    if (not m_hubPlayerSession)
 
573
        return;
 
574
 
 
575
    if (m_mediaPlayerControl)
 
576
    {
 
577
        delete m_mediaPlayerControl;
 
578
        m_mediaPlayerControl = nullptr;
 
579
    }
 
580
}
 
581
 
 
582
void AalMediaPlayerService::destroyPlayerSession()
 
583
{
 
584
    qDebug() << Q_FUNC_INFO;
 
585
 
 
586
    if (not m_hubPlayerSession)
 
587
        return;
 
588
 
 
589
    try {
 
590
        // Invalidates the media-hub player session
 
591
        m_hubService->destroy_session(m_sessionUuid, media::Player::Client::default_configuration());
 
592
        m_sessionUuid.clear();
 
593
 
 
594
        // When we arrived here the session is already invalid and we
 
595
        // can safely drop the reference.
 
596
        m_hubPlayerSession = nullptr;
 
597
    }
 
598
    catch (const std::runtime_error &e) {
 
599
        qWarning() << "Failed to destroy existing media-hub player session: " << e.what();
 
600
    }
518
601
}
519
602
 
520
603
void AalMediaPlayerService::deleteVideoRendererControl()
521
604
{
522
 
    if (m_hubPlayerSession == nullptr)
523
 
        return;
524
 
 
525
 
    delete m_videoOutput;
526
 
    m_videoOutput = nullptr;
 
605
    if (m_videoOutput)
 
606
    {
 
607
        delete m_videoOutput;
 
608
        m_videoOutput = nullptr;
 
609
    }
527
610
}
528
611
 
529
 
void AalMediaPlayerService::deleteMetaDataReaderControl()
 
612
void AalMediaPlayerService::deletePlaylistControl()
530
613
{
531
 
    if (m_hubPlayerSession == nullptr)
532
 
        return;
 
614
    qDebug() << Q_FUNC_INFO;
533
615
 
534
 
    delete m_metaDataReaderControl;
535
 
    m_metaDataReaderControl = nullptr;
 
616
    if (m_mediaPlaylistProvider)
 
617
    {
 
618
        delete m_mediaPlaylistProvider;
 
619
        m_mediaPlaylistProvider = nullptr;
 
620
    }
 
621
    if (m_mediaPlaylistControl)
 
622
    {
 
623
        delete m_mediaPlaylistControl;
 
624
        m_mediaPlaylistControl = nullptr;
 
625
    }
536
626
}
537
627
 
538
628
void AalMediaPlayerService::signalQMediaPlayerError(const media::Player::Error &error)
580
670
    // the app is notified about this so it can change it's status
581
671
    switch (m_newStatus)
582
672
    {
583
 
        qDebug() << "PlaybackStatus changed to: " << m_newStatus;
584
673
        case media::Player::PlaybackStatus::ready:
585
674
        case media::Player::PlaybackStatus::stopped:
586
675
            m_mediaPlayerControl->setState(QMediaPlayer::StoppedState);
597
686
        default:
598
687
            qWarning() << "Unknown PlaybackStatus: " << m_newStatus;
599
688
    }
 
689
 
 
690
    qDebug() << "PlaybackStatus changed to: " << m_newStatus;
 
691
}
 
692
 
 
693
void AalMediaPlayerService::onApplicationStateChanged(Qt::ApplicationState state)
 
694
{
 
695
    try {
 
696
        switch (state)
 
697
        {
 
698
            case Qt::ApplicationSuspended:
 
699
                qDebug() << "** Application has been suspended";
 
700
                break;
 
701
            case Qt::ApplicationHidden:
 
702
                qDebug() << "** Application is now hidden";
 
703
                break;
 
704
            case Qt::ApplicationInactive:
 
705
                qDebug() << "** Application is now inactive";
 
706
#ifdef DO_PLAYER_ATTACH_DETACH
 
707
                disconnect_signals();
 
708
                m_hubService->detach_session(m_sessionUuid, media::Player::Client::default_configuration());
 
709
                m_doReattachSession = true;
 
710
#endif
 
711
                break;
 
712
            case Qt::ApplicationActive:
 
713
                qDebug() << "** Application is now active";
 
714
#ifdef DO_PLAYER_ATTACH_DETACH
 
715
                // Avoid doing this for when the client application first loads as this
 
716
                // will break video playback
 
717
                if (m_doReattachSession)
 
718
                {
 
719
                    m_hubPlayerSession = m_hubService->reattach_session(m_sessionUuid, media::Player::Client::default_configuration());
 
720
                    // Make sure the client's status (position, duraiton, state, etc) are all correct when reattaching
 
721
                    // to the media-hub Player session
 
722
                    updateClientSignals();
 
723
                    connect_signals();
 
724
                }
 
725
#endif
 
726
                break;
 
727
            default:
 
728
                qDebug() << "Unknown ApplicationState";
 
729
                break;
 
730
        }
 
731
    } catch (const std::runtime_error &e) {
 
732
        qWarning() << "Failed to respond to ApplicationState change: " << e.what();
 
733
    }
 
734
}
 
735
 
 
736
void AalMediaPlayerService::updateClientSignals()
 
737
{
 
738
    qDebug() << Q_FUNC_INFO;
 
739
    if (m_mediaPlayerControl == nullptr)
 
740
        return;
 
741
 
 
742
    Q_EMIT m_mediaPlayerControl->durationChanged(duration());
 
743
    Q_EMIT m_mediaPlayerControl->positionChanged(position());
 
744
    switch (m_newStatus)
 
745
    {
 
746
        case media::Player::PlaybackStatus::ready:
 
747
        case media::Player::PlaybackStatus::stopped:
 
748
            m_mediaPlayerControl->setState(QMediaPlayer::StoppedState);
 
749
            break;
 
750
        case media::Player::PlaybackStatus::paused:
 
751
            m_mediaPlayerControl->setState(QMediaPlayer::PausedState);
 
752
            break;
 
753
        case media::Player::PlaybackStatus::playing:
 
754
            m_mediaPlayerControl->setState(QMediaPlayer::PlayingState);
 
755
            break;
 
756
        default:
 
757
            qWarning() << "Unknown PlaybackStatus: " << m_newStatus;
 
758
    }
 
759
}
 
760
 
 
761
void AalMediaPlayerService::connect_signals()
 
762
{
 
763
    if (!m_endOfStreamConnection.is_connected())
 
764
    {
 
765
        m_endOfStreamConnection = m_hubPlayerSession->end_of_stream().connect([this]()
 
766
        {
 
767
            m_firstPlayback = false;
 
768
            Q_EMIT playbackComplete();
 
769
        });
 
770
    }
 
771
}
 
772
 
 
773
void AalMediaPlayerService::disconnect_signals()
 
774
{
 
775
    if (m_endOfStreamConnection.is_connected())
 
776
        m_endOfStreamConnection.disconnect();
600
777
}
601
778
 
602
779
void AalMediaPlayerService::onError(const core::ubuntu::media::Player::Error &error)
605
782
    signalQMediaPlayerError(error);
606
783
}
607
784
 
608
 
void AalMediaPlayerService::pushPlaylist()
609
 
{
610
 
    if (m_hubPlayerSession == NULL)
611
 
    {
612
 
        qWarning() << "Cannot push playlist without a valid media-hub player session";
613
 
        return;
614
 
    }
615
 
 
616
 
    if (m_mediaPlaylist == NULL)
617
 
        return;
618
 
 
619
 
    for (int i = 0; i < m_mediaPlaylist->mediaCount(); i++)
620
 
    {
621
 
        const media::Track::UriType uri(m_mediaPlaylist->media(i).canonicalUrl().url().toStdString());
622
 
        m_hubPlayerSession->track_list()->add_track_with_uri_at(uri, media::TrackList::after_empty_track(), false);
623
 
    }
624
 
}
625
 
 
626
785
void AalMediaPlayerService::setPlayer(const std::shared_ptr<core::ubuntu::media::Player> &player)
627
786
{
628
787
    m_hubPlayerSession = player;
629
788
 
630
789
    createMediaPlayerControl();
631
790
    createVideoRendererControl();
632
 
    createMetaDataReaderControl();
633
791
 
634
 
    m_hubPlayerSession->playback_status_changed().connect(
635
 
        [this](const media::Player::PlaybackStatus &status) {
636
 
            m_newStatus = status;
637
 
            QMetaObject::invokeMethod(this, "onPlaybackStatusChanged", Qt::QueuedConnection);
638
 
        });
 
792
    if (!m_playbackStatusChangedConnection.is_connected())
 
793
    {
 
794
        m_playbackStatusChangedConnection = m_hubPlayerSession->playback_status_changed().connect(
 
795
            [this](const media::Player::PlaybackStatus &status) {
 
796
                m_newStatus = status;
 
797
                QMetaObject::invokeMethod(this, "onPlaybackStatusChanged", Qt::QueuedConnection);
 
798
            });
 
799
    }
639
800
}
640
801
 
641
802
void AalMediaPlayerService::setService(const std::shared_ptr<core::ubuntu::media::Service> &service)