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
1=== modified file 'src/aal/aalmediaplayerservice.cpp'
2--- src/aal/aalmediaplayerservice.cpp 2014-09-22 16:11:46 +0000
3+++ src/aal/aalmediaplayerservice.cpp 2014-10-15 10:24:28 +0000
4@@ -38,13 +38,22 @@
5
6 using namespace std::placeholders;
7
8+namespace
9+{
10 enum {
11 OK = 0,
12 NO_ERROR = 0,
13 BAD_VALUE = -EINVAL,
14 };
15
16-AalMediaPlayerService *AalMediaPlayerService::m_service = 0;
17+core::ubuntu::media::Player::FrameAvailableCb empty_frame_available_cb = [](void*)
18+{
19+};
20+
21+core::ubuntu::media::Player::PlaybackCompleteCb empty_playback_complete_cb = [](void*)
22+{
23+};
24+}
25
26 AalMediaPlayerService::AalMediaPlayerService(QObject *parent):
27 QMediaService(parent),
28@@ -61,25 +70,16 @@
29 , m_frameDecodeAvg(0)
30 #endif
31 {
32- m_service = this;
33-
34 m_hubService = media::Service::Client::instance();
35
36 if (!newMediaPlayer())
37 qWarning() << "Failed to create a new media player backend. Video playback will not function." << endl;
38
39- m_videoOutput = new AalVideoRendererControl(this);
40- m_mediaPlayerControl = new AalMediaPlayerControl(this);
41-
42 if (m_hubPlayerSession == NULL)
43 return;
44
45- m_hubPlayerSession->set_playback_complete_callback([](void *context)
46- {
47- auto control = static_cast<AalMediaPlayerControl*>(context);
48- control->playbackComplete();
49- },
50- static_cast<void*>(m_mediaPlayerControl));
51+ createMediaPlayerControl();
52+ createVideoRendererControl();
53
54 m_hubPlayerSession->playback_status_changed().connect(
55 std::bind(&AalMediaPlayerService::onPlaybackStatusChanged, this, _1));
56@@ -87,10 +87,8 @@
57
58 AalMediaPlayerService::~AalMediaPlayerService()
59 {
60- if (m_mediaPlayerControl != NULL)
61- delete m_mediaPlayerControl;
62- if (m_videoOutput != NULL)
63- delete m_videoOutput;
64+ deleteMediaPlayerControl();
65+ deleteVideoRendererControl();
66 }
67
68 QMediaControl *AalMediaPlayerService::requestControl(const char *name)
69@@ -98,7 +96,7 @@
70 if (qstrcmp(name, QMediaPlayerControl_iid) == 0)
71 {
72 if (m_mediaPlayerControlRef == 0 && m_mediaPlayerControl == NULL)
73- m_mediaPlayerControl = new AalMediaPlayerControl(this);
74+ createMediaPlayerControl();
75
76 ++m_mediaPlayerControlRef;
77 return m_mediaPlayerControl;
78@@ -107,7 +105,7 @@
79 if (qstrcmp(name, QVideoRendererControl_iid) == 0)
80 {
81 if (m_videoOutputRef == 0 && m_videoOutput == NULL)
82- m_videoOutput = new AalVideoRendererControl(this);
83+ createVideoRendererControl();
84
85 ++m_videoOutputRef;
86 return m_videoOutput;
87@@ -124,14 +122,7 @@
88 --m_mediaPlayerControlRef;
89
90 if (m_mediaPlayerControlRef == 0)
91- {
92- if (m_mediaPlayerControl != NULL)
93- {
94- delete m_mediaPlayerControl;
95- m_mediaPlayerControl = NULL;
96- control = NULL;
97- }
98- }
99+ deleteMediaPlayerControl();
100 }
101 else if (control == m_videoOutput)
102 {
103@@ -139,14 +130,7 @@
104 --m_videoOutputRef;
105
106 if (m_videoOutputRef == 0)
107- {
108- if (m_videoOutput != NULL)
109- {
110- delete m_videoOutput;
111- m_videoOutput = NULL;
112- control = NULL;
113- }
114- }
115+ deleteVideoRendererControl();
116 }
117 }
118
119@@ -202,6 +186,12 @@
120 if (context != NULL)
121 {
122 auto s = static_cast<AalMediaPlayerService*>(context);
123+
124+ // We might receive this callback after the control has been released.
125+ // In that case, we return early.
126+ if (not s->videoOutputControl())
127+ return;
128+
129 #ifdef MEASURE_PERFORMANCE
130 s->measurePerformance();
131 #endif
132@@ -453,8 +443,49 @@
133 }
134 }
135
136+void AalMediaPlayerService::createMediaPlayerControl()
137+{
138+ m_mediaPlayerControl = new AalMediaPlayerControl(this);
139+ m_hubPlayerSession->set_playback_complete_callback([](void *context)
140+ {
141+ auto control = static_cast<AalMediaPlayerControl*>(context);
142+ control->playbackComplete();
143+ },
144+ m_mediaPlayerControl);
145+}
146+
147+void AalMediaPlayerService::createVideoRendererControl()
148+{
149+ m_videoOutput = new AalVideoRendererControl(this);
150+}
151+
152+void AalMediaPlayerService::deleteMediaPlayerControl()
153+{
154+ m_hubPlayerSession->set_playback_complete_callback(
155+ empty_playback_complete_cb,
156+ nullptr);
157+
158+ delete m_mediaPlayerControl;
159+ m_mediaPlayerControl = NULL;
160+}
161+
162+void AalMediaPlayerService::deleteVideoRendererControl()
163+{
164+ m_hubPlayerSession->set_frame_available_callback(
165+ empty_frame_available_cb,
166+ nullptr);
167+
168+ delete m_videoOutput;
169+ m_videoOutput = NULL;
170+}
171+
172 void AalMediaPlayerService::onPlaybackStatusChanged(const media::Player::PlaybackStatus &status)
173 {
174+ // The media player control might have been released prior to this call. For that, we check for
175+ // null and return early in that case.
176+ if (m_mediaPlayerControl == nullptr)
177+ return;
178+
179 // If the playback status changes from underneath (e.g. GStreamer or media-hub), make sure
180 // the app is notified about this so it can change it's status
181 switch (status)
182@@ -497,6 +528,12 @@
183 void AalMediaPlayerService::setPlayer(const std::shared_ptr<core::ubuntu::media::Player> &player)
184 {
185 m_hubPlayerSession = player;
186+
187+ createMediaPlayerControl();
188+ createVideoRendererControl();
189+
190+ m_hubPlayerSession->playback_status_changed().connect(
191+ std::bind(&AalMediaPlayerService::onPlaybackStatusChanged, this, _1));
192 }
193
194 void AalMediaPlayerService::setService(const std::shared_ptr<core::ubuntu::media::Service> &service)
195
196=== modified file 'src/aal/aalmediaplayerservice.h'
197--- src/aal/aalmediaplayerservice.h 2014-09-22 16:11:46 +0000
198+++ src/aal/aalmediaplayerservice.h 2014-10-15 10:24:28 +0000
199@@ -83,8 +83,6 @@
200
201 void pushPlaylist();
202
203- static AalMediaPlayerService *instance() { return m_service; }
204-
205 /* This is for unittest purposes to be able to set a mock-object version of a
206 * player object */
207 void setPlayer(const std::shared_ptr<core::ubuntu::media::Player> &player);
208@@ -101,9 +99,14 @@
209 #endif
210
211 private:
212+ void createMediaPlayerControl();
213+ void createVideoRendererControl();
214+
215+ void deleteMediaPlayerControl();
216+ void deleteVideoRendererControl();
217+
218 void onPlaybackStatusChanged(const core::ubuntu::media::Player::PlaybackStatus &status);
219
220- static AalMediaPlayerService *m_service;
221 std::shared_ptr<core::ubuntu::media::Service> m_hubService;
222 std::shared_ptr<core::ubuntu::media::Player> m_hubPlayerSession;
223
224
225=== modified file 'src/aal/aalmediaplayerserviceplugin.cpp'
226--- src/aal/aalmediaplayerserviceplugin.cpp 2014-03-26 16:08:35 +0000
227+++ src/aal/aalmediaplayerserviceplugin.cpp 2014-10-15 10:24:28 +0000
228@@ -27,7 +27,7 @@
229 QMediaService* AalServicePlugin::create(QString const& key)
230 {
231 if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER))
232- return new AalMediaPlayerService;
233+ return new AalMediaPlayerService();
234 else
235 qWarning() << "Key not supported:" << key;
236
237
238=== modified file 'unittests/tst_mediaplayerplugin.cpp'
239--- unittests/tst_mediaplayerplugin.cpp 2014-04-25 21:12:56 +0000
240+++ unittests/tst_mediaplayerplugin.cpp 2014-10-15 10:24:28 +0000
241@@ -67,10 +67,10 @@
242 {
243 m_hubService.reset(new TestService());
244 m_service.reset(new AalMediaPlayerService(this));
245- m_service->setService(m_hubService);
246- m_mediaPlayerControl = m_service->mediaPlayerControl();
247+ m_service->setService(m_hubService);
248 m_player.reset(new TestPlayer());
249 m_service->setPlayer(m_player);
250+ m_mediaPlayerControl = m_service->mediaPlayerControl();
251 m_playerControl = m_service->requestControl(QMediaPlayerControl_iid);
252 QVERIFY(m_playerControl != NULL);
253 m_rendererControl = m_service->requestControl(QVideoRendererControl_iid);

Subscribers

People subscribed via source and target branches