Skip to content

Commit b03ddc7

Browse files
zhirongwangzhirongwang
andauthored
fix(video360): prevent teardown crash when closing 360 video preview (#1692)
Co-authored-by: zhirongwang <zhirongwang@box.com>
1 parent b330d20 commit b03ddc7

2 files changed

Lines changed: 48 additions & 21 deletions

File tree

src/lib/viewers/box3d/video360/Video360Viewer.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class Video360Viewer extends DashViewer {
2222
renderer;
2323

2424
/** @property {Video360Controls} - Instance of the Video360Controls */
25-
controls;
25+
video360Controls;
2626

2727
/** @property {Box3D.Texture2DAsset} - Asset for the skybox texture */
2828
textureAsset;
@@ -65,6 +65,14 @@ class Video360Viewer extends DashViewer {
6565

6666
/** @inheritdoc */
6767
destroy() {
68+
// Tear down 360 controls before super.destroy(), which destroys this.controls
69+
// (DashViewer's React ControlsRoot when createControls() has not run yet).
70+
if (this.video360Controls) {
71+
this.destroyControls();
72+
this.video360Controls = null;
73+
this.controls = null;
74+
}
75+
6876
super.destroy();
6977

7078
if (this.skybox) {
@@ -82,11 +90,6 @@ class Video360Viewer extends DashViewer {
8290
this.videoAsset = null;
8391
}
8492

85-
if (this.controls) {
86-
this.destroyControls();
87-
this.controls = null;
88-
}
89-
9093
if (this.renderer) {
9194
// Remove event listeners from box3d, if any on it
9295
this.renderer.getBox3D().off('mouseDown', this.onCanvasMouseDown);
@@ -137,8 +140,10 @@ class Video360Viewer extends DashViewer {
137140
* @return {void}
138141
*/
139142
createControls() {
140-
this.controls = new Video360Controls(this.mediaContainerEl);
141-
this.controls.on(EVENT_TOGGLE_VR, this.handleToggleVr);
143+
this.video360Controls = new Video360Controls(this.mediaContainerEl);
144+
// Overwrite this.controls so DashViewer.renderUI() skips React controls.
145+
this.controls = this.video360Controls;
146+
this.video360Controls.on(EVENT_TOGGLE_VR, this.handleToggleVr);
142147

143148
// Add listeners to hide and show controls
144149
if (!this.renderer || !this.renderer.getBox3D()) {
@@ -163,8 +168,12 @@ class Video360Viewer extends DashViewer {
163168
* @return {void}
164169
*/
165170
destroyControls() {
166-
this.controls.removeListener(EVENT_TOGGLE_VR, this.handleToggleVr);
167-
this.controls.destroy();
171+
if (!this.video360Controls) {
172+
return;
173+
}
174+
175+
this.video360Controls.removeListener(EVENT_TOGGLE_VR, this.handleToggleVr);
176+
this.video360Controls.destroy();
168177

169178
// Remove listeners to hide and show controls
170179
if (!this.renderer || !this.renderer.getBox3D()) {
@@ -250,7 +259,9 @@ class Video360Viewer extends DashViewer {
250259
* @return {void}
251260
*/
252261
handleShowVrButton() {
253-
this.controls.showVrButton();
262+
if (this.video360Controls) {
263+
this.video360Controls.showVrButton();
264+
}
254265
}
255266

256267
/**

src/lib/viewers/box3d/video360/__tests__/Video360Viewer-test.js

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,28 @@ describe('lib/viewers/box3d/video360/Video360Viewer', () => {
118118
expect(videoAsset.destroy).toBeCalled();
119119
});
120120

121-
test('should invoke .destroyControls() if it exists', () => {
121+
test('should invoke .destroyControls() if video360Controls exists', () => {
122122
const destroyStub = jest.spyOn(viewer, 'destroyControls').mockImplementation();
123123

124-
viewer.controls = {};
124+
viewer.video360Controls = {};
125125
viewer.destroy();
126126

127127
expect(destroyStub).toBeCalled();
128128
});
129129

130+
test('should not invoke .destroyControls() when only DashViewer React controls exist', () => {
131+
const destroyStub = jest.spyOn(viewer, 'destroyControls').mockImplementation();
132+
133+
viewer.controls = {
134+
destroy: jest.fn(),
135+
render: jest.fn(),
136+
};
137+
viewer.destroy();
138+
139+
expect(destroyStub).not.toBeCalled();
140+
expect(viewer.controls.destroy).toBeCalled();
141+
});
142+
130143
describe('if renderer exists', () => {
131144
let rendererMock;
132145
let b3dMock;
@@ -282,12 +295,14 @@ describe('lib/viewers/box3d/video360/Video360Viewer', () => {
282295
});
283296

284297
afterEach(() => {
298+
viewer.video360Controls = null;
285299
viewer.controls = null;
286300
});
287301

288302
test('should create and store an instance of Video360Controls', () => {
289303
viewer.createControls();
290-
expect(viewer.controls).toBeInstanceOf(Video360Controls);
304+
expect(viewer.video360Controls).toBeInstanceOf(Video360Controls);
305+
expect(viewer.controls).toBe(viewer.video360Controls);
291306
});
292307

293308
test('should attach event handler for vr toggle by invoking .controls.on() with EVENT_TOGGLE_VR and .handleToggleVr()', () => {
@@ -319,7 +334,7 @@ describe('lib/viewers/box3d/video360/Video360Viewer', () => {
319334
removeListener: jest.fn(),
320335
destroy: jest.fn(),
321336
};
322-
viewer.controls = controls;
337+
viewer.video360Controls = controls;
323338
viewer.destroyControls();
324339
canvas = {
325340
removeEventListener: jest.fn(),
@@ -336,14 +351,15 @@ describe('lib/viewers/box3d/video360/Video360Viewer', () => {
336351
});
337352

338353
afterEach(() => {
354+
viewer.video360Controls = null;
339355
viewer.controls = null;
340356
});
341357

342-
test('should remove event handler for EVENT_TOGGLE_VR by invoking .controls.removeListener() with EVENT_TOGGLE_VR and .handleToggleVr()', () => {
358+
test('should remove event handler for EVENT_TOGGLE_VR by invoking .video360Controls.removeListener() with EVENT_TOGGLE_VR and .handleToggleVr()', () => {
343359
expect(controls.removeListener).toBeCalledWith(EVENT_TOGGLE_VR, viewer.handleToggleVr);
344360
});
345361

346-
test('should invoke .controls.destroy()', () => {
362+
test('should invoke .video360Controls.destroy()', () => {
347363
expect(controls.destroy).toBeCalled();
348364
});
349365

@@ -552,14 +568,14 @@ describe('lib/viewers/box3d/video360/Video360Viewer', () => {
552568
});
553569

554570
describe('handleShowVrButton()', () => {
555-
test('should invoke .controls.showVrButton()', () => {
556-
viewer.controls = {
571+
test('should invoke .video360Controls.showVrButton()', () => {
572+
viewer.video360Controls = {
557573
showVrButton: jest.fn(),
558574
};
559575
viewer.handleShowVrButton();
560-
expect(viewer.controls.showVrButton).toBeCalled();
576+
expect(viewer.video360Controls.showVrButton).toBeCalled();
561577

562-
viewer.controls = null;
578+
viewer.video360Controls = null;
563579
});
564580
});
565581

0 commit comments

Comments
 (0)