

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

# Integrasikan aplikasi web Anda dengan pengalihan WebRTC
<a name="webrtc-redirection-integration"></a>

Pengalihan WebRTC memungkinkan aplikasi web yang berjalan di WorkSpaces dalam sesi untuk menggunakan perangkat audio sisi klien asli. Topik ini menunjukkan pengembang aplikasi web bagaimana mendeteksi lingkungan pengalihan WebRTC dan mengintegrasikannya.

Saat pengalihan WebRTC diaktifkan pada a, WorkSpace ekstensi browser Amazon DCV WebRTC Redirection menyuntikkan SDK proxy ke halaman web. Aplikasi Anda dapat mendeteksi proxy ini dan menggunakannya untuk mengarahkan panggilan API WebRTC standar - termasuk UserMedia get RTCPeerConnection dan - ke perangkat lokal pengguna daripada perangkat virtual remote. WorkSpace Ini memberikan kinerja yang jauh lebih baik dan latensi yang lebih rendah dibandingkan dengan media streaming melalui protokol tampilan DCV.

Aplikasi Anda harus menangani kedua kasus: ketika berjalan di dalam WorkSpace dengan pengalihan WebRTC diaktifkan, dan ketika berjalan di browser standar tanpa itu. Proxy bersifat opsional - jika tidak ada, aplikasi Anda dapat kembali ke WebRTC standar.

## Prasyarat
<a name="webrtc-prereqs"></a>

### Untuk pengguna akhir
<a name="webrtc-prereqs-users"></a>

