티스토리 뷰

728x90

최근에 지인이 추천해준 책 중 One Thing(원씽)을 읽고 있는데 한 글귀가 맘에 들어 남겨봅니다.

'단 하나의 일을 위한 약속' - 자신의 일을 완벽하게 내것으로 만들어 최고의 경지에 이르고자 하는 마음을 가질것

 

그러기 위해 오늘 블로깅 주제는 WebRTC 구현을 하면서 긴 시간 날 괴롭혔던 

카메라화면방향(videoOrientaion)을 완벽하게 내것으로 만들어보려 블로깅을 해보려고 합니다.

 

 


 

스트리밍 화면 방향이..?

 

해당 문제는 iOS16이상버전에서 화면회전이 활성화가 되어있을때 나타나던 현상이었습니다.

 

일단 iOS16이상 버전에서 발생하는 문제이니 #available로 분기처리

if #available(iOS 16.0, *) {
    // iOS 16버전이상은 이 구문 실행
}

 

 

그 다음 아래 두개를 감지할 수 있는게 필요했습니다.

  1. 현재 기기방향
  2. 사용자가 기기방향을 돌렸을때 어떤 방향인지 감지

 

1. 기기화면방향(UIDevice)

 

현재 기기화면방향을 가져오려면 아래와 같이 사용해주면 됩니다.

var currentDeviceOrientaion = UIDevice.current.orientation

 

UIDeviceOrientation 이라는 친구를 타고 들어가면 enum형태로 각 방향대로 case가 정리되어있는걸 볼수 있습니다.

public enum UIDeviceOrientation : Int, @unchecked Sendable {

    
    case unknown = 0 // 알 수 없음

    case portrait = 1 // 세로방향, 홈버튼 하단

    case portraitUpsideDown = 2 // 세로방향, 홈버튼 상단

    case landscapeLeft = 3 // 가로방향, 홈버튼 우측

    case landscapeRight = 4 // 가로방향, 홈버튼 좌측

    case faceUp = 5 // 누워있는상태, 전면 하늘 (고개들어)

    case faceDown = 6 // 누워있는상태, 전면 바닥 (고개숙여)
}

 

 

참고
기기방향회전을 하지않은 초기에는 unknown으로 잡힘

 

 

이제 현재 기기의 방향(orientation)을 구해왔으니, 기기가 돌아갔을때 상태를 감지하는게 필요하겠네요.

2. 화면방향 실시간 감지 (NotificationCenter)

기기방향감지는 NotificationCenter에서 UIDevice.orientationDidChangeNotification을 사용했습니다.

override func viewDidLoad() {
        super.viewDidLoad()
        observeOrientation()
    }


private func observeOrientation() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(setOrientation),
            name: UIDevice.orientationDidChangeNotification,
            object: nil
        )
}

@objc func setOrientation() {
        if #available(iOS 16.0, *) {
            print("화면회전감지")
            setOrientationOveriOS16()
        }
}

 

viewDidLoad 시점에 NotificationCenter로 화면방향 돌아가는걸 감지하면 

화면방향 실시간 감지하는것 까지 완료

 

위 코드에서 기기를 회전할때마다 "화면회전감지" 프린트가 찍힐거고 저기에 아까 구했던 UIDevice.current.Orientation으로 현재기기방향을 가져올겁니다.

 

3. 돌아간 방향에 따라 스트리밍 영상화면방향 조정 (RxSwift)

WebRTC 카메라 세팅이 완료된 후 기기가 회전할때마다 방출하는 이벤트(UIDevice.current.Orientation)를 갖고 스트리밍화면방향을 맞춰줍니다.

private var orientationSubject = PublishSubject<AVCaptureVideoOrientation>()

