

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Kasus Penggunaan Tingkat Lanjut untuk SDK Siaran iOS IVS \| Streaming Low-Latency
<a name="broadcast-ios-use-cases"></a>

Di sini kami menyajikan beberapa kasus penggunaan lanjutan. Mulailah dengan pengaturan dasar di atas dan lanjutkan di sini.

## Buat Konfigurasi Siaran
<a name="broadcast-ios-create-configuration"></a>

Di sini kita membuat konfigurasi khusus dengan dua slot mixer yang memungkinkan kita untuk mengikat dua sumber video ke mixer. One (`custom`) adalah layar penuh dan diletakkan di belakang yang lain (`camera`), yang lebih kecil dan di sudut kanan bawah. Perhatikan bahwa untuk `custom` slot kami tidak mengatur posisi, ukuran, atau mode aspek. Karena kami tidak mengatur parameter ini, slot menggunakan pengaturan video untuk ukuran dan posisi.

```
let config = IVSBroadcastConfiguration()
try config.audio.setBitrate(128_000)
try config.video.setMaxBitrate(3_500_000)
try config.video.setMinBitrate(500_000)
try config.video.setInitialBitrate(1_500_000)
try config.video.setSize(CGSize(width: 1280, height: 720))
config.video.defaultAspectMode = .fit
config.mixer.slots = [
    try {
        let slot = IVSMixerSlotConfiguration()
        // Do not automatically bind to a source
        slot.preferredAudioInput = .unknown
        // Bind to user image if unbound
        slot.preferredVideoInput = .userImage
        try slot.setName("custom")
        return slot
    }(),
    try {
        let slot = IVSMixerSlotConfiguration()
        slot.zIndex = 1
        slot.aspect = .fill
        slot.size = CGSize(width: 300, height: 300)
        slot.position = CGPoint(x: config.video.size.width - 400, y: config.video.size.height - 400)
        try slot.setName("camera")
        return slot
    }()
]
```

## Buat Sesi Siaran (Versi Lanjutan)
<a name="broadcast-ios-create-session-advanced"></a>

