• Media playback with AVKit
    • AVKit의 포지션

      • AVFoundation를 기반으로 동작. 그 아래의 Core Media도 일부 사용
      • UIKit에서는 AVPlayerViewController, AppKit에서는 AVPlayerView를 주요 인터페이스로 사용
        • 공통적으로 AVRoutePickerView를 제공
    • iOS 예제

      import AVKit
      
      let player = AVPlayer(url: "<https://my.example/video.m3u8>")
      
      let playerViewController = AVPlayerViewController()
      playerViewController.player = player
      
      present(playerViewController, animated: true)
      
    • 그 외에도 수많은 기반 기술들을 기반으로 하고 있다.

      • AVPlayerLayer로 비디오 렌더링을 한다던지
  • What's new
    • iOS 13
      • FullScreen callbacks

        • embed된 player가 fullscreen이 되거나 fullscreen에서 돌아올 때 호출
        • AVPlayerViewControllerDelegate를 통해서 사용
        • iOS 13 SDK를 쓰면 iOS 12부터 사용 가능하다.
        @available(iOS 12.0, *)
        
        func playerViewController(_ playerViewController: AVPlayerViewController,
        		willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator)
        
        func playerViewController(_ playerViewController: AVPlayerViewController,
        		willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator)
        
        func playerViewController(_ playerViewController: AVPlayerViewController,
        		willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        	coordinator.animate(alongsideTransition: { (context) in
        		// Add coordinated animations
        	}) { context in
        		if context.isCancelled {
        				// 여전히 embedding상태
        		} else {
        				// 풀스크린 상태
        				// playerViewController의 레퍼런스를 잡아야 하면 여기서 잡아준다.
        		}
        	}
        }
        
        • 스크롤 때문에 원래 위치가 화면에서 벗어나거나, 아예 플레이어 자체가 뷰 계층에서 제거될 수도 있다. → 이때를 대비해 따로 레퍼런스를 잡아야 한다.

          • 돌아올 때 다시 원복시켜놓는다.
          func playerViewController(_ playerViewController: AVPlayerViewController,
          		willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
          	// 스크롤로 인해 벗어났다면, playerViewController의 레이아웃을 복구한다.
          }
          
      • AVPlayerViewController in iPad apps on the Mac

        • 터치바, 키보드, PIP 지원이 자동으로 이뤄진다.
        • 코드추가를 하지 않고도, mac을 지원 가능(10.15부터) → 카탈리스트 이야기겠지?
      • External Metadata

        • Title, Artwork등의 데이터는 영상에 있을수도 있지만, 없을 수도 있다.
        • 이런 데이터를 위해서, 추가적으로 데이터를 제공할 수도 있다.
        @available(iOS 12.0, *)
        extension AVPlayerItem {
        	open var extenalMetadata: [AVMetadataItem]
        }
        
      • Improved support for custom controls

        • 하고 싶은 것
          • Interactive dismissals
          • Landscape support for portrait-only apps
          • Keyboard and Touch Bar support
          • Now Playing management
          • Automatic video zoom
        • 기본 제공
          • showsPlaybackControls를 false로
          • modal Present로 띄우기
          • contentOverlayView로 컨트롤들을 추가
          • statusBar나 home indicator등은 UIViewController의 메소드를 오버라이드해서 쓰기
          • 처리되지 않은 터치는 통과시키기(아래의 뷰로)
          • 더블탭은 Video zoom을 위해서 AVKit에게 넘기기
  • Best Practices
    • Showing FullScreen
      • UIWindowScene의 좌표 공간 전체를 덮는 형태
      • Use Case
        • Splash Screen
          • 요구사항
            • 내 UI 아래에 존재해야 한다.
            • 상호작용할 수 있는 control 없음
            • status bar나 home indicator를 숨길 필요는 없다.
            • 루프 가능
            • 비디오는 항상 화면 전체를 채워야 한다.
            • 알파 채널이 존재하면, 커스텀 백그라운드 컬러가 있어야 한다.
            • 오디오는 부가적으로 추가한다.
          • 필요 코드
            • 뷰컨트롤러 containment

              parent.addChild(playerViewController)
              parent.view.addSubView(playerViewController.view)
              playerViewController.didMove(toParent: parent)
              
              playerViewController.willMove(toParent: nil)
              playerViewController.view.removeFromSuperView()
              playerViewController.removeFromParent()
              
            • 컨트롤 제거

              playerViewController.showsPlaybackControls = false
              
            • 화면 채우기 설정

              playerViewController.videoGravity = .resizeAspectFill
              
            • 백그라운드 컬러 설정(필요시)

              playerViewController.view.backgroundColor = .clear
              
            • 외부에 재생되는 것을 막는다.

              AVPlayer.allowsExternalPlayback = false
              
            • 부가 오디오 재생: AVAudioSession

              • 카테고리는 .ambient
            • AVAudioSession.silenceSecondaryAudioHintNotification을 감시해라

              • 사용자가 다른 오디오를 켰을 때, splash 화면 소리는 꺼야한다.
        • fullscreen playback
          • 요구사항

            • 가로 세로 모두 대응
            • 줌, 언줌 기능 추가(언줌 될 때는 기기 화면에 의해 짤리면 안된다)
            • 뮤트 버튼 클릭시 약간의 lamp, 슬라이더 애니매이션
            • interactive dismiss할때, 소리 페이드 아웃
          • 필요 코드: 대부분은 AVPlayerViewController()를 쓰면 자동으로 얻을 수 있다.

            import AVKit
            
            let player = AVPlayer(url: "<https://my.example/video.m3u8>")
            
            player.currentItem?.externalMetadata = // [AVMetaData]
            
            let playerViewController = AVPlayerViewController()
            playerViewController.player = player
            
            present(playerViewController, animated: true)
            
          • 베스트 프렉티스

            • 모달로 띄워라(child로 하지말고)
            • modalPresentationStyle은 기본으로 유지하라
              • 새로 띄워진 뷰가 완전히 덮고 있으면, UIKit이 최적화를 위해서 presentingView를 없앨 수 있다.
              • 또한 앱이 portrait만 지원하더라도, 플레이어가 가로를 지원하도록 할 수도 있다.
            • AVPlayerViewController의 videoGravity는 설정하지 말라 → 자동적으로 동작하도록 두는 것이 좋다. 줌 상황에서 동적으로 동작하도록
            • fullscreen으로 동작하는 것은 delegate로 트래킹하라. → viewController라이프 사이클에 의존 금지
          • AVPlayerItem은 버퍼링되기 전에 설정하고 AVPlayer에 넘겨라

          • AVPlayer.status와 AVPlayerItem.status를 Observing하라. → KVO로

            • .readyToPlayer 상태가 아니면 playeback하지 말라
            • .failed면 에러를 확인하라
              • error가 .mediaServiceWereReset일 시에는 player와 playerItem을 다시 만들어서 넣어주면 된다.
          • useExternalPlaybackWhileExternalScreenIsActive 옵션을 키면, 미러링에 최적화된다.

          • AudioSession 설정은 .playback

    • Embedding inline
    • Picture-in-Picture
  • Playback in TvOS