すべてのプロダクト
Search
ドキュメントセンター

:AOQ 経由で fun-asr-realtime を使用したリアルタイム音声の文字起こし

最終更新日:Sep 02, 2026

AOQ を使用して fun-asr-realtime に接続し、マイクの音声をストリーミングして、リアルタイムで文字起こし結果を受信します。クライアントコードは Android Java を使用しており、AOQ がサポートする他のプラットフォームでも同じインターフェースを提供します。

ソリューションの概要

fun-asr-realtime は、音声ストリームをリアルタイムで句読点付きテキストに文字起こしします。AOQ SDK は、メディアとイベントを別々のトラックで転送します。クライアントは Audio トラックで音声を送信し、Data トラックを使用して制御イベントを送信し、認識イベントを受信します。このモデルは Realtime イベントプロトコルではなく、Inference イベントプロトコルを使用します。

このソリューションは、ライブキャプション、会議の文字起こし、音声入力、インテリジェントアシスタントに適しています。Audio トラックにより、イベントメッセージで音声をエンコードする必要がなくなり、Data トラックは run-task、result-generated、finish-task などのタスクのセマンティクスを保持します。

  1. クライアントは、アプリケーションサーバーから一時的な AOQ 接続認証情報をリクエストします。
  2. アプリケーションサーバーは、API キーを使用して Alibaba Cloud Model Studio からトークンをリクエストし、接続フィールドをクライアントに返します。
  3. クライアントは AOQ 接続を確立し、run-task を送信します。task-started を受信した後、クライアントはマイクの音声の送信を開始します。
  4. サーバーは継続的に result-generated イベントを返します。クライアントが finish-task を送信した後、最終結果と task-finished を待機します。

前提条件

  1. Alibaba Cloud Model Studio を有効にし、API キーの取得と設定の説明に従って API キーを作成してください。API キーはアプリケーションサーバーにのみ保存してください。クライアントコードに含めたり、コードリポジトリにコミットしたりしないでください。
  2. アプリケーションがデプロイされているリージョンの AOQ エンドポイントを選択してください。エンドポイントの選択については、「リージョン、デプロイ範囲、エンドポイントの選択」をご参照ください。
  3. 「SDK のダウンロード」の説明に従って、最新の AOQ Client SDK をダウンロードしてください。このチュートリアルでは PCM 音声を転送するため、オプションの Opus プラグインは不要です。
  4. 「トークン認証」の説明に従ってアプリケーションサーバーを設定し、AOQ Inference プロトコル用のサーバー側プロキシ認証を実装してください。新しい接続を確立する前に、クライアントはアプリケーションサーバーから新しい接続認証情報を取得する必要があります。

SDK のインポート

開発プラットフォームに応じた SDK 統合手順を選択してください。クライアント実装では Android Java を使用していますが、他のプラットフォームでも同じ API 設計とイベントフローに従います。

Android

  1. AoqClientSdk-release.aar を app/libs に配置し、app/build.gradle で依存関係と ABI を設定してください。
android {
    defaultConfig {
        minSdk 21
        ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.aar'])
}
  1. AndroidManifest.xml でネットワークと録音の権限を宣言してください。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
  1. 録音を開始する前に、RECORD_AUDIO ランタイム権限をリクエストしてください。音声認識には CAMERA 権限は不要です。

iOS

  1. AoqClientSdk.framework を Xcode プロジェクトにドラッグしてください。[Target] > [General] > [Frameworks, Libraries, and Embedded Content] で、[Embed & Sign] を選択してください。この SDK は、iOS 13.0 以降を実行する arm64 デバイスをサポートしています。
  2. Info.plist に NSMicrophoneUsageDescription を追加してください。音声認識には NSCameraUsageDescription は不要です。
  3. Swift では import AoqClientSdk を、Objective-C では #import <AoqClientSdk/AoqClientSdk.h> を使用してください。

HarmonyOS

  1. AoqClientSdk.har を entry/libs に配置し、entry/oh-package.json5 で依存関係を宣言してください。この SDK は API 12 と互換性があり、arm64-v8a をサポートしています。
{
  "dependencies": {
    "@aoq/client-sdk": "file:./libs/AoqClientSdk.har"
  }
}
  1. entry/src/main/module.json5 でネットワークとマイクの権限を宣言してください。
"requestPermissions": [
  { "name": "ohos.permission.INTERNET" },
  {
    "name": "ohos.permission.MICROPHONE",
    "reason": "$string:perm_mic_reason",
    "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" }
  }
]
  1. 録音を開始する前に、abilityAccessCtrl.createAtManager().requestPermissionsFromUser を呼び出して、マイクへのアクセスをリクエストしてください。