Pengguna akhir membutuhkan yang berikut ini:
+ A WorkSpace menggunakan protokol DCV. Untuk informasi selengkapnya, lihat [Protokol untuk Pribadi WorkSpaces](amazon-workspaces-networking.md#amazon-workspaces-protocols).
**catatan**  
Pengalihan WebRTC di sisi server saat ini hanya didukung pada Windows. WorkSpaces
+  WorkSpaces Klien yang didukung dari [clients.amazonworkspaces.com](https://clients.amazonworkspaces.com). Platform yang didukung: Windows, macOS, Linux (Ubuntu 22.04 dan Ubuntu 24.04, amd64), dan Web.
+ Pengalihan WebRTC diaktifkan melalui Kebijakan Grup. Saat diaktifkan, kebijakan akan secara otomatis menginstal ekstensi browser di Chrome dan Edge melalui registri. Untuk informasi selengkapnya, lihat [Kelola Windows Anda WorkSpaces secara WorkSpaces Pribadi](group_policy.md). Jika diperlukan, pengguna dapat menginstal ekstensi secara manual: [Chrome](https://chromewebstore.google.com/detail/amazon-dcv-webrtc-redirec/diilpfplcnhehakckkpmcmibmhbingnd) dan [Edge](https://microsoftedge.microsoft.com/addons/detail/amazon-dcv-webrtc-redirec/kjbbkjjiecchbcdoollhgffghfjnbhef).

### Untuk pengembang
<a name="webrtc-prereqs-devs"></a>

Aplikasi web Anda harus:
+ Gunakan API WebRTC standar (seperti get dan) UserMedia RTCPeerConnection
+ Sertakan kode deteksi dan inisialisasi seperti yang dijelaskan dalam topik ini

## Bagaimana cara mengintegrasikan
<a name="webrtc-how-to-integrate"></a>

Integrasi melibatkan empat langkah: mendeteksi lingkungan pengalihan, mengganti API WebRTC, memetakan elemen audio, dan menangani koneksi ulang.

### Langkah 1: Mendeteksi lingkungan pengalihan
<a name="webrtc-step1-detect"></a>

Tambahkan kode inisialisasi ini ke aplikasi Anda. Callback berjalan saat proxy siap, atau setelah batas waktu jika pengalihan tidak tersedia.

```
let proxy = null;

function handleInitCallback(result) {
    if (result.success) {
        // Redirection is available
        proxy = result.proxy;
        console.log('WebRTC redirection enabled, version:', proxy.getVersion());
        console.log('Client info:', proxy.clientInfo);

        // Override WebRTC APIs to use redirection
        proxy.overrideWebRTC();

        // Set up reconnection handling
        setupReconnectionHandling();
    } else {
        // Not in a redirection environment  - use standard WebRTC
        console.log('WebRTC redirection not available:', result.error);
    }
}

// Register the initialization callback
if (globalThis.DCVWebRTCPeerConnectionProxyV2) {
    globalThis.DCVWebRTCPeerConnectionProxyV2.setInitCallback(handleInitCallback, 5000);
}
```

Poin kunci:
+ Periksa `globalThis.DCVWebRTCPeerConnectionProxyV2` untuk mendeteksi ekstensi
+ Panggilan `setInitCallback()` dengan handler Anda dan batas waktu - 5000 ms direkomendasikan
+ Callback menerima objek hasil dengan `success` boolean dan salah satu atau `proxy` `error`
+ Panggilan `proxy.overrideWebRTC()` untuk mengarahkan API WebRTC standar

### Langkah 2: Gunakan API WebRTC standar
<a name="webrtc-step2-apis"></a>

Setelah menelepon`overrideWebRTC()`, gunakan WebRTC API secara normal. Proxy secara transparan mengarahkan mereka ke klien lokal.

**catatan**  
Pengalihan video saat ini tidak didukung. Ditetapkan `video: false` dalam `getUserMedia` permintaan.

```
// Get user media  - automatically redirected
const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: false   // Video redirection not yet supported
});

// Create peer connection  - automatically redirected
const pc = new RTCPeerConnection(configuration);

// Everything else works as standard WebRTC
pc.addTrack(stream.getAudioTracks()[0], stream);
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
```

Jika Anda perlu mengakses API browser asli (misalnya, untuk merekam video dari browser jarak jauh daripada klien lokal), mereka disimpan dalam`proxy.overridenApis`:

```
// Get the original getUserMedia (runs in remote browser, not redirected)
const originalGetUserMedia = proxy.overridenApis.get('navigator.mediaDevices.getUserMedia');

// Available original APIs:
// 'navigator.mediaDevices.getUserMedia'
// 'navigator.mediaDevices.addEventListener'
// 'navigator.mediaDevices.removeEventListener'
// 'navigator.mediaDevices.enumerateDevices'
// 'navigator.mediaDevices.getDisplayMedia'
// 'window.RTCPeerConnection'
// 'window.RTCPeerConnection.generateCertificate'
// 'window.AudioContext'
// 'window.Worker' (experimental)

const remoteStream = await originalGetUserMedia.call(navigator.mediaDevices, {
    audio: false,
    video: true
});
```

### Langkah 3: Peta elemen audio
<a name="webrtc-step3-audio"></a>

Untuk pemutaran audio, hubungi `mapAudioElement()` sebelum mengatur `srcObject` elemen audio apa pun.

```
const audioElement = document.querySelector('audio#remote-audio');

// Map the audio element before setting srcObject
proxy.mapAudioElement(audioElement);

// Now use the audio element normally
audioElement.srcObject = remoteStream;
await audioElement.play();

// Control playback
audioElement.pause();
audioElement.volume = 0.8;
audioElement.muted = false;

// Change output device
await audioElement.setSinkId(deviceId);
```

### Langkah 4: Tangani koneksi ulang
<a name="webrtc-step4-reconnection"></a>

Layanan pengalihan dapat menjadi tidak tersedia untuk sementara, misalnya karena masalah jaringan atau koneksi ulang klien.

**penting**  
Setelah koneksi ulang, semua objek proxy yang dibuat sebelumnya menjadi tidak valid karena konteks browser klien dimuat ulang sepenuhnya. Anda harus menutup koneksi yang ada dan membuat objek WebRTC baru.

```
function setupReconnectionHandling() {
    proxy.addStatusChangeEventListener((event) => {
        switch (event.status) {
            case 'unavailable':
                console.error('Redirection lost');
                handleRedirectionLost();
                break;
            case 'available':
                console.info('Redirection restored');
                handleRedirectionRestored();
                break;
        }
    });
}

function handleRedirectionLost() {
    // Try to close cleanly  - proxies may throw exceptions after reconnection
    try {
        if (peerConnection) { peerConnection.close(); }
    } catch (error) {
        console.warn('Error closing peer connection (proxy may be invalid):', error);
    }
    showReconnectingMessage();
}

function handleRedirectionRestored() {
    // IMPORTANT: All existing proxy objects are invalid after reconnection.
    // Create new RTCPeerConnection, MediaStream, and other WebRTC objects.
    hideReconnectingMessage();
    restartCall(); // Must create fresh WebRTC objects
}
```

Anda dapat menyesuaikan waktu detak jantung:

```
proxy.resetHeartbeat({
    heartbeatTimeoutMs: 5000,      // Time before marking unavailable
    heartbeatIntervalPeriodMs: 500 // How often to check
});
```

## Pencacahan perangkat
<a name="webrtc-device-enumeration"></a>

Perubahan perangkat - misalnya, pengguna yang mencolokkan headset - terdeteksi secara otomatis. Gunakan `makeMediaDevicesProxy()` untuk mendengarkan perubahan perangkat pada klien lokal:

```
const mediaDevices = proxy.makeMediaDevicesProxy();
mediaDevices.ondevicechange = async () => {
    const devices = await navigator.mediaDevices.enumerateDevices();
    updateDeviceList(devices);
};
```

Gunakan `proxy.clientInfo` untuk menentukan platform klien mana pengguna terhubung dari:

```
// clientInfo contains:
// - platform: 'web' | 'windows' | 'macOS' | 'linux'
// - version: SDK version string
// - userAgent: browser user agent string
// - browserDetails: { browser: string, version: string }

switch (proxy.clientInfo.platform) {
    case 'web':     console.log('Connecting from web client'); break;
    case 'windows': console.log('Connecting from Windows native client'); break;
    case 'macOS':   console.log('Connecting from macOS native client'); break;
    case 'linux':   console.log('Connecting from Linux native client'); break;
}
```

## Lanjutan: Pemrosesan audio dengan Web Audio API
<a name="webrtc-advanced-audio"></a>

Anda dapat menggunakan Web Audio API untuk memproses aliran audio sebelum mengirimnya melalui koneksi rekan:

```
const audioContext = new AudioContext();
const source = audioContext.createMediaStreamSource(micStream);
const gainNode = audioContext.createGain();
const destination = audioContext.createMediaStreamDestination();

source.connect(gainNode);
gainNode.connect(destination);

// Control microphone volume
gainNode.gain.value = 0.5; // 50% volume

// Use the processed stream
pc.addTrack(destination.stream.getAudioTracks()[0], destination.stream);
```

## Contoh lengkap
<a name="webrtc-complete-example"></a>

Contoh berikut menunjukkan integrasi lengkap dengan inisialisasi, penanganan rekoneksi, deteksi perubahan perangkat, dan penyiapan panggilan:

```
let proxy = null;
let peerConnection = null;
let localStream = null;

function initializeRedirection() {
    if (globalThis.DCVWebRTCPeerConnectionProxyV2) {
        globalThis.DCVWebRTCPeerConnectionProxyV2.setInitCallback((result) => {
            if (result.success) {
                proxy = result.proxy;
                proxy.overrideWebRTC();
                proxy.addStatusChangeEventListener(handleStatusChange);
                proxy.resetHeartbeat({ heartbeatTimeoutMs: 5000, heartbeatIntervalPeriodMs: 500 });
                setupDeviceChangeListener();
            } else {
                console.log('Redirection not available:', result.error);
            }
        }, 5000);
    }
}

function handleStatusChange(event) {
    if (event.status === 'unavailable') {
        try {
            if (peerConnection) { peerConnection.close(); peerConnection = null; }
            if (localStream) { localStream.getTracks().forEach(t => t.stop()); localStream = null; }
        } catch (error) {
            console.warn('Error cleaning up (proxies invalid):', error);
            peerConnection = null;
            localStream = null;
        }
    } else if (event.status === 'available') {
        startCall(); // Create fresh WebRTC objects
    }
}

function setupDeviceChangeListener() {
    const mediaDevices = proxy.makeMediaDevicesProxy();
    mediaDevices.ondevicechange = async () => {
        const devices = await navigator.mediaDevices.enumerateDevices();
        updateDeviceUI(devices);
    };
}

async function startCall() {
    try {
        localStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });
        peerConnection = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });
        localStream.getTracks().forEach(track => peerConnection.addTrack(track, localStream));

        peerConnection.ontrack = (event) => {
            const remoteAudio = document.querySelector('audio#remote');
            if (proxy) { proxy.mapAudioElement(remoteAudio); }
            remoteAudio.srcObject = event.streams[0];
            remoteAudio.play();
        };

        peerConnection.onicecandidate = (event) => {
            if (event.candidate) { sendToSignalingServer({ type: 'ice-candidate', candidate: event.candidate }); }
        };

        const offer = await peerConnection.createOffer();
        await peerConnection.setLocalDescription(offer);
        sendToSignalingServer({ type: 'offer', sdp: offer });
    } catch (error) {
        console.error('Failed to start call:', error);
    }
}

initializeRedirection();
```

## Menguji integrasi Anda
<a name="webrtc-testing"></a>

### Tanpa pengalihan
<a name="webrtc-testing-without"></a>

Aplikasi Anda berfungsi normal saat ekstensi tidak diinstal, saat berjalan di luar a WorkSpace, atau saat pengalihan WebRTC tidak diaktifkan melalui Kebijakan Grup. Uji dengan membuka aplikasi Anda di browser biasa.

### Dengan pengalihan
<a name="webrtc-testing-with"></a>

Untuk menguji dengan pengalihan diaktifkan:

1. Buat protokol WorkSpace menggunakan DCV dan aktifkan pengaturan Kebijakan Grup pengalihan WebRTC. Lihat [Kelola Windows Anda WorkSpaces secara WorkSpaces Pribadi](group_policy.md).

1. Unduh dan instal WorkSpaces klien dari [clients.amazonworkspaces.com](https://clients.amazonworkspaces.com) dan sambungkan ke file. WorkSpace Verifikasi ekstensi Chrome atau Edge diinstal (otomatis saat GPO disetel).

1. Buka aplikasi web Anda di WorkSpace browser. Periksa konsol untuk pesan “WebRTC redirection enabled”. Verifikasi fungsionalitas audio dengan perangkat lokal, uji pencacahan dan peralihan perangkat, dan verifikasi penanganan koneksi ulang.

## Praktik terbaik
<a name="webrtc-best-practices"></a>

Ikuti rekomendasi ini saat mengintegrasikan dengan pengalihan WebRTC:
+ Selalu periksa ketersediaan pengalihan - jangan pernah menganggap proxy ada
+ Panggil `overrideWebRTC()` lebih awal - sebelum membuat objek WebRTC
+ Memetakan elemen audio sebelum digunakan - panggilan `mapAudioElement()` sebelum pengaturan `srcObject`
+ Menangani rekoneksi - setelah rekoneksi, semua objek proxy tidak valid; selalu buat objek WebRTC baru
+ Uji kedua mode - pastikan aplikasi Anda berfungsi dengan benar dengan dan tanpa pengalihan
+ Gunakan API WebRTC standar - proxy mengarahkannya secara transparan; tidak diperlukan API khusus untuk penggunaan dasar
+ Bersihkan sumber daya - hapus pendengar acara dan tutup koneksi setelah selesai

## Pemecahan masalah
<a name="webrtc-troubleshooting"></a>

### Pengalihan tidak terdeteksi
<a name="webrtc-troubleshooting-not-detected"></a>
+ Verifikasi ekstensi browser diinstal dan diaktifkan (periksa`chrome://extensions`)
+ Konfirmasikan Kebijakan Grup pengalihan WebRTC diaktifkan pada WorkSpace
+ Verifikasi bahwa Anda menjalankan di dalam WorkSpace protokol menggunakan DCV
+ Periksa konsol browser untuk pesan inisialisasi
+ Verifikasi bahwa versi WorkSpaces klien mendukung pengalihan WebRTC (Windows 5.21.0 atau yang lebih baru, macOS 5.31.0 atau yang lebih baru, Linux 2026.0 atau yang lebih baru, atau klien Web)

### Audio atau video tidak berfungsi
<a name="webrtc-troubleshooting-audio-video"></a>
+ Verifikasi `overrideWebRTC()` dipanggil sebelum membuat objek WebRTC
+ Verifikasi elemen audio dipetakan dengan `mapAudioElement()` sebelum pengaturan `srcObject`
+ Periksa konsol browser untuk kesalahan
+ Verifikasi izin perangkat diberikan

### Masalah koneksi ulang
<a name="webrtc-troubleshooting-reconnection"></a>
+ Terapkan `addStatusChangeEventListener()` untuk mendeteksi perubahan ketersediaan
+ Setelah koneksi ulang, selalu buat baru RTCPeerConnection dan MediaStream objek - proxy lama tidak valid dan akan melempar
+ Tinjau konfigurasi detak jantung jika tidak tersedianya terdeteksi terlalu lambat atau terlalu cepat

## Referensi API
<a name="webrtc-api-reference"></a>

Berikut ini merangkum API proxy:

```
interface DCVWebRTCProxy {
    // Version and client info
    getVersion(): string;
    clientInfo: {
        platform: 'web' | 'windows' | 'macOS' | 'linux';
        version: string;
        userAgent: string;
        browserDetails: { browser: string; version: string; };
    };

    // Core methods
    overrideWebRTC(): void;
    mapAudioElement(element: HTMLAudioElement): void;

    // Device management
    makeMediaDevicesProxy(): MediaDevices;

    // Status monitoring
    addStatusChangeEventListener(callback: (event: StatusChangeEvent) => void): void;
    resetHeartbeat(config: { heartbeatTimeoutMs: number, heartbeatIntervalPeriodMs: number }): void;

    // Access original (non-redirected) browser APIs
    overridenApis: Map<string, Function>;
}

interface StatusChangeEvent {
    status: 'available' | 'unavailable';
    lastHeartbeat?: number;
}
```