Reincubate의 Camo SDK를 사용하면 애플리케이션에서 macOS 및 Windows용 Camo Studio로 실시간 오디오/영상 데이터를 전송할 수 있습니다. USB 또는 무선으로 작동하며, USB는 지연 시간과 성능에 최적화되어 앱에서 최소한의 리소스만 사용합니다. 무선은 케이블의 제약에서 자유롭게 해줍니다.
Camo SDK는 상업적 파트너 및 협력사가 사용할 수 있습니다. 자세한 내용은 enterprise@reincubate.com으로 문의하십시오.
현재 SDK는 iOS 12 이상을 실행하는 실제 iOS 또는 iPadOS 기기(시뮬레이터 및 Mac Catalyst 제외)에서 실행되는 iOS 애플리케이션만 지원합니다. Camo SDK는 기본적으로 Objective-C와 호환되지 않으므로, 앱이 주로 Objective-C로 작성된 경우 래퍼를 만들어야 할 수도 있습니다.
API 레퍼런스
바로 시작하고 싶다면 Camo SDK가 제공하는 모든 심볼을 문서화한 전체 API 레퍼런스를 확인하십시오. 그렇지 않다면 이 문서에서 SDK와의 샘플 통합 과정을 안내합니다.
Camo SDK 설치하기
Camo SDK를 받으면 CamoProducerKit.xcframework라는 파일도 함께 받게 됩니다. 이 자체 완결형 프레임워크는 외부 종속성 없이 필요한 모든 것을 갖추고 있어 설치가 간편합니다.
- 프로젝트 내비게이터에서 애플리케이션의 프로젝트를 선택하십시오.
- 프로젝트의 타겟 사이드바에서 애플리케이션의 타겟을 선택하십시오. 사이드바가 보이지 않는다면 페이지 상단의 드롭다운에 있을 수 있습니다.
- “General” 탭에 있는지 확인한 다음, “Frameworks, Libraries, and Embedded Content” 헤더까지 아래로 스크롤하십시오.
CamoProducerKit.xcframework파일을 드래그하여 해당 헤더 아래의 파일 목록에 놓으십시오.- SDK가 “Embed & Sign”으로 설정되어 있는지 확인하십시오.
완료되면 다음 그림과 같이 프레임워크가 표시됩니다.

