リアルタイム通信インターフェースについて



リアルタイム通信インターフェースについて

Web Real-Time Communication(WebRTC)規格は、2つのピア間でビデオ、オーディオ、任意のデータのリアルタイム送信をサポートします。AmazonはWebRTCをサポートすることで、Alexaとスマートホームデバイスの間のオーディオ、ビデオ、(オプションで)任意のデータのリアルタイムストリーミングを実現しています。Alexaがリアルタイム通信(RTC)データチャネルを介してコマンドをデバイスに伝えると、デバイスがデータチャネルを介して応答し、状態を返します。オーディオとビデオを有効にするには、AlexaスキルにAlexa.RTCSessionControllerインターフェースを実装します。データチャネルのサポートを追加する場合、パン、チルト、ズームをサポートするカメラ用にAlexa.RangeControllerインターフェースも実装します。

デバイスとのリモート通信には、FireTVのほか、Echo Dot、Echo Plus、Echo Show、Echo SpotといったすべてのEchoデバイスを使用できます。ユーザーはAlexaアプリでカメラからのライブフィードを見ることもできます。

Alexa.RTCSessionControllerのシグナリング

以下は、Alexaとスマートホームスキルとの間のWebRTCシグナリングプロトコルのシーケンス図です。

InitiateSessionWithOffer、AnswerGenerated、SessionConnected、SessionDisconnectedを使って通信しているRTCSessionControllerのディレクティブとイベントの順序を表した図

セッション記述プロトコルのオファー/アンサー形式

RTCSessionControllerインターフェースは、セッション記述プロトコル(SDP)を使ってピア間のセッション機能をネゴシエートします。

オファー/アンサー交換の例

各メディアトラックには、Interactive Connectivity Establishment(ICE)候補一式があります。この例は、タイプがhostのICE候補を示しています。デバイスがパブリックゲートウェイ経由でルーティングされない場合、サーバーリフレクシブ候補(STUNを使用)またはリレー候補(TURNを使用)も含めます。

v=0
o=- 3747690900 3747690900 IN IP4 0.0.0.0
s=a 2 z
c=IN IP4 0.0.0.0
t=0 0
a=group:BUNDLE audio0 video0
m=audio 1 RTP/SAVPF 96 0
a=candidate:1 1 UDP 2013266430 xxx.xxx.xxx.xxx 8620 typ host
a=candidate:2 1 TCP 1010827775 xxx.xxx.xxx.xxx 45351 typ host tcptype passive
a=candidate:3 2 UDP 2013266429 xxx.xxx.xxx.xxx 50066 typ host
a=candidate:4 2 TCP 1010827774 xxx.xxx.xxx.xxx 65157 typ host tcptype passive
a=candidate:5 2 TCP 1015022078 xxx.xxx.xxx.xxx 9 typ host tcptype active
a=candidate:6 1 TCP 1015022079 xxx.xxx.xxx.xxx 9 typ host tcptype active
a=setup:actpass
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=rtpmap:96 opus/48000/2
a=rtcp:9 IN IP4 0.0.0.0
a=rtcp-mux
a=sendrecv
a=mid:audio0
a=ssrc:118039096 cname:user2571875795@host-433aaf59
a=ice-ufrag:AGVf
a=ice-pwd:h3JAYGhIaQ/Nvyaz9dLoz9
a=fingerprint:sha-256 34:D4:54:17:0C:95:2A:79:FF:72:10:21:E9:6E:F3:77:86:2F:8D:6C:33:45:BA:14:1D:43:01:D7:CD:0A:1A:84
m=video 1 RTP/SAVPF 99
a=candidate:4 1 UDP 2013266430 xxx.xxx.xxx.xxx 8620 typ host
a=candidate:5 1 TCP 1015022079 xxx.xxx.xxx.xxx 9 typ host tcptype active
a=candidate:4 2 UDP 2013266429 xxx.xxx.xxx.xxx 50066 typ host
a=candidate:6 1 TCP 1010827775 xxx.xxx.xxx.xxx 45351 typ host tcptype passive
a=candidate:5 2 TCP 1015022078 xxx.xxx.xxx.xxx 9 typ host tcptype active
a=candidate:6 2 TCP 1010827774 xxx.xxx.xxx.xxx 65157 typ host tcptype passive
b=AS:500
a=setup:actpass
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=rtpmap:99 H264/90000
a=rtcp:9 IN IP4 0.0.0.0
a=rtcp-mux
a=sendrecv
a=mid:video0
a=rtcp-fb:99 nack
a=rtcp-fb:99 nack pli
a=rtcp-fb:99 ccm fir
a=ssrc:3643559644 cname:user2571875795@host-433aaf59
a=ice-ufrag:AGVf
a=ice-pwd:h3JAYGhIaQ/Nvyaz9dLoz9
a=fingerprint:sha-256 34:D4:54:17:0C:95:2A:79:FF:72:10:21:E9:6E:F3:77:86:2F:8D:6C:33:45:BA:14:1D:43:01:D7:CD:0A:1A:84