Buat `IVSBroadcastSession` seperti yang Anda lakukan dalam [contoh dasar](broadcast-ios-getting-started.md#broadcast-ios-create-session), tetapi berikan konfigurasi kustom Anda di sini. Juga sediakan `nil` untuk array perangkat, karena kami akan menambahkannya secara manual.

```
let broadcastSession = try IVSBroadcastSession(
   configuration: config, // The configuration we created above
   descriptors: nil, // We’ll manually attach devices after
   delegate: self)
```

## Iterasi dan Pasang Perangkat Kamera
<a name="broadcast-ios-attach-camera"></a>

Di sini kami mengulangi melalui perangkat input yang terdeteksi SDK. SDK hanya akan mengembalikan perangkat bawaan di iOS. Bahkan jika perangkat audio Bluetooth terhubung, mereka akan muncul sebagai perangkat bawaan. Untuk informasi selengkapnya, lihat [Masalah & Solusi yang Diketahui di SDK Siaran iOS IVS \| Streaming Low-Latency](broadcast-ios-issues.md).

Setelah kami menemukan perangkat yang ingin kami gunakan, kami memanggil `attachDevice` untuk melampirkannya:

```
let frontCamera = IVSBroadcastSession.listAvailableDevices()
    .filter { $0.type == .camera && $0.position == .front }
    .first
if let camera = frontCamera {
    broadcastSession.attach(camera, toSlotWithName: "camera") { device, error in
        // check error
    }
}
```

## Swap Kamera
<a name="broadcast-ios-swap-cameras"></a>

```
// This assumes you’ve kept a reference called `currentCamera` that points to the current camera.
let wants: IVSDevicePosition = (currentCamera.descriptor().position == .front) ? .back : .front
// Remove the current preview view since the device will be changing.
previewView.subviews.forEach { $0.removeFromSuperview() }
let foundCamera = IVSBroadcastSession
        .listAvailableDevices()
        .first { $0.type == .camera && $0.position == wants }
guard let newCamera = foundCamera else { return }
broadcastSession.exchangeOldDevice(currentCamera, withNewDevice: newCamera) { newDevice, _ in
    currentCamera = newDevice
    if let camera = newDevice as? IVSImageDevice {
        do {
            previewView.addSubview(try finalCamera.previewView())
        } catch {
            print("Error creating preview view \(error)")
        }
    }
}
```

## Buat Sumber Input Kustom
<a name="broadcast-ios-create-input-source"></a>

Untuk memasukkan data suara atau gambar yang dihasilkan, digunakan, `createImageSource` atau aplikasi Anda`createAudioSource`. Kedua metode ini membuat perangkat virtual (`IVSCustomImageSource`dan`IVSCustomAudioSource`) yang dapat diikat ke mixer seperti perangkat lain.

Perangkat yang dikembalikan oleh kedua metode ini menerima `CMSampleBuffer` melalui `onSampleBuffer` fungsinya:
+ Untuk sumber video, format piksel harus`kCVPixelFormatType_32BGRA`,`420YpCbCr8BiPlanarFullRange`, atau`420YpCbCr8BiPlanarVideoRange`.
+ Untuk sumber audio, buffer harus berisi data PCM Linear.

Anda tidak dapat menggunakan input `AVCaptureSession` dengan kamera untuk memberi makan sumber gambar khusus saat juga menggunakan perangkat kamera yang disediakan oleh SDK siaran. Jika Anda ingin menggunakan beberapa kamera secara bersamaan, gunakan `AVCaptureMultiCamSession` dan sediakan dua sumber gambar khusus.

Sumber gambar khusus terutama harus digunakan dengan konten statis seperti gambar, atau dengan konten video:

```
let customImageSource = broadcastSession.createImageSource(withName: "video")
try broadcastSession.attach(customImageSource, toSlotWithName: "custom")
```

## Monitor Konektivitas Jaringan
<a name="broadcast-ios-network-connection"></a>

Adalah umum bagi perangkat seluler untuk sementara kehilangan dan mendapatkan kembali konektivitas jaringan saat bepergian. Karena itu, penting untuk memantau konektivitas jaringan aplikasi Anda dan merespons dengan tepat ketika ada perubahan. 

Ketika koneksi penyiar terputus, status SDK siaran akan berubah menjadi dan kemudian. `error` `disconnected` Anda akan diberitahu tentang perubahan ini melalui. `IVSBroadcastSessionDelegate` Saat Anda menerima perubahan status ini:

1. Pantau status konektivitas aplikasi siaran Anda dan panggil `start` dengan titik akhir dan kunci aliran Anda, setelah koneksi Anda dipulihkan.

1. **Penting:** Pantau callback delegasi status dan pastikan status berubah `connected` setelah menelepon `start` lagi.

## Lepaskan Perangkat
<a name="broadcast-ios-detach-device"></a>

Jika Anda ingin melepaskan dan tidak mengganti perangkat, lepaskan dengan `IVSDevice` atau: `IVSDeviceDescriptor`

```
broadcastSession.detachDevice(currentCamera)
```

## ReplayKit Integrasi
<a name="broadcast-ios-replaykit"></a>

Untuk melakukan streaming layar perangkat dan audio sistem di iOS, Anda harus mengintegrasikan dengan [ReplayKit](https://developer.apple.com/documentation/replaykit?language=objc). SDK siaran Amazon IVS memudahkan untuk diintegrasikan ReplayKit menggunakan. `IVSReplayKitBroadcastSession` Di `RPBroadcastSampleHandler` subclass Anda, buat instance dari`IVSReplayKitBroadcastSession`, lalu:
+ Mulai sesi di `broadcastStarted`
+ Hentikan sesi di `broadcastFinished`

Objek sesi akan memiliki tiga sumber khusus untuk gambar layar, audio aplikasi, dan audio mikrofon. Berikan yang `CMSampleBuffers` disediakan `processSampleBuffer` ke sumber khusus tersebut.

Untuk menangani orientasi perangkat, Anda perlu mengekstrak ReplayKit-specific metadata dari buffer sampel. Gunakan kode berikut:

```
let imageSource = session.systemImageSource;
if let orientationAttachment = CMGetAttachment(sampleBuffer, key: RPVideoSampleOrientationKey as CFString, attachmentModeOut: nil) as? NSNumber,
    let orientation = CGImagePropertyOrientation(rawValue: orientationAttachment.uint32Value) {
    switch orientation {
    case .up, .upMirrored:
        imageSource.setHandsetRotation(0)
    case .down, .downMirrored:
        imageSource.setHandsetRotation(Float.pi)
    case .right, .rightMirrored:
        imageSource.setHandsetRotation(-(Float.pi / 2))
    case .left, .leftMirrored:
        imageSource.setHandsetRotation((Float.pi / 2))
    }
}
```

Dimungkinkan untuk mengintegrasikan ReplayKit menggunakan `IVSBroadcastSession` alih-alih`IVSReplayKitBroadcastSession`. Namun, ReplayKit-specific varian ini memiliki beberapa modifikasi untuk mengurangi jejak memori internal, untuk tetap berada dalam langit-langit memori Apple untuk ekstensi siaran.

## Dapatkan Pengaturan Siaran yang Disarankan
<a name="broadcast-ios-recommended-settings"></a>

Untuk mengevaluasi koneksi pengguna Anda sebelum memulai siaran, gunakan `IVSBroadcastSession.recommendedVideoSettings` untuk menjalankan tes singkat. Saat tes berjalan, Anda akan menerima beberapa rekomendasi, dipesan dari yang paling banyak hingga yang paling tidak direkomendasikan. Dalam versi SDK ini, tidak mungkin untuk mengkonfigurasi ulang saat ini`IVSBroadcastSession`, jadi Anda harus mengalokasikan dan kemudian membuat yang baru dengan pengaturan yang disarankan. Anda akan terus menerima `IVSBroadcastSessionTestResults` sampai `result.status` ada `Success` atau`Error`. Anda dapat memeriksa kemajuan dengan`result.progress`.

Amazon IVS mendukung bitrate maksimum 8, 5 Mbps (untuk saluran yang `STANDARD` atau`ADVANCED`), sehingga `type` yang `maximumBitrate` dikembalikan oleh metode ini tidak pernah melebihi 8, 5 Mbps. Untuk memperhitungkan fluktuasi kecil dalam kinerja jaringan, yang direkomendasikan yang `initialBitrate` dikembalikan oleh metode ini sedikit kurang dari bitrate sebenarnya yang diukur dalam pengujian. (Menggunakan 100% dari bandwidth yang tersedia biasanya tidak disarankan.)

```
func runBroadcastTest() {
    self.test = session.recommendedVideoSettings(with: IVS_RTMPS_URL, streamKey: IVS_STREAMKEY) { [weak self] result in
        if result.status == .success {
            self?.recommendation = result.recommendations[0];
        }
    }
}
```

## Menggunakan Auto-Reconnect
<a name="broadcast-ios-auto-reconnect"></a>

IVS mendukung koneksi ulang otomatis ke siaran jika siaran berhenti secara tak terduga tanpa memanggil `stop` API; misalnya, kerugian sementara dalam konektivitas jaringan. Untuk mengaktifkan sambung ulang otomatis, setel `enabled` properti ke. `IVSBroadcastConfiguration.autoReconnect` `true`

Ketika sesuatu menyebabkan aliran berhenti secara tak terduga, SDK mencoba ulang hingga 5 kali, mengikuti strategi backoff linier. Ini memberi tahu aplikasi Anda tentang status coba lagi melalui fungsi. `IVSBroadcastSessionDelegate.didChangeRetryState`

Di belakang layar, sambungkan kembali otomatis menggunakan fungsionalitas [pengambilalihan aliran](streaming-config.md#streaming-config-stream-takeover) IVS dengan menambahkan nomor prioritas, dimulai dengan 1, hingga akhir kunci aliran yang disediakan. Selama durasi `IVSBroadcastSession` instance, angka itu bertambah 1 setiap kali penyambungan kembali dicoba. Ini berarti jika koneksi perangkat terputus 4 kali selama siaran, dan setiap kerugian memerlukan 1-4 upaya coba lagi, prioritas streaming terakhir bisa berada di mana saja antara 5 dan 17. Karena itu, *kami menyarankan Anda untuk tidak menggunakan pengambilalihan aliran IVS dari perangkat lain sementara sambungan ulang otomatis diaktifkan di SDK untuk saluran yang sama*. Tidak ada jaminan prioritas apa yang digunakan SDK pada saat itu, dan SDK akan mencoba menyambung kembali dengan prioritas yang lebih tinggi jika perangkat lain mengambil alih.

## Gunakan Video Latar Belakang
<a name="broadcast-ios-background-video"></a>

Anda dapat melanjutkan RelayKit non-broadcast, bahkan dengan aplikasi Anda di latar belakang.

Untuk menghemat daya dan menjaga aplikasi latar depan responsif, iOS hanya memberikan satu aplikasi sekaligus akses ke GPU. Amazon IVS Broadcast SDK menggunakan GPU pada beberapa tahap pipeline video, termasuk menyusun beberapa sumber input, menskalakan gambar, dan menyandikan gambar. Sementara aplikasi penyiaran berada di latar belakang, tidak ada jaminan bahwa SDK dapat melakukan salah satu tindakan ini.

Untuk mengatasi ini, gunakan `createAppBackgroundImageSource` metode ini. Ini memungkinkan SDK untuk terus menyiarkan video dan audio saat berada di latar belakang. Ia mengembalikan`IVSBackgroundImageSource`, yang merupakan normal `IVSCustomImageSource` dengan `finish` fungsi tambahan. Setiap `CMSampleBuffer` yang disediakan ke sumber gambar latar belakang dikodekan pada frame rate yang disediakan oleh aslinya. `IVSVideoConfiguration` Stempel waktu pada diabaikan`CMSampleBuffer`.

SDK kemudian menskalakan dan mengkodekan gambar-gambar tersebut dan menyimpannya dalam cache, secara otomatis mengulang feed tersebut saat aplikasi Anda masuk ke latar belakang. Saat aplikasi Anda kembali ke latar depan, perangkat gambar yang terpasang menjadi aktif kembali dan aliran yang dikodekan sebelumnya berhenti melakukan perulangan.

Untuk membatalkan proses ini, gunakan`removeImageSourceOnAppBackgrounded`. Anda tidak perlu memanggil ini kecuali Anda ingin secara eksplisit mengembalikan perilaku latar belakang SDK; jika tidak, itu dibersihkan secara otomatis pada dealokasi. `IVSBroadcastSession`

**Catatan:** *Kami sangat menyarankan agar Anda memanggil metode ini sebagai bagian dari konfigurasi sesi siaran, sebelum sesi ditayangkan*. Metode ini mahal (mengkodekan video), sehingga kinerja siaran langsung saat metode ini berjalan dapat menurun.

### Contoh: Menghasilkan Gambar Statis untuk Video Latar Belakang
<a name="background-video-example-static-image"></a>

Menyediakan satu gambar ke sumber latar belakang menghasilkan GOP penuh dari gambar statis itu.

Berikut adalah contoh menggunakan CIImage:

```
// Create the background image source
guard let source = session.createAppBackgroundImageSource(withAttemptTrim: true, onComplete: { error in
    print("Background Video Generation Done - Error: \(error.debugDescription)")
}) else {
    return
}

// Create a CIImage of the color red.
let ciImage = CIImage(color: .red)

// Convert the CIImage to a CVPixelBuffer
let attrs = [
    kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue,
    kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue,
    kCVPixelBufferMetalCompatibilityKey: kCFBooleanTrue,
] as CFDictionary

var pixelBuffer: CVPixelBuffer!
CVPixelBufferCreate(kCFAllocatorDefault,
                    videoConfig.width,
                    videoConfig.height,
                    kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
                    attrs,
                    &pixelBuffer)

let context = CIContext()
context.render(ciImage, to: pixelBuffer)

// Submit to CVPixelBuffer and finish the source
source.add(pixelBuffer)
source.finish()
```

Sebagai alternatif, alih-alih membuat CIImage dengan warna solid, Anda dapat menggunakan gambar yang dibundel. Satu-satunya kode yang ditampilkan di sini adalah cara mengonversi UIImage menjadi CIImage untuk digunakan dengan sampel sebelumnya:

```
// Load the pre-bundled image and get it’s CGImage
guard let cgImage = UIImage(named: "image")?.cgImage else {
    return
}

// Create a CIImage from the CGImage
let ciImage = CIImage(cgImage: cgImage)
```

### Contoh: Video dengan AVAssetImageGenerator
<a name="background-video-example-avassetimagegenerator"></a>

Anda dapat menggunakan `AVAssetImageGenerator` untuk menghasilkan `CMSampleBuffers` dari `AVAsset` (meskipun bukan aliran HLS`AVAsset`):

```
// Create the background image source
guard let source = session.createAppBackgroundImageSource(withAttemptTrim: true, onComplete: { error in
    print("Background Video Generation Done - Error: \(error.debugDescription)")
}) else {
    return
}

// Find the URL for the pre-bundled MP4 file
guard let url = Bundle.main.url(forResource: "sample-clip", withExtension: "mp4") else {
    return
}
// Create an image generator from an asset created from the URL.
let generator = AVAssetImageGenerator(asset: AVAsset(url: url))
// It is important to specify a very small time tolerance.
generator.requestedTimeToleranceAfter = .zero
generator.requestedTimeToleranceBefore = .zero

// At 30 fps, this will generate 4 seconds worth of samples.
let times: [NSValue] = (0...120).map { NSValue(time: CMTime(value: $0, timescale: CMTimeScale(config.video.targetFramerate))) }
var completed = 0

let context = CIContext(options: [.workingColorSpace: NSNull()])

// Create a pixel buffer pool to efficiently feed the source
let attrs = [
    kCVPixelBufferPixelFormatTypeKey: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
    kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue,
    kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue,
    kCVPixelBufferMetalCompatibilityKey: kCFBooleanTrue,
    kCVPixelBufferWidthKey: videoConfig.width,
    kCVPixelBufferHeightKey: videoConfig.height,
] as CFDictionary
var pool: CVPixelBufferPool!
CVPixelBufferPoolCreate(kCFAllocatorDefault, nil, attrs, &pool)

generator.generateCGImagesAsynchronously(forTimes: times) { requestTime, image, actualTime, result, error in
    if let image = image {
        // convert to CIImage then CVpixelBuffer
        let ciImage = CIImage(cgImage: image)
        var pixelBuffer: CVPixelBuffer!
        CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pool, &pixelBuffer)
        context.render(ciImage, to: pixelBuffer)
        source.add(pixelBuffer)
    }
    completed += 1
    if completed == times.count {
        // Mark the source finished when all images have been processed
        source.finish()
    }
}
```

Dimungkinkan untuk menghasilkan `CVPixelBuffers` menggunakan `AVPlayer` dan`AVPlayerItemVideoOutput`. Namun, itu membutuhkan penggunaan `CADisplayLink` dan eksekusi lebih dekat ke waktu nyata, sementara `AVAssetImageGenerator` dapat memproses frame lebih cepat.

### Batasan
<a name="background-video-limitations"></a>

Aplikasi Anda memerlukan [hak audio latar belakang](https://developer.apple.com/documentation/xcode/configuring-background-execution-modes) untuk menghindari penangguhan setelah masuk ke latar belakang.

`createAppBackgroundImageSource`dapat dipanggil hanya saat aplikasi Anda berada di latar depan, karena perlu akses ke GPU untuk menyelesaikannya.

`createAppBackgroundImageSource`selalu mengkodekan ke GOP penuh. Misalnya, jika Anda memiliki interval keyframe 2 detik (default) dan berjalan pada 30 fps, itu mengkodekan kelipatan 60 frame.
+ Jika kurang dari 60 frame disediakan, frame terakhir diulang hingga 60 frame tercapai, terlepas dari nilai opsi trim.
+ Jika lebih dari 60 frame disediakan dan opsi trim adalah`true`, N frame terakhir dijatuhkan, di mana N adalah sisa dari jumlah total frame yang dikirimkan dibagi 60.
+ Jika lebih dari 60 frame disediakan dan opsi trim adalah`false`, frame terakhir diulang hingga kelipatan berikutnya dari 60 frame tercapai.