샘플 애플리케이션에 임베드된 Camo SDK
앱과 통합하기
실제로 작동하는 Camo SDK
Camo SDK에는 기기 카메라 및 마이크는 물론 번들로 제공되는 영상 파일에서도 데이터를 스트리밍하는 방법을 보여주는 데모 앱이 함께 제공됩니다.
Camo 서비스 제어하기
CamoProducerKit의 핵심에는 CamoController가 있으며, 이는 Camo SDK를 제어할 수 있는 하나의 중앙 집중식 인터페이스를 앱에 제공합니다.
앱에서 CamoController의 인스턴스를 초기화해야 합니다. 이는 앱 실행 시점에 하거나 나중으로 미룰 수 있습니다. start()로 명시적으로 시작하기 전까지 Camo 컨트롤러는 리소스를 거의 사용하지 않습니다. 다만 초기화 시 오디오 및 영상 인코딩을 준비합니다.
import CamoProducerKit
class MyVideoManager {
let controller = CamoController()
// ...
}
앱에서 Camo 통합을 활성화하여 연결을 지원하는 Camo 서비스를 시작하려면 start()를 호출하십시오. 사용을 마쳤다면 stop()을 호출하여 중지할 수 있습니다.
controller.start()
// ...
controller.stop()
Camo 서비스는 언제 시작하고 중지해야 할까요?
CamoProducerKit은 항상 최소한의 리소스만 사용하도록 설계되었습니다. 다만 Camo Studio와의 연결을 지원하기 위해 서비스를 계속 실행해 두면 약간의 리소스가 사용됩니다.
최상의 사용자 경험을 위해서는 Camo 서비스를 항상 활성화된 상태로 두는 것을 권장합니다. 또는 온보딩 과정에서 사용자에게 Camo 통합에 대해 안내하고 직접 선택할 기회를 제공할 수도 있습니다.
이러한 리소스를 확보해야 한다면 Camo 서비스를 중지하는 것이 도움이 될 수 있습니다. 다만 사용자에게 알리지 않고 이를 수행하는 것은 권장하지 않습니다.
이 코드는 시작 단계일 뿐이며, 아직 Camo Studio로부터 새 연결을 수락할 수는 없습니다.
새 연결에 응답하기
앱이 Camo Studio로부터 새 연결을 수락할 수 있으려면 먼저 CamoControllerDelegate를 구현해야 합니다. 이 두 개의 델리게이트 메서드를 구현하면 연결 상태 변경에 대한 알림을 받고, 연결을 수락할지 거부할지 결정할 수 있습니다.
extension MyVideoManager: CamoControllerDelegate {
// Upon receiving a connection request, you can decide whether or not to accept it.
func camoControllerShouldAcceptIncomingConnection(_ controller: CamoController) -> Bool {
// You could return false if you aren't ready to accept connections, such as during onboarding.
return true
}
// Called whenever the connection state changes, such as if the Camo service starts or stops, or if a new connection is made.
func camoController(_ controller: CamoController, stateDidChangeTo state: CamoControllerState?) {
// From here, you can update your UI and other state
print("New state:", state)
}
}
이 작업을 마치면 이제 앱을 열고 USB로 연결하여 Camo Studio에서 기기를 확인할 수 있습니다.
무선 연결
무선 연결을 사용하려면 사용자가 로컬 네트워크 액세스 권한을 부여해야 합니다. Bonjour 서비스는 Info.plist에 NSBonjourServices로 추가해야 합니다.
_camo._tcp_camopairing._tcp
camoController.start()를 호출하면 SDK가 페어링 및 Camo Studio와의 네트워크 연결 준비를 마칩니다.
페어링
사용자가 Camo Studio에서 “+” 버튼을 클릭하면 페어링 프로세스가 시작됩니다. Camo Studio는 앱 측에서 스캔해야 하는 QR 코드를 표시합니다.
페어링 단계:
- Camo Studio에서 “+”를 클릭하여 QR 코드 표시
- QR 코드를 스캔하여 데이터를 문자열로 가져오기
camoController.pairStudioWithQRCodeData(codeData) { success in }를 호출하여 해당 데이터를 SDK에 전달pairStudioWithQRCodeData메서드에는 페어링 성공 여부를 알려주는 콜백이 있음- SDK가 Camo Studio와 페어링을 수행하고 연결이 자동으로 설정됨
페어링을 취소해야 하는 경우(예: 사용자가 QR 스캐너나 앱을 닫은 경우) camoController.cancelPairing()를 호출해야 합니다
페어링에는 30초의 제한 시간이 있습니다. pairStudioWithQRCodeData을 호출한 후 30초 안에 페어링이 이루어지지 않으면 pairStudioWithQRCodeData 메서드의 콜백이 success 값 false로 호출됩니다.
페어링된 장치
페어링이 완료되면 SDK는 페어링 데이터를 페어링된 장치 목록에 저장합니다. CamoController에는 이 목록을 다루기 위한 두 가지 메서드가 있습니다.
- 목록을 가져오는
pairedDevices(UI에 목록을 표시하려는 경우) - 장치를 삭제하는
removePairedDevice
다음번에 Camo Studio에 무선으로 연결하려면 Camo Studio에서 “+” 버튼을 클릭하고 연결이 설정될 때까지 기다리기만 하면 되며, QR 코드를 다시 스캔할 필요는 없습니다.
연결 상태 확인하기
CamoController는 CamoControllerState 속성을 제공하며, 이는 앞서 살펴본 상태 변경 델리게이트 메서드에도 포함되어 있습니다. 이 열거형은 UI에 표시할 연결된 컴퓨터 이름 등 앱에 유용한 정보를 제공합니다.
연결 상태를 반영하도록 UI를 업데이트하는 방법의 예는 다음과 같습니다.
func camoController(_ controller: CamoController, stateDidChangeTo state: CamoControllerState?) {
let statusText = { () -> String in
guard case let .running(serviceState) = state else {
return "Camo service not running"
}
switch serviceState {
case .active(let connection): return "Connected to \(connection.name)"
case .paused(let connection): return "Paused, but connected to \(connection.name)"
case .notConnected: return "Camo service running, but no connection"
}
}()
DispatchQueue.main.async {
self.statusTextLabel.text = statusText
}
}
오디오/영상 데이터 전송하기
클라이언트에 최대한의 유연성을 제공하기 위해 Camo SDK는 캡처를 제공하거나 제어하지 않습니다. 대신 CamoController에 오디오 및 영상 데이터를 제공하는 것은 개발자의 몫입니다. 이는 두 가지 간단한 API 호출로 수행할 수 있습니다.
// upon receiving video from the camera or elsewhere
camoController.enqueueVideo(sampleBuffer: sampleBuffer)
// upon receiving audio from the microphone or elsewhere
camoController.enqueuePCMAudio(data: chunk)
불필요한 처리 피하기
Camo SDK에 제공할 오디오/영상 데이터를 처리하기 전에, 불필요한 리소스 소비를 방지하기 위해 활성 상태이며 일시 정지되지 않은 연결이 있는지 확인해야 합니다. 이는 CamoController에서 state를 확인하여 수행할 수 있습니다.
영상 전송하기
영상 파이프라인에서 CMSampleBuffer에 액세스할 수 있다면, 이 데이터를 Camo SDK에 전달하는 것은 매우 간단합니다.
이 때문에 기본적인 영상 AVCaptureSession으로 이를 설정하는 것은 매우 간단합니다. 실제 작동 예는 다음과 같습니다.
class CaptureController: AVCaptureVideoDataOutputSampleBufferDelegate {
// ...
func startSession() throws {
guard let camera = AVCaptureDevice.default(for: .video) else { fatalError("No camera found") }
let input = try AVCaptureDeviceInput(device: camera)
captureSession.addInput(input)
let output = AVCaptureVideoDataOutput()
output.alwaysDiscardsLateVideoFrames = true
output.setSampleBufferDelegate(self, queue: videoDataOutputQueue)
captureSession.addOutput(output)
captureSession.startRunning()
}
// ...
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
camoController.enqueueVideo(sampleBuffer: sampleBuffer)
}
}
영상 프레임을 전송할 때는 다음을 확인하십시오.
- 프레임 지속 시간이 30FPS인지
- 픽셀 형식이
kCVPixelFormatType_32BGRA인지
자세한 내용은 API 레퍼런스에서 확인할 수 있습니다.
오디오 전송하기
오디오 전송은 영상과 유사하지만, 애플리케이션이 오디오를 수신하는 방식에 따라 몇 가지 단계가 더 필요할 수 있습니다. 샘플 구현은 Camo SDK에 포함된 데모 앱을 참고하십시오.
오디오 데이터를 전송할 때는 다음을 확인하십시오.
- 샘플링 레이트가 48kHz인지
- 오디오 코덱이 LPCM인지
- 채널 수가 2개인지
- 비트 심도가 32비트인지
- 오디오 패킷당 샘플 수는 Studio(macOS 또는 Windows)에 따라 다르며, CamoController.audioSamplesRequired에서 확인할 수 있습니다.
자세한 내용은 API 레퍼런스에서 확인할 수 있습니다.