Skip to content
shiguredoPublic

About

Sans-I/O Rust library for Media over QUIC Transport (MOQT)

Topics

Resources

Stars

6 stars

Watchers

0 watching

Forks

Repository files navigation

moqt-rs

shiguredo_moqt Documentation License Discord

Note

ブラウザ上で動作する MOQT 実装は shiguredo/moqt-js で公開しています。

Warning

このライブラリは開発中であり、仕様が積極的に変更される場合があります。

About Shiguredo's open source software

We will not respond to PRs or issues that have not been discussed on Discord. Also, Discord is only available in Japanese.

Please read https://github.com/shiguredo/oss before use.

時雨堂のオープンソースソフトウェアについて

利用前に https://github.com/shiguredo/oss をお読みください。

概要

Rust で実装した Sans I/O かつ no_std 対応の Media over QUIC Transport (MOQT) ライブラリです。 MOQT / LOC / MSF / C4M の codec と、1 本の Transport Session に閉じたセッション状態機械を提供します。

特徴

  • Sans I/O
  • no_std 対応
  • 依存は hashbrown / noflate / nojson / base64ct の 4 つのみ (暗号処理は optional feature aws-lc-rs)
  • 1 本の Transport Session に閉じた endpoint-local な Session 状態機械
    • I/O、非同期処理、relay が担う namespace 発見・告知と forwarding は含まない
  • バッファ付きインクリメンタルデコーダー (MessageDecoder / SubgroupStreamDecoder / FetchStreamDecoder)
  • FETCH 応答のデルタ圧縮エンコーダー (FetchStreamEncoder)
  • 対応仕様
    • Media over QUIC Transport (MOQT) draft-22
    • Low Overhead Container (LOC) draft-04
    • MOQT Streaming Format (MSF) draft-01
    • Authorization scheme for MOQT using Common Access Tokens (C4M) draft-01

使い方

制御メッセージの encode / decode

ControlMessage は Type (varint) | Length (u16 big-endian) | Message Body 形式で encode / decode します。

use shiguredo_moqt::error::MessageError;
use shiguredo_moqt::{message::{ControlMessage, Setup}, parameter::SetupOptions};

fn main() -> Result<(), MessageError> {
    // SETUP メッセージを作成してエンコード
    let msg = ControlMessage::Setup(Setup {
        options: SetupOptions::new(),
    });
    let bytes = msg.encode()?;
    // bytes を制御ストリームに書き出す...

    // 受信バイト列からデコード
    let (decoded, consumed) = ControlMessage::decode(&bytes)?;
    let _ = (decoded, consumed);
    Ok(())
}

インクリメンタルデコード

QUIC / WebTransport のフレーム境界とメッセージ境界は一致しないため、受信バッファに蓄積しながらデコードします。

use shiguredo_moqt::decoder::MessageDecoder;
use shiguredo_moqt::error::MessageError;

fn main() -> Result<(), MessageError> {
    let mut decoder = MessageDecoder::new();
    // 受信データを追記する
    // decoder.push(&data);
    if let Some(msg) = decoder.try_decode_message()? {
        // msg を Session::recv_control 等に渡す
        let _ = msg;
    }
    Ok(())
}

Data stream も同じ push + try_decode パターンです。

  • SubgroupStreamDecoder:try_decode_header() でヘッダー、try_decode_object() でオブジェクトを順次デコードし、ペイロードは try_read_payload() / consume_payload() で進める
  • FetchStreamDecoder:FETCH 応答のデコード
  • FetchStreamEncoder:FETCH 応答のデルタ圧縮エンコード

セッション (SETUP 確立とイベント駆動)

Session は I/O を持たない純粋な状態機械です。 new_client / new_server で生成し、poll_event() で取り出した SessionEvent::SendControl 等を I/O 層に渡して送信します。

use shiguredo_moqt::parameter::SetupOptions;
use shiguredo_moqt::session::core::Session;
use shiguredo_moqt::session::types::{SessionError, SessionEvent, Transport};

fn main() -> Result<(), SessionError> {
    let mut session = Session::new_client(Transport::Quic, SetupOptions::new())?;
    while let Some(event) = session.poll_event() {
        match event {
            SessionEvent::SendControl(msg) => {
                // 制御ストリームに msg.encode() を書き出す
                let _ = msg;
            }
            SessionEvent::Established => {
                // 両側の SETUP が完了
            }
            SessionEvent::CloseSession(e) => {
                // QUIC CONNECTION_CLOSE 等で接続を閉じる
                let _ = e;
            }
            _ => {}
        }
    }
    Ok(())
}

