

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# ウェブアプリケーションを WebRTC リダイレクトと統合する
<a name="webrtc-redirection-integration"></a>

WebRTC リダイレクトを使用すると、WorkSpaces セッション内で実行されているウェブアプリケーションは、クライアント側のネイティブオーディオデバイスを使用できます。このトピックでは、ウェブアプリケーション開発者が WebRTC リダイレクト環境を検出して統合する方法を示します。

WorkSpace で WebRTC リダイレクトが有効になっている場合、Amazon DCV WebRTC リダイレクトブラウザ拡張機能はプロキシ SDK をウェブページに挿入します。アプリケーションはこのプロキシを検出し、それを使用して、getUserMedia や RTCPeerConnection などの標準の WebRTC API コールを、リモート WorkSpace の仮想デバイスではなく、ユーザーのローカルデバイスにリダイレクトできます。これにより、DCV ディスプレイプロトコルを介したメディアのストリーミングと比較して、パフォーマンスが大幅に向上し、レイテンシーが短縮されます。

アプリケーションは、WebRTC リダイレクトが有効になっている WorkSpace WebRTC リダイレクトが有効になっていない標準ブラウザで実行する場合の両方のケースを処理する必要があります。プロキシはオプションです。存在しない場合、アプリケーションは標準の WebRTC にフォールバックできます。

## 前提条件
<a name="webrtc-prereqs"></a>

### エンドユーザー向け
<a name="webrtc-prereqs-users"></a>

