@@ -255,6 +255,59 @@ - (void)testSeekToWhilePausedStartsDisplayLinkTemporarily {
255255 OCMVerify ([mockDisplayLink setRunning: NO ]);
256256}
257257
258+ - (void )testInitStartsDisplayLinkTemporarily {
259+ NSObject <FlutterTextureRegistry> *mockTextureRegistry =
260+ OCMProtocolMock (@protocol (FlutterTextureRegistry));
261+ NSObject <FlutterPluginRegistrar> *registrar =
262+ [GetPluginRegistry () registrarForPlugin: @" InitStartsDisplayLinkTemporarily" ];
263+ NSObject <FlutterPluginRegistrar> *partialRegistrar = OCMPartialMock (registrar);
264+ OCMStub ([partialRegistrar textures ]).andReturn (mockTextureRegistry);
265+ FVPDisplayLink *mockDisplayLink =
266+ OCMPartialMock ([[FVPDisplayLink alloc ] initWithRegistrar: registrar
267+ callback: ^(){
268+ }]);
269+ StubFVPDisplayLinkFactory *stubDisplayLinkFactory =
270+ [[StubFVPDisplayLinkFactory alloc ] initWithDisplayLink: mockDisplayLink];
271+ AVPlayerItemVideoOutput *mockVideoOutput = OCMPartialMock ([[AVPlayerItemVideoOutput alloc ] init ]);
272+ StubAVPlayer *stubAVPlayer = [[StubAVPlayer alloc ] init ];
273+ FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc ]
274+ initWithAVFactory: [[StubFVPAVFactory alloc ] initWithPlayer: stubAVPlayer
275+ output: mockVideoOutput]
276+ displayLinkFactory: stubDisplayLinkFactory
277+ registrar: partialRegistrar];
278+
279+ FlutterError *initalizationError;
280+ [videoPlayerPlugin initialize: &initalizationError];
281+ XCTAssertNil (initalizationError);
282+ FVPCreateMessage *create = [FVPCreateMessage
283+ makeWithAsset: nil
284+ uri: @" https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8"
285+ packageName: nil
286+ formatHint: nil
287+ httpHeaders: @{}];
288+ FlutterError *createError;
289+ FVPTextureMessage *textureMessage = [videoPlayerPlugin create: create error: &createError];
290+ NSInteger textureId = textureMessage.textureId ;
291+
292+ // Init should start the display link temporarily.
293+ OCMVerify ([mockDisplayLink setRunning: YES ]);
294+
295+ // Simulate a buffer being available.
296+ OCMStub ([mockVideoOutput hasNewPixelBufferForItemTime: kCMTimeZero ])
297+ .ignoringNonObjectArgs ()
298+ .andReturn (YES );
299+ // Any non-zero value is fine here since it won't actually be used, just NULL-checked.
300+ CVPixelBufferRef fakeBufferRef = (CVPixelBufferRef)1 ;
301+ OCMStub ([mockVideoOutput copyPixelBufferForItemTime: kCMTimeZero itemTimeForDisplay: NULL ])
302+ .ignoringNonObjectArgs ()
303+ .andReturn (fakeBufferRef);
304+ // Simulate a callback from the engine to request a new frame.
305+ FVPVideoPlayer *player = videoPlayerPlugin.playersByTextureId [@(textureId)];
306+ [player copyPixelBuffer ];
307+ // Since a frame was found, and the video is paused, the display link should be paused again.
308+ OCMVerify ([mockDisplayLink setRunning: NO ]);
309+ }
310+
258311- (void )testSeekToWhilePlayingDoesNotStopDisplayLink {
259312 NSObject <FlutterTextureRegistry> *mockTextureRegistry =
260313 OCMProtocolMock (@protocol (FlutterTextureRegistry));
@@ -288,8 +341,8 @@ - (void)testSeekToWhilePlayingDoesNotStopDisplayLink {
288341 NSInteger textureId = textureMessage.textureId ;
289342
290343 // Ensure that the video is playing before seeking.
291- FlutterError *pauseError ;
292- [videoPlayerPlugin play: textureMessage error: &pauseError ];
344+ FlutterError *playError ;
345+ [videoPlayerPlugin play: textureMessage error: &playError ];
293346
294347 XCTestExpectation *initializedExpectation = [self expectationWithDescription: @" seekTo completes" ];
295348 FVPPositionMessage *message = [FVPPositionMessage makeWithTextureId: textureId position: 1234 ];
@@ -318,6 +371,46 @@ - (void)testSeekToWhilePlayingDoesNotStopDisplayLink {
318371 OCMVerify (never (), [mockDisplayLink setRunning: NO ]);
319372}
320373
374+ - (void )testPauseWhileWaitingForFrameDoesNotStopDisplayLink {
375+ NSObject <FlutterTextureRegistry> *mockTextureRegistry =
376+ OCMProtocolMock (@protocol (FlutterTextureRegistry));
377+ NSObject <FlutterPluginRegistrar> *registrar =
378+ [GetPluginRegistry () registrarForPlugin: @" PauseWhileWaitingForFrameDoesNotStopDisplayLink" ];
379+ NSObject <FlutterPluginRegistrar> *partialRegistrar = OCMPartialMock (registrar);
380+ OCMStub ([partialRegistrar textures ]).andReturn (mockTextureRegistry);
381+ FVPDisplayLink *mockDisplayLink =
382+ OCMPartialMock ([[FVPDisplayLink alloc ] initWithRegistrar: registrar
383+ callback: ^(){
384+ }]);
385+ StubFVPDisplayLinkFactory *stubDisplayLinkFactory =
386+ [[StubFVPDisplayLinkFactory alloc ] initWithDisplayLink: mockDisplayLink];
387+ AVPlayerItemVideoOutput *mockVideoOutput = OCMPartialMock ([[AVPlayerItemVideoOutput alloc ] init ]);
388+ FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc ]
389+ initWithAVFactory: [[StubFVPAVFactory alloc ] initWithPlayer: nil output: mockVideoOutput]
390+ displayLinkFactory: stubDisplayLinkFactory
391+ registrar: partialRegistrar];
392+
393+ FlutterError *initalizationError;
394+ [videoPlayerPlugin initialize: &initalizationError];
395+ XCTAssertNil (initalizationError);
396+ FVPCreateMessage *create = [FVPCreateMessage
397+ makeWithAsset: nil
398+ uri: @" https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8"
399+ packageName: nil
400+ formatHint: nil
401+ httpHeaders: @{}];
402+ FlutterError *createError;
403+ FVPTextureMessage *textureMessage = [videoPlayerPlugin create: create error: &createError];
404+
405+ // Run a play/pause cycle to force the pause codepath to run completely.
406+ FlutterError *playPauseError;
407+ [videoPlayerPlugin play: textureMessage error: &playPauseError];
408+ [videoPlayerPlugin pause: textureMessage error: &playPauseError];
409+
410+ // Since a buffer hasn't been available yet, the pause should not have stopped the display link.
411+ OCMVerify (never (), [mockDisplayLink setRunning: NO ]);
412+ }
413+
321414- (void )testDeregistersFromPlayer {
322415 NSObject <FlutterPluginRegistrar> *registrar =
323416 [GetPluginRegistry () registrarForPlugin: @" testDeregistersFromPlayer" ];
0 commit comments