

# IVS Broadcast SDK: 혼합 디바이스
<a name="broadcast-mixed-devices"></a>

혼합 디바이스는 여러 개의 입력 소스로 단일 출력을 생성하는 오디오 및 비디오 디바이스입니다. 디바이스 혼합은 여러 화면(비디오) 요소와 오디오 트랙을 정의하고 관리할 수 있는 강력한 기능입니다. 카메라, 마이크, 화면 캡처, 앱에서 생성한 오디오 및 비디오와 같은 여러 소스의 비디오와 오디오를 결합할 수 있습니다. 전환을 사용하여 IVS로 스트리밍하는 비디오에서 이러한 소스를 이동하고 스트림 중간에 소스를 추가하거나 제거할 수 있습니다.

혼합 디바이스에는 이미지 버전과 오디오 버전이 있습니다. 혼합 이미지 디바이스를 생성하려면 다음을 직접적으로 호출합니다.

Android에서 `DeviceDiscovery.createMixedImageDevice()`

iOS에서 `IVSDeviceDiscovery.createMixedImageDevice()`

반환된 디바이스는 다른 디바이스와 마찬가지로 `BroadcastSession`(저지연 스트리밍) 또는 `Stage`(실시간 스트리밍)에 연결할 수 있습니다.

## 용어
<a name="broadcast-mixed-devices-terminology"></a>

![\[IVS 브로드캐스팅 혼합 디바이스 용어입니다.\]](http://docs.aws.amazon.com/ko_kr/ivs/latest/LowLatencyUserGuide/images/Broadcast_SDK_Mixer_Glossary.png)



| Term | 설명 | 
| --- | --- | 
| 장치 | 오디오 또는 이미지 입력을 생성하는 하드웨어 또는 소프트웨어 구성 요소입니다. 디바이스의 예로는 마이크, 카메라, Bluetooth 헤드셋 및 화면 캡처 또는 사용자 정의 이미지 입력과 같은 가상 디바이스가 있습니다. | 
| 혼합 디바이스 | 다른 `Device`와 마찬가지로 `BroadcastSession`에 연결할 수 있지만, `Source` 객체를 추가할 수 있는 추가 API가 있는 `Device`입니다. 혼합 디바이스에는 오디오 또는 이미지를 합성하여 단일 출력 오디오와 이미지 스트림을 생성하는 내부 믹서가 있습니다. 혼합 디바이스에는 이미지 버전 또는 오디오 버전이 있습니다.  | 
| 혼합 디바이스 구성 | 혼합 디바이스의 구성 객체입니다. 혼합 이미지 디바이스의 경우 차원과 프레임 속도 등 속성이 구성됩니다. 혼합 오디오 디바이스의 경우 채널 개수가 구성됩니다. | 
|  소스 | 화면상의 시각적 요소의 위치와 오디오 믹스에서 오디오 트랙의 속성을 정의하는 컨테이너. 혼합 디바이스는 0개 이상의 소스로 구성할 수 있습니다. 소스에는 소스의 미디어 사용 방식에 영향을 미치는 구성이 주어집니다. 위 이미지에서는 네 가지 이미지 소스를 보여줍니다. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/ivs/latest/LowLatencyUserGuide/broadcast-mixed-devices.html)  | 
| 소스 구성 |  혼합 디바이스에 들어가는 소스의 구성 객체입니다. 아래에 전체 구성 객체가 설명되어 있습니다.  | 
| Transition | 슬롯을 새 위치로 이동하거나 일부 속성을 변경하려면 `MixedDevice.transitionToConfiguration()`을 사용합니다. 이 메서드는 다음을 수행합니다. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/ivs/latest/LowLatencyUserGuide/broadcast-mixed-devices.html) | 

## 혼합 오디오 디바이스
<a name="broadcast-mixed-audio-device"></a>

### 구성
<a name="broadcast-mixed-audio-device-configuration"></a>

Android에서 `MixedAudioDeviceConfiguration`

iOS에서 `IVSMixedAudioDeviceConfiguration`


| 이름 | Type | 설명 | 
| --- | --- | --- | 
| `channels` | Integer | 오디오 믹서의 출력 채널 수 유효한 값: 1, 2. 1은 모노 오디오, 2는 스테레오 오디오입니다. 기본값: 2. | 

### 소스 구성
<a name="broadcast-mixed-audio-device-source-configuration"></a>

Android에서 `MixedAudioDeviceSourceConfiguration`

iOS에서 `IVSMixedAudioDeviceSourceConfiguration`


