

# IVS Android Broadcast SDK의 고급 사용 사례 \$1 저지연 스트리밍
<a name="broadcast-android-use-cases"></a>

여기서는 몇 가지 고급 사용 사례를 제공합니다. 위의 기본 설정으로 시작하고 여기에서 계속합니다.

## 브로드캐스트 구성 생성
<a name="broadcast-android-create-configuration"></a>

여기서는 두 개의 비디오 소스를 믹서에 바인딩할 수 있도록 두 개의 믹서 슬롯이 있는 사용자 지정 구성을 생성합니다. 하나(`custom`)는 전체 화면이고 다른 슬롯(`camera`) 뒤에 배치되며, 다른 슬롯은 더 작고 오른쪽 맨 아래에 있습니다. `custom` 슬롯의 경우 위치, 크기 또는 가로 세로 비율 모드를 설정하지 않습니다. 이러한 파라미터를 설정하지 않으므로 슬롯에서는 크기 및 위치에 비디오 설정을 사용합니다.

```
BroadcastConfiguration config = BroadcastConfiguration.with($ -> {
    $.audio.setBitrate(128_000);
    $.video.setMaxBitrate(3_500_000);
    $.video.setMinBitrate(500_000);
    $.video.setInitialBitrate(1_500_000);
    $.video.setSize(1280, 720);
    $.mixer.slots = new BroadcastConfiguration.Mixer.Slot[] {
            BroadcastConfiguration.Mixer.Slot.with(slot -> {
                // Do not automatically bind to a source
                slot.setPreferredAudioInput(
                           Device.Descriptor.DeviceType.UNKNOWN);
                // Bind to user image if unbound
                slot.setPreferredVideoInput(
                           Device.Descriptor.DeviceType.USER_IMAGE);
                slot.setName("custom");
                return slot;
            }),
            BroadcastConfiguration.Mixer.Slot.with(slot -> {
                slot.setzIndex(1);
                slot.setAspect(BroadcastConfiguration.AspectMode.FILL);
                slot.setSize(300, 300);
                slot.setPosition($.video.getSize().x - 350,
                        $.video.getSize().y - 350);
                slot.setName("camera");
                return slot;
            })
    };
    return $;
});
```

## 브로드캐스트 세션 생성(고급 버전)
<a name="broadcast-android-create-session-advanced"></a>

