0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Microsoft Foundry】Voice Live APIでAvatarとリアルタイム会話を実現する - WebRTC接続の仕組みを詳解

Last updated at Posted at 2026-01-18

はじめに

本記事は、以前の記事で紹介したAzure AI Foundry Voice Live APIの続編です。前回はAI Agent Modeでの音声会話の基本実装を解説しましたが、今回はAvatar機能を追加し、フォトリアリスティックなアバターとリアルタイムで会話できる仕組みを紹介します。

特に、Voice Live API固有のWebRTC接続フローに焦点を当て、どのようにしてAvatarの映像・音声ストリームを確立するかを詳しく解説します。

Microsoft Ignite 2025での発表

Microsoft Ignite 2025では、AIエージェントと音声技術に関する重要なセッションが公開されています。

セッション 内容
BRK197: AI powered automation & multi-agent orchestration in Microsoft Foundry Microsoft Foundry Agent Framework(Semantic Kernel + AutoGen)を使ったマルチエージェントシステムの構築
BRK198: Let your agentic apps talk with Azure Speech Voice Live API(GA)の紹介とLLMを活用した新しい音声API

これらのセッションでは、Voice Live APIが正式リリース(GA)となり、エージェントアプリケーションに音声インターフェースを追加するための包括的なソリューションとして位置づけられています。

サンプルコード

本記事で解説するサンプルコードは以下のリポジトリで公開しています。このサンプルでは主に以下の機能を提供しています。

  • WebSocket通信によるVoice Live APIのライブラリ
  • WebRTC通信によるアバターのリアルタイム会話
  • FFmpeg,FFplayを使ったコンソールアプリでのサンプル(AIモデル/AIエージェント)


Microsoft Foundryとは

Microsoft Foundry(旧Azure AI Studio/Azure AI Foundry)は、AIアプリケーションの開発・デプロイ・運用を統合的に行うためのプラットフォームです。

主な特徴

  • 統合されたAI開発環境: Azure OpenAI、Azure AI Services、カスタムモデルを一元管理
  • Agent Service: AIエージェントの構築・ホスティング・管理
  • Voice Live API: リアルタイム音声会話機能(本記事のテーマ)
  • 責任あるAI: コンテンツフィルタリング、セーフティ機能の組み込み

Voice Live APIは、音声認識・生成AI・音声合成を単一のAPIで統合し、低遅延でのリアルタイム音声会話を実現します。


Voice Live APIとAvatar統合の概要

Voice Live APIの特徴

Voice Live APIは以下の機能を提供します:

機能 説明
音声入力 Azure Speech to Textによる高精度な音声認識(140以上のロケール対応)
生成AI GPT-4o、GPT-5、Phi等のモデルによる応答生成
音声出力 Azure Text to Speechによる自然な音声合成(600以上の音声)
会話機能拡張 ノイズ抑制、エコーキャンセル、割り込み検出、発話終了検出
Avatar統合 フォトリアリスティックなアバターによる映像出力

Avatar機能とは

Text to Speech Avatarは、テキストをフォトリアリスティックな人間の映像に変換する機能です。Voice Live APIでは、この機能を統合することで、音声と同期したアバター映像をリアルタイムでストリーミングできます。

標準AvatarとカスタムAvatar

種類 説明
標準Avatar Microsoftが提供するプリセットキャラクター(lisa、harry等)
カスタムAvatar 独自の映像・写真から作成したオリジナルアバター

アーキテクチャと通信フロー

Voice Live APIでAvatar機能を使用する場合、通常のWebSocket通信に加えてWebRTC接続が必要になります。このセクションでは、接続確立までの詳細なフローを解説します。

3者間通信フロー(概要)

Voice Live APIでAvatar機能を使用する場合、WebSocketWebRTCの2種類の通信プロトコルが必要になります。

2つの通信プロトコル

プロトコル 役割 通信相手
WebSocket 制御チャネル(セッション管理、シグナリング) Foundryサーバ
WebRTC メディアチャネル(映像・音声ストリーム) Avatarサーバ

Avatar使用時の音声配信経路の違い

Avatar機能を使用する場合、エージェントからの音声はWebRTC経由で配信されます。これはAvatar非使用時とは異なる動作です。

モード 音声の配信経路
Avatar非使用 WebSocket経由(response.audio.deltaメッセージ)
Avatar使用 WebRTC経由(Opusオーディオストリーム)

