Use AOQ to connect to fun-asr-realtime for streaming microphone audio and receiving real-time speech recognition results. Client code examples use Android Java; other AOQ-supported platforms share the same interface.
Overview
fun-asr-realtime transcribes an audio stream into punctuated text in real time. The AOQ SDK separates media and events into distinct tracks: the client sends audio on the Audio track and exchanges control/recognition events on the Data track. This model uses the Inference event protocol rather than the Realtime event protocol.
This approach suits real-time captions, meeting transcription, voice input, and intelligent assistants. The Audio track avoids encoding audio into event messages, while the Data track preserves full task semantics such as run-task, result-generated, and finish-task.
- The client requests temporary AOQ connection credentials from the business AppServer.
- The AppServer uses an API Key to request a Token from QwenCloud, then returns the connection fields to the client.
- The client establishes an AOQ connection and sends run-task; after receiving task-started, it begins streaming microphone audio.
- The server continuously returns result-generated events; the client sends finish-task and waits for the final result and task-finished.
Prerequisites
- Activate QwenCloud and obtain an API Key following Get and configure an API Key. Keep the API Key only on the business AppServer -- never embed it in client code or commit it to a repository.
- Download the latest AOQ Client SDK as described in SDK download. This tutorial transports PCM audio and does not require the optional Opus plugin.
- Set up a business AppServer and implement AOQ Inference server-side proxy authentication as described in Token authentication. The client should obtain fresh connection credentials from the AppServer before each new connection.
Import the SDK
Choose the import method for your development platform. The following client implementation uses Android Java; other platforms share the same interface design and event flow.
- Android
- iOS
- HarmonyOS
- Linux (Python)
- Place AoqClientSdk-release.aar in the app/libs directory and configure the dependency and ABI filters in app/build.gradle:
- Declare network and recording permissions in AndroidManifest.xml:
- Request the RECORD_AUDIO permission at runtime before starting recording. Speech recognition alone does not require CAMERA permission.
Try the demo
QwenCloud provides an Android demo app to quickly verify AOQ connectivity. Download the APK and configure the API key and workspaceId to try selected models.
Scan the following QR code to download the demo:

Implementation flow
- The AppServer uses the Inference Token endpoint to obtain AOQ connection parameters for fun-asr-realtime.
- The client converts the Token response into an AoqConnectConfig, publishes Audio and Data tracks, and subscribes to the Data track.
- The client configures audio encoding parameters per business requirements and model specifications, starts microphone capture without sending audio, then establishes the AOQ connection.
- After connecting, the client sends run-task; upon receiving task-started, it enables Audio track sending.
- The client handles result-generated in onDataMsg; to end recording, it disables Audio track sending and then sends finish-task.
- After receiving task-finished, the client can start a new recognition round on the same connection with a new task_id, or disconnect and destroy the engine.

AppServer Token request
Set DASHSCOPE_API_KEY on the AppServer and send a request to the AOQ Inference Token endpoint. clientIp is the terminal's real public IP; this field is optional but recommended so the service can assign an appropriate Relay access point.
If the AppServer cannot determine the terminal's real public IP, remove the clientIp field from the request body entirely -- do not pass an empty string.
| Response field | SDK field |
|---|---|
| aoqTokenForClient | AoqConnectConfig.token |
| sid | AoqConnectConfig.sid |
| clientRelayCertFingerprint | AoqConnectConfig.certFingerprint |
| clientRelayEndpoints | AoqConnectConfig.relayEndpoints |
Implement the Android client
The following steps break down the Android Java client code in the order of connection and task execution. Each snippet comes from the complete example shown later.
1. Create the engine and set callbacks
Create the AOQ client engine and register connection status and Data track event callbacks. Implement callback handling per your business logic; start the recognition task only after a successful connection.
2. Configure audio encoding
Configure the audio encoding sent to the model. Set the format, sample rate, and channel count per your business requirements and model specifications. The following example uses 16 kHz mono PCM; for supported ranges, see the run-task parameters in Client events.
3. Configure connection and transport tracks
Configure the AOQ connection using the credentials returned by the AppServer, and choose which tracks to publish and subscribe. The following code publishes Audio and Data tracks and subscribes to the Data track for real-time speech recognition.
4. Start audio capture and connect
Configure audio capture and establish the AOQ connection. Choose built-in or external capture, VoIP mode, and channel count per your business needs. Keep Audio track sending disabled until task-started is received.
5. Start the recognition task
After connecting, generate a task ID and send run-task to start recognition. Configure model, format, sample_rate, and other task parameters per your model and audio input. For full parameter descriptions, see Client events.
6. Handle server events
Handle task status, recognition results, and error events, passing results to the business layer. Implement callback logic per your application's display and state management needs; send audio only after receiving task-started and filter heartbeat events when displaying results. For full response structures, see Server events.
7. End the recognition task
When the user finishes the current recording session, stop audio uplink and send finish-task. Keep the connection open until the final recognition result and task-finished are received; then start a new task or release the connection as needed. For event formats, see Client events.
8. Disconnect and destroy the engine
When the page is destroyed or recognition is no longer needed, release audio capture, the AOQ connection, and engine resources. Choose the release timing per your application lifecycle -- do not release immediately after sending finish-task.
Complete example
This Android Java class converts the AppServer's JSON response into an AoqConnectConfig and combines the connection, capture, task, and resource release logic described above.
AsrClient.java full code
AsrClient.java full code
Usage example
Pass the AppServer's Token response to parseConnectConfig, then create the client. Recognition starts automatically after the first successful connection. The stop button only ends the current task; release the connection and local resources only when the page is destroyed.
Run and verify
- Start the AppServer. Confirm the Token request returns HTTP 200 with sid, aoqTokenForClient, clientRelayEndpoints, and clientRelayCertFingerprint.
- Install and run the app on an Android device, grant microphone permission, and speak.
- Observe the callbacks. The normal event sequence is:
Common scenarios
Multiple recognition rounds on a single connection
After receiving task-finished, call beginRecognition to start the next recognition round on the same AOQ connection. Each round must use a new task_id. There is no need to request a new Token or rebuild the connection; however, if the connection has already been dropped, you must obtain new credentials.
Android background recognition
On Android 10 and above, to continue capturing microphone audio after the app enters the background, use a foreground service with foregroundServiceType=microphone and start the service while the app is still visible to the user.
FAQ
| Problem | Solution |
|---|---|
| Connection fails | Confirm the Token has not expired and check whether the AppServer is passing the terminal's real public IP. Do not reuse an old Token after disconnection. |
| Task started but no recognition results | Confirm Audio track sending is enabled only after receiving task-started, and verify the audio format, sample rate, and other input parameters per the model's Client events. |
| No final result received | Disable Audio track sending before sending finish-task; wait for the final result-generated and task-finished -- do not disconnect immediately. |
| Android SDK fails to load | Confirm the AAR is included as a dependency and the app packages only SDK-supported ABIs (armeabi-v7a or arm64-v8a). |
| Next task on the same connection is rejected | Confirm the previous round received task-finished, and generate a new task_id for the new run-task. |