Linux (Python)

  1. SDK を展開し、aoq_client_sdk.py、libAoqClientSdk.so、libonnxruntime.so.1.16.3 を同じディレクトリに保持してください。
  2. SDK ディレクトリを Python モジュールと共有ライブラリの検索パスに追加してください。
export PYTHONPATH="$PWD/AoqClientSdk:$PYTHONPATH"
export LD_LIBRARY_PATH="$PWD/AoqClientSdk:$LD_LIBRARY_PATH"
  1. Python で import aoq_client_sdk を使用してください。AOQ_CLIENT_SDK_LIB を libAoqClientSdk.so の絶対パスに設定することもできます。

デモの試用

Alibaba Cloud Model Studio の Android デモを使用すると、AOQ 接続を迅速に検証できます。APK をダウンロードし、API キーと workspaceId を設定して、選択したモデルを試してください。

次の QR コードをスキャンして、デモをダウンロードしてください。

QR code for downloading the demo

実装フロー

  1. アプリケーションサーバーは Inference トークン URL を使用して、fun-asr-realtime の AOQ 接続パラメータを取得します。
  2. クライアントはトークンレスポンスを AoqConnectConfig にマッピングし、Audio トラックと Data トラックをパブリッシュし、Data トラックをサブスクライブします。
  3. クライアントは、ビジネス要件とモデル要件に基づいて音声エンコードパラメータを設定し、音声送信を無効にしてマイクキャプチャを開始し、AOQ 接続を確立します。
  4. 接続が確立された後、クライアントは run-task を送信し、task-started を受信した後に Audio トラックの送信を有効にします。
  5. クライアントは onDataMsg で result-generated を処理します。認識を停止するには、まず Audio トラックの送信を無効にしてから、finish-task を送信します。
  6. task-finished を受信した後、クライアントは新しい task_id を使用して同じ接続で別のタスクを開始するか、接続を切断してエンジンを破棄できます。
Sequence diagram for real-time speech recognition with fun-asr-realtime over AOQ

アプリケーションサーバーでのトークン取得

アプリケーションサーバーで DASHSCOPE_API_KEY を設定し、選択したリージョンのエンドポイントにリクエストを送信してください。clientIp は、クライアントデバイスの実際のパブリック IP アドレスです。このフィールドはオプションですが、サービスが適切なリレーエンドポイントを選択できるように提供することを推奨します。