Avatar非使用時の音声処理については前回の記事で解説しています。

シグナリングサーバとしてのFoundry: 一般的なWebRTCアプリケーションでは別途シグナリングサーバを用意する必要がありますが、Voice Live APIではFoundryサーバがシグナリングサーバの役割を担います。WebSocket経由でICEサーバー情報の取得やSDP交換を行い、その後WebRTCでAvatarサーバと直接通信します。

WebRTC接続フロー(詳細)

上記の3者間通信を、クライアント側の実装観点からより詳細に見ていきます。

Voice Live API を使ったサンプルコード解説

実際にMicrosoft FoundryのVoice Live APIを使い方について紹介したいと思います。
Voice Live APIを使うサンプルは以下のサイトに公開しています。アバターを使わない方法については以前紹介した手順になります。

最近、C#用のSDKもあります。当時はC#用ライブラリが提供されていなかっため、今回のサンプルAPI経由で実装しています。

全体アーキテクチャ

今回作成したVoice Live APIのAvatarを使うサンプルの全体的なアークテクチャです。先ほど説明した通り、最初はFoundryのサービスに足してWebSocket通信で接続します。Avatarを利用する設定を送信すると応答にICEサーバに関する情報が含まれているので、この情報を元にWebRTCのペアリングの手続きを行い、WebRTCの接続を開始することでアバターによる音声会話が可能になります。

各ステップの詳細

1. session.updateでのAvatar使用宣言

Avatar機能を使用するには、session.updateメッセージにavatar設定を含めます。

{
  "type": "session.update",
  "session": {
    "modalities": ["text", "audio"],
    "voice": {
      "name": "ja-JP-NanamiNeural",
      "type": "azure-standard"
    },
    "avatar": {
      "character": "lisa",
      "style": "casual-sitting",
      "customized": false,
      "video": {
        "bitrate": 2000000,
        "codec": "h264",
        "resolution": {
          "width": 1920,
          "height": 1080
        },
        "background": {
          "color": "#00FF00FF"
        }
      }
    }
  }
}

2. session.updatedでのICEサーバー情報取得

サーバーからの応答には、WebRTC接続に必要なICEサーバー情報が含まれます。

{
  "type": "session.updated",
  "session": {
    "avatar": {
      "ice_servers": [
        {
          "urls": ["turn:xxx.turn.azure.com:443?transport=tcp"],
          "username": "...",
          "credential": "..."
        }
      ]
    }
  }
}

重要: ICEサーバー情報はサーバーから提供されるものを使用します。これが一般的なWebRTCアプリケーションとの大きな違いです。

3. ICE候補の収集とSDPオファー作成

受け取ったICEサーバー情報を使用してRTCPeerConnectionを作成し、SDPオファーを生成します。

4. session.avatar.connectでSDPオファー送信

生成したSDPオファーをBase64エンコードして送信します。

{
  "type": "session.avatar.connect",
  "client_sdp": "eyJ0eXBlIjogIm9mZmVyIiwic2RwIjogInY9MC4uLiJ9..."
}

5. session.avatar.connectingでSDPアンサー受信

サーバーからSDPアンサーを受信し、WebRTC接続を確立します。情報はBase64デコードする必要があります。
アンサーをWebRTCクライアントに設定しサーバとの接続を行うことでアバターの映像と音声がリアルタイムで配信されます。

{
  "type": "session.avatar.connecting",
  "server_sdp": "eyJ0eXBlIjogImFuc3dlciIsInNkcCI6ICJ2PTAuLi4ifQ..."
}

開発環境とセットアップ

必要なAzureリソース

リソース 説明
Microsoft Foundry リソース Voice Live APIのエンドポイント
AI Agent(オプション) AI Agent Modeで使用する場合

認証について: Avatar ModeおよびAI Agent ModeではAPI Key認証は使用できません。Entra ID認証(DefaultAzureCredential) が必要です。

必要なNuGetパッケージ

