🚀

libwebrtcのオーディオコーデック "L16"とは何か

2022/12/12に公開

先日の時雨堂さんのオンラインイベントで音声コーデックLyraを体験したときのことです。
「googCodecNameがL16という謎のaudioメディアがwebrtc-internals で見えます」
このL16というオーディオコーデックとは?

audio codec L16

https://datatracker.ietf.org/doc/rfc2586/

L16 denotes uncompressed audio data, using 16-bit signed representation in twos-complement notation and network byte order.

「L16は2の補数表現の符号付き16bitでネットワークバイトオーダーの非圧縮のオーディオデータを表します。」

現在世の中にあるオーディオデバイスの多くは2の補数表現の符号付き16bitを使いますがバイトオーダーは「リトルエンディアン」です。L16はネットワークで音声データをやりとりする仕様なので、ネットワークバイトオーダー(= ビッグエンディアン)と規定しているようですね。

L16はここには載っていないのでWebRTCの標準仕様ではなく、今のところはGoogleのlibwebrtcの独自実装と言えます。
https://developer.mozilla.org/en-US/docs/Web/Media/Formats/WebRTC_codecs
ちなみに video codec としてAV1も(まだ)載っていません。

ソースコードを検索

https://webrtc.googlesource.com/src/webrtc/+/f54860e9ef0b68e182a01edc994626d21961bc4b/api/audio_codecs/L16
AudioEncoderL16::MakeAudioEncoder()ではAudioEncoderPcm16Bのインスタンスを返しています。

https://webrtc.googlesource.com/src/+/c8fa692ec44fd6ba4fa3d085ac3161a262fc18c5/webrtc/modules/audio_coding/codecs/pcm16b

pcm16b.c
size_t WebRtcPcm16b_Encode(const int16_t* speech,
                           size_t len,
                           uint8_t* encoded) {
  size_t i;
  for (i = 0; i < len; ++i) {
    uint16_t s = speech[i];
    encoded[2 * i] = s >> 8;
    encoded[2 * i + 1] = s;
  }
  return 2 * len;
}
size_t WebRtcPcm16b_Decode(const uint8_t* encoded,
                           size_t len,
                           int16_t* speech) {
  size_t i;
  for (i = 0; i < len / 2; ++i)
    speech[i] = encoded[2 * i] << 8 | encoded[2 * i + 1];
  return len / 2;
}

確かに16bitのデータのエンディアンをひっくり返しているだけです。

L16の応用

L16は非圧縮の音声データを流すので、普通はデータ量が多くなりすぎてしまうので使うことはないのではないかと思ってしまいます。
ところがこれをWebRTC Encoded TransformのAPIを組み合わせて使うことで面白くなってきました。
https://www.w3.org/TR/webrtc-encoded-transform/

これを使うとエンコード済のメディアデータにjavascript(つまりwasmでも)で加工することができます。元々この切り口はE2EE(End-to-end encryption)のクライアントサイドでの暗号化/復号化のために用意されたものでした。
冒頭に書いたLyraの音声コーデックでの通信はこの仕組みを使っていました。
wasmにクロスコンパイルされたLyraのエンコーダ、デコーダをWebRTC Encoded Transformの切り口で使って実現していました。ブラウザとしてはL16のコーデックの音声データを「カスタム化した暗号化モジュール」を通して通信を行ったという扱いになります。

Lyraのエンコーダ、デコーダは元データとして符号付き16bitリトルエンディアンのフォーマット向けに提供されているわけですが、エンディアンの変換は上記のようなコードをもう一度実行するだけなので、そのような処理を追加することは簡単です。

この方法を使えば、なんでも独自のオーディオコーデックをはさみこめるという可能性が見えてきました。wasmで実装されたコーデックは通信の直前にどれを使うか選んでダウンロードすることが可能です。機械学習を応用した新しいコーデックは今後色々でてきそうです。楽しみですね。

これができる条件は以下の3つです。

  • オーディオコーデックとしてL16をサポートしている
  • WebRTC Encoded Transformをサポートしている
  • wasmでスレッドなど新しい仕様をサポートしている

現状これを満たしているブラウザはChromeだけだそうです。Safari, Firefoxもぜひ取り入れて欲しいものです。

関連

https://zenn.dev/tetsu_koba/articles/01bab6642c23d0
https://zenn.dev/tetsu_koba/articles/3bd92ec53face9

Discussion