9

When using the AVPlayerViewController, the user is allowed to select whether the subtitles are on a specific language, off, or set to auto. Setting the requiresFullSubtitles property I can force the display of subtitles, but that is not what I want.

Is there a way to detect what the user has selected for the subtitle setting, whether a language is selected, off, or auto?

Now Playing Info Center

picciano
  • 22,341
  • 9
  • 69
  • 82
  • 1
    Sounds like a good feature request to submit to Apple. – matt Mar 21 '18 at 17:02
  • I don't know anything about `AVFoundation`, but if it's not possible then how are you expected to switch to the correct subtitle? – mfaani Mar 21 '18 at 17:07

4 Answers4

4

There is a notification AVPlayerItemMediaSelectionDidChangeNotification appeared in iOS 13 and tvOS 13

You can subscribe your AVPlayerItem to this notification:

if (@available(iOS 13.0, tvOS 13.0, *)) {
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(handleMediaSelectionChange:)
                                             name:AVPlayerItemMediaSelectionDidChangeNotification
                                           object:playerItem];
}

And then you can detect what language or subtitle user has selected:

- (void)handleMediaSelectionChange:(NSNotification *)notification {
    AVPlayerItem *playerItem = (AVPlayerItem *)notification.object;
    if([playerItem.asset isKindOfClass:[AVURLAsset class]]){
        AVURLAsset *asset = (AVURLAsset *)playerItem.asset;
        AVMediaSelectionGroup *audio = [asset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible];
        AVMediaSelectionGroup *subtitles = [asset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible];
        AVMediaSelectionOption *selectedAudio = [playerItem.currentMediaSelection selectedMediaOptionInMediaSelectionGroup:audio];
        AVMediaSelectionOption *selectedSubtitles = [playerItem.currentMediaSelection selectedMediaOptionInMediaSelectionGroup:subtitles];
    }
}
kotvaska
  • 639
  • 7
  • 11
3

mc01's answer is correct, but if you want a cut-and-paste solution for Swift 4, here is what is ended up with:

var selectedSubtitleLocale: Locale?

fileprivate func detectSubtitleLanguage() {
    var locale: Locale?

    if let playerItem = player?.currentItem,
        let group = playerItem.asset.mediaSelectionGroup(forMediaCharacteristic: AVMediaCharacteristic.legible) {
        let selectedOption = playerItem.currentMediaSelection.selectedMediaOption(in: group)
        locale = selectedOption?.locale
    }

    selectedSubtitleLocale = locale
}
picciano
  • 22,341
  • 9
  • 69
  • 82
1

You can grab the currently selected language options & also grab the language info when it's used to set the subtitle or audio track, as described in "Adding Subtitles and Alternative Audio Tracks."

Available subtitles & audio tracks are found in an array of availableMediaCharacteristics for the video asset.

They're grouped in an AVMediaSelectionGroup by whether they are AVMediaCharacteristicAudible or AVMediaCharacteristicLegible ...

The currently selected option is found by:

`func selectedMediaOption(in mediaSelectionGroup: AVMediaSelectionGroup) -> AVMediaSelectionOption?`

It could return nil so "none," or it would return whatever language is selected. So you could set up some custom 'didChange' listener on that property. Doesn't seem to be any sort of publicly available notification for this, so you'd have to make your own.

Whenever you would select/set the subtitle option on the player, you could capture and use that same information to do whatever it is you intend to do with it:

if let group = asset.mediaSelectionGroup(forMediaCharacteristic: AVMediaCharacteristicLegible) {
    let locale = Locale(identifier: "es-ES")
    let options =
        AVMediaSelectionGroup.mediaSelectionOptions(from: group.options, with: locale)
    if let option = options.first {

        /*** DO WHATEVER YOU WANT HERE AFTER CAPTURING THE LANGUAGE SELECTION  & RETRIEVING AN AVAILABLE SUBTITLE ***/ 

       playerItem.select(option, in: group)
    }
}
mc01
  • 3,750
  • 19
  • 24
1

Swift version of @kotvaska

You can add this observer while configuring session/periodic observers

NotificationCenter.default.addObserver(
    self,
    selector: #selector(didMediaToggle(_:)),
    name: AVPlayerItem.mediaSelectionDidChangeNotification,
    object: nil
)

@objc func didMediaToggle(_ sender: Notification) {
    print("LOGGER: mediaSelectionDidChangeNotification:", sender.description)
    let subtitles = player.currentItem?.asset.mediaSelectionGroup(forMediaCharacteristic: .legible)
    print("LOGGER: mediaSelectionDidChangeNotification: subtitles:", subtitles)
}
/// this will not be called in case of `CC`, aka only `On` and `Off` case

For CC you can give a shot to this notification as CC(Closed Captions) is completely different from Subtitles.

NotificationCenter.default.addObserver(
    self,
    selector: #selector(didCaptionsToggle(_:)),
    name: UIAccessibility.closedCaptioningStatusDidChangeNotification,
    object: nil
)
Abhishek Thapliyal
  • 3,497
  • 6
  • 30
  • 69