func startCaptureLocalVideo(renderer: RTCVideoRenderer) {
        // 1
        guard let capturer = videoCapturer as? RTCCameraVideoCapturer else { return }
        // WebRTC 카메라 세팅 로직...
        // code...
        
        capturer.startCapture(with: captureDevice, format: format, fps: Int(fps.magnitude)) { _ in
            self.bindOrientation() // 기기방향이 바뀔때마다 방출되는 UIDevice.current.Orientation을 처리하는 메서드
            
            if #available(iOS 16.0, *) {
                self.setVideoOrientation(capturer)
            }
        }
    }

private func bindOrientation() {
        self.orientationSubject.bind { [weak capturer] captureOrientaion in
            // 2
            capturer?.captureSession.connections.first?.videoOrientation = captureOrientaion
        }
        .disposed(by: self.disposeBag)
    }

 

1. RTCCameraVideoCapturer을 타고 들어가보면 Obj-c로 되어있지만 내부에 카메라화면방향을 조절할 수 있는 프로퍼티(videoOrientaion)를 가진 AVCaptureSession을 사용하고 있는걸 확인할 수 있습니다.

 

2. 기기방향이 바뀔때마다 현재기기방향에 따라 스트리밍화면방향이 정방향으로 보여지게 조정해줍니다.

 

 

 

아까 기기방향이 바뀔때 현재기기방향을 감지하고, (setOrientation())

카메라화면방향을 정방향으로 나오게 바꿔주는 메서드 (setOrientationOveriOS16())

@objc func setOrientation() {
        if #available(iOS 16.0, *) {
            // print("화면회전감지")
            setOrientationOveriOS16()
        }
}

private func setOrientationOveriOS16() {
        currentDeviceOrientation = UIDevice.current.orientation
        
        switch currentDeviceOrientation {
        // 1
        case .portrait, .portraitUpsideDown:
            self.orientationSubject.onNext(.portraitUpsideDown)
        // 2
        case .landscapeLeft, .landscapeRight:
            self.orientationSubject.onNext(.landscapeRight)
            
        default:
            print("observe: unknown, faceup, facedown, nil")
            return
        }
    }

 

 

1. 현재기기방향에 따라 카메라화면방향(videoOrientation)을 바꿔줍니다

2. 1번과 동일

 

참고
전면, 후면카메라에 따라 videoOrientation에 대해 각각 설정을 해주셔야 합니다.

 

 

 

적용후

기기방향을 돌렸을때 스트리밍화면 모습

 

좌) 적용전, 우) 적용후

 

 

느낀점

이벤트 감지를하고 거기에 맞게 반응해주는 기능을 구현해보려고 했고 배웠던건 아래와 같습니다.

  • 이벤트 감지를 위한 NotificationCenter
  • 감지된 이벤트에 따라 반응하게 했던 RxSwift
  • 스트리밍 카메라 관련 로직 RTCCameraCapturer
  • 현재 기기방향에 접근할 수 있는 UIDevice.current.Orientation

현재 카메라 로직을 이용해 움직임 감지를 구현하고 있는데 WebRTCCamera를 가지고 녹화와 스트리밍 둘다 사용할 수 있게 리팩토링중인데 작업을 하면서 이전엔 안될거라 생각했었던게 조금씩 파보니 어떻게 접근해야 될지 보이는것 같습니다.

 

그리고.. 좀전에 블로깅을 하면서 찾아본내용중 이런 내용이 있었습니다.

UIDevice Orientaion을 믿으시나요?

override func viewDidLoad() {
  super.viewDidLoad()
println(UIDeviceOrientationIsLandscape(UIDevice.currentDevice().orientation))
println(UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation))
}

 

관련해서는 알아보고 블로깅 해봐야겠네요..!

728x90

'iOS' 카테고리의 다른 글

[iOS] CoreData  (0) 2024.03.17
[iOS] 빌드 환경에 따른 분기처리 (Dev, Release)  (2) 2024.01.20
[iOS] 비디오 플레이어 닫힘 감지  (9) 2023.12.23
[WebRTC] ICE, SDP 심화  (0) 2023.07.30
[iOS] Localization - 다국어 지원  (0) 2023.05.16