Teams会議の内容をリアルタイムに文字起こししたい、解析したい、別システムと連携したい――そんなニーズに正面から応える公式な方法が「Microsoft Teams会議に参加するCalling Bot」です。本記事では、Graph APIとAzure各種サービスを組み合わせて、会議のリアルタイム音声(必要に応じて映像)を取得するための具体的な実装パターンを、アーキテクチャから運用まで一気通貫で解説します。
Microsoft Teams会議からリアルタイム音声を取得する全体像
まず、「どうやってTeams会議の音声に触れるか」の全体像を整理します。ポイントは、クライアントPC側でキャプチャするのではなく、Teams会議に“参加者としてボットを入れる”という発想です。
マイクやスピーカーを仮想デバイスで奪うような力技ではなく、Microsoftが公式に提供している「Calling Bot + Microsoft Graph(Cloud Communications API)」を使うことで、コンプライアンスを守りながらリアルタイムメディアにアクセスできます。
アーキテクチャ概要
| レイヤー | 役割 | 具体的なサービス/技術 |
|---|---|---|
| クライアント | 通常の会議参加者 | Teamsクライアント(PC / モバイル / Web) |
| 会議プラットフォーム | 会議のホスト・メディアルーティング | Microsoft Teams(Microsoft 365 / Teams Premiumなど) |
| ボット | 会議に参加しメディアを受信 | Teams Calling Bot(Azure Bot Service) |
| シグナリング | 通話の確立・切断・状態通知 | Microsoft Graph /communications/calls エンドポイント |
| メディア処理 | RTP音声・映像の受信/送信 | Teams Bot Framework Media SDK / Graph Calling SDK |
| 音声認識 | リアルタイム文字起こし | Azure Cognitive Services Speech / Direct Line Speech |
| 業務アプリ | 議事録作成・解析・保存 | Webアプリ、バックエンドAPI、データベースなど |
この構成をベースに、ボットが会議に参加した瞬間から、RTPとして送られてくる音声ストリームを自前アプリに流し込み、さらにAzure Speechでリアルタイム文字起こしするのが王道パターンです。
公式ルートで実現するための前提条件と注意点
実装ステップに入る前に、前提や制約を押さえておくと後戻りを防げます。
| 項目 | 内容 | 補足 |
|---|---|---|
| テナント権限 | Azure AD(Entra ID)のアプリケーション権限に対する テナント管理者の同意が必須 | Calls.AccessMedia.All など高権限スコープを利用 |
| ライセンス | Microsoft Teamsが有効なMicrosoft 365ライセンス | 会議に参加するユーザー全員 + ボット用テナント |
| ネットワーク | ボット用WebアプリはインターネットからHTTPSで到達可能 | GraphからのWebhook/メディア経路に必要 |
| コンプライアンス | 録音・文字起こしに関する社内規程・法令への準拠 | 会議参加者へのアナウンス、保存期間の管理など |
特にCalls.AccessMedia.Allのような権限は非常に強力で、テナント全体の通話メディアへのアクセスが許可されるため、アクセス管理と監査ログをきちんと整備しておくことが重要です。
ステップ1:AzureでTeams Calling Botを登録し、権限を付与する
最初のステップは、Azure上で「ボットの素体」を用意し、Teams通話にアクセスするための権限を設定することです。
アプリ登録の流れ
- Azureポータルに管理者または開発者アカウントでサインイン。
- Microsoft Entra ID(旧 Azure AD) > アプリの登録 から新規アプリを作成。
- サポートされているアカウントの種類を「この組織ディレクトリ内のアカウントのみ」など、要件に合わせて選択。
- 認証情報として、クライアントシークレットまたは証明書を登録(本番は証明書推奨)。
Graph APIの権限設定
続いて、Calling Botとして必要なGraph APIのアプリケーション権限を付与します。代表的な権限の例を表にまとめます。
| 権限名(Application) | 用途 | 必須度 |
|---|---|---|
| Calls.AccessMedia.All | 通話のメディア(音声・映像)へのアクセス | リアルタイムメディア取得には必須 |
| Calls.Initiate.All / Calls.InitiateGroupCall.All | ボットが通話を発信・グループ通話を開始 | ボット起点で会議を作る場合に必要 |
| Calls.JoinGroupCall.All / Calls.JoinGroupCallAsGuest.All | 既存の会議にボットとして参加 | 既存会議への参加には必須 |
| OnlineMeetings.Read.All | 会議のURLや参加情報の取得 | 会議情報をGraphから引く場合に必要 |
すべての権限を追加したら、テナント管理者による「管理者の同意」を実行します。これを忘れると、ボットからGraphを呼び出しても認可エラーになり、会議に参加できません。
Azure Bot ServiceでTeams Calling Botを作成
アプリ登録ができたら、それを使ってAzure Botリソースを作成します。
- AzureポータルでBot Channels RegistrationまたはAzure Botリソースを新規作成。
- 先ほど登録したアプリケーションIDとシークレット(または証明書)をひも付け。
- メッセージングエンドポイント(ボットのエンドポイントURL)を暫定で設定(後で変更可)。
- チャンネル設定でMicrosoft Teamsを有効化し、Callingをオンにして、通話制御用WebhookのURLを指定。
この時点で、「Teamsから呼び出せるCalling Botの雛形」が完成します。
ステップ2:Graph APIでボットをTeams会議に参加させる
次に、実際にボットを会議に参加させて、通話メディアの経路を作ります。ここで利用するのが、Microsoft Graph /communications/calls エンドポイントです。
ボットを既存会議に招待するパターン
既にユーザーがTeamsクライアントから会議を開催しているケースでは、その会議にボットを招待します。代表的な流れは次の通りです。
- Graphの
/me/onlineMeetingsまたは/users/{id}/onlineMeetingsなどから、対象会議のjoinWebUrlを取得。 - Botバックエンドから、アプリケーション権限で
/communications/callsに対してPOST。 - ボディには、ボットの参加情報とターゲット会議(joinWebUrl)を指定。
- Graphが通話リソースを作成し、ボットのシグナリングWebhookに対してイベントを通知。
イメージとしては、次のようなJSONを送信します(簡略化例)。
{
"callbackUri": "https://your-bot.example.com/api/calls",
"requestedModalities": [ "audio" ],
"tenantId": "<tenant-id>",
"meetingInfo": {
"@odata.type": "#microsoft.graph.joinMeetingIdMeetingInfo",
"joinWebUrl": "https://teams.microsoft.com/l/meetup-join/..."
},
"bot": {
"id": "your-bot-app-id",
"identity": {
"@odata.type": "#microsoft.graph.applicationIdentity",
"application": {
"id": "your-bot-app-id",
"displayName": "Teams Realtime Audio Bot"
}
}
}
}
この呼び出しが成功すると、ボットのエンドポイントには「呼び出しが開始された」「メディアが確立された」といったイベントが順次POSTされ、続いてメディアSDK側のコールバックが動き始めます。
ボット主導で新規会議を作成するパターン
逆に、ボットが主導して会議を立ち上げたい場合は、次のような流れになります。
- Graphのオンライン会議APIで新しい会議を作成(
onlineMeetings)。 - 作成された会議の
joinWebUrlを取得。 - 上記と同様に
/communications/callsでボットを会議に参加させる。 - 必要に応じて、ユーザーにはメールやチャットで会議URLを共有。
これにより、「ボットを呼び出すと自動的に新規Teams会議が立ち上がり、そこにボット自身が参加してリアルタイム音声を取得する」といったシナリオも実現可能です。
ステップ3:リアルタイムメディア(RTP)の取得と制御
ボットが会議に入室すると、次は音声・映像の実データを扱います。ここで登場するのが、Teams Bot Framework Media SDKやGraph Calling SDKです。
メディアSDKの位置づけ
Graphの呼び出しはあくまで「通話のシグナリング(開始・終了・参加者変更など)」を扱うもので、リアルタイムのRTPパケット自体は、専用のメディアSDKがコールバックを通じて受け取ります。
| コンポーネント | 役割 | 備考 |
|---|---|---|
| Graph Calling API | 通話リソースの作成・更新・削除 | HTTPベース、JSON |
| Media SDK / Calling SDK | RTP音声・映像の送受信、メディア制御 | UDP/TCPベース、専用プロトコル |
| Botアプリケーション | メディアイベントの処理・外部サービス連携 | 任意の言語・フレームワークで実装 |
SDKでは概ね次のようなイベントが提供されます。
- 接続確立時に「メディアセッション開始」イベント
- 一定フレームごとの音声バッファ(PCMなど)をコールバック
- 映像フレーム(H.264など)をコールバック
- ミュート状態の変更、参加者の入退室、ドミナントスピーカー変更通知
これらのコールバックを受け取ったら、アプリ側で音声ストリームをそのままAzure Speechに流すか、あるいは一時的にバッファリングしつつ処理キューに入れる構成にします。
音声と映像は別ストリームとして扱う
Media SDKでは、音声と映像は別々のストリームとして扱われるのが一般的です。
- 音声ストリーム:16kHz/16bit PCMなどのフォーマットで扱いやすい
- 映像ストリーム:H.264などのエンコード済みフレームが多い
多くのユースケースでは、まずは音声だけを取得して文字起こしし、その後必要に応じて映像も扱う、という段階的な導入が現実的です。映像は帯域・処理負荷が大きいため、クラウドコストや解析ロジックの複雑さも増します。
ステップ4:リアルタイム音声をAzure Speechで文字起こしする
ボットが受け取った音声ストリームをそのまま保存するだけでは活用しづらいため、多くの場合はリアルタイム文字起こし(Speech-to-Text)の処理を組み合わせます。
標準的な構成:Speech-to-TextストリーミングAPI
Azure Cognitive Services Speechは、WebSocketやgRPCなどのストリーミングAPIを通じて、音声をリアルタイムに送信し、逐次的に認識結果を返してくれます。
典型的な実装フローは次のようになります。
- Media SDKの音声コールバックで、一定サイズ(例:20ms~100ms)ごとにPCMバッファを受信。
- ボットアプリ内で、そのバッファをAzure SpeechのストリーミングクライアントにPush。
- Azure Speechからは、
- 中間結果(partial)
- 確定結果(final)
- 確定結果を蓄積して会議の逐次議事録として保存し、中間結果はリアルタイム字幕としてUIに表示するなど用途に応じて活用。
ボット側のコードはイメージ的に次のようになります(疑似コード)。
// Media SDKからの音声コールバック
onAudioFrameReceived(frame) {
// frame.buffer: PCMバイト列
speechClient.sendAudio(frame.buffer);
}
// Azure Speechからのイベント
speechClient.on("partialResult", text => {
// リアルタイム字幕などに利用
});
speechClient.on("finalResult", text => {
// データベースに保存、検索インデックスを更新
});
超低遅延が必要な場合:Direct Line Speechの活用
会議内容をその場でボットが理解し、対話したりアクションを起こしたりするようなケースでは、さらに低遅延なパイプラインが求められます。その場合、Azure Bot ServiceとAzure Speechを組み合わせたDirect Line Speechを使うと、音声→テキスト→自然言語理解→応答までをできるだけ短いレイテンシで回すことができます。
ただし、Teams会議のCalling BotとDirect Line Speechの連携はやや高度な設計になるため、まずは「音声→Azure Speech→テキスト」のパイプラインを安定稼働させ、その上に対話や自動要約などのロジックを積み上げる形がおすすめです。
ステップ5:デプロイと運用設計
ボットが単体で動くようになったら、次は本番運用に耐えうる形に仕上げます。
代表的なデプロイパターン
| 構成 | 特徴 | 向いているケース |
|---|---|---|
| Azure App Service + Azure Bot Service | マネージドなWebアプリ環境で運用コストが低い | 中規模までのボット、Windows依存が少ない場合 |
| Azure Kubernetes Service (AKS) | コンテナ化してスケール制御が柔軟、メディア処理を分散しやすい | 高負荷な映像処理や多拠点展開が必要な場合 |
| オンプレミス + Azure接続 | 機微データを社内に保持しつつ、GraphやSpeechはクラウド利用 | 厳格なデータレジデンシ要件がある場合 |
ログと監視
- Graph APIの呼び出しログ(失敗率・レスポンス時間)
- Media SDKのエラー/警告(パケットロス、ネットワーク断など)
- Azure Speechの認識エラー(レート制限、認証エラー)
- キュー長や処理時間など、バックエンド側のメトリクス
これらをApplication InsightsやLog Analyticsに集約しておくと、問題が起きた会議をあとからトレースでき、運用トラブルの切り分けが格段に楽になります。
サードパーティ代替案:Recall.aiなど「会議Bot API」を使う
ここまで紹介した構成は、あくまで自前でCalling Botを実装・運用する前提です。しかし、現実には「そこまで投資できない」「Teams以外のZoomやGoogle Meetにも対応したい」といった要望も多くあります。
その場合の選択肢が、Recall.aiのような「会議Bot API」サービスです。これらのサービスは、次のような点を肩代わりしてくれます。
- Teams / Zoom / Google Meet それぞれの会議ボットの登録・認証・権限管理
- リアルタイムメディアの取得と再エンコード、WebSocketやHTTP経由での配信
- 音声認識・翻訳・要約などの基本機能
- API一つで複数プラットフォームを横断して扱える統一インターフェース
メリットとデメリットを整理すると次の通りです。
| 観点 | 自前実装(Calling Bot) | サードパーティ(会議Bot API) |
|---|---|---|
| 初期実装コスト | 高い(設計・検証に時間がかかる) | 低い(API連携が中心) |
| ランニングコスト | クラウドリソース次第だが、長期的には有利なことも | 従量課金が中心、利用量が多いと高額になる可能性 |
| カスタマイズ性 | 非常に高い(メディア処理を自由に設計可能) | 提供範囲の中でのカスタマイズに限定される |
| マルチプラットフォーム対応 | 各サービスごとに実装が必要 | 多くの場合、1つのAPIで複数サービスを扱える |
| 将来のAPI変更リスク | 自社で追従が必要 | サービス側が吸収してくれる |
「まずはPoCや小規模サービスとして素早く立ち上げたい」「Teams以外の会議サービスもまとめて扱いたい」といった場合は、これらのサービスを入口として採用し、スケールに応じて段階的に自前実装に移行する戦略も有効です。
話者分離(スピーカー識別)をどう実現するか
リアルタイム文字起こしの次の一歩として、「誰が話したか」まで識別したいというニーズもよくあります。ここは実装難度が一段上がるポイントです。
基本的な前提:音声は通常ミックス済み
Teamsからボットに送られてくる音声は、多くの場合「全参加者がミックスされた1本の音声ストリーム」です。そのため、単純にAzure Speechにかけるだけでは「話者A」「話者B」といった識別はできません。
実現のためのアプローチ例
- ドミナントスピーカーイベントの利用
Media SDKや通話イベントから「現在の発話者が誰か」という情報が通知される場合、それをタイムスタンプと一緒にログし、テキストの区切りごとに話者ラベルを付与する。 - 音声特徴量によるクラスタリング
音声を短いフレームに分解し、特徴量を抽出してクラスタリングすることで、発話パターンから話者をグルーピングする(話者名と紐付けるには追加処理が必要)。 - GraphのaudioRoutingGroupsの活用
参加者ごとに別ストリームを割り振れる構成が使える場合、参加者ごとに個別の音声ストリームを保持し、それぞれ別々にSTTを走らせる。
実務上は、「簡易的にドミナントスピーカー情報をテキストにタグ付けする」程度から始め、必要に応じて高度な話者分離ロジックを追加していくのが現実的です。
ネットワークと品質設計のポイント
リアルタイムメディアを扱う以上、ネットワーク品質はサービスの品質に直結します。特に注意したいのは以下の点です。
バッファリングと再送制御
- 数百ミリ秒〜1秒程度のバッファを持たせ、軽微なパケットロスやジッタを吸収
- Azure Speechなど下流サービスへの送信は、バッファから均一なレートで流す
- ボット側の処理が遅延した場合は、古いフレームを捨てるなどバックプレッシャー対策を実装
帯域とスケール
会議数や参加人数が増えるに従い、ボットが扱うトラフィックは急激に増えます。
- 1会議あたりの平均帯域(音声のみなら数百kbps程度が多い)を見積もる
- 同時接続数のピークを想定し、スケールアウト戦略(多インスタンス構成)を検討
- Speech-to-Textの同時セッション数やレート制限も確認しておく
こうした観点をあらかじめ設計書に落とし込んでおくと、PoCから本番に移行する際のギャップを最小化できます。
セキュリティ・コンプライアンス上の注意点
会議の音声・映像を扱う以上、セキュリティとコンプライアンスは外せません。代表的な注意点を整理します。
- 会議参加者への明示的な通知
ボットが録音・解析を行っていることを、会議タイトル・チャット・ボット名などで明示。 - 保存期間と削除ポリシー
音声データ・文字起こしデータの保存期限を定め、自動削除の仕組みを実装。 - アクセス制御
議事録や音声データにアクセスできるユーザーを最小限に絞り、役割ベースで管理。 - 暗号化
保存時はストレージの暗号化、転送経路はTLS/HTTPSを徹底。 - 監査ログ
誰がいつどの会議のデータを閲覧・エクスポートしたかを監査できるようにする。
特に海外拠点を含むグローバル企業では、国や地域ごとに録音に関する法規制が異なるため、法務部門との連携が不可欠です。
ユースケース別の設計パターン
最後に、リアルタイム音声取得Botの活用シーンと、それぞれに向いた設計のポイントをいくつか紹介します。
| ユースケース | 要件 | 設計のポイント |
|---|---|---|
| 自動議事録作成 | 会議終了後に全文検索可能な議事録を提供 | リアルタイム性より精度重視。Speechの認識結果を後処理で整形・要約。 |
| リアルタイム字幕・翻訳 | 会議中に字幕や翻訳を表示 | 低遅延のSTTと翻訳API、UIへのストリーミング更新が鍵。 |
| コールセンター品質管理 | 会話内容のリアルタイム解析・キーワード検出 | キーワードスポッティングや感情分析モデルとの連携が有効。 |
| 業務プロセスの自動起動 | 「発注」「契約」などのワードでワークフローを起動 | キーフレーズ抽出とRPA・ワークフロー製品との連携。 |
同じ「リアルタイム音声取得」でも、求められる要件によってアーキテクチャの重心が変わります。まずは自社のユースケースを明確にし、それに合わせてボット・STT・周辺システムの役割分担を設計することが成功の近道です。
まとめ:Teams会議のリアルタイム音声取得は「Calling Bot + Graph API」が王道
Microsoft Teams会議からリアルタイムで音声(場合によっては映像も)を取得したい場合、公式にサポートされるルートは次の流れになります。
- AzureでTeams Calling Bot用のアプリ登録を行い、Calls.AccessMedia.Allなどの通話メディア権限を付与する。
- Azure Bot Serviceでボットを作成し、TeamsチャンネルとCallingを有効化する。
- Microsoft Graphの
/communications/callsエンドポイントを使ってボットを会議に参加させる。 - Teams Bot Framework Media SDK / Graph Calling SDKでRTP音声(映像)をリアルタイムに受信する。
- 受信した音声をAzure SpeechなどのSTTサービスへストリーミングし、文字起こしや解析を行う。
- 必要に応じて、サードパーティの会議Bot APIを利用して実装負荷や将来のAPI変更リスクを低減する。
この一連の仕組みを整えることで、Teams会議の内容をリアルタイムに「データ化」し、議事録作成、自動要約、ダッシュボード可視化、業務プロセス連携など、さまざまな高度な活用が可能になります。
まずは小さな会議やPoCから始めて、段階的に機能とスケールを拡張していく――それが、Teams会議のリアルタイム音声ボットを現実的なコストで自社に根付かせるための王道パターンと言えるでしょう。

コメント