Cisco Webex Devices の SIP INVITE  SDP を Cisco Unified CM Lua Script を利用して変換してみた

[Cisco Systems Japan Advent Calendar 2018](https://qiita.com/advent-calendar/2018/cisco)
をみながら、私のフィールドのビデオ会議関連に何か役立てないかなと徒然書く企画の2回目です。


@kazkaz_o3  さんが投稿した  [SIP のレスポンスを Lua Script を利用して変換してみた](https://qiita.com/radiantmarch/items/936b43f32210e4689179) はまさに私のフィールドで、参考になります。 Cisco Unified Communications Manager の Lua Script により、SIP のヘッダを書き換えシーケンス中のレスポンスをサービスプロバイダ仕様に合わせた形で変更することができます。
この Lua Script はサービスプロバイダだけではなく、ビデオ会議にも応用がききます。ビデオ会議の相互接続性を解決するという観点でも利用が可能です。
こういった処理を気軽に行えるのが H.323 と比較して SIP の大きなメリットとなります。

# 解決したい課題: メディアの非互換

SIP は相互接続性に優れたプロトコルですが、ビデオのメディアそのものの相互接続性は、コーデックの相性に左右されるなどして解決できないケースがあります。例えば、 [Cisco CollaborationEndpoint Software 9 Release Notes](https://www.cisco.com/c/dam/en/us/td/docs/telepresence/endpoint/software/ce9/release-notes/ce-software-release-notes-ce9.pdf) を見ると、 H.265 の相互接続性が他社性端末と取れないという記述があります。

<img width="796" alt="スクリーンショット 2018-12-30 1.31.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/216119/fe18f65f-55aa-fb48-7f46-0ede0b605229.png">


解決策として、端末の H.265 の能力をオフにするという記載がありますが、これでは、シスコ端末同士の H.265 の接続性も失われてしまいます。

# SIP Normalization 適用前のシーケンス

Cisco Webex Devices > Cisco Unified CM > (SIP Trunk) > 他社端末 という構成を想定します。ほかの相互接続性の考慮点として、SIP のINVITE にSDPを記載する Early Offer に変更しています。Cisco Unified CM は SDP をつけない Delayed Offer が標準設定になっています。

<img width="657" alt="スクリーンショット 2018-12-30 0.37.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/216119/e2ec1b73-0f2d-67c9-4d64-6348100ba7f8.png">

```
Early Offer support for voice and video calls : Best Effort (no MTP inserted)
```

H.265 の能力を持つ端末からの発信時の Cisco Unified CM > 他社端末間の INVITE 例となります。

```
00113686.001 |10:19:44.067 |AppInfo  |SIPTcp - wait_SdlSPISignal: Outgoing SIP TCP message to 10.65.74.38 on port 5060 index 1383 
[21690,NET]
INVITE sip:3000@10.65.74.38:5060 SIP/2.0
Via: SIP/2.0/TCP 198.18.133.3:5060;branch=z9hG4bK232762e22ece
From: <sip:1134@198.18.133.3>;tag=10983~0a37f347-c14b-44f5-8299-186aa2addafc-27036136
To: <sip:3000@10.65.74.38>
Date: Sat, 29 Dec 2018 16:19:43 GMT
Call-ID: 8b71bf00-c2719e9f-2320-38512c6@198.18.133.3
Supported: timer,resource-priority,replaces
Min-SE:  1800
User-Agent: Cisco-CUCM12.0
Allow: INVITE, OPTIONS, INFO, BYE, CANCEL, ACK, PRACK, UPDATE, REFER, SUBSCRIBE, NOTIFY
CSeq: 101 INVITE
Expires: 180
Allow-Events: presence
Supported: X-cisco-srtp-fallback,X-cisco-original-called
Call-Info: <urn:x-cisco-remotecc:callinfo>;x-cisco-video-traffic-class=IMMERSIVE
Session-ID: 41e8b996f6f255fc8af6a398f287a2b8;remote=00000000000000000000000000000000
Cisco-Guid: 2339487488-0000065536-0000000019-0059052742
Session-Expires:  1800
P-Asserted-Identity: <sip:1134@198.18.133.3>
Remote-Party-ID: <sip:1134@198.18.133.3>;party=calling;screen=yes;privacy=off
Contact: <sip:1134@198.18.133.3:5060;transport=tcp>;video;audio;sip.cisco.multistream;+multiple-codecs-in-ans
Max-Forwards: 69
Content-Type: application/sdp
Content-Length: 2088

v=0
o=CiscoSystemsCCM-SIP 10983 1 IN IP4 198.18.133.3
s=SIP Call
c=IN IP4 10.65.74.36
b=TIAS:5952000
b=AS:5952
t=0 0
a=cisco-mari-rate
a=cisco-mari:v1
m=audio 18654 RTP/AVP 108 114 9 0 8 18 105 104 123 101
b=TIAS:64000
a=extmap:14 http://protocols.cisco.com/timestamp#100us
a=rtpmap:108 MP4A-LATM/90000
a=fmtp:108 bitrate=64000;profile-level-id=24;object=23
a=rtpmap:114 opus/48000/2
a=fmtp:114  maxaveragebitrate=128000;stereo=1
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:105 G7221/16000
a=fmtp:105 bitrate=24000
a=rtpmap:104 G7221/16000
a=fmtp:104 bitrate=32000
a=rtpmap:123 X-ULPFECUC/8000
a=fmtp:123  multi_ssrc=1;feedback=0;max_esel=1450;m=8;max_n=64;FEC_ORDER=FEC_SRTP;non_seq=1
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=no
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=trafficclass:conversational.audio.immersive.aq:admitted
m=video 20522 RTP/AVP 99 97 100 126 123
b=TIAS:5952000
a=label:11
a=answer:full
a=extmap:14 http://protocols.cisco.com/timestamp#100us
a=rtcp-fb:* ccm pan
a=cisco-mari-psre:97 ltrf=3
a=cisco-mari-psre:100 ltrf=3
a=cisco-mari-psre:126 ltrf=3
a=rtpmap:99 H265/90000
a=fmtp:99  level-id=90;max-lsr=125337600;max-lps=2088960;max-tr=22;max-tc=20;max-fps=6000;x-cisco-hevc=529
a=rtpmap:97 H264/90000
a=fmtp:97 profile-level-id=428016;packetization-mode=0;max-mbps=490000;max-fs=8160;max-cpb=200;max-br=5000;max-smbps=490000;max-fps=6000
a=rtpmap:100 H264/90000
a=fmtp:100 profile-level-id=640C16;packetization-mode=1;max-mbps=490000;max-fs=8160;max-cpb=200;max-br=5000;max-smbps=490000;max-fps=6000
a=rtpmap:126 H264/90000
a=fmtp:126 profile-level-id=428016;packetization-mode=1;max-mbps=490000;max-fs=8160;max-cpb=200;max-br=5000;max-smbps=490000;max-fps=6000
a=rtpmap:123 X-ULPFECUC/90000
a=fmtp:123  multi_ssrc=1;feedback=0;max_esel=1450;m=8;max_n=64;FEC_ORDER=FEC_SRTP;non_seq=1
a=content:main
a=rtcp-fb:* nack pli
a=rtcp-fb:* ccm fir
a=rtcp-fb:* ccm tmmbr
a=trafficclass:conversational.video.immersive.aq:admitted
m=application 25082 RTP/AVP 102
a=rtpmap:102 H224/4800

```

ビデオ会議端末は様々な操作も SDP で表現するため、多くの情報が載っています。 H.265 に関係するところは下記の2行です。この2行を削除するスクリプトを検討します。

```
a=rtpmap:99 H265/90000
a=fmtp:99 level-id=90;max-lsr=125337600;max-lps=2088960;max-tr=22;max-tc=20;max-fps=6000;x-cisco-hevc=529
```


# スクリプトの実装

[Developer Guide for SIP Transparency and Normalization](https://www.cisco.com/c/en/us/td/docs/voice_ip_comm/cucm/sip_tn/9_1_1/sip_t_n/4-sdp_api.html#wp1063905)の SDP の項目を眺めていると、 **removeLine** という命令があることがわかります。今回はそのサンプルを利用して作成しました。

```
M = {}
function M.outbound_INVITE(msg)
    local sdp = msg:getSdp()
    if sdp
    then
        sdp = sdp:removeLine("a=rtpmap:", "H265")
        sdp = sdp:removeLine("a=fmtp", "x-cisco-hevc")
        msg:setSdp(sdp)
    end
end
return M
```

<img width="670" alt="スクリーンショット 2018-12-30 1.43.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/216119/8236ef6c-b247-137a-558f-694ecd339fdd.png">

該当する SIP Trunk へ適用

<img width="797" alt="スクリーンショット 2018-12-30 1.45.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/216119/e14294ce-339f-676a-6cbd-1cbff8c4e7d1.png">



スクリプト適用後の SIP INVITE になります。 H.265 関連の2行が消えました。

```
00110621.001 |10:13:08.920 |AppInfo  |SIPTcp - wait_SdlSPISignal: Outgoing SIP TCP message to 10.65.74.38 on port 5060 index 1339 
[21163,NET]
INVITE sip:3000@10.65.74.38:5060 SIP/2.0
Via: SIP/2.0/TCP 198.18.133.3:5060;branch=z9hG4bK22a9424d4fd1
From: <sip:1134@198.18.133.3>;tag=10791~0a37f347-c14b-44f5-8299-186aa2addafc-27036134
To: <sip:3000@10.65.74.38>
Date: Sat, 29 Dec 2018 16:13:08 GMT
Call-ID: a0018780-c2719d14-22a4-38512c6@198.18.133.3
Supported: timer,resource-priority,replaces
Min-SE:  1800
User-Agent: Cisco-CUCM12.0
Allow: INVITE, OPTIONS, INFO, BYE, CANCEL, ACK, PRACK, UPDATE, REFER, SUBSCRIBE, NOTIFY
CSeq: 101 INVITE
Expires: 180
Allow-Events: presence
Supported: X-cisco-srtp-fallback,X-cisco-original-called
Call-Info: <urn:x-cisco-remotecc:callinfo>;x-cisco-video-traffic-class=IMMERSIVE
Session-ID: 245e4ac67e415a928bfd4764cf65abfe;remote=00000000000000000000000000000000
Cisco-Guid: 2684454784-0000065536-0000000018-0059052742
Session-Expires:  1800
P-Asserted-Identity: <sip:1134@198.18.133.3>
Remote-Party-ID: <sip:1134@198.18.133.3>;party=calling;screen=yes;privacy=off
Contact: <sip:1134@198.18.133.3:5060;transport=tcp>;video;audio;sip.cisco.multistream;+multiple-codecs-in-ans
Max-Forwards: 69
Content-Length: 1956
Content-Type: application/sdp

v=0
o=CiscoSystemsCCM-SIP 10791 1 IN IP4 198.18.133.3
s=SIP Call
c=IN IP4 10.65.74.36
b=TIAS:5952000
b=AS:5952
t=0 0
a=cisco-mari-rate
a=cisco-mari:v1
m=audio 18806 RTP/AVP 108 114 9 0 8 18 105 104 123 101
b=TIAS:64000
a=extmap:14 http://protocols.cisco.com/timestamp#100us
a=rtpmap:108 MP4A-LATM/90000
a=fmtp:108 bitrate=64000;profile-level-id=24;object=23
a=rtpmap:114 opus/48000/2
a=fmtp:114  maxaveragebitrate=128000;stereo=1
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:105 G7221/16000
a=fmtp:105 bitrate=24000
a=rtpmap:104 G7221/16000
a=fmtp:104 bitrate=32000
a=rtpmap:123 X-ULPFECUC/8000
a=fmtp:123  multi_ssrc=1;feedback=0;max_esel=1450;m=8;max_n=64;FEC_ORDER=FEC_SRTP;non_seq=1
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=no
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=trafficclass:conversational.audio.immersive.aq:admitted
m=video 21396 RTP/AVP 99 97 100 126 123
b=TIAS:5952000
a=label:11
a=answer:full
a=extmap:14 http://protocols.cisco.com/timestamp#100us
a=rtcp-fb:* ccm pan
a=cisco-mari-psre:97 ltrf=3
a=cisco-mari-psre:100 ltrf=3
a=cisco-mari-psre:126 ltrf=3
a=rtpmap:97 H264/90000
a=fmtp:97 profile-level-id=428016;packetization-mode=0;max-mbps=490000;max-fs=8160;max-cpb=200;max-br=5000;max-smbps=490000;max-fps=6000
a=rtpmap:100 H264/90000
a=fmtp:100 profile-level-id=640C16;packetization-mode=1;max-mbps=490000;max-fs=8160;max-cpb=200;max-br=5000;max-smbps=490000;max-fps=6000
a=rtpmap:126 H264/90000
a=fmtp:126 profile-level-id=428016;packetization-mode=1;max-mbps=490000;max-fs=8160;max-cpb=200;max-br=5000;max-smbps=490000;max-fps=6000
a=rtpmap:123 X-ULPFECUC/90000
a=fmtp:123  multi_ssrc=1;feedback=0;max_esel=1450;m=8;max_n=64;FEC_ORDER=FEC_SRTP;non_seq=1
a=content:main
a=rtcp-fb:* nack pli
a=rtcp-fb:* ccm fir
a=rtcp-fb:* ccm tmmbr
a=trafficclass:conversational.video.immersive.aq:admitted
m=application 26360 RTP/AVP 102
a=rtpmap:102 H224/4800
```

H.265 の能力を持つ他社製端末の手持ちがなかったため、シスコ製品同士で接続し、H.265 ではなく H.264 で接続されることを確認しました。今回、 SIP Trunk の宛先全てに適用していますが、スクリプトを駆使することで、宛先別に変換することも可能です。


# 謝辞

@kazkaz_o3  さん、[昨年のシスコルータでSIPでVPNを張ってみた](https://qiita.com/kazkaz_o3/items/2a0a5f8b4cbad0d04026) に引き続き　[SIP ネタの投稿](https://qiita.com/kazkaz_o3/items/9935eb3b4d436453a39e)ありがとうございました。