| 이름 | Type | 설명 | 
| --- | --- | --- | 
| `gain` | Float | 오디오 게인. 이 값은 승수이므로 1을 초과하는 모든 값은 게인을 증가시키고 1 미만의 값은 게인을 감소시킵니다. 유효한 값은 0\$12입니다. 기본값: 1. | 

## 혼합 이미지 디바이스
<a name="broadcast-mixed-image-device"></a>

### 구성
<a name="broadcast-mixed-image-device-configuration"></a>

Android에서 `MixedImageDeviceConfiguration`

iOS에서 `IVSMixedImageDeviceConfiguration`


| 이름 | Type | 설명 | 
| --- | --- | --- | 
| `size` | Vec2 | 비디오 캔버스 크기. | 
| `targetFramerate` | Integer | 혼합 디바이스의 목표 초당 프레임 수입니다. 평균적으로 이 값을 충족해야 하지만, 특정 상황(예: 높은 CPU 또는 GPU 부하)에서는 시스템이 프레임을 떨어뜨릴 수 있습니다. | 
| `transparencyEnabled` | 부울 | 그러면 이미지 소스 구성에서 `alpha` 속성을 사용하여 블렌딩할 수 있습니다. `true`로 설정하면 메모리와 CPU 소비가 증가합니다. 기본값: `false`. | 

### 소스 구성
<a name="broadcast-mixed-image-device-source-configuration"></a>

Android에서 `MixedImageDeviceSourceConfiguration`

iOS에서 `IVSMixedImageDeviceSourceConfiguration`


| 이름 | Type | 설명 | 
| --- | --- | --- | 
| `alpha` | Float | 슬롯의 알파입니다. 이미지에 알파 값이 있는 배수입니다. 유효한 값: 0\$11. 0은 완전히 투명하고, 1은 완전히 불투명합니다. 기본값: 1. | 
| `aspect` | AspectMode | 슬롯에 렌더링된 모든 이미지에 대한 종횡비 모드. 유효한 값: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/ivs/latest/LowLatencyUserGuide/broadcast-mixed-devices.html) 기본값: `Fit`  | 
| `fillColor` | Vec4 | 슬롯 및 이미지 종횡비가 일치하지 않을 때 `aspect Fit`이 사용되어 색상을 채웁니다. 형식은 (빨간색, 녹색, 파란색, 알파) 입니다. 각 채널에 대해 유효한 값: 0\$11. 기본값: (0, 0, 0, 0). | 
| `position` | Vec2 | 캔버스의 왼쪽 위 모서리를 기준으로 한 슬롯 위치(단위: 픽셀). 슬롯의 원점도 왼쪽 위입니다. | 
| `size` | Vec2 | 슬롯의 크기(픽셀) 이 값 설정도 `matchCanvasSize`를 `false`로 설정합니다. 기본값: (0, 0). 하지만 `matchCanvasSize` 기본값이 `true`이므로 슬롯의 렌더링된 크기는 (0, 0)이 아닌 캔버스 크기입니다. | 
| `zIndex` | Float | 슬롯의 상대적 순서. `zIndex` 값이 높은 슬롯은 `zIndex` 값이 낮은 슬롯 위에 그려집니다. | 

## 혼합 이미지 디바이스 생성 및 구성
<a name="broadcast-mixed-image-device-creating-configuring"></a>

