AOQ を使用して qwen3.5-omni-plus-realtime に接続し、クライアントがプッシュツートーク会話とオプションの画像による質問のためにターンの境界を制御できるようにします。クライアントコードは iOS Swift を使用します。
ソリューション概要
Qwen-Omni-Realtime は、サーバー側の VAD とクライアント制御のマニュアルモードをサポートしています。本チュートリアルでは、session.turn_detection を null に設定します。クライアントは、ユーザーがボタンを押している間に音声を送信し、ユーザーがボタンを離したときに音声をコミットして明示的にレスポンスをリクエストします。
マニュアルモードは、ハードウェアインターコムボタン、長押しコントロール、アプリケーションがターンの境界を決定するノイズの多い環境、およびオプションで画像を含むターンに適しています。音声は AOQ 音声トラック経由で転送されます。input_audio_buffer.append は送信しないでください。
項目 | VAD モード | マニュアルモード |
ターンの境界 |
| ボタンまたはアプリケーションの状態によって制御 |
セッション設定 |
|
|
音声のコミット | サービスによって自動的に実行 | クライアントが |
レスポンストリガー | サービスによって自動的にトリガー | クライアントが |
画像入力 | 連続ビデオトラックまたはデータトラック経由の画像 | 連続ビデオトラックまたはデータトラック経由の画像 |
前提条件
- Model Studio を有効化し、「API キーの取得と設定」に従ってください。API キーはアプリケーションサーバーにのみ保存してください。クライアントコードに含めたり、コードリポジトリにコミットしたりしないでください。
- アプリケーションがデプロイされているリージョンの AOQ エンドポイントを確認してください。選択のガイダンスについては、「リージョン、デプロイスコープ、およびエンドポイントの選択」をご参照ください。
- 「SDKのダウンロード」に記載されているように、最新の AOQ Client SDK をダウンロードしてください。
- Qwen-Omni-Realtime の AOQ 認証手順に従って AppServer を構築します。新しい接続のたびに、クライアントは AppServer から新しい接続認証情報を取得する必要があります。
SDKのインポート
開発プラットフォーム用の SDK をインポートします。クライアント実装では iOS Swift を使用します。他のプラットフォームでも同じインターフェースとイベントフローが提供されています。本チュートリアルでは PCM 音声ストリームを使用します。Opus エンコーディングはプラグインによって提供されます。アップリンクで Opus を使用する場合は、Opus プラグインをインポートしてください。
- Android
- iOS
- HarmonyOS
- Linux (Python)
AoqClientSdk-release.aarをapp/libsに配置し、app/build.gradleで依存関係と SDK がサポートする ABI を設定します。
AndroidManifest.xmlで以下のパーミッションを宣言します。
- 対応するデバイスを使用する前に、実行時に
RECORD_AUDIOとCAMERAのパーミッションをリクエストします。
実装フロー
- アプリケーションサーバーは、
Realtimeトークン URL からqwen3.5-omni-plus-realtimeの AOQ 接続パラメータを取得します。 - クライアントはエンジンを作成し、音声コーデックとトラックを設定します。連続的な視覚理解が必要な場合は、ビデオトラックも設定します。
- クライアントはローカルキャプチャと再生を開始し、デフォルトで音声トラックの送信を無効にし、AOQ に接続して
session.updateを送信します。 session.updatedを受信した後、continuous-videoオプションはビデオトラックを有効にします。音声トラックは、ユーザーがトークボタンを押すまで無効のままです。- ユーザーがボタンを押すと、クライアントは音声トラックを有効にします。離すと、音声トラックを無効にし、オプションで画像を送信してから、
input_audio_buffer.commitとresponse.createを送信します。 response.doneを受信した後、別のターンを開始できます。終了するには、デバイスを停止し、切断してエンジンを破棄します。
- 連続ビデオトラック
- データトラック経由で画像を送信
session.updated の後にビデオ送信を有効にします。モデルは最新のフレームを継続的に認識します。各音声ターンは、音声をコミットしてレスポンスをリクエストするだけで済みます。
アプリケーションサーバーからのトークンの取得
アプリケーションサーバーで DASHSCOPE_API_KEY を設定し、選択したリージョンのエンドポイントにリクエストを送信します。clientIp はクライアントの実際のパブリック IP アドレスです。このフィールドはオプションですが、指定すると、サービスが適切なリレーエンドポイントを割り当てるのに役立ちます。
clientIp を省略してください。レスポンスフィールド | SDK フィールド |
|
|
|
|
|
|
|
|
|
|
iOSクライアントの実装
クライアントがアプリケーションサーバーから AoqConnectConfig を取得した後、以下の手順に従って iOS でプッシュツートーク音声会話を実装します。
1. エンジンの作成とコールバックの登録
シングルトン AOQ エンジンを作成し、アプリケーションオブジェクトをコールバックレシーバーとして登録します。コールバックで接続状態、サーバーイベント、エラー、および警告を処理します。
2. 音声およびビデオデバイスの開始
音声キャプチャと再生を初期化します。continuous-video オプションの場合のみカメラを開始します。これらのメソッドが呼び出される前に、マイクとカメラのパーミッションを取得してください。
3. コーデックとトラックの設定
選択したモデルとアプリケーションの音声フォーマットに応じて音声コーデックを設定し、画像入力オプションに応じてトラックを選択します。以下の音声とビデオの値は例です。モデルの要件とアプリケーションシナリオに合わせて調整してください。接続が確立される前に、音声トラックの送信を無効にしてください。
- 連続ビデオトラック
- データトラック経由で画像を送信
4. マニュアルセッションの設定
接続が確立された後、sendDataMsg を呼び出して session.update イベントを送信します。turn_detection を null に設定し、アプリケーションに適した音声、指示、および出力モダリティを選択します。例の音声パラメータは SDK コーデック設定と一致させてください。すべてのフィールドについては、「クライアントイベント」をご参照ください。
5. セッション設定の待機
onDataMsg コールバックで session.updated イベントを処理します。このイベントを受信するまで、メディアを送信しないでください。continuous-video オプションの場合は、この時点で enableSendMediaStream を呼び出してビデオトラックを有効にしますが、ユーザーがボタンを押す前の音声が入力バッファに入らないように、音声トラックは無効のままにしてください。
6. プッシュツートークインタラクションの実装
ボタンが押されたら、enableSendMediaStream を呼び出して音声トラックを有効にします。離したら、enableSendMediaStream を呼び出して音声トラックを無効にし、ターンに音声が含まれていることを確認し、オプションで画像を送信してから、sendDataMsg を呼び出して input_audio_buffer.commit と response.create を送信します。
7. 画像入力オプションの選択
連続的な視覚理解と時折の画像による質問では、異なるトラック設定と送信動作を使用します。帯域幅、消費電力、およびインタラクションデザインに基づいてオプションを選択してください。
- 連続ビデオトラック
- データトラック経由で単一の画像を送信
input_image_buffer.append を送信しないでください。8. 切断とエンジンの破棄
セッションが終了したら、切断してエンジンを破棄します。disconnect または destroy は自動的にメディアデバイスを閉じるため、stop メソッドを個別に呼び出す必要はありません。AoqClientEngine はシングルトンであり、destroy が呼び出されるまで再度作成することはできません。
完全な例
以下のクラスは、アプリケーションサーバーのトークンレスポンスからマッピングされた AoqConnectConfig を受け取ります。本番環境では、UI状態、パーミッション、エラー回復、および画像圧縮を追加してください。
実行と検証
音声のみのプッシュツートークターンを 1 回と、画像を含むターンを 1 回完了します。期待される結果:
- 音声トラックは、ボタンが押される前は無効になっており、ボタンが押されている間は継続的に音声を送信します。
- 離した後、
input_audio_buffer.committed、response.created、およびresponse.doneが順番に受信され、モデルの音声がサブスクライブされた音声トラック経由で再生されます。 - 単一画像オプションでは、モデルはターンの画像と音声を使用してレスポンスします。連続ビデオでは、最新のビデオフレームを使用します。
重要な考慮事項
AOQは音声トラック経由で音声を転送します。input_audio_buffer.appendも送信しないでください。input_audio_buffer.commitはターンをコミットするだけで、モデルのレスポンスをトリガーしません。その後にresponse.createを送信してください。- 空の音声バッファをコミットしないでください。サービスはエラーを返します。
session.updatedの前にメディア送信を有効にしないでください。マニュアルモードでは、ユーザーがボタンを押す前に音声トラックを有効にしないでください。