エンドユーザーには以下が必要です。
+ DCV プロトコルを使用する WorkSpace。詳細については、「[WorkSpaces Personal のプロトコル](amazon-workspaces-networking.md#amazon-workspaces-protocols)」を参照してください。
**注記**  
サーバー側の WebRTC リダイレクトは、現在 Windows WorkSpaces でのみサポートされています。
+ [clients.amazonworkspaces.com](https://clients.amazonworkspaces.com) でサポートされている WorkSpaces クライアント。サポートされているプラットフォーム: Windows、macOS、Linux (Ubuntu 22.04 および Ubuntu 24.04、amd64)、および Web。
+ グループポリシーを通じて有効になっている WebRTC リダイレクト。有効にすると、ポリシーはレジストリを介してブラウザ拡張機能を Chrome と Edge に自動的にインストールします。詳細については、「[WorkSpaces Personal で Windows WorkSpaces を管理する](group_policy.md)」を参照してください。必要に応じて、ユーザーは拡張機能 [Chrome](https://chromewebstore.google.com/detail/amazon-dcv-webrtc-redirec/diilpfplcnhehakckkpmcmibmhbingnd) と [Edge](https://microsoftedge.microsoft.com/addons/detail/amazon-dcv-webrtc-redirec/kjbbkjjiecchbcdoollhgffghfjnbhef) を手動でインストールできます。

### デベロッパー向け
<a name="webrtc-prereqs-devs"></a>

ウェブアプリケーションは次の条件を満たす必要があります。
+ 標準の WebRTC APIs (getUserMedia や RTCPeerConnection など) を使用する
+ このトピックで説明されているように、検出コードと初期化コードを含める

## 統合方法
<a name="webrtc-how-to-integrate"></a>

統合には、リダイレクト環境の検出、WebRTC APIs上書き、オーディオ要素のマッピング、再接続の処理の 4 つのステップが含まれます。

### ステップ 1: リダイレクト環境を検出する
<a name="webrtc-step1-detect"></a>

この初期化コードをアプリケーションに追加します。コールバックは、プロキシの準備ができたとき、またはリダイレクトが利用できない場合はタイムアウト後に実行されます。

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

キーポイント:
+ 拡張機能を検出する`globalThis.DCVWebRTCPeerConnectionProxyV2`には、 を確認します。
+ ハンドラーとタイムアウト`setInitCallback()`を使用して を呼び出す - 5000 ミリ秒を推奨
+ コールバックは、ブール値と `proxy`または `success` のいずれかの結果オブジェクトを受け取ります。 `error`
+ を呼び出し`proxy.overrideWebRTC()`て標準の WebRTC APIs

### ステップ 2: 標準の WebRTC APIs
<a name="webrtc-step2-apis"></a>

を呼び出した後は`overrideWebRTC()`、通常どおり WebRTC APIsを使用します。プロキシはローカルクライアントに透過的にリダイレクトします。

**注記**  
ビデオリダイレクトは現在サポートされていません。`getUserMedia` リクエスト`video: false`で を設定します。

```
// 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);
```

元のブラウザ APIs にアクセスする必要がある場合 (ローカルクライアントではなくリモートブラウザからビデオをキャプチャする場合など）、それらは に保持されます`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
});
```

### ステップ 3: オーディオ要素をマッピングする
<a name="webrtc-step3-audio"></a>

オーディオ再生の場合は、オーディオ要素で を設定する`mapAudioElement()`前に `srcObject`を呼び出します。

```
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);
```

### ステップ 4: 再接続を処理する
<a name="webrtc-step4-reconnection"></a>

リダイレクトサービスは、ネットワークの問題やクライアントの再接続などにより、一時的に使用できなくなる可能性があります。

**重要**  
再接続後、クライアントブラウザコンテキストが完全に再ロードされるため、以前に作成したすべてのプロキシオブジェクトが無効になります。既存の接続を閉じて、新しい WebRTC オブジェクトを作成する必要があります。

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

ハートビートのタイミングをカスタマイズできます。

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

## デバイス列挙
<a name="webrtc-device-enumeration"></a>

デバイスの変更 - ヘッドセットをプラグインするユーザーなど - は自動的に検出されます。を使用して`makeMediaDevicesProxy()`、ローカルクライアントでデバイスの変更をリッスンします。

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

を使用して`proxy.clientInfo`、ユーザーが接続元のクライアントプラットフォームを決定します。

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

## アドバンスト: Web Audio API によるオーディオ処理
<a name="webrtc-advanced-audio"></a>

Web Audio API を使用して、ピア接続を介してオーディオストリームを送信する前にオーディオストリームを処理できます。

```
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);
```

## 完全な例
<a name="webrtc-complete-example"></a>

次の例は、初期化、再接続処理、デバイス変更検出、通話設定との完全な統合を示しています。

```
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();
```

## 統合のテスト
<a name="webrtc-testing"></a>

### リダイレクトなし
<a name="webrtc-testing-without"></a>

アプリケーションは、拡張機能がインストールされていない場合、WorkSpace の外部で実行されている場合、またはグループポリシーで WebRTC リダイレクトが有効になっていない場合に正常に動作します。通常のブラウザでアプリケーションを開いてテストします。

### リダイレクトあり
<a name="webrtc-testing-with"></a>

リダイレクトを有効にしてテストするには:

1. DCV プロトコルを使用して WorkSpace を作成し、WebRTC リダイレクトグループポリシー設定を有効にします。「[WorkSpaces Personal で Windows WorkSpaces を管理する](group_policy.md)」を参照してください。

1. [clients.amazonworkspaces.com](https://clients.amazonworkspaces.com) から WorkSpaces クライアントをダウンロードしてインストールし、WorkSpace に接続します。Chrome または Edge 拡張機能がインストールされていることを確認します (GPO が設定されている場合は自動）。

1. WorkSpace ブラウザでウェブアプリケーションを開きます。コンソールでWebRTC リダイレクトが有効」メッセージを確認します。ローカルデバイスでオーディオ機能を検証し、デバイスの列挙と切り替えをテストし、再接続処理を検証します。

## ベストプラクティス
<a name="webrtc-best-practices"></a>

WebRTC リダイレクトと統合する場合は、次の推奨事項に従ってください。
+ リダイレクトの可用性を常に確認する - プロキシが存在すると想定しない
+ WebRTC オブジェクトを作成する前に を`overrideWebRTC()`早期に呼び出す
+ 使用前にオーディオ要素をマッピングする - 設定`mapAudioElement()`前に を呼び出す `srcObject`
+ 再接続の処理 - 再接続後、すべてのプロキシオブジェクトが無効になります。常に新しい WebRTC オブジェクトを作成します。
+ 両方のモードをテストする - リダイレクトの有無にかかわらずアプリが正しく動作することを確認する
+ 標準の WebRTC APIs を使用する - プロキシはそれらを透過的にリダイレクトします。基本的な使用にカスタム APIs は必要ありません
+ リソースをクリーンアップする - イベントリスナーを削除し、完了したら接続を閉じます

## トラブルシューティング
<a name="webrtc-troubleshooting"></a>

### リダイレクトが検出されません
<a name="webrtc-troubleshooting-not-detected"></a>
+ ブラウザ拡張機能がインストールされ、有効になっていることを確認します ( をチェック`chrome://extensions`)
+ WorkSpace で WebRTC リダイレクトグループポリシーが有効になっていることを確認する
+ DCV プロトコルを使用して WorkSpace 内で実行されていることを確認します。
+ ブラウザコンソールで初期化メッセージを確認する
+ WorkSpaces クライアントバージョンが WebRTC リダイレクト (Windows 5.21.0 以降、macOS 5.31.0 以降、Linux 2026.0 以降、またはウェブクライアント) をサポートしていることを確認します。

### オーディオまたはビデオが機能しない
<a name="webrtc-troubleshooting-audio-video"></a>
+ WebRTC オブジェクトを作成する前に が呼び出`overrideWebRTC()`されたことを確認する
+ 設定`mapAudioElement()`する前にオーディオ要素が にマッピングされていることを確認する `srcObject`
+ ブラウザコンソールでエラーを確認する
+ デバイスアクセス許可が付与されていることを確認する

### 再接続の問題
<a name="webrtc-troubleshooting-reconnection"></a>
+ を実装`addStatusChangeEventListener()`して可用性の変化を検出する
+ 再接続後、常に新しい RTCPeerConnection オブジェクトと MediaStream オブジェクトを作成します。古いプロキシは無効でスローされます。
+ 使用不能が遅すぎたり、速すぎたりした場合にハートビート設定を確認する

## API リファレンス
<a name="webrtc-api-reference"></a>

プロキシ API の概要を次に示します。

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