![\[믹싱을 위한 브로드캐스트 세션 구성.\]](http://docs.aws.amazon.com/ko_kr/ivs/latest/LowLatencyUserGuide/images/Broadcast_SDK_Mixer_Configuring.png)


다음은 가이드의 시작 부분에 있는 것과 비슷한 장면을 만들 때 사용하는 화면에 표시되는 3가지 요소입니다.
+ 카메라용 왼쪽 하단 슬롯.
+ 로고 오버레이용 오른쪽 하단 슬롯.
+ 영화용 오른쪽 상단 슬롯.

캔버스의 원점은 왼쪽 상단 모서리이며 슬롯에 대해 동일합니다. 따라서 (0, 0)에 슬롯을 배치하면 전체 슬롯이 보이는 왼쪽 상단 모서리에 배치됩니다.

### iOS
<a name="broadcast-mixed-image-device-creating-configuring-ios"></a>

```
let deviceDiscovery = IVSDeviceDiscovery()
let mixedImageConfig = IVSMixedImageDeviceConfiguration()
mixedImageConfig.size = CGSize(width: 1280, height: 720)
try mixedImageConfig.setTargetFramerate(60)
mixedImageConfig.isTransparencyEnabled = true
let mixedImageDevice = deviceDiscovery.createMixedImageDevice(with: mixedImageConfig)

// Bottom Left
let cameraConfig = IVSMixedImageDeviceSourceConfiguration()
cameraConfig.size = CGSize(width: 320, height: 180)
cameraConfig.position = CGPoint(x: 20, y: mixedImageConfig.size.height - cameraConfig.size.height - 20)
cameraConfig.zIndex = 2
let camera = deviceDiscovery.listLocalDevices().first(where: { $0 is IVSCamera }) as? IVSCamera
let cameraSource = IVSMixedImageDeviceSource(configuration: cameraConfig, device: camera)
mixedImageDevice.add(cameraSource)

// Top Right
let streamConfig = IVSMixedImageDeviceSourceConfiguration()
streamConfig.size = CGSize(width: 640, height: 320)
streamConfig.position = CGPoint(x: mixedImageConfig.size.width - streamConfig.size.width - 20, y: 20)
streamConfig.zIndex = 1
let streamDevice = deviceDiscovery.createImageSource(withName: "stream")
let streamSource = IVSMixedImageDeviceSource(configuration: streamConfig, device: streamDevice)
mixedImageDevice.add(streamSource)

// Bottom Right
let logoConfig = IVSMixedImageDeviceSourceConfiguration()
logoConfig.size = CGSize(width: 320, height: 180)
logoConfig.position = CGPoint(x: mixedImageConfig.size.width - logoConfig.size.width - 20,
                              y: mixedImageConfig.size.height - logoConfig.size.height - 20)
logoConfig.zIndex = 3
let logoDevice = deviceDiscovery.createImageSource(withName: "logo")
let logoSource = IVSMixedImageDeviceSource(configuration: logoConfig, device: logoDevice)
mixedImageDevice.add(logoSource)
```

### Android
<a name="broadcast-mixed-image-device-creating-configuring-android"></a>

```
val deviceDiscovery = DeviceDiscovery(this /* context */)
val mixedImageConfig = MixedImageDeviceConfiguration().apply {
    setSize(BroadcastConfiguration.Vec2(1280f, 720f))
    setTargetFramerate(60)
    setEnableTransparency(true)
}
val mixedImageDevice = deviceDiscovery.createMixedImageDevice(mixedImageConfig)

// Bottom Left
val cameraConfig = MixedImageDeviceSourceConfiguration().apply {
    setSize(BroadcastConfiguration.Vec2(320f, 180f))
    setPosition(BroadcastConfiguration.Vec2(20f, mixedImageConfig.size.y - size.y - 20))
    setZIndex(2)
}
val camera = deviceDiscovery.listLocalDevices().firstNotNullOf { it as? CameraSource }
val cameraSource = MixedImageDeviceSource(cameraConfig, camera)
mixedImageDevice.addSource(cameraSource)

// Top Right
val streamConfig = MixedImageDeviceSourceConfiguration().apply {
    setSize(BroadcastConfiguration.Vec2(640f, 320f))
    setPosition(BroadcastConfiguration.Vec2(mixedImageConfig.size.x - size.x - 20, 20f))
    setZIndex(1)
}
val streamDevice = deviceDiscovery.createImageInputSource(streamConfig.size)
val streamSource = MixedImageDeviceSource(streamConfig, streamDevice)
mixedImageDevice.addSource(streamSource)

// Bottom Right
val logoConfig = MixedImageDeviceSourceConfiguration().apply {
    setSize(BroadcastConfiguration.Vec2(320f, 180f))
    setPosition(BroadcastConfiguration.Vec2(mixedImageConfig.size.x - size.x - 20, mixedImageConfig.size.y - size.y - 20))
    setZIndex(1)
}
val logoDevice = deviceDiscovery.createImageInputSource(logoConfig.size)
val logoSource = MixedImageDeviceSource(logoConfig, logoDevice)
mixedImageDevice.addSource(logoSource)
```

## 소스 제거
<a name="broadcast-mixed-devices-removing-sources"></a>

소스를 제거하려면 제거하려는 `Source` 객체로 `MixedDevice.remove`를 직접적으로 호출합니다.

## 애니메이션 전환
<a name="broadcast-mixed-devices-animations-transitions"></a>

전환 메서드는 슬롯의 구성을 새 구성으로 대체합니다. 이 대체에 지속 시간을 0보다 높은 시간(초)을 설정하여 애니메이션을 적용할 수 있습니다.

### 애니메이션할 수 있는 속성은 무엇인가요?
<a name="broadcast-mixed-devices-animations-properties"></a>

슬롯 구조의 모든 속성에 애니메이션이 적용될 수 있는 것은 아닙니다. Float 유형을 기반으로 하는 모든 속성에 애니메이션을 적용할 수 있으며, 다른 속성은 애니메이션의 시작 또는 종료 시점에 적용됩니다.


| 이름 | 애니메이션으로 만들 수 있나요? | 임팩트 포인트 | 
| --- | --- | --- | 
| `Audio.gain` | 예 | 보간 | 
| `Image.alpha` | 예 | 보간 | 
| `Image.aspect` | 아니요 | 종료 | 
| `Image.fillColor` | 예 | 보간 | 
| `Image.position` | 예 | 보간 | 
| `Image.size` | 예 | 보간 | 
| `Image.zIndex` 참고: `zIndex`는 3D 공간을 통해 2D 평면을 이동하므로 두 평면이 애니메이션 중간 지점에서 교차할 때 전환이 발생합니다. 이 값은 계산될 수 있지만 `zIndex` 값은 시작과 종료에 따라 다릅니다. 보다 원활한 전환을 위해 이 값을 `alpha`와 결합합니다.  | 예 | 알 수 없음 | 

### 간단한 예제
<a name="broadcast-mixed-devices-animations-examples"></a>

아래는 [혼합 이미지 디바이스 생성 및 구성](#broadcast-mixed-image-device-creating-configuring)의 위에서 정의된 구성을 사용하는 전체 화면 카메라 전환 예제입니다. 0.5초에 걸쳐 애니메이션이 표시됩니다.

#### iOS
<a name="broadcast-mixed-devices-animations-examples-ios"></a>

```
// Continuing the example from above, modifying the existing cameraConfig object.
cameraConfig.size = CGSize(width: 1280, height: 720)
cameraConfig.position = CGPoint.zero
cameraSource.transition(to: cameraConfig, duration: 0.5) { completed in
    if completed {
        print("Animation completed")
    } else {
        print("Animation interrupted")
    }
}
```

#### Android
<a name="broadcast-mixed-devices-animations-examples-android"></a>

```
// Continuing the example from above, modifying the existing cameraConfig object.
cameraConfig.setSize(BroadcastConfiguration.Vec2(1280f, 720f))
cameraConfig.setPosition(BroadcastConfiguration.Vec2(0f, 0f))
cameraSource.transitionToConfiguration(cameraConfig, 500) { completed ->
    if (completed) {
        print("Animation completed")
    } else {
        print("Animation interrupted")
    }
}
```

## 브로드캐스트 미러링
<a name="broadcast-mixed-devices-mirroring"></a>


| 다음 방향으로 브로드캐스트에 연결된 이미지 디바이스를 미러링하려면 | …에 음수 값 사용 | 
| --- | --- | 
| 수평 | 슬롯의 너비 | 
| 수직 | 슬롯의 높이 | 
| 수평 및 수직 모두 | 슬롯의 너비 및 높이 모두 | 

미러링 시 슬롯을 올바른 위치에 놓으려면 위치를 같은 값으로 조정해야 합니다.

다음은 브로드캐스트를 수평 및 수직으로 미러링하는 예입니다.

### iOS
<a name="broadcast-mixed-devices-mirroring-ios"></a>

수평 미러링:

```
let cameraSource = IVSMixedImageDeviceSourceConfiguration()
cameraSource.size = CGSize(width: -320, height: 720)
// Add 320 to position x since our width is -320
cameraSource.position = CGPoint(x: 320, y: 0)
```

수직 미러링:

```
let cameraSource = IVSMixedImageDeviceSourceConfiguration()
cameraSource.size = CGSize(width: 320, height: -720)
// Add 720 to position y since our height is -720
cameraSource.position = CGPoint(x: 0, y: 720)
```

### Android
<a name="broadcast-mixed-devices-mirroring-android"></a>

수평 미러링:

```
val cameraConfig = MixedImageDeviceSourceConfiguration().apply {
    setSize(BroadcastConfiguration.Vec2(-320f, 180f))
   // Add 320f to position x since our width is -320f
    setPosition(BroadcastConfiguration.Vec2(320f, 0f))
}
```

수직 미러링:

```
val cameraConfig = MixedImageDeviceSourceConfiguration().apply {
    setSize(BroadcastConfiguration.Vec2(320f, -180f))
    // Add 180f to position y since our height is -180f
    setPosition(BroadcastConfiguration.Vec2(0f, 180f))
}
```

참고: 이 미러링은 `ImagePreviewView`(Android) 및 `IVSImagePreviewView`(iOS)의 `setMirrored` 메서드와 다릅니다. 해당 메서드는 디바이스의 로컬 미리 보기에만 영향을 주며 브로드캐스트에는 영향을 주지 않습니다.