サポートされる通信タイプ

RTCSessionControllerインターフェースは、単方向(半二重)と双方向(全二重)の通信に対応しています。玄関のインターホンに接続されたEcho Plusのようなオーディオ専用のシナリオの場合、通信は双方向であることが必要です。玄関のカメラに接続されたEcho Showのようなオーディオとビデオのシナリオの場合、Alexaはビデオ通信では単方向のみ、オーディオ通信では単方向と双方向に対応します。

  • 単方向(半二重)通信の場合、ユーザーは2方向で通信できますが、同時に通信することはできません。例:
    • トランシーバー
    • ボタンを押して話す(プッシュトゥトーク)インターホン
      デバイスがアコースティックエコーキャンセレーションに対応していない場合、半二重を選択します。
  • 双方向(全二重)通信の場合、ユーザーは2方向で同時に通信できます。例:
    • 電話
    • 電話形式のインターホン

サポートされる解像度

サポートされている解像度は480p~1080pです。

前提条件とサービスレベル要件

最適なユーザーエクスペリエンスには待機時間が短いことが非常に重要です。RTCSessionControllerを使用するには、以下の要件を満たす必要があります。

  • Alexaでは、デバイスが1分以上のライブストリーミングをサポートすることが必要です。

  • スキルがどのようなオファーを受信したとしても、6秒以内にSDPアンサーを返す必要があります。

  • デバイスまたはプラットフォームがWebRTCに準拠しているか、またはWebRTCによるプロトコル一式とWebRTCで使用されている次のすべての復元メカニズムに対応している必要があります。
    • Negative Acknowledgement(NACK
    • Picture Loss Indication(PLI
    • Full Intra Request(FIR
    • Receiver Estimated Maximum Bitrate(REMB
  • リソースに関する考慮事項として、bundlingrtcp-muxのサポートが必要です。バンドルを使用してオーディオとビデオを同じ接続で送信し、オープンソケットの数を減らしてください。

  • 全二重通信をサポートする場合は、デバイスにアコースティックエコーキャンセレーション(AEC)とノイズ抑制の効果的なアルゴリズムを導入する必要があります。

  • 半二重通信をサポートする場合は、標準的なライブビューシナリオでプッシュトゥトーク機能を使用できます。検出応答で、isFullDuplexAudioSupportedfalseと宣言してください。

  • ビデオをサポートするには、次のいずれかのビデオコーデックを使用する必要があります。
    • H264(ハイプロファイル、レベル4.1まで)
  • オーディオをサポートするには、次のいずれかのオーディオコーデックを使用する必要があります。
    • Opus(推奨コーデック)
    • PCMU/PCMAまたはG.711
    • AAC-LC、HE-AAC
  • ICE候補としてUDPまたはTCPを使用できますが、IPv4の使用が必須です。トリクルICEはサポートされていません。すべてのICE候補を事前に収集し、SDPアンサーで送信する必要があります。
  • ICE候補の数を最小限に絞り込むことで、デバイスが6秒以内に応答できるようにします。

パン、チルト、ズームをサポートするカメラ

Alexaユーザーがパン、チルト、ズームの機能を使えるようにするには、デバイスにRTCSessionControllerインターフェースとRangeControllerインターフェースを実装する必要があります。Alexaは、Alexa.RangeControllerディレクティブを使用してカメラに次の機能の実行をリクエストします。

  • パン – 水平面上でカメラを左右に回転します。
  • チルト – 垂直面上でカメラを上下に回転します。
  • ズーム – より詳細に見えるよう範囲を狭める(ズームイン)か、詳細は見えなくても範囲を広げる(ズームアウト)か、ビューを変更します。

カメラの範囲を指定する

カメラにはすべてを実装することも、パン、チルト、ズームの一部を実装することもできます。カメラがサポートするプロパティを指定するには、Alexa.RangeControllerinstanceフィールドをCamera.PanCamera.TiltCamera.Zoomに設定します。

instanceごとに、カメラがサポートする最小および最大の範囲を指定します。パンとチルトには、カメラの実視野(FOV)のパーセンテージとして範囲を指定します。たとえば、カメラが90度の水平FOVを持ち、合計360度回転できる場合、可動範囲は400%となります。範囲は、範囲全体にFOVが何回入るかを表します。合計サポート範囲は0~400や-200~200などのように定義できます。–200~200に設定すると、Alexaは真向いの方向にゼロを使用できます。ズームには、0~最大ズームの範囲をパーセンテージで指定します。

次の図は、ユーザーがAlexaに右にパンするようリクエストした前と後のカメラの実視野を表しています。この例では、カメラは90度のFOVを持ち、360度回転できます。

リクエストの後、カメラは90度右に回転します。

以下の例は、パンをサポートするカメラのAlexa.RangeControllerインターフェースです。これらのプロパティを検出応答で送信します。プロパティの詳細については、Alexa.RangeControllerを参照してください。

クリップボードにコピーされました。

{
    "type": "AlexaInterface",
    "interface": "Alexa.RangeController",
    "version": "3",
    "instance": "Camera.Pan",
    "capabilityResources": {
        "friendlyNames": [{
                "@type": "text",
                "value": {
                    "text": "カメラのパン",
                    "locale": "ja-JP"
                }
            },
            {
                "@type": "text",
                "value": {
                    "text": "カメラの回転",
                    "locale": "ja-JP"
                }
            },
            {
                "@type": "text",
                "value": {
                    "text": "回転",
                    "locale": "ja-JP"
                }
            }
        ]
    },
    "properties": {
        "supported": [{
            "name": "rangeValue"
        }],
        "retrievable": true,
        "proactivelyReported": true
    },
    "configuration": {
        "supportedRange": {
            "minimumValue": -200,
            "maximumValue": 200,
            "precision": 1
        },
        "presets": [{
                "rangeValue": -200,
                "presetResources": {
                    "friendlyNames": [{
                        "@type": "text",
                        "value": {
                            "text": "一番左",
                            "locale": "ja-JP"
                        }
                    }]
                }
            },
            {
                "rangeValue": 0,
                "presetResources": {
                    "friendlyNames": [{
                        "@type": "text",
                        "value": {
                            "text": "中央",
                            "locale": "ja-JP"
                        }
                    }]
                }
            },
            {
                "rangeValue": 200,
                "presetResources": {
                    "friendlyNames": [{
                        "@type": "text",
                        "value": {
                            "text": "一番右",
                            "locale": "ja-JP"
                        }
                    }]
                }
            }
        ]
    }
}

パン、チルト、ズームのディレクティブに応答する

パン、チルト、ズームをリクエストするには、AlexaはSetRangeValueAdjustRangeValueのいずれかのディレクティブをRTCデータチャネル経由でデバイスに送信します。モーションが完了するのを待たずにすぐに応答します。モーションが完了、部分的に完了、あるいは失敗した後、カメラの現在位置とともにAlexa.ChangeReportイベントを非同期に送信します。Alexa.ChangeReportイベントをRTCデータチャネルとAlexaゲートウェイの両方を経由してAlexaに送信します。

  • カメラがリクエストされたモーションを実行できる場合、最終的な位置とともにAlexa.Responseを返します。ここで、最終的な位置がリクエストされた位置になりました。
  • カメラがリクエストされたモーションを部分的に実行できる場合、最終的な位置とともにAlexa.Responseを返します。たとえば、リクエストにカメラ範囲外の範囲が含まれている場合、最終的な位置はカメラを動かせる限界の位置となります。
  • カメラがリクエストを実行できないとわかっている場合、Alexa.ErrorResponseを返します。
  • Alexaまたは任意の外部ソースからのリクエストに従って完全または部分的に位置を変更した場合、カメラの現在位置とともにAlexa.ChangeReportイベントを送信します。
  • Alexa.Responseの後にリクエストされたモーションが失敗した場合、カメラの現在位置とともにAlexa.ChangeReportイベントを送信します。

以下は、パンとチルトのリクエストと応答のペイロードの例です。

中央にパンするリクエスト

{
  "directive": {
    "header": {
      "namespace": "Alexa.RangeController",
      "instance": "Camera.Pan",
      "name": "SetRangeValue",
      "messageId": "<メッセージID>",
      "correlationToken": "<opaque相関トークン>",
      "payloadVersion": "3"
    },
    "endpoint": {
      "scope": {
        "type": "BearerToken",
        "token": "<OAuth2ベアラートークン>"
      },
      "endpointId": "<エンドポイントID>",
      "cookie": {}
    },
    "payload": {
      "rangeValue": 0
    }
  }
}

中央にパンした場合の応答

クリップボードにコピーされました。

{
  "event": {
    "header": {
      "namespace": "Alexa",
      "name": "Response",
      "messageId": "<メッセージID>",
      "correlationToken": "<opaque相関トークン>",
      "payloadVersion": "3"
    },
    "endpoint": {
      "scope": {
        "type": "BearerToken",
        "token": "<OAuth2ベアラートークン>"
      },
      "endpointId": "<エンドポイントID>"
    },
    "payload": {}
  },
  "context": {
    "properties": [
      {
        "namespace": "Alexa.RangeController",
        "instance": "Camera.Pan",
        "name": "rangeValue",
        "value": "0",
        "timeOfSample": "2017-02-03T16:20:50.52Z",
        "uncertaintyInMilliseconds": 0
      }
    ]
  }
}

下に20%チルトするリクエスト

{
  "directive": {
    "header": {
      "namespace": "Alexa.RangeController",
      "instance": "Camera.Tilt",
      "name": "AdjustRangeValue",
      "messageId": "<メッセージID>",
      "correlationToken": "<opaque相関トークン>",
      "payloadVersion": "3"
    },
    "endpoint": {
      "scope": {
        "type": "BearerToken",
        "token": "<OAuth2ベアラートークン>"
      },
      "endpointId": "<エンドポイントID>",
      "cookie": {}
    },
    "payload": {
      "rangeValueDelta": -20,
      "rangeValueDeltaDefault": false
    }
  }
}

チルトがサポートされていない場合の応答

クリップボードにコピーされました。


{
  "event": {
    "header": {
      "namespace": "Alexa",
      "name": "ErrorResponse",
      "messageId": "<メッセージID>",
      "payloadVersion": "3"
    },
    "endpoint":{
      "endpointId": "<エンドポイントID>"
    },
    "payload": {
      "type": "INVALID_VALUE",
      "message": "カメラはチルトをサポートしていません。"
    }
  }
}