受信側:

  • bidi request stream の先頭メッセージ:recv_request()
  • bidi request stream の応答:recv_stream_message(request_id, msg)
  • uni data stream:recv_data_stream_type() / recv_subgroup_header() / recv_subgroup_object() / recv_fetch_header()
    • recv_subgroup_header() / recv_subgroup_object() は TrackDataAcceptance を返す。recv_subgroup_object() は受信 Object ごとに購読フィルタを再適用し、フィルタ不通過は FilteredOut、キャンセル済み subscription への不要 Object は Discarded になる
  • datagram:recv_object_datagram()

送信側:

  • send_subscribe() / send_publish() / send_fetch() 等
  • tick(now_ms) で GOAWAY drain や delivery timeout の期限を進める

カタログとタイムライン (MSF)

use shiguredo_moqt::error::MessageError;
use shiguredo_moqt::msf::MsfCatalogDocument;

fn main() -> Result<(), MessageError> {
    // Full / Delta を自動判別してデコード
    let bytes = Vec::new();
    let doc = MsfCatalogDocument::decode(&bytes)?;
    let encoded = doc.encode()?;
    let _ = encoded;
    Ok(())
}

Media / Event Timeline は msf::{encode_media_timeline / decode_media_timeline / encode_event_timeline / decode_event_timeline} で JSON と相互変換します。 TimelineEncodingOptions { gzip: true } で gzip 圧縮し、デコード時は gzip magic (0x1F 0x8B) を検出して自動展開します。

実装状況

対応仕様ごとの実装状況です。

モジュール構成とアーキテクチャは docs/moqt.md を参照してください。

サンプル

サンプルは Tokio、s2n-quic、shiguredo_http3、shiguredo_http2 を利用しています。 引数のパースには noargs、ログには tracing を利用しています。

  • moq-pub:QUIC / WebTransport over HTTP/3 / WebTransport over HTTP/2 で relay に接続し、video / audio / catalog track を PUBLISH する
  • moq-sub:QUIC / WebTransport over HTTP/3 / WebTransport over HTTP/2 で relay に接続し、catalog を SUBSCRIBE して取得し、video / audio を SUBSCRIBE して再生する
  • tokio-moq:publisher / subscriber が共有する QUIC / WebTransport over HTTP/3 / WebTransport over HTTP/2 トランスポート層 (ライブラリ)

前提条件は Rust 1.95 以降です。 サンプルが使う s2n-quic が 1.95 を要求するためです。 shiguredo_moqt ライブラリと pbt だけであれば 1.93 で構築できます。

# publisher (疑似キャプチャ)
cargo run -p moq-pub -- --url moqt://127.0.0.1:4443 --namespace moq-example --fake-capture-device

# subscriber
cargo run -p moq-sub -- --url moqt://127.0.0.1:4443 --namespace moq-example

接続経路は --url の scheme ではなく --transport (quic / wt-h3 / wt-h2) で選びます。既定は quic です。

wt-h3 / wt-h2 (WebTransport) は experimental です。s2n-quic が RESET_STREAM_AT を送出できず、WebTransport が MUST とする Reliable Size 付きのデータストリーム reset を行えないためです (詳細は examples/README.md を参照してください)。

URL の MSF fragment (#msf:<track-identifier>&c4m=<base64 token>) で C4M 認可トークンを SETUP と各制御メッセージ (PUBLISH / SUBSCRIBE / REQUEST_UPDATE) の AUTHORIZATION_TOKEN として送信できます。 --namespace を省略した場合は MSF fragment の track-identifier が示す namespace を Track Namespace として使います (--namespace と MSF fragment のどちらも無い場合はエラーになります)。

接続先となる MOQT relay は別途用意してください。 詳細なオプションは examples/README.md と各クレートの --help を参照してください。

Agent Skills

Agent Skills 形式のスキルを同梱しています。 gh skill install コマンドで対応する AI エージェント (Claude Code, Cursor, GitHub Copilot, Gemini CLI 等) にインストールできます。 エージェントはこのライブラリの API や準拠仕様を理解した上で支援できます。

gh skill install shiguredo/moqt-rs shiguredo-moqt

スキルの内容は skills/shiguredo-moqt/SKILL.md を参照してください。

規格書

このライブラリが準拠している主な IETF draft です。

ビルドとテスト

# 全テスト実行
make test

# PBT のみ実行
make pbt

# カバレッジ付きで全テスト実行
make cover

# Fuzzing を全ターゲットで 30 秒ずつ実行
make fuzzing

# clippy
make clippy

# フォーマット
make fmt

# ビルド確認
make check

ライセンス

Apache License 2.0

Copyright 2026 Shiguredo Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

About

Sans-I/O Rust library for Media over QUIC Transport (MOQT)

Topics

Resources

Stars

6 stars

Watchers

0 watching

Forks

Used by

Contributors

Languages