[기본 예제](broadcast-android-getting-started.md#broadcast-android-create-session)에서 했던 것처럼 `BroadcastSession`을 생성하지만, 여기서는 사용자 지정 구성을 제공합니다. 또한 디바이스를 수동으로 추가할 것이므로 디바이스 배열에 `null`을 입력합니다.

```
// Create a broadcast-session instance and sign up to receive broadcast
// events and errors.
Context ctx = getApplicationContext();
broadcastSession = new BroadcastSession(ctx,
                       broadcastListener,
                       config, // The configuration we created above
                       null); // We’ll manually attach devices after
```

## 카메라 디바이스 반복 및 연결
<a name="broadcast-android-attach-camera"></a>

여기서는 SDK가 감지한 입력 디바이스를 반복합니다. Android 7(Nougat)에서는 이 경우 기본 마이크 디바이스만 반환됩니다. 이 Android 버전에서 Amazon IVS Broadcast SDK가 기본이 아닌 디바이스 선택을 지원하지 않기 때문입니다.

사용할 디바이스를 찾으면 `attachDevice`를 호출하여 연결합니다. 입력 디바이스 연결이 완료되면 기본 스레드에서 Lambda 함수가 호출됩니다. 실패할 경우 리스너에서 오류가 표시됩니다.

```
for(Device.Descriptor desc: BroadcastSession.listAvailableDevices(getApplicationContext())) {
    if(desc.type == Device.Descriptor.DeviceType.CAMERA &&
            desc.position == Device.Descriptor.Position.FRONT) {
        session.attachDevice(desc, device -> {
            LinearLayout previewHolder = findViewById(R.id.previewHolder);
            ImagePreviewView preview = ((ImageDevice)device).getPreviewView();
            preview.setLayoutParams(new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.MATCH_PARENT));
            previewHolder.addView(preview);
            // Bind the camera to the mixer slot we created above.
            session.getMixer().bind(device, "camera");
        });
        break;
    }
}
```

## 카메라 전환
<a name="broadcast-android-swap-cameras"></a>

```
// This assumes you’ve kept a reference called "currentCamera" that points to
// a front facing camera
for(Device device: BroadcastSession.listAvailableDevices()) {
   if(device.type == Device.Descriptor.DeviceType.CAMERA &&
          Device.position != currentCamera.position) {
        // Remove the preview view for the old device.
        // setImagePreviewTextureView is an example function 
        // that handles your view hierarchy.
        setImagePreviewView(null);
        session.exchangeDevices(currentCamera, device, camera -> {
             // Set the preview view for the new device.
             setImagePreviewView(camera.getPreviewView());
             currentCamera = camera;
        });
        break;
   }
}
```

## 입력 표면 생성
<a name="broadcast-android-create-input-surface"></a>

앱에서 생성하는 사운드 또는 이미지 데이터를 입력하려면 `createImageInputSource` 또는 `createAudioInputSource`를 사용합니다. 이 두 메서드 모두 가상 디바이스를 생성하고 연결하며, 해당 디바이스는 다른 디바이스처럼 믹서에 바인딩될 수 있습니다.

`createImageInputSource`에서 반환된 `SurfaceSource`에는 `getInputSurface` 메서드가 있으며, 이 메서드는 Camera2 API, OpenGL, Vulkan 또는 표면(Surface)에 쓸 수 있는 기타 항목과 함께 사용할 수 있는 `Surface`를 제공합니다.

`createAudioInputSource`에서 반환된 `AudioDevice`는 AudioRecorder나 기타 방법으로 생성된 선형 PCM 데이터를 수신할 수 있습니다.

```
SurfaceSource source = session.createImageInputSource();
Surface surface = source.getInputSurface();
session.getMixer().bind(source, “custom”);
```

## 디바이스 분리
<a name="broadcast-android-detach-device"></a>

디바이스를 분리만 하고 교체하지 않으려는 경우 `Device` 또는 `Device.Descriptor`을(를) 사용하여 디바이스를 분리하세요.

```
session.detachDevice(currentCamera);
```

## 화면 및 시스템 오디오 캡처
<a name="broadcast-android-screen-audio-capture"></a>

Amazon IVS Broadcast SDK for Android에는 디바이스의 화면(Android 6 이상) 및 시스템 오디오(Android 10 이상) 캡처를 간소화하는 몇 가지 헬퍼가 포함되어 있습니다. 이러한 항목을 수동으로 관리하려는 경우 사용자 지정 이미지 입력 소스와 사용자 지정 오디오 입력 소스를 생성할 수 있습니다.

화면 및 시스템 오디오 캡처 세션을 생성하려면 먼저 권한 요청 의도를 생성해야 합니다.

```
public void startScreenCapture() {
    MediaProjectionManager manager =
                         (MediaProjectionManager) getApplicationContext()
                         .getSystemService(Context.MEDIA_PROJECTION_SERVICE);
    if(manager != null) {
        Intent intent = manager.createScreenCaptureIntent();
        startActivityIfNeeded(intent, SCREEN_CAPTURE_REQUEST_ID);
    }
}
```

이 기능을 사용하려면 `com.amazonaws.ivs.broadcast.SystemCaptureService`를 확장하는 클래스를 제공해야 합니다. 메서드를 재정의할 필요는 없지만 서비스 간의 잠재적인 충돌을 방지하기 위해 해당 클래스가 있어야 합니다.

또한 Android 매니페스트에 몇 가지 요소를 추가해야 합니다.

```
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application ...>
    <service android:name=".ExampleSystemCaptureService"
         android:foregroundServiceType="mediaProjection" 
         android:isolatedProcess="false" />
</application>
...
```

`SystemCaptureService`를 확장하는 클래스는 `<service>` 요소에 명명되어 있어야 합니다. Android 9 이상에서는 `foregroundServiceType`이 `mediaProjection`이어야 합니다.

권한 의도가 반환되면 화면 및 시스템 오디오 캡처 세션 생성을 계속할 수 있습니다. Android 8 이상에서는 사용자의 알림 패널에 표시될 알림을 제공해야 합니다. Amazon IVS Broadcast SDK for Android에서는 간편한 메서드인 `createServiceNotificationBuilder`를 제공합니다. 또는 고유한 알림을 제공할 수도 있습니다.

```
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode != SCREEN_CAPTURE_REQUEST_ID
       || Activity.RESULT_OK != resultCode) {
        return;
    }
    Notification notification = null;
    if(Build.VERSION.SDK_INT >= 26) {
        Intent intent = new Intent(getApplicationContext(),
                                   NotificationActivity.class);
        notification = session
                         .createServiceNotificationBuilder("example",
                                            "example channel", intent)
                         .build();
    }
    session.createSystemCaptureSources(data,
                  ExampleSystemCaptureService.class,
                  Notification,
                  devices -> {
        // This step is optional if the mixer slots have been given preferred
        // input device types SCREEN and SYSTEM_AUDIO
        for (Device device : devices) {
            session.getMixer().bind(device, "game");
        }
    });
}
```

## 권장 브로드캐스트 설정 가져오기
<a name="broadcast-android-recommended-settings"></a>

브로드캐스트를 시작하기 전에 사용자 연결을 평가하려면 `recommendedVideoSettings` 메서드를 사용하여 간단한 테스트를 실행합니다. 테스트가 실행되면 가장 권장되는 것에서 가장 권장되지 않는 것 순서로 여러 권장 사항이 표시됩니다. 이 버전의 SDK에서는 현재 `BroadcastSession`을 다시 구성할 수 없으므로, 해당 세션을 `release()`한 다음 권장 설정으로 새 세션을 생성해야 합니다. `Result.status`가 `SUCCESS` 또는 `ERROR`가 될 때까지 계속 `BroadcastSessionTest.Results`가 표시됩니다. `Result.progress`를 사용하여 진행률을 확인할 수 있습니다.

Amazon IVS에서는 최대 8.5Mbps의 비트 전송률(`type`이 `STANDARD` 또는 `ADVANCED`인 채널의 경우)을 지원하므로 이 메서드에서 반환되는 `maximumBitrate`는 8.5Mbps를 초과하지 않습니다. 네트워크 성능의 작은 변동을 고려하기 위해 이 메서드에서 반환되는 권장 `initialBitrate`는 테스트에서 측정된 실제 비트 전송률보다 약간 작습니다. (일반적으로 사용 가능한 대역폭의 100%를 사용하는 것은 바람직하지 않습니다.)

```
void runBroadcastTest() {
    this.test = session.recommendedVideoSettings(RTMPS_ENDPOINT, RTMPS_STREAMKEY,
        result -> {
            if (result.status == BroadcastSessionTest.Status.SUCCESS) {
                this.recommendation = result.recommendations[0];
            }
        });
}
```

## 자동 재연결 사용
<a name="broadcast-android-auto-reconnect"></a>

IVS는 `stop` API를 직접적으로 호출하지 않고 브로드캐스트가 예기치 않게 중지되는 경우(예: 네트워크 연결의 일시적 손실) 브로드캐스트에 대한 자동 재연결을 지원합니다. 자동 재연결을 활성화하려면 `BroadcastConfiguration.autoReconnect`에서 `setEnabled(true)`를 직접적으로 호출합니다.

무언가가 예기치 않게 스트림을 중지하면 SDK는 선형 백오프 전략에 따라 최대 5회까지 재시도합니다. `BroadcastSession.Listener.onRetryStateChanged` 메서드를 통해 애플리케이션에 재시도 상태를 알립니다.

백그라운드에서는 자동 재연결이 제공된 스트림 키 끝에 1로 시작하는 우선순위 번호를 추가하여 IVS [스트림 인수](streaming-config.md#streaming-config-stream-takeover) 기능을 사용합니다. `BroadcastSession` 인스턴스 기간에 재연결을 시도할 때마다 해당 수가 1씩 증가합니다. 즉, 브로드캐스트 중에 디바이스 연결이 4회 손실되고 각 손실에서 1회\$14회의 재시도가 필요한 경우 마지막 스트림의 우선순위는 5\$117일 수 있습니다. 따라서 *동일한 채널에 대한 SDK에서 자동 재연결이 활성화된 동안에는 다른 디바이스에서 IVS 스트림 인수를 사용하지 않는 것이 좋습니다*. 해당 시점에 SDK가 사용하는 우선순위는 보장되지 않으며, 다른 디바이스가 인수하는 경우 SDK는 더 높은 우선순위로 재연결을 시도합니다.

## Bluetooth 마이크 사용
<a name="broadcast-android-bluetooth-microphones"></a>

Bluetooth 마이크 장치를 사용하여 브로드캐스트하기 위해서는 Bluetooth SCO 연결을 시작해야 합니다.

```
Bluetooth.startBluetoothSco(context);
// Now bluetooth microphones can be used
…
// Must also stop bluetooth SCO
Bluetooth.stopBluetoothSco(context);
```