<PackageReference Include="Azure.Identity" Version="1.14.2" />
<PackageReference Include="SIPSorcery" Version="8.0.23" />
<PackageReference Include="SIPSorceryMedia.Abstractions" Version="8.0.12" />
<PackageReference Include="Concentus" Version="2.2.2" />
<PackageReference Include="FFMpegCore" Version="5.1.0" />
<PackageReference Include="NAudio" Version="2.2.1" />
パッケージ 用途
Azure.Identity Entra ID認証
SIPSorcery WebRTC実装
SIPSorceryMedia.Abstractions メディアフォーマット抽象化
Concentus Opusオーディオコーデック
FFMpegCore H.264映像処理
NAudio オーディオ入出力

WebRTCライブラリ - SIPSorcery

本サンプルでは、.NET向けWebRTCライブラリとしてSIPSorceryを使用しています。

SIPSorceryは、.NETで実装されたオープンソースのSIP/VoIP/WebRTCライブラリです。ブラウザ外でWebRTC通信を行う.NETアプリケーション(コンソールアプリ、デスクトップアプリ、サーバーサイド等)において、WebRTC接続の確立やメディアストリームの処理を実現できます。

特徴 説明
Pure .NET実装 ネイティブ依存なしで動作
WebRTC対応 ICE、DTLS、SRTP、SDP等のプロトコルをサポート
柔軟なメディア処理 コーデック処理を外部ライブラリと組み合わせ可能

ブラウザではWebRTC APIが標準で提供されていますが、.NETコンソールアプリケーションやサーバーサイドアプリケーションからWebRTC通信を行う場合は、SIPSorceryのようなライブラリが必要になります。

外部依存(Avatar Mode)

  • FFmpeg: H.264映像処理に必要
  • FFplay: 映像再生に必要
# FFmpegのインストール確認
ffmpeg -version
ffplay -version

実装解説 - セッション設定とAvatar構成

VoiceLiveSessionOptionsクラス

セッション設定を管理するクラスです。Avatar設定もここに含まれます。

// ファイル: src/VoiceLiveAPI.Core/VoiceLiveSessionOptions.cs

public class VoiceLiveSessionOptions : IClientSessionUpdate
{
    [JsonPropertyName("modalities")]
    public string[] Modalities { get; set; } = { "audio", "text" };

    [JsonPropertyName("voice")]
    public Voice Voice { get; set; }

    [JsonPropertyName("avatar")]
    public Avatar Avatar { get; set; }

    [JsonPropertyName("turn_detection")]
    public TurnDetection TurnDetection { get; set; }

    // ... その他のプロパティ
}

Avatarクラス

Avatar設定を表現するクラスです。

// ファイル: src/VoiceLiveAPI.Core/Commons/Messages/Parts/Avatar.cs

public class Avatar
{
    [JsonPropertyName("character")]
    public string Character { get; set; } = null;

    [JsonPropertyName("style")]
    public string Style { get; set; } = null;

    [JsonPropertyName("customized")]
    public bool? Customized { get; set; }

    [JsonPropertyName("ice_servers")]
    public IceServers[] IceServers { get; set; } = null;

    [JsonPropertyName("video")]
    public Video Video { get; set; } = null;
}

Avatar設定の例

var options = new VoiceLiveSessionOptions
{
    Modalities = new[] { "text", "audio" },
    Voice = new Voice
    {
        Name = "ja-JP-Nanami:DragonHDLatestNeural",
        Type = "azure-standard"
    },
    Avatar = new Avatar
    {
        Character = "lisa",
        Style = "casual-sitting",
        Customized = false,
        Video = new Video
        {
            Bitrate = 2000000,
            Codec = "h264",
            Resolution = new Resolution { Width = 1920, Height = 1080 },
            Background = new Background { Color = "#00FF00FF" }
        }
    },
    TurnDetection = new TurnDetection
    {
        Type = "server_vad",
        Threshold = 0.5f,
        SilenceDurationMs = 500,
        CreateResponse = true
    }
};

実装解説 - WebRTC接続の確立

AvatarClientクラス

WebRTC接続を管理する中核クラスです。

// ファイル: src/VoiceLiveAPI.Avatars/AvatarClient.cs

public class AvatarClient : ILogOutputClass
{
    private RTCPeerConnection pc;
    private uint lastVideoTimestamp;
    private uint lastAudioTimestamp;

    public event VideoFrameReceivedDelegate OnVideoFrameReceived;
    public event AudioFrameReceivedDelegate OnAudioFrameReceived;

