Merge lp:~thomas-voss/qtubuntu-media/fix-races-for-access-to-destroyed-controls into lp:qtubuntu-media

Proposed by Thomas Voß
Status: Merged
Approved by: Jim Hodapp
Approved revision: 48
Merged at revision: 47
Proposed branch: lp:~thomas-voss/qtubuntu-media/fix-races-for-access-to-destroyed-controls
Merge into: lp:qtubuntu-media
Diff against target: 253 lines (+80/-40)
4 files modified
src/aal/aalmediaplayerservice.cpp (+71/-34)
src/aal/aalmediaplayerservice.h (+6/-3)
src/aal/aalmediaplayerserviceplugin.cpp (+1/-1)
unittests/tst_mediaplayerplugin.cpp (+2/-2)
To merge this branch: bzr merge lp:~thomas-voss/qtubuntu-media/fix-races-for-access-to-destroyed-controls
Reviewer Review Type Date Requested Status
Antti Kaijanmäki (community) Approve
PS Jenkins bot continuous-integration Approve
Michał Sawicz Approve
Review via email: mp+238404@code.launchpad.net

Commit message

Make sure that invocations on probably deleted objects in async callbacks are guarded.
Condense creation/deletion of controls in one place.

Description of the change

Make sure that invocations on probably deleted objects in async callbacks are guarded.
Condense creation/deletion of controls in one place.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

Code makes sense! Will try it out from a silo, trying to reproduce the crash.

review: Approve
48. By Thomas Voß

Adjust test setup for stricter checks in ctor.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Antti Kaijanmäki (kaijanmaki) wrote :

OK. Looks better to me :)

review: Approve
Revision history for this message
Antti Kaijanmäki (kaijanmaki) wrote :

Does not fix bug #1376467.

Seems to fix bug #1380736.

tested on krillin, rtm-proposed image #105

Revision history for this message
Michał Sawicz (saviq) wrote :

Confirmed, steps in bug #1376467 are still broken.

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

