

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

# Kasus Penggunaan Lanjutan untuk IVS iOS Broadcast SDK \| 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.

## Membuat 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. Satu (`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 khusus 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 telah dideteksi SDK. SDK hanya akan mengembalikan perangkat bawaan di iOS. Bahkan jika perangkat audio Bluetooth terhubung, mereka akan muncul sebagai perangkat bawaan.

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
    }
}
```

## Tukar 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 aplikasi Anda, gunakan, `createImageSource` atau`createAudioSource`. Kedua metode ini membuat perangkat virtual (`IVSCustomImageSource`dan`IVSCustomAudioSource`) yang dapat diikat ke mixer seperti perangkat lainnya.

Perangkat yang dikembalikan oleh kedua metode ini menerima a `CMSampleBuffer` melalui fung `onSampleBuffer` sinya:
+ 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 sambil juga menggunakan perangkat kamera yang disediakan oleh SDK siaran. Jika Anda ingin menggunakan beberapa kamera secara bersamaan, gunakan `AVCaptureMultiCamSession` dan berikan 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")
```

## Memantau 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 `error` dan kemudian`disconnected`. Anda akan diberitahu tentang perubahan ini melalui`IVSBroadcastSessionDelegate`. Ketika Anda menerima perubahan status ini:

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

1. **Penting: ** Pantau panggilan balik delegasi negara dan pastikan status berubah menjadi `connected` setelah menelepon `start` lagi.

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

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

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

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

Untuk melakukan streaming layar perangkat dan audio sistem di iOS, Anda harus berintegrasi dengan [ ReplayKit](https://developer.apple.com/documentation/replaykit?language=objc). Amazon IVS broadcast SDK memudahkan untuk mengintegrasikan ReplayKit penggunaan`IVSReplayKitBroadcastSession`. Di `RPBroadcastSampleHandler` subkelas Anda, buat instance`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 al `IVSBroadcastSession` ih-alih`IVSReplayKitBroadcastSession`. Namun, ReplayKit-specific varian ini memiliki beberapa modifikasi untuk mengurangi jejak memori internal, agar tetap berada dalam batas memori Apple untuk ekstensi siaran.

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

Untuk mengevaluasi koneksi pengguna Anda sebelum memulai siaran, gunakan `IVSBroadcastSession.recommendedVideoSettings` untuk menjalankan tes singkat. Saat pengujian 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 mengalokasinya 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 `type` `STANDARD` atau`ADVANCED`), sehingga yang `maximumBitrate` dikembalikan oleh metode ini tidak pernah melebihi 8,5 Mbps. Untuk memperhitungkan fluktuasi kecil dalam kinerja jaringan, yang disarankan `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, kehilangan sementara dalam konektivitas jaringan. Untuk mengaktifkan koneksi ulang otomatis, setel `enabled` properti ke. `IVSBroadcastConfiguration.autoReconnect` `true`

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

Di balik layar, auto-reconnect menggunakan [ fungsionalitas ](streaming-config.md#streaming-config-stream-takeover) pengambilalihan aliran IVS dengan menambahkan nomor prioritas, dimulai dengan 1, ke akhir kunci aliran yang disediakan. Untuk durasi `IVSBroadcastSession` instance, angka itu bertambah 1 setiap kali koneksi ulang dicoba. Ini berarti jika koneksi perangkat terputus 4 kali selama siaran, dan setiap kehilangan memerlukan 1-4 upaya coba lagi, prioritas streaming terakhir bisa berada di antara 5 dan 17. Karena itu, * kami sarankan Anda tidak menggunakan pengambilalihan aliran IVS dari perangkat lain saat koneksi 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 non-si RelayKit aran, bahkan dengan aplikasi Anda di latar belakang.

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

Untuk mengatasi hal ini, gunakan `createAppBackgroundImageSource` metode ini. Ini memungkinkan SDK untuk terus menyiarkan video dan audio saat berada di latar belakang. Ini mengembalikan sebuah`IVSBackgroundImageSource`, yang merupakan normal `IVSCustomImageSource` dengan `finish` fungsi tambahan. Setiap `CMSampleBuffer` yang disediakan untuk sumber gambar latar belakang dikodekan pada kecepatan bingkai 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 umpan itu ketika aplikasi Anda masuk ke latar belakang. Saat aplikasi Anda kembali ke latar depan, perangkat gambar terlampir menjadi aktif kembali dan aliran yang telah dikodekan 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 deallokasi. `IVSBroadcastSession`

**Catatan: ** * Kami sangat menyarankan 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 mungkin terdegradasi.

### 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 ke 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 an `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 a `CADisplayLink` dan mengeksekusi lebih dekat ke real-time, sementara `AVAssetImageGenerator` dapat memproses frame jauh 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 ditangguhkan 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 dengan 60.
+ Jika lebih dari 60 frame disediakan dan opsi trim adalah`false`, frame terakhir diulang sampai kelipatan 60 frame berikutnya tercapai.