    public async Task AvatarConnectAsync(IceServers server, VoiceLiveSession session)
    {
        var sdpData = await CreateSdpOfferAsync(server);
        await sdpData.SendAsync(session);
    }

    // ...
}

SDPオファーの作成

ICEサーバー情報を使用してRTCPeerConnectionを作成し、SDPオファーを生成します。Microsoft Founrdyで利用できる映像と音声はそれぞれH.264、Opus形式になっています。このため、オファーを作成する際にはこれらを候補に入れておきます。
(正しく設定していなくてもサーバからのアンサーにはこれらが含まれているので動作に問題ありません。)

AvatarClient.cs
// ファイル: src/VoiceLiveAPI.Avatars/AvatarClient.cs - CreateSdpOfferAsync メソッド

private async Task<SessionAvatarConnect> CreateSdpOfferAsync(IceServers server)
{
    // 1. RTCConfiguration作成(ICEサーバー設定)
    var cfg = new RTCConfiguration
    {
        iceServers = new List<RTCIceServer>
        {
            new RTCIceServer
            {
                urls = server.Urls[0],
                username = server.UserName,
                credential = server.Credential
            }
        },
        X_UseRsaForDtlsCertificate = false
    };

    pc = new RTCPeerConnection(cfg);

    // 2. メディアトラックの追加(受信専用)
    var h264 = new SDPAudioVideoMediaFormat(
        SDPMediaTypesEnum.video, 96, "H264/90000",
        "packetization-mode=1;profile-level-id=42e01f");
    var opus = new SDPAudioVideoMediaFormat(
        SDPMediaTypesEnum.audio, 111, "opus/48000/2");

    pc.addTrack(new MediaStreamTrack(
        SDPMediaTypesEnum.video, false,
        new List<SDPAudioVideoMediaFormat> { h264 },
        MediaStreamStatusEnum.RecvOnly));
    pc.addTrack(new MediaStreamTrack(
        SDPMediaTypesEnum.audio, false,
        new List<SDPAudioVideoMediaFormat> { opus },
        MediaStreamStatusEnum.RecvOnly));

    // 3. ICE候補収集完了を待機
    TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
    pc.onicegatheringstatechange += s =>
    {
        if (s == RTCIceGatheringState.complete)
            tcs.TrySetResult(true);
    };

    pc.createOffer();
    await tcs.Task;

    // 4. SDPオファー作成
    RTCSessionDescriptionInit fullOffer = pc.createOffer();
    await pc.setLocalDescription(fullOffer);

    // 5. SDPをBase64エンコードしてJSON形式に
    string sdp = pc.localDescription.sdp.ToString();
    sdp = sdp.Replace("UDP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF");
    sdp = sdp.Replace("\r", "\\r").Replace("\n", "\\n");
    sdp = $"{{\"type\": \"offer\",\"sdp\": \"{sdp}\"}}";

    return new SessionAvatarConnect
    {
        ClientSdp = Convert.ToBase64String(Encoding.UTF8.GetBytes(sdp))
    };
}

SDPアンサーの処理

サーバーからのSDPアンサーを受信して適用します。

AvatarClient.cs
// ファイル: src/VoiceLiveAPI.Avatars/AvatarClient.cs - AvatarConnecting メソッド

public void AvatarConnecting(string sdp)
{
    Dictionary<string, object> dict = JsonSerializer.Deserialize<Dictionary<string, object>>(sdp);
    string str = dict["sdp"].ToString()?.Replace("\\r\\n", "\r\n");

    pc.setRemoteDescription(new RTCSessionDescriptionInit
    {
        sdp = str,
        type = RTCSdpType.answer
    });
}

実装解説 - 映像・音声フレームの受信と処理

イベントハンドラの設定

WebRTC接続が確立されると、映像・音声フレームがイベントとして配信されます。

AvatarClient.cs
// ファイル: src/VoiceLiveAPI.Avatars/AvatarClient.cs - SetLogProc メソッド(抜粋)

// 映像フレーム受信
pc.OnVideoFrameReceived += delegate(IPEndPoint remote, uint ssrc, byte[] frame, VideoFormat fmt)
{
    OnVideoFrameReceived?.Invoke(remote, ssrc, frame, fmt, lastVideoTimestamp);
};