Does not seem to fix #1378311 with the example.qml attached in that bug description.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/aal/aalmediaplayerservice.cpp'
--- src/aal/aalmediaplayerservice.cpp 2014-09-22 16:11:46 +0000
+++ src/aal/aalmediaplayerservice.cpp 2014-10-15 10:24:28 +0000
@@ -38,13 +38,22 @@
3838
39using namespace std::placeholders;39using namespace std::placeholders;
4040
41namespace
42{
41enum {43enum {
42 OK = 0,44 OK = 0,
43 NO_ERROR = 0,45 NO_ERROR = 0,
44 BAD_VALUE = -EINVAL,46 BAD_VALUE = -EINVAL,
45};47};
4648
47AalMediaPlayerService *AalMediaPlayerService::m_service = 0;49core::ubuntu::media::Player::FrameAvailableCb empty_frame_available_cb = [](void*)
50{
51};
52
53core::ubuntu::media::Player::PlaybackCompleteCb empty_playback_complete_cb = [](void*)
54{
55};
56}
4857
49AalMediaPlayerService::AalMediaPlayerService(QObject *parent):58AalMediaPlayerService::AalMediaPlayerService(QObject *parent):
50 QMediaService(parent),59 QMediaService(parent),
@@ -61,25 +70,16 @@
61 , m_frameDecodeAvg(0)70 , m_frameDecodeAvg(0)
62#endif71#endif
63{72{
64 m_service = this;
65
66 m_hubService = media::Service::Client::instance();73 m_hubService = media::Service::Client::instance();
6774
68 if (!newMediaPlayer())75 if (!newMediaPlayer())
69 qWarning() << "Failed to create a new media player backend. Video playback will not function." << endl;76 qWarning() << "Failed to create a new media player backend. Video playback will not function." << endl;
7077
71 m_videoOutput = new AalVideoRendererControl(this);
72 m_mediaPlayerControl = new AalMediaPlayerControl(this);
73
74 if (m_hubPlayerSession == NULL)78 if (m_hubPlayerSession == NULL)
75 return;79 return;
7680
77 m_hubPlayerSession->set_playback_complete_callback([](void *context)81 createMediaPlayerControl();
78 {82 createVideoRendererControl();
79 auto control = static_cast<AalMediaPlayerControl*>(context);
80 control->playbackComplete();
81 },
82 static_cast<void*>(m_mediaPlayerControl));
8383
84 m_hubPlayerSession->playback_status_changed().connect(84 m_hubPlayerSession->playback_status_changed().connect(
85 std::bind(&AalMediaPlayerService::onPlaybackStatusChanged, this, _1));85 std::bind(&AalMediaPlayerService::onPlaybackStatusChanged, this, _1));
@@ -87,10 +87,8 @@
8787
88AalMediaPlayerService::~AalMediaPlayerService()88AalMediaPlayerService::~AalMediaPlayerService()
89{89{
90 if (m_mediaPlayerControl != NULL)90 deleteMediaPlayerControl();
91 delete m_mediaPlayerControl;91 deleteVideoRendererControl();
92 if (m_videoOutput != NULL)
93 delete m_videoOutput;
94}92}
9593
96QMediaControl *AalMediaPlayerService::requestControl(const char *name)94QMediaControl *AalMediaPlayerService::requestControl(const char *name)
@@ -98,7 +96,7 @@
98 if (qstrcmp(name, QMediaPlayerControl_iid) == 0)96 if (qstrcmp(name, QMediaPlayerControl_iid) == 0)
99 {97 {
100 if (m_mediaPlayerControlRef == 0 && m_mediaPlayerControl == NULL)98 if (m_mediaPlayerControlRef == 0 && m_mediaPlayerControl == NULL)
101 m_mediaPlayerControl = new AalMediaPlayerControl(this);99 createMediaPlayerControl();
102100
103 ++m_mediaPlayerControlRef;101 ++m_mediaPlayerControlRef;
104 return m_mediaPlayerControl;102 return m_mediaPlayerControl;
@@ -107,7 +105,7 @@
107 if (qstrcmp(name, QVideoRendererControl_iid) == 0)105 if (qstrcmp(name, QVideoRendererControl_iid) == 0)
108 {106 {
109 if (m_videoOutputRef == 0 && m_videoOutput == NULL)107 if (m_videoOutputRef == 0 && m_videoOutput == NULL)
110 m_videoOutput = new AalVideoRendererControl(this);108 createVideoRendererControl();
111109
112 ++m_videoOutputRef;110 ++m_videoOutputRef;
113 return m_videoOutput;111 return m_videoOutput;
@@ -124,14 +122,7 @@
124 --m_mediaPlayerControlRef;122 --m_mediaPlayerControlRef;
125123
126 if (m_mediaPlayerControlRef == 0)124 if (m_mediaPlayerControlRef == 0)
127 {125 deleteMediaPlayerControl();
128 if (m_mediaPlayerControl != NULL)
129 {
130 delete m_mediaPlayerControl;
131 m_mediaPlayerControl = NULL;
132 control = NULL;
133 }
134 }
135 }126 }
136 else if (control == m_videoOutput)127 else if (control == m_videoOutput)
137 {128 {
@@ -139,14 +130,7 @@
139 --m_videoOutputRef;130 --m_videoOutputRef;
140131
141 if (m_videoOutputRef == 0)132 if (m_videoOutputRef == 0)
142 {133 deleteVideoRendererControl();
143 if (m_videoOutput != NULL)
144 {
145 delete m_videoOutput;
146 m_videoOutput = NULL;
147 control = NULL;
148 }
149 }
150 }134 }
151}135}
152136
@@ -202,6 +186,12 @@
202 if (context != NULL)186 if (context != NULL)
203 {187 {
204 auto s = static_cast<AalMediaPlayerService*>(context);188 auto s = static_cast<AalMediaPlayerService*>(context);
189
190 // We might receive this callback after the control has been released.
191 // In that case, we return early.
192 if (not s->videoOutputControl())
193 return;
194
205#ifdef MEASURE_PERFORMANCE195#ifdef MEASURE_PERFORMANCE
206 s->measurePerformance();196 s->measurePerformance();
207#endif197#endif
@@ -453,8 +443,49 @@
453 }443 }
454}444}
455445
446void AalMediaPlayerService::createMediaPlayerControl()
447{
448 m_mediaPlayerControl = new AalMediaPlayerControl(this);
449 m_hubPlayerSession->set_playback_complete_callback([](void *context)
450 {
451 auto control = static_cast<AalMediaPlayerControl*>(context);
452 control->playbackComplete();
453 },
454 m_mediaPlayerControl);
455}
456
457void AalMediaPlayerService::createVideoRendererControl()
458{
459 m_videoOutput = new AalVideoRendererControl(this);
460}
461
462void AalMediaPlayerService::deleteMediaPlayerControl()
463{
464 m_hubPlayerSession->set_playback_complete_callback(
465 empty_playback_complete_cb,
466 nullptr);
467
468 delete m_mediaPlayerControl;
469 m_mediaPlayerControl = NULL;
470}
471
472void AalMediaPlayerService::deleteVideoRendererControl()
473{
474 m_hubPlayerSession->set_frame_available_callback(
475 empty_frame_available_cb,
476 nullptr);
477
478 delete m_videoOutput;
479 m_videoOutput = NULL;
480}
481
456void AalMediaPlayerService::onPlaybackStatusChanged(const media::Player::PlaybackStatus &status)482void AalMediaPlayerService::onPlaybackStatusChanged(const media::Player::PlaybackStatus &status)
457{483{
484 // The media player control might have been released prior to this call. For that, we check for
485 // null and return early in that case.
486 if (m_mediaPlayerControl == nullptr)
487 return;
488
458 // If the playback status changes from underneath (e.g. GStreamer or media-hub), make sure489 // If the playback status changes from underneath (e.g. GStreamer or media-hub), make sure
459 // the app is notified about this so it can change it's status490 // the app is notified about this so it can change it's status
460 switch (status)491 switch (status)
@@ -497,6 +528,12 @@
497void AalMediaPlayerService::setPlayer(const std::shared_ptr<core::ubuntu::media::Player> &player)528void AalMediaPlayerService::setPlayer(const std::shared_ptr<core::ubuntu::media::Player> &player)
498{529{
499 m_hubPlayerSession = player;530 m_hubPlayerSession = player;
531
532 createMediaPlayerControl();
533 createVideoRendererControl();
534
535 m_hubPlayerSession->playback_status_changed().connect(
536 std::bind(&AalMediaPlayerService::onPlaybackStatusChanged, this, _1));
500}537}
501538
502void AalMediaPlayerService::setService(const std::shared_ptr<core::ubuntu::media::Service> &service)539void AalMediaPlayerService::setService(const std::shared_ptr<core::ubuntu::media::Service> &service)
503540
=== modified file 'src/aal/aalmediaplayerservice.h'
--- src/aal/aalmediaplayerservice.h 2014-09-22 16:11:46 +0000
+++ src/aal/aalmediaplayerservice.h 2014-10-15 10:24:28 +0000
@@ -83,8 +83,6 @@
8383
84 void pushPlaylist();84 void pushPlaylist();
8585
86 static AalMediaPlayerService *instance() { return m_service; }
87
88 /* This is for unittest purposes to be able to set a mock-object version of a86 /* This is for unittest purposes to be able to set a mock-object version of a
89 * player object */87 * player object */
90 void setPlayer(const std::shared_ptr<core::ubuntu::media::Player> &player);88 void setPlayer(const std::shared_ptr<core::ubuntu::media::Player> &player);
@@ -101,9 +99,14 @@
101#endif99#endif
102100
103private:101private:
102 void createMediaPlayerControl();
103 void createVideoRendererControl();
104
105 void deleteMediaPlayerControl();
106 void deleteVideoRendererControl();
107
104 void onPlaybackStatusChanged(const core::ubuntu::media::Player::PlaybackStatus &status);108 void onPlaybackStatusChanged(const core::ubuntu::media::Player::PlaybackStatus &status);
105109
106 static AalMediaPlayerService *m_service;
107 std::shared_ptr<core::ubuntu::media::Service> m_hubService;110 std::shared_ptr<core::ubuntu::media::Service> m_hubService;
108 std::shared_ptr<core::ubuntu::media::Player> m_hubPlayerSession;111 std::shared_ptr<core::ubuntu::media::Player> m_hubPlayerSession;
109112
110113
=== modified file 'src/aal/aalmediaplayerserviceplugin.cpp'
--- src/aal/aalmediaplayerserviceplugin.cpp 2014-03-26 16:08:35 +0000
+++ src/aal/aalmediaplayerserviceplugin.cpp 2014-10-15 10:24:28 +0000
@@ -27,7 +27,7 @@
27QMediaService* AalServicePlugin::create(QString const& key)27QMediaService* AalServicePlugin::create(QString const& key)
28{28{
29 if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER))29 if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER))
30 return new AalMediaPlayerService;30 return new AalMediaPlayerService();
31 else31 else
32 qWarning() << "Key not supported:" << key;32 qWarning() << "Key not supported:" << key;
3333
3434
=== modified file 'unittests/tst_mediaplayerplugin.cpp'
--- unittests/tst_mediaplayerplugin.cpp 2014-04-25 21:12:56 +0000
+++ unittests/tst_mediaplayerplugin.cpp 2014-10-15 10:24:28 +0000
@@ -67,10 +67,10 @@
67{67{
68 m_hubService.reset(new TestService());68 m_hubService.reset(new TestService());
69 m_service.reset(new AalMediaPlayerService(this));69 m_service.reset(new AalMediaPlayerService(this));
70 m_service->setService(m_hubService);70 m_service->setService(m_hubService);
71 m_mediaPlayerControl = m_service->mediaPlayerControl();
72 m_player.reset(new TestPlayer());71 m_player.reset(new TestPlayer());
73 m_service->setPlayer(m_player);72 m_service->setPlayer(m_player);
73 m_mediaPlayerControl = m_service->mediaPlayerControl();
74 m_playerControl = m_service->requestControl(QMediaPlayerControl_iid);74 m_playerControl = m_service->requestControl(QMediaPlayerControl_iid);
75 QVERIFY(m_playerControl != NULL);75 QVERIFY(m_playerControl != NULL);
76 m_rendererControl = m_service->requestControl(QVideoRendererControl_iid);76 m_rendererControl = m_service->requestControl(QVideoRendererControl_iid);

Subscribers

People subscribed via source and target branches