curl -X POST \
  "https://{endpoint}/api/v1/webrtc/inference?model=fun-asr-realtime" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${DASHSCOPE_API_KEY}" \
  -H "x-dashscope-rtc-transport: moq" \
  -d "{\"clientIp\": \"${CLIENT_REAL_IP}\"}"

注記アプリケーションサーバーがクライアントデバイスの実際のパブリック IP アドレスを取得できない場合は、空の文字列を渡す代わりに、リクエストボディから clientIp を省略してください。

次のレスポンスフィールドをクライアントに返してください。API キーをクライアントに返さないでください。すべてのリクエストフィールドとレスポンスフィールドについては、「トークン認証」をご参照ください。

レスポンスフィールド

SDK フィールド

aoqTokenForClient

AoqConnectConfig.token

sid

AoqConnectConfig.sid

clientRelayCertFingerprint

AoqConnectConfig.certFingerprint

clientRelayEndpoints

AoqConnectConfig.relayEndpoints

extraInfo.workspaceIdHash

AoqConnectConfig.workspaceIdHash

Android クライアントの実装

次の手順では、実際の接続とタスクのシーケンスに従って、Android Java クライアントコードを分割します。各スニペットは、このトピックの後半にある完全な例から抜粋したものです。

1. エンジンの作成とコールバックの登録

AOQ クライアントエンジンを作成し、接続状態の変化と Data トラックイベントのコールバックを登録してください。アプリケーションに応じてコールバックロジックを実装し、接続が確立された後にのみ認識を開始してください。

AoqClientListener listener = new AoqClientListener() {
    @Override
    public void onConnectionStatusChange(AoqClientEngine.AoqConnectionStatus status) {
        connected = status == AoqClientEngine.AoqConnectionStatus
                .AoqConnectionStatusConnected;
        if (connected) {
            beginRecognition();
        }
    }

    @Override
    public void onDataMsg(AoqClientEngine.AoqDataMsg msg) {
        handleServerEvent(msg);
    }
};

AoqClientEngine.AoqCreateConfig createConfig = new AoqClientEngine.AoqCreateConfig();
createConfig.workDir = context.getFilesDir().getAbsolutePath();
engine = AoqClientEngine.createEngine(context, createConfig, listener);

2. 音声エンコードの設定

モデルに送信する音声エンコードを設定してください。アプリケーションとモデルの要件に基づいて、フォーマット、サンプルレート、チャンネル数を設定してください。次のコードでは、16 kHz モノラル PCM を例として使用しています。サポートされる値については、「クライアントイベント」の run-task パラメータをご参照ください。

AoqClientEngine.AoqAudioCodecConfig encoder =
        new AoqClientEngine.AoqAudioCodecConfig();
encoder.trackType = AoqClientEngine.AoqTrackType.AoqTrackTypeAudio;
encoder.codecType = AoqClientEngine.AoqEncoderType.AoqEncoderTypeAudioPCM;
encoder.sampleRate = 16000;
encoder.channel = 1;
encoder.bitrate = 256000;
engine.setAudioEncoderConfig(encoder);

3. 接続とトランスポートトラックの設定

アプリケーションサーバーから返された認証情報を使用して AOQ 接続を設定し、アプリケーションに基づいてパブリッシュおよびサブスクライブするトラックを選択してください。リアルタイム音声認識の場合、この例では Audio トラックと Data トラックをパブリッシュし、Data トラックをサブスクライブします。

addTrack(connectConfig, true,
        AoqClientEngine.AoqTrackType.AoqTrackTypeAudio);
addTrack(connectConfig, true,
        AoqClientEngine.AoqTrackType.AoqTrackTypeData);
addTrack(connectConfig, false,
        AoqClientEngine.AoqTrackType.AoqTrackTypeData);

4. 音声キャプチャの開始と接続の確立

音声キャプチャを設定し、AOQ 接続を確立してください。アプリケーションに基づいて、組み込みキャプチャまたは外部キャプチャ、VoIP モードの有効化、チャンネル数を選択してください。task-started を受信するまで、Audio トラックの送信を無効のままにしてください。

AoqClientEngine.AoqAudioCaptureConfig capture =
        new AoqClientEngine.AoqAudioCaptureConfig();
capture.isExternal = false;
capture.isVoipMode = true;
capture.channel = 1;
engine.startAudioCapture(capture);

// task-started を受信するまで音声を送信しないでください。
engine.enableSendMediaStream(
        AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
engine.connect(connectConfig);

5. 認識タスクの開始

接続が確立された後、タスク ID を生成し、run-task を送信して認識を開始してください。使用するモデルと音声入力に応じて、model、format、sample_rate、その他のタスクパラメータを設定してください。詳細については、「クライアントイベント」をご参照ください。

taskId = UUID.randomUUID().toString();
JSONObject header = createHeader("run-task");
JSONObject parameters = new JSONObject()
        .put("format", "pcm")
        .put("sample_rate", 16000);
JSONObject payload = new JSONObject()
        .put("task_group", "audio")
        .put("task", "asr")
        .put("function", "recognition")
        .put("model", "fun-asr-realtime")
        .put("parameters", parameters)
        .put("input", new JSONObject());
send(new JSONObject().put("header", header).put("payload", payload));

6. サーバーイベントの処理

タスクの状態、認識結果、エラーを処理し、結果をアプリケーションに渡してください。UI と状態管理の要件に基づいてコールバックを実装してください。task-started を受信した後にのみ音声を送信し、ハートビートイベントは表示される文字起こしから除外してください。完全なレスポンススキーマについては、「サーバーイベント」をご参照ください。

String eventName = header.optString("event", "");
if ("task-started".equals(eventName)) {
    taskStarted = true;
    engine.enableSendMediaStream(
            AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, true);
} else if ("result-generated".equals(eventName)) {
    JSONObject payload = event.optJSONObject("payload");
    JSONObject output = payload == null ? null : payload.optJSONObject("output");
    JSONObject sentence = output == null ? null : output.optJSONObject("sentence");
    if (sentence != null && !sentence.optBoolean("heartbeat", false)) {
        String text = sentence.optString("text", "");
        if (!text.isEmpty()) {
            resultListener.onResult(
                    text, sentence.optBoolean("sentence_end", false));
        }
    }
} else if ("task-finished".equals(eventName)) {
    resetTaskState();
    resultListener.onTaskFinished();
} else if ("task-failed".equals(eventName)) {
    String message = header.optString("error_message", "Recognition failed");
    resetTaskState();
    resultListener.onError(message);
}

7. 認識タスクの終了

ユーザーが現在の録音を終了したら、音声の送信を停止し、finish-task を送信してください。最終的な文字起こしと task-finished が到着するまで、接続を開いたままにしてください。その後、アプリケーションのフローに基づいて、別のタスクを開始するか、接続を解放できます。イベント形式については、「クライアントイベント」をご参照ください。

engine.enableSendMediaStream(
        AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
JSONObject payload = new JSONObject().put("input", new JSONObject());
send(new JSONObject()
        .put("header", createHeader("finish-task"))
        .put("payload", payload));

8. 接続の切断とエンジンの破棄

ページが破棄されたとき、または認識が不要になったときに、音声キャプチャ、AOQ 接続、エンジンリソースを解放してください。アプリケーションのライフサイクルに基づいて解放ポイントを選択し、finish-task を送信した直後にリソースを解放しないでください。

engine.enableSendMediaStream(
        AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
engine.stopAudioCapture();
engine.disconnect();
AoqClientEngine.destroy();

完全な例

この Android Java クラスは、アプリケーションサーバーからの JSON レスポンスを AoqConnectConfig にマッピングし、前述の接続、キャプチャ、タスク、リソース解放ロジックを組み合わせたものです。

import android.content.Context;

import com.alibaba.aoq.clientsdk.AoqClientEngine;
import com.alibaba.aoq.clientsdk.AoqClientListener;

import org.json.JSONArray;
import org.json.JSONObject;

import java.nio.charset.StandardCharsets;
import java.util.UUID;

public final class AsrClient {
    public interface ResultListener {
        void onResult(String text, boolean sentenceEnd);

        void onTaskFinished();

        void onError(String message);
    }

    private final AoqClientEngine engine;
    private final ResultListener resultListener;
    private String taskId;
    private boolean connected;
    private boolean taskStarted;

    public AsrClient(Context context, AoqClientEngine.AoqConnectConfig connectConfig,
                     ResultListener resultListener) {
        this.resultListener = resultListener;
        AoqClientListener listener = new AoqClientListener() {
            @Override
            public void onConnectionStatusChange(AoqClientEngine.AoqConnectionStatus status) {
                connected = status == AoqClientEngine.AoqConnectionStatus
                        .AoqConnectionStatusConnected;
                if (connected) {
                    beginRecognition();
                }
            }

            @Override
            public void onDataMsg(AoqClientEngine.AoqDataMsg msg) {
                handleServerEvent(msg);
            }
        };

        AoqClientEngine.AoqCreateConfig createConfig = new AoqClientEngine.AoqCreateConfig();
        createConfig.workDir = context.getFilesDir().getAbsolutePath();
        engine = AoqClientEngine.createEngine(context, createConfig, listener);

        configureAudioEncoder();
        configureTracks(connectConfig);
        startAudioCapture();
        engine.connect(connectConfig);
    }

    private void configureAudioEncoder() {
        AoqClientEngine.AoqAudioCodecConfig encoder = new AoqClientEngine.AoqAudioCodecConfig();
        encoder.trackType = AoqClientEngine.AoqTrackType.AoqTrackTypeAudio;
        encoder.codecType = AoqClientEngine.AoqEncoderType.AoqEncoderTypeAudioPCM;
        encoder.sampleRate = 16000;
        encoder.channel = 1;
        encoder.bitrate = 256000;
        engine.setAudioEncoderConfig(encoder);
    }

    private static void configureTracks(AoqClientEngine.AoqConnectConfig connectConfig) {
        addTrack(connectConfig, true, AoqClientEngine.AoqTrackType.AoqTrackTypeAudio);
        addTrack(connectConfig, true, AoqClientEngine.AoqTrackType.AoqTrackTypeData);
        addTrack(connectConfig, false, AoqClientEngine.AoqTrackType.AoqTrackTypeData);
    }

    private void startAudioCapture() {
        AoqClientEngine.AoqAudioCaptureConfig capture =
                new AoqClientEngine.AoqAudioCaptureConfig();
        capture.isExternal = false;
        capture.isVoipMode = true;
        capture.channel = 1;
        engine.startAudioCapture(capture);
        engine.enableSendMediaStream(AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
    }

    /** 既存の AOQ 接続で別の認識タスクを開始します。 */
    public void beginRecognition() {
        if (!connected || taskStarted || taskId != null) {
            return;
        }
        taskId = UUID.randomUUID().toString();
        JSONObject header = createHeader("run-task");
        JSONObject parameters = new JSONObject()
                .put("format", "pcm")
                .put("sample_rate", 16000);
        JSONObject payload = new JSONObject()
                .put("task_group", "audio")
                .put("task", "asr")
                .put("function", "recognition")
                .put("model", "fun-asr-realtime")
                .put("parameters", parameters)
                .put("input", new JSONObject());
        send(new JSONObject().put("header", header).put("payload", payload));
    }

    /** 現在のタスクを停止します。接続を閉じる前に task-finished を待ちます。 */
    public void finishRecognition() {
        if (taskId == null) {
            return;
        }
        engine.enableSendMediaStream(AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
        JSONObject payload = new JSONObject().put("input", new JSONObject());
        send(new JSONObject()
                .put("header", createHeader("finish-task"))
                .put("payload", payload));
    }

    public void close() {
        engine.enableSendMediaStream(AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
        engine.stopAudioCapture();
        engine.disconnect();
        AoqClientEngine.destroy();
    }

    private void handleServerEvent(AoqClientEngine.AoqDataMsg msg) {
        if (msg == null || msg.data == null) {
            return;
        }
        JSONObject event = new JSONObject(new String(msg.data, StandardCharsets.UTF_8));
        JSONObject header = event.optJSONObject("header");
        if (header == null) {
            return;
        }

        String eventName = header.optString("event", "");
        if ("task-started".equals(eventName)) {
            taskStarted = true;
            engine.enableSendMediaStream(
                    AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, true);
        } else if ("result-generated".equals(eventName)) {
            handleRecognitionResult(event);
        } else if ("task-finished".equals(eventName)) {
            resetTaskState();
            resultListener.onTaskFinished();
        } else if ("task-failed".equals(eventName)) {
            String message = header.optString("error_message", "Recognition failed");
            resetTaskState();
            resultListener.onError(message);
        }
    }

    private void handleRecognitionResult(JSONObject event) {
        JSONObject payload = event.optJSONObject("payload");
        JSONObject output = payload == null ? null : payload.optJSONObject("output");
        JSONObject sentence = output == null ? null : output.optJSONObject("sentence");
        if (sentence == null || sentence.optBoolean("heartbeat", false)) {
            return;
        }
        String text = sentence.optString("text", "");
        if (!text.isEmpty()) {
            resultListener.onResult(text, sentence.optBoolean("sentence_end", false));
        }
    }

    private void resetTaskState() {
        engine.enableSendMediaStream(AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
        taskStarted = false;
        taskId = null;
    }

    private JSONObject createHeader(String action) {
        return new JSONObject()
                .put("action", action)
                .put("task_id", taskId)
                .put("streaming", "duplex");
    }

    private void send(JSONObject event) {
        AoqClientEngine.AoqDataMsg msg = new AoqClientEngine.AoqDataMsg();
        msg.data = event.toString().getBytes(StandardCharsets.UTF_8);
        engine.sendDataMsg(msg);
    }

    private static void addTrack(AoqClientEngine.AoqConnectConfig config, boolean publish,
                                 AoqClientEngine.AoqTrackType type) {
        AoqClientEngine.AoqTrackParam track = new AoqClientEngine.AoqTrackParam();
        track.trackType = type;
        if (publish) {
            config.publishTracks.add(track);
        } else {
            config.subscribeTracks.add(track);
        }
    }

    /** アプリケーションサーバーのトークンレスポンスを SDK 接続設定にマッピングします。 */
    public static AoqClientEngine.AoqConnectConfig parseConnectConfig(String responseText) {
        JSONObject response = new JSONObject(responseText);
        AoqClientEngine.AoqConnectConfig config = new AoqClientEngine.AoqConnectConfig();
        config.token = response.optString("aoqTokenForClient", "");
        config.sid = response.optString("sid", "");
        config.certFingerprint = response.optString("clientRelayCertFingerprint", "");

        JSONArray endpoints = response.optJSONArray("clientRelayEndpoints");
        if (endpoints != null) {
            for (int i = 0; i < endpoints.length(); i++) {
                JSONObject item = endpoints.optJSONObject(i);
                if (item == null) {
                    continue;
                }
                AoqClientEngine.AoqRelayEndpoint endpoint =
                        new AoqClientEngine.AoqRelayEndpoint();
                endpoint.routeIndex = item.has("route_index")
                        ? item.optInt("route_index", i) : i;
                endpoint.endpoint = item.optString("endpoint", "");
                endpoint.port = item.optInt("port", 0);
                config.relayEndpoints.add(endpoint);
            }
        }

        JSONObject extraInfo = response.optJSONObject("extraInfo");
        config.workspaceIdHash = extraInfo == null
                ? "" : extraInfo.optString("workspaceIdHash", "");
        return config;
    }
}

使用例

アプリケーションサーバーからのトークンレスポンスを parseConnectConfig に渡し、クライアントを作成してください。接続が確立された後、最初の認識タスクが自動的に開始されます。停止ボタンは現在のタスクのみを終了します。ページが破棄されたときに、接続とローカルリソースを解放してください。

private AsrClient client;

void startRecognition(Context context, String tokenResponseText) {
    AoqClientEngine.AoqConnectConfig config =
            AsrClient.parseConnectConfig(tokenResponseText);

    client = new AsrClient(context, config, new AsrClient.ResultListener() {
        @Override
        public void onResult(String text, boolean sentenceEnd) {
            // 部分的または最終的な文で UI を更新します。
        }

        @Override
        public void onTaskFinished() {
            // 開始ボタンを有効にするか、別のタスクのために beginRecognition() を呼び出します。
        }

        @Override
        public void onError(String message) {
            // エラーを表示またはログに記録します。
        }
    });
}

void onStopButtonClick() {
    // タスクを終了し、task-finished が到着するまで AOQ 接続を開いたままにしてください。
    client.finishRecognition();
}

void onPageDestroyed() {
    // ページが閉じられたときにのみローカルリソースを解放してください。
    client.close();
}

実行と検証

  1. アプリケーションサーバーを起動してください。トークンリクエストが HTTP 200 を返し、sid、aoqTokenForClient、clientRelayEndpoints、clientRelayCertFingerprint、extraInfo.workspaceIdHash が含まれていることを確認してください。
  2. Android デバイスにアプリをインストールして実行し、マイクへのアクセスを許可して、話してください。
  3. コールバックを観察してください。通常のイベントシーケンスは次のとおりです。
task-started
result-generated (sentence_end=false)
result-generated (sentence_end=true)
task-finished

話している間、部分的な文字起こしが返されます。finishRecognition が呼び出された後、現在の文の最終的な文字起こしと task-finished が返されます。finish-task を送信した直後に切断しないでください。

一般的なシナリオ

1つの接続で複数の認識タスクを実行

task-finished を受信した後、beginRecognition を呼び出して、同じ AOQ 接続で別のタスクを開始してください。各タスクには新しい task_id が必要です。接続がアクティブな間は、別のトークンをリクエストしたり、再接続したりする必要はありません。接続が閉じられた場合は、新しい接続認証情報を取得してください。

Androidでのバックグラウンド認識

Android 10 以降では、foregroundServiceType=microphone のフォアグラウンドサービスを使用して、アプリがバックグラウンドにある間もマイクキャプチャを続行してください。アプリがユーザーに表示されている間にサービスを開始してください。

トラブルシューティング

問題

ソリューション

接続に失敗する

トークンが有効であること、エンドポイントがアプリケーションリージョンと一致していること、アプリケーションサーバーがクライアントデバイスの実際のパブリック IP アドレスを渡していることを確認してください。接続が閉じられた後にトークンを再利用しないでください。

タスクは開始するが、文字起こしが返されない

task-started を受信した後にのみ、Audio トラックの送信を有効にしてください。入力形式、サンプルレート、その他のパラメータを、モデルの「クライアントイベント」と照合してください。

最終的な文字起こしが返されない

finish-task を送信する前に、Audio トラックの送信を無効にしてください。すぐに切断するのではなく、最終的な result-generated イベントと task-finished を待ってください。

Android SDK の読み込みに失敗する

AAR が依存関係として含まれていること、およびアプリが SDK がサポートする ABI (armeabi-v7a または arm64-v8a) をパッケージ化していることを確認してください。

同じ接続での後続のタスクが拒否される

前のタスクの task-finished を受信したことを確認し、次の run-task イベント用に新しい task_id を生成してください。

関連トピック

すべてのパラメータ、イベントフィールド、および他のプラットフォーム用の API については、次をご参照ください。