// 音声フレーム受信
pc.OnAudioFrameReceived += delegate(EncodedAudioFrame audioFrame)
{
    byte[] audioData = audioFrame.EncodedAudio;
    if (audioData != null && audioData.Length > 0)
    {
        OnAudioFrameReceived?.Invoke(audioData, lastAudioTimestamp);
    }
};

// 接続状態変更
pc.onconnectionstatechange += state =>
{
    if (state == RTCPeerConnectionState.connected)
    {
        pc.Start();
    }
};

メディアフォーマット

メディア コーデック クロックレート 備考
映像 H.264 90000 Hz profile-level-id=42e01f
音声 Opus 48000 Hz 2チャンネル

サンプルアプリケーションの実行

サンプルアプリケーションを使って実際に動作確認したい場合の手順は以下の通りです。このアプリではFoundryへの接続情報はdotnet user-scretsを利用して設定情報をプロジェクトから切り離しています。

セットアップ

  1. リポジトリのクローン
git clone https://github.com/TakahiroMiyaura/VoiceLiveAPISamples.git
cd VoiceLiveAPISamples
  1. シークレットの設定
dotnet user-secrets init --project src\VoiceLiveConsoleApp
dotnet user-secrets set "Identity:AzureEndpoint" "https://ai.azure.com/.default" --project src\VoiceLiveConsoleApp
dotnet user-secrets set "VoiceLiveAPI:AzureEndpoint" "<your Azure AI Services Endpoint>" --project src\VoiceLiveConsoleApp
dotnet user-secrets set "AzureAIFoundry:AgentProjectName" "<your Project Name>" --project src\VoiceLiveConsoleApp
dotnet user-secrets set "AzureAIFoundry:AgentId" "<your Agent Id>" --project src\VoiceLiveConsoleApp
  1. ビルドと実行

サンプルはAPIKEYとEntraID認証をサポートしていますがAvatarを使う場合はAPIKeyが使えません。
このため、実行する際にはあらかじめAzureへの接続を行う必要があります。

az Login
dotnet build src\VoiceLiveConsoleApp
dotnet run --project src/VoiceLiveConsoleApp

操作方法

コンソールに出力される手順に従って選択することで動作します。
Avatarについて接続までに時間を要する(約1分)ため少し待つ必要があります。会話のやりとりをスムーズにするためサンプルでは音節が切れたタイミングで自動的に録音を止めています。これはFoundry側で音声を処理する際に無音状態を検出して各処理が実施されるためです。会話が終了した後、メッセージを処理する途中で雑音によって新しいメッセージとしてして処理されてしまうと、実行中のメッセージがキャンセルされることがあるためです。

Choose connection mode:
1. AI Model Mode
2. AI Agent Mode
3. Avatar Mode (with video streaming)
Enter your choice (1, 2, or 3): 3

Choose authentication method:
1. API Key
2. Entra ID (DefaultAzureCredential)
Enter your choice (1 or 2): 2
キー 操作
R 録音開始/停止
P 再生開始/停止
V Avatar映像ストリーミングの切り替え
F FFplayで映像再生
Q 終了

まとめ

本記事では、Microsoft Foundry Voice Live APIのAvatar機能について、特にWebRTC接続フローに焦点を当てて解説しました。Avatarを使って自身の作ったAIエージェントを動作させるための便利な機能だと思います。
アバターでの会話が必要な利用シーンは少ないかもしれないですが、テキスト以外のやり取りやUXとしての体験を向上したい場合に使えるのではないでしょうか。今回は簡単なサンプルとして標準で提供されているアバターを使っていますが、先日のIgniteで紹介されていたカスタムアバターを使用する事でオリジナルのキャラクターをインターフェースとしてAIエージェントを利用することもできます。

ポイント

今回のポイントを整理してみました。Avatarを利用する場合

  1. Avatar使用宣言: session.updateavatar設定を含めることでAvatar機能を有効化
  2. ICEサーバー情報: サーバーから提供されるice_serversを使用してWebRTC接続を構成
  3. SDP交換: session.avatar.connect/session.avatar.connectingメッセージでSDPを交換
  4. メディアストリーム: H.264映像とOpus音声をWebRTC経由で受信
  5. Avatarを使用した場合、WebSocket通信からresponse.audio.deltaメッセージは受け取ることはできません。Avatarの音声として受信することになります。

参考資料

公式ドキュメント

Microsoft Ignite 2025 セッション

関連記事

サンプルコード

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?