From 2801cdfbe03d0681e917307c63b5bd11d61f6ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Tue, 2 Nov 2021 10:22:17 +0100 Subject: [PATCH 1/8] Bump version number --- Demo/Demo.xcconfig | 2 +- Package.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Demo/Demo.xcconfig b/Demo/Demo.xcconfig index 8d9801a5..b5893a8e 100644 --- a/Demo/Demo.xcconfig +++ b/Demo/Demo.xcconfig @@ -1,5 +1,5 @@ // Version information -MARKETING_VERSION = 6.1.5 +MARKETING_VERSION = 6.1.6 // Deployment targets IPHONEOS_DEPLOYMENT_TARGET = 9.0 diff --git a/Package.swift b/Package.swift index ecff51cd..f3a9a3f0 100644 --- a/Package.swift +++ b/Package.swift @@ -3,7 +3,7 @@ import PackageDescription struct ProjectSettings { - static let marketingVersion: String = "6.1.5" + static let marketingVersion: String = "6.1.6" } let package = Package( From ddf1950c863560f06085b989f31058ee35a86f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Wed, 17 Nov 2021 17:55:17 +0100 Subject: [PATCH 2/8] Add flag to opt-in for picture in picture --- .../AdvancedPlayerViewController~ios.m | 2 ++ .../SRGMediaPlayer/SRGMediaPlayerController.m | 24 ++++++++++++++----- .../include/SRGMediaPlayerController.h | 8 ++++++- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Demo/Sources/Players/Advanced/AdvancedPlayerViewController~ios.m b/Demo/Sources/Players/Advanced/AdvancedPlayerViewController~ios.m index 6db10d6c..c68bd9ed 100644 --- a/Demo/Sources/Players/Advanced/AdvancedPlayerViewController~ios.m +++ b/Demo/Sources/Players/Advanced/AdvancedPlayerViewController~ios.m @@ -105,6 +105,8 @@ - (void)viewDidLoad self.audioOnlyImageView.image = nil; self.audioOnlyImageView.image = audioOnlyImage; + self.mediaPlayerController.pictureInPictureEnabled = YES; + SRGMediaPlayerView *playerView = self.mediaPlayerController.view; playerView.viewMode = self.media.is360 ? SRGMediaPlayerViewModeMonoscopic : SRGMediaPlayerViewModeFlat; diff --git a/Sources/SRGMediaPlayer/SRGMediaPlayerController.m b/Sources/SRGMediaPlayer/SRGMediaPlayerController.m index b7256f17..ae0f01d7 100644 --- a/Sources/SRGMediaPlayer/SRGMediaPlayerController.m +++ b/Sources/SRGMediaPlayer/SRGMediaPlayerController.m @@ -107,6 +107,7 @@ @interface SRGMediaPlayerController () targetSegment; // Will be nilled when reached @property (nonatomic) SRGMediaPlayerSelectionReason selectionReason; +@property (nonatomic, getter=isPictureInPictureEnabled) BOOL pictureInPictureEnabled; @property (nonatomic) AVPictureInPictureController *pictureInPictureController API_AVAILABLE(ios(9.0), tvos(14.0)); @property (nonatomic, copy) void (^pictureInPictureControllerCreationBlock)(AVPictureInPictureController *pictureInPictureController) API_AVAILABLE(ios(9.0), tvos(14.0)); @property (nonatomic) NSNumber *savedAllowsExternalPlayback; @@ -128,7 +129,6 @@ @interface SRGMediaPlayerController () *)textStyleRules self.player.currentItem.textStyleRules = _textStyleRules; } +- (void)setPictureInPictureEnabled:(BOOL)pictureInPictureEnabled +{ + _pictureInPictureEnabled = pictureInPictureEnabled; + [self updatePictureInPictureForView:self.view]; +} + - (AVPictureInPictureController *)pictureInPictureController API_AVAILABLE(ios(9.0), tvos(14.0)) { if (self.playerViewController) { @@ -797,13 +804,18 @@ - (void)setPictureInPictureController:(AVPictureInPictureController *)pictureInP - (void)updatePictureInPictureForView:(SRGMediaPlayerView *)view API_AVAILABLE(ios(9.0), tvos(14.0)) { - AVPlayerLayer *playerLayer = view.playerLayer; - if (playerLayer.readyForDisplay) { - if (self.pictureInPictureController.playerLayer != playerLayer) { - self.pictureInPictureController = [[AVPictureInPictureController alloc] initWithPlayerLayer:playerLayer]; - self.pictureInPictureControllerCreationBlock ? self.pictureInPictureControllerCreationBlock(self.pictureInPictureController) : nil; + if (self.pictureInPictureEnabled) { + AVPlayerLayer *playerLayer = view.playerLayer; + if (playerLayer.readyForDisplay) { + if (self.pictureInPictureController.playerLayer != playerLayer) { + self.pictureInPictureController = [[AVPictureInPictureController alloc] initWithPlayerLayer:playerLayer]; + self.pictureInPictureControllerCreationBlock ? self.pictureInPictureControllerCreationBlock(self.pictureInPictureController) : nil; + } } } + else { + self.pictureInPictureController = nil; + } } - (BOOL)allowsExternalNonMirroredPlayback diff --git a/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h b/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h index f8ccc565..df342039 100644 --- a/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h +++ b/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h @@ -843,7 +843,8 @@ NS_ASSUME_NONNULL_BEGIN @end /** - * Picture in picture functionality (not available on all devices). + * Picture in picture functionality (not available on all devices). Picture in picture is an opt-in: You must set the + * controller `pictureInPictureEnabled` property to `YES` if you want it to offer picture in picture support for it. * * Remark: When the application is sent to the background on iOS, the behavior is the same as the vanilla picture in picture * controller: If the managed player layer is the one of a view controller's root view ('full screen'), picture @@ -870,6 +871,11 @@ NS_ASSUME_NONNULL_BEGIN */ @interface SRGMediaPlayerController (PictureInPicture) +/** + * Set to `YES` to activate picture in picture for the controller. Default is `NO`. + */ +@property (nonatomic, getter=isPictureInPictureEnabled) BOOL pictureInPictureEnabled API_AVAILABLE(ios(9.0), tvos(14.0)); + /** * Return the picture in picture controller if picture in picture is available for the device, `nil` otherwise. * From a0cb6db4fe5503db9f7288fb77c02370d62a36f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Wed, 17 Nov 2021 17:59:09 +0100 Subject: [PATCH 3/8] Update documentation --- Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h | 4 +++- docs/GETTING_STARTED.md | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h b/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h index df342039..cc94f549 100644 --- a/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h +++ b/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h @@ -844,7 +844,9 @@ NS_ASSUME_NONNULL_BEGIN /** * Picture in picture functionality (not available on all devices). Picture in picture is an opt-in: You must set the - * controller `pictureInPictureEnabled` property to `YES` if you want it to offer picture in picture support for it. + * controller `pictureInPictureEnabled` property to `YES` if you want it to support picture in picture. You should also + * implement a picture in picture controller delegate to manage the picture in picture lifecycle (you can register + * a delegate with a blocked assigned to `pictureInPictureControllerCreationBlock`). * * Remark: When the application is sent to the background on iOS, the behavior is the same as the vanilla picture in picture * controller: If the managed player layer is the one of a view controller's root view ('full screen'), picture diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 9d9512c3..aa8d6b2f 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -30,11 +30,11 @@ SRGMediaPlayerViewController *mediaPlayerViewController = [[SRGMediaPlayerViewCo }]; ``` -Please refer to `AVPlayerViewController` [documentation](https://developer.apple.com/documentation/avkit/avpictureinpicturecontroller) for further integration instructions, from picture in picture to optional settings. +Please refer to `AVPlayerViewController` [documentation](https://developer.apple.com/documentation/avkit/avpictureinpicturecontroller) for further integration instructions, from picture in picture support to optional settings. ### Remark -Picture in picture requires your application to declare the corresponding background mode capability, as well as an audio session category set to `AVAudioSessionCategoryPlayback`. +You must opt-in for picture in picture by setting the `pictureInPictureEnabled` property to `YES`. Picture in picture also requires your application to declare the corresponding background mode capability, as well as an audio session category set to `AVAudioSessionCategoryPlayback`. ## Designing custom players From b21ab8b2657a6dff9af95a1fdfc537658285ed53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 18 Nov 2021 08:40:00 +0100 Subject: [PATCH 4/8] Improve implementation when the controller is managed by SRGMediaPlayerViewController --- .../SRGMediaPlayer/SRGMediaPlayerController.m | 17 ++++++++++++++--- .../include/SRGMediaPlayerController.h | 3 +++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Sources/SRGMediaPlayer/SRGMediaPlayerController.m b/Sources/SRGMediaPlayer/SRGMediaPlayerController.m index ae0f01d7..29114fc6 100644 --- a/Sources/SRGMediaPlayer/SRGMediaPlayerController.m +++ b/Sources/SRGMediaPlayer/SRGMediaPlayerController.m @@ -107,7 +107,7 @@ @interface SRGMediaPlayerController () targetSegment; // Will be nilled when reached @property (nonatomic) SRGMediaPlayerSelectionReason selectionReason; -@property (nonatomic, getter=isPictureInPictureEnabled) BOOL pictureInPictureEnabled; +@property (nonatomic, getter=isPictureInPictureEnabled) BOOL pictureInPictureEnabled API_AVAILABLE(ios(9.0), tvos(14.0)); @property (nonatomic) AVPictureInPictureController *pictureInPictureController API_AVAILABLE(ios(9.0), tvos(14.0)); @property (nonatomic, copy) void (^pictureInPictureControllerCreationBlock)(AVPictureInPictureController *pictureInPictureController) API_AVAILABLE(ios(9.0), tvos(14.0)); @property (nonatomic) NSNumber *savedAllowsExternalPlayback; @@ -129,6 +129,7 @@ @interface SRGMediaPlayerController () *)textStyleRules self.player.currentItem.textStyleRules = _textStyleRules; } +- (BOOL)isPictureInPictureEnabled +{ + if (self.playerViewController) { + return YES; + } + else { + return _pictureInPictureEnabled; + } +} + - (void)setPictureInPictureEnabled:(BOOL)pictureInPictureEnabled { _pictureInPictureEnabled = pictureInPictureEnabled; [self updatePictureInPictureForView:self.view]; } -- (AVPictureInPictureController *)pictureInPictureController API_AVAILABLE(ios(9.0), tvos(14.0)) +- (AVPictureInPictureController *)pictureInPictureController { if (self.playerViewController) { return nil; @@ -778,7 +789,7 @@ - (AVPictureInPictureController *)pictureInPictureController API_AVAILABLE(ios(9 } } -- (void)setPictureInPictureController:(AVPictureInPictureController *)pictureInPictureController API_AVAILABLE(ios(9.0), tvos(14.0)) +- (void)setPictureInPictureController:(AVPictureInPictureController *)pictureInPictureController { if (_pictureInPictureController) { [_pictureInPictureController removeObserver:self keyPath:@keypath(_pictureInPictureController.pictureInPicturePossible)]; diff --git a/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h b/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h index cc94f549..4977ec8e 100644 --- a/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h +++ b/Sources/SRGMediaPlayer/include/SRGMediaPlayerController.h @@ -875,6 +875,9 @@ NS_ASSUME_NONNULL_BEGIN /** * Set to `YES` to activate picture in picture for the controller. Default is `NO`. + * + * @discussion Setting this property has no effect when the controller is used by `SRGMediaPlayerViewController`, as + * picture in picture is always enabled in this special case. */ @property (nonatomic, getter=isPictureInPictureEnabled) BOOL pictureInPictureEnabled API_AVAILABLE(ios(9.0), tvos(14.0)); From 830c93d3c7e02d3deef15bd89b6e290043c9e453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 18 Nov 2021 08:45:05 +0100 Subject: [PATCH 5/8] Update documentation --- .../include/SRGMediaPlayerViewController.h | 2 ++ docs/GETTING_STARTED.md | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Sources/SRGMediaPlayer/include/SRGMediaPlayerViewController.h b/Sources/SRGMediaPlayer/include/SRGMediaPlayerViewController.h index c4d49894..e366f189 100644 --- a/Sources/SRGMediaPlayer/include/SRGMediaPlayerViewController.h +++ b/Sources/SRGMediaPlayer/include/SRGMediaPlayerViewController.h @@ -43,6 +43,8 @@ NS_ASSUME_NONNULL_BEGIN * standard Apple player user experience, at the expense of a few limitations: * - 360° medias are not playable with monoscopic or stereoscopic support. * - Background playback behavior cannot be customized. + * - Picture in picture is always enabled (but still requires you to implement its controller delegate methods to + * manage the picture in picture lifecycle). * * If you need one of the above features you should implement your own player layout instead. */ diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index aa8d6b2f..33b75255 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -32,10 +32,6 @@ SRGMediaPlayerViewController *mediaPlayerViewController = [[SRGMediaPlayerViewCo Please refer to `AVPlayerViewController` [documentation](https://developer.apple.com/documentation/avkit/avpictureinpicturecontroller) for further integration instructions, from picture in picture support to optional settings. -### Remark - -You must opt-in for picture in picture by setting the `pictureInPictureEnabled` property to `YES`. Picture in picture also requires your application to declare the corresponding background mode capability, as well as an audio session category set to `AVAudioSessionCategoryPlayback`. - ## Designing custom players Custom player layouts can be designed entirely in Interface Builder, whether you are using xibs or storyboards. You can create your custom player entirely in code if you want, but using Interface Builder is recommended. @@ -110,6 +106,14 @@ You can also drop an `SRGAirPlayButton` onto your layout (displayed only when Ai If you want users to reliably enable AirPlay playback also from the control center, you should use `SRGAirPlayButton` with your player layout, or integrate `MPRemoteCommandCenter`. These ensures your application is the current one registered with the control center when the user interacts with it, so that playback can actually be sent to an AirPlay receiver. If your application is not the current one at the moment the route is changed in the control center, playback will stay local. +## Picture in picture support + +SRG Media Player supports picture in picture, both on iOS and on tvOS. You must opt-in for picture in picture by setting the `pictureInPictureEnabled` property to `YES` on an `SRGMediaPlayerController` instance. Picture in picture also requires your application to declare the corresponding background mode capability, as well as an audio session category set to `AVAudioSessionCategoryPlayback`. + +When picture in picture has been enabled your application is responsible of implementing the `AVPictureInPictureControllerDelegate` methods to manage the picture in picture lifecycle, in particular the restoration process. You can register your delegate within a block assigned to the `pictureInPictureControllerCreationBlock` property, which is called after a picture in picture controller has been made available. + +Note that, if you are using `SRGMediaPlayerViewController` to display the standard system player user interface, the underlying `SRGMediaPlayerController` will always have picture in picture enabled. To ensure correct integration your application must provide a `SRGMediaPlayerViewControllerDelegate` implementing picture in picture lifecycle, most notably for restoration. + ## Audio session management No audio session specific management is provided by the library. Managing audio sessions is entirely the responsibility of the application, which gives you complete freedom over how playback happens, especially in the background or when switching between applications. As for AirPlay setup (see above), you can use the various block hooks to setup and restore audio session settings as required by your application. From 6e1515ac01785ea3fc293767ab81ac8ca6653492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 18 Nov 2021 09:47:50 +0100 Subject: [PATCH 6/8] Make picture in picture behavior in presence of a player view controller more explicit --- Sources/SRGMediaPlayer/SRGMediaPlayerController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SRGMediaPlayer/SRGMediaPlayerController.m b/Sources/SRGMediaPlayer/SRGMediaPlayerController.m index 29114fc6..6030099c 100644 --- a/Sources/SRGMediaPlayer/SRGMediaPlayerController.m +++ b/Sources/SRGMediaPlayer/SRGMediaPlayerController.m @@ -815,7 +815,7 @@ - (void)setPictureInPictureController:(AVPictureInPictureController *)pictureInP - (void)updatePictureInPictureForView:(SRGMediaPlayerView *)view API_AVAILABLE(ios(9.0), tvos(14.0)) { - if (self.pictureInPictureEnabled) { + if (! self.playerViewController && self.pictureInPictureEnabled) { AVPlayerLayer *playerLayer = view.playerLayer; if (playerLayer.readyForDisplay) { if (self.pictureInPictureController.playerLayer != playerLayer) { From 3c6115940182d60dc4e148928ff031a69779906b Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Tue, 30 Nov 2021 16:08:47 +0100 Subject: [PATCH 7/8] Update Italian translations --- Sources/SRGMediaPlayer/Resources/it.lproj/Localizable.strings | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SRGMediaPlayer/Resources/it.lproj/Localizable.strings b/Sources/SRGMediaPlayer/Resources/it.lproj/Localizable.strings index 28593684..f9611929 100644 --- a/Sources/SRGMediaPlayer/Resources/it.lproj/Localizable.strings +++ b/Sources/SRGMediaPlayer/Resources/it.lproj/Localizable.strings @@ -46,7 +46,7 @@ "When '%@' is enabled, and if the selected audio track language differs from the device settings, subtitles or Closed Captions might be displayed automatically." = "Quando \"%@\" è attivato, se la pista audio è differente da quella selezionata sul dispositivo, i sottotitoli vengono mostrati automaticamente."; /* Instructions for subtitles customization */ -"You can adjust text appearance and enable Closed Captions and SDH automatic selection in the Accessibility settings." = "Potete regolare la visualizzazione e la sezione automatica dei sottotitoli nelle impostazioni di accessibilità."; +"You can adjust text appearance and enable Closed Captions and SDH automatic selection in the Accessibility settings." = "Puoi regolare la visualizzazione e la sezione automatica dei sottotitoli nelle impostazioni di accessibilità."; /* Instructions for audio customization */ -"You can enable Audio Description automatic selection in the Accessibility settings." = "Potete regolare l'attivazione automatica dell'audio descrizione nelle impostazioni di accessibilità."; +"You can enable Audio Description automatic selection in the Accessibility settings." = "Puoi regolare l'attivazione automatica dell'audio descrizione nelle impostazioni di accessibilità."; From b046b6a0e88b49bc53de2070a8d800c46308d769 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Fri, 10 Dec 2021 15:28:14 +0100 Subject: [PATCH 8/8] Bump version number --- Demo/Demo.xcconfig | 2 +- Package.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Demo/Demo.xcconfig b/Demo/Demo.xcconfig index b5893a8e..08c942f0 100644 --- a/Demo/Demo.xcconfig +++ b/Demo/Demo.xcconfig @@ -1,5 +1,5 @@ // Version information -MARKETING_VERSION = 6.1.6 +MARKETING_VERSION = 6.2.0 // Deployment targets IPHONEOS_DEPLOYMENT_TARGET = 9.0 diff --git a/Package.swift b/Package.swift index f3a9a3f0..9f5cd217 100644 --- a/Package.swift +++ b/Package.swift @@ -3,7 +3,7 @@ import PackageDescription struct ProjectSettings { - static let marketingVersion: String = "6.1.6" + static let marketingVersion: String = "6.2.0" } let package = Package(