Reconhecimento de fala em tempo real com o AOQ + fun-asr-realtime
Use o QOA para se conectar fun-asr-realtime para transmitir áudio de microfone e receber resultados de reconhecimento de fala em tempo real. Exemplos de código de cliente usam Android Java; outras plataformas suportadas pelo AOQ compartilham a mesma interface.
Visão geral
fun-asr-realtime transcreve um fluxo de áudio em texto pontuado em tempo real. O SDK do AOQ separa mídia e eventos em faixas distintas: o cliente envia áudio na faixa de áudio e troca de controle/reconhecimento de eventos na faixa de dados. Este modelo usa o protocolo de eventos de inferência em vez do protocolo de eventos em tempo real.
Esta abordagem se adequa a legendas em tempo real, transcrição de reuniões, entrada de voz e assistentes inteligentes. A faixa de áudio evita codificar áudio em mensagens de eventos, enquanto a faixa de dados preserva semântica de tarefas completas, como tarefas de execução, resultados gerados e tarefas de finalização.
- O cliente pede credenciais temporárias de conexão do AppServer.
- O AppServer usa uma chave API para solicitar um Token de QwenCloud, então retorna os campos de conexão para o cliente.
- O cliente estabelece uma conexão AOQ e envia uma tarefa de execução, após receber a tarefa iniciada, começa a transmitir áudio do microfone.
- O servidor retorna continuamente eventos gerados por resultados, o cliente envia tarefas finais e espera pelo resultado final e finalizado.
Pré-requisitos
- Ativar QwenCloud e obter uma chave API seguindo [Obter e configurar uma chave API] (/api-reference/preparation/api-key). Mantenha a chave API apenas no AppServer de negócios -- nunca incorpore em código de cliente ou compromete-a em um repositório.
- Baixe o mais recente cliente do AOQ SDK como descrito em [SDK download] (/api-reference/realtime-api/sdk-download). Este tutorial transporta áudio Opus e requer o plugin Opus.
- Configure um AppServer de negócios e implemente a autenticação de proxy do lado do servidor de inferência AOQ, conforme descrito em Autenticação do Token. O cliente deve obter novas credenciais de conexão do AppServer antes de cada nova conexão.
Importar o SDK
Escolha o método de importação para sua plataforma de desenvolvimento. A implementação do cliente seguinte usa o Android Java, outras plataformas compartilham o mesmo design de interface e fluxo de eventos.
Android
1. Coloque a libPluginOpus.so do plugin Opus em app/src/main/jniLibs/armeabi-v7a/ e app/src/main/jniLibs/arm64-v8a/ para os ABIs correspondentes. Coloque AoqClientSdk-release.aar no diretório app/libs e configure a dependência e os filtros ABI em app/build.gradle:
```groovy
android {
defaultConfig {
minSdk 21
ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' }
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.aar'])
}
```
2. Declare a rede e as permissões de gravação no AndroidManifest.xml:
```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" />
```
3. Peça permissão para gravar antes de começar a gravação. Reconhecimento de fala sozinho não requer permissão da CÂMERA.
iOS
1. Arraste o AoqClientSdk.framework e o PluginOpus.framework para seu projeto Xcode e selecione Incorporar e Iniciar o Alvo > Geral > Frameworks, Bibliotecas e Conteúdo Incorporado. O SDK suporta dispositivos iOS 13.0+ arm64.
2. Adicione NSMicrophoneUsageDescription para Info.plist. Reconhecimento de fala sozinho não requer NSCameraUsageDescription.
3. Para projetos Swift, use `import AoqClientSdk`; para o objetivo-C, use `#import <AoqClientSdk/AoqClientSdk.h>`.
HarmonyOS
1. Coloque libPluginOpus.so do plugin Opus em entrada/libs/arm64-v8a/. Coloque AoqClientSdk.har em entrada/libs e declare a dependência em entrada/oh-pacote.json5. O SDK é compatível com API 12 e suporta arm64-v8a:
```json
{
"dependencies": {
"@aoq/client-sdk": "file:./libs/AoqClientSdk.har"
}
}
```
2. Declare permissão de rede e microfone em entrada/src/main/module.json5:
```json
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" },
{
"name": "ohos.permission.MICROPHONE",
"reason": "$string:perm_mic_reason",
"usedScene": { "abilities": ["EntryAbility"], "when": "inuse" }
}
]
```
3. Abilidade de chamadaAccessCtrl.createAtManager().PedidoPermissões do Usuário para solicitar permissão do microfone antes de iniciar a gravação.
Linux (Python)
1. Extrair o SDK e manter aoq\_client\_sdk.py, libAoqClientSdk.so, e libonnxruntime.so.1.16.3 no mesmo diretório.
2. Adicione o diretório SDK aos caminhos de pesquisa de bibliotecas dinâmicas e Python:
```bash
export PYTHONPATH="$PWD/AoqClientSdk:$PYTHONPATH"
export LD_LIBRARY_PATH="$PWD/AoqClientSdk:$LD_LIBRARY_PATH"
```
3. Importar em seu código Python com `import aoq_client_sdk`. Alternativamente, especifique o caminho absoluto para a variável de ambiente libAoqClientSdk.so via AOQ\_CLIENT\_SDK\_LIB.
Tente a demo.
QwenCloud fornece um aplicativo de demonstração Android para verificar rapidamente conectividade AOQ. Baixe o APK e configure a chave da API e workspaceId para tentar modelos selecionados.
Analise o seguinte código QR para baixar a demonstração:
[Código QR para baixar a demo] (https://g-adoc.alcasset.com/media/maas_docs/sfm/common/images/6a4b3c2d1e0f92cc.png)
Fluxo de implementação
- O AppServer usa o ponto final do Token para obter parâmetros de conexão AOQ para fun-asr-realtime.
- O cliente converte a resposta Token em uma AoqConnectConfig, publica faixas de áudio e dados, e assina a faixa de dados.
- O cliente configura parâmetros de codificação de áudio por requisitos de negócios e especificações de modelos, inicia a captura de microfone sem enviar áudio, e estabelece a conexão AOQ.
- Após a conexão, o cliente envia tarefas de execução, ao receber tarefas iniciadas, ele permite o envio de áudio.
- O cliente lida com resultados gerados no DataMsg, para terminar a gravação, ele desativa o envio de áudio e então envia tarefas finais.
- Após receber a tarefa finalizada, o cliente pode iniciar uma nova rodada de reconhecimento na mesma conexão com uma nova tarefa, ou desconectar e destruir o motor.
[aoq-realtime-asr-sequence-zh] (http://icms-x-dita-hz.oss-cn-hangzhou.aliyuncs.com/zh-CN/images/p1094760.png)
Pedido do AppServer Token
Defina DASHSCOPE_API_KEY no AppServer e envie uma solicitação para o ponto final do AOQ Inference Token. clientIp é o IP público real do terminal; este campo é opcional, mas recomendado para que o serviço possa atribuir um ponto de acesso adequado ao Relay.
curl -X POST \
"https://maas.qwencloudapi.com/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}\"}"
Se o AppServer não puder determinar o IP público real do terminal, remova o campo clienteIp do corpo de solicitação inteiramente -- não passe uma string vazia.
Devolva os seguintes campos de resposta do AppServer ao cliente. Nunca devolva a chave API para o cliente em produção. Para os parâmetros completos de solicitação e campos de resposta, veja Autenticação do Token.
| Campo de resposta. | Campo SDK |
|---|---|
| AoqTokenForClient | AoqConnectConfig.token |
| Sid. | AoqConnectConfig.sid |
| CLIENTE RELAYCertFingerprint | AoqConnectConfig.certFingerprint |
| CLIENTE RELAYEndpoints | AoqConnectConfig.relayEndpoints |
| ExtraInfo. Espaço de trabalhoIdHash | AoqConnectConfig. Espaço de trabalhoIdHash |
Implemente o cliente Android
Os passos seguintes quebram o código do cliente Android Java na ordem de conexão e execução de tarefas. Cada trecho vem do exemplo completo mostrado mais tarde.
1. Crie o motor e ajuste as chamadas.
Crie o motor do cliente do AOQ e registre o status de conexão e os dados de retorno de eventos. Implementar o tratamento de retorno de chamadas de acordo com sua lógica de negócios, iniciar a tarefa de reconhecimento apenas após uma conexão bem sucedida.
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);
- Dois. Configurar codificação de áudio
Configure a codificação de áudio enviada para o modelo. Defina o formato, taxa de amostragem e contagem de canais de acordo com seus requisitos de negócios e especificações de modelos. O exemplo a seguir usa o mono Opus de 16 kHz; para intervalos suportados, veja os parâmetros de execução em Eventos do cliente.
AoqClientEngine.AoqAudioCodecConfig encoder =
new AoqClientEngine.AoqAudioCodecConfig();
encoder.trackType = AoqClientEngine.AoqTrackType.AoqTrackTypeAudio;
encoder.codecType = AoqClientEngine.AoqEncoderType.AoqEncoderTypeAudioOpus;
encoder.sampleRate = 16000;
encoder.channel = 1;
encoder.bitrate = 24000;
engine.setAudioEncoderConfig(encoder);
3. Configure conexões e rotas de transporte.
Configure a conexão do AOQ usando as credenciais devolvidas pelo AppServer, e escolha quais faixas publicar e assinar. O seguinte código publica faixas de áudio e dados e assina a faixa de dados para reconhecimento de fala em tempo real.
addTrack(connectConfig, true,
AoqClientEngine.AoqTrackType.AoqTrackTypeAudio);
addTrack(connectConfig, true,
AoqClientEngine.AoqTrackType.AoqTrackTypeData);
addTrack(connectConfig, false,
AoqClientEngine.AoqTrackType.AoqTrackTypeData);
- Quatro. Comece a captura de áudio e conecte-se.
Configure a captura de áudio e estabeleça a conexão do QAO. Escolha captura integrada ou externa, modo VoIP e contagem de canais para suas necessidades de negócios. Mantenha o áudio desactivado até que a tarefa seja recebida.
AoqClientEngine.AoqAudioCaptureConfig capture =
new AoqClientEngine.AoqAudioCaptureConfig();
capture.isExternal = false;
capture.isVoipMode = true;
capture.channel = 1;
engine.startAudioCapture(capture);
// Do not send audio until task-started is received.
engine.enableSendMediaStream(
AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
engine.connect(connectConfig);
- Cinco. Comece a tarefa de reconhecimento.
Depois de se conectar, gere uma tarefa de identificação e envie uma tarefa de execução para começar o reconhecimento. Configure o modelo, formato, amostra e outros parâmetros de tarefa por modelo e entrada de áudio. Para descrições completas dos parâmetros, veja [Eventos do cliente] (/api-reference/qwen-audio-realtime/client-events).
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));
Seis. Lidar com eventos de servidores
Lidar com status de tarefa, resultados de reconhecimento e eventos de erro, passando resultados para a camada de negócios. Implemente lógica de retorno de chamadas de acordo com as necessidades de gerenciamento de estado e exibição de sua aplicação; envie áudio somente após receber eventos cardíacos iniciados e filtrar quando exibir resultados. Para estruturas de resposta completa, veja [Eventos de servidor] (/api-reference/qwen-audio-realtime/server-events).
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? - 7? Termine a tarefa de reconhecimento.
Quando o usuário terminar a sessão de gravação atual, pare o link de áudio e envie a tarefa final. Mantenha a conexão aberta até que o resultado final de reconhecimento e finalização da tarefa sejam recebidos, e comece uma nova tarefa ou libere a conexão conforme necessário. Para formatos de eventos, veja [Eventos do cliente] (/api-reference/qwen-audio-realtime/client-events).
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));
Oito. Desligue e destrua o motor.
Quando a página for destruída ou o reconhecimento não for mais necessário, libere a captura de áudio, a conexão com o AOQ e os recursos do motor. Escolha o tempo de lançamento por seu ciclo de vida da aplicação. Não solte imediatamente após enviar a tarefa final.
engine.enableSendMediaStream(
AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
engine.stopAudioCapture();
engine.disconnect();
AoqClientEngine.destroy();
Exemplo completo.
Esta classe Java do Android converte a resposta JSON do AppServer em uma AoqConnectConfig e combina a lógica de conexão, captura, tarefa e liberação de recursos descrita acima.
AsrClient.java full code
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.AoqEncoderTypeAudioOpus;
encoder.sampleRate = 16000;
encoder.channel = 1;
encoder.bitrate = 24000;
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);
}
/** Start a new recognition task on the existing AOQ connection. */
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));
}
/** End the current task. Wait for task-finished before disconnecting. */
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);
}
}
/** Convert the AppServer Token response into an SDK connection config. */
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;
}
}
Exemplo de uso
Passe a resposta do AppServer Token para a ParseConnectConfig, e então crie o cliente. Reconhecimento começa automaticamente após a primeira conexão bem sucedida. O botão de parada só termina a tarefa atual; solte a conexão e os recursos locais apenas quando a página é destruída.
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) {
// Update UI with intermediate or final sentence.
}
@Override
public void onTaskFinished() {
// Enable start button, or call beginRecognition() for a new task.
}
@Override
public void onError(String message) {
// Display or log the error.
}
});
}
void onStopButtonClick() {
// End the current task while keeping the AOQ connection until task-finished.
client.finishRecognition();
}
void onPageDestroyed() {
// Release local resources only when the page closes.
client.close();
}
Corra e verifique.
- Ligue o AppServer. Confirme que a solicitação Token retorna HTTP 200 com sid, aoqTokenForClient, clienteRelayEndpoints, clienteRelayCertFingerprint, e extraInfo.workspaceIdHash.
- Instale e execute o aplicativo em um dispositivo Android, conceda permissão ao microfone e fale.
- Observe as chamadas. A sequência normal de eventos é:
task-started
result-generated (sentence_end=false)
result-generated (sentence_end=true)
task-finished
Você deve receber o texto de reconhecimento intermediário continuamente enquanto fala. Depois de chamar o fim de reconhecimento, você deve receber o texto final para a sentença atual seguido de tarefa terminada. Não desligue imediatamente após enviar a tarefa final.
Cenários comuns
Múltiplas rodadas de reconhecimento em uma única conexão.
Após receber a tarefa finalizada, comece a chamar a reconhecer para começar a próxima rodada de reconhecimento na mesma conexão do QAO. Cada rodada deve usar uma nova tarefa. Não há necessidade de pedir um novo Token ou reconstruir a conexão, mas se a conexão já foi descartada, você deve obter novas credenciais.
Reconhecimento de fundo Android
No Android 10 ou mais, para continuar capturando áudio do microfone depois que o aplicativo entrar em segundo plano, use um serviço de primeiro plano com primeiro planoServiceType=microfone e comece o serviço enquanto o aplicativo ainda está visível para o usuário.
FAQ
| Problema. | Solução |
|---|---|
| A conexão falhou. | Confirme se o Token não expirou e verifique se o AppServer está passando o IP público do terminal. Não reutilize um velho Token após a desconexão. |
| A tarefa começou, mas sem resultados de reconhecimento. | Confirmar envio de áudio só é ativado após receber a tarefa iniciada, e verificar o formato de áudio, taxa de amostragem, e outros parâmetros de entrada por o modelo Eventos de clientes. |
| Nenhum resultado final recebido. | Desativar o envio de áudio antes de enviar a tarefa final; esperar pelo resultado final gerado e finalizado -- não desconectar imediatamente. |
| Android SDK não carrega | Confirme que o AAR está incluído como dependência e os pacotes de aplicativos só são ABIs suportados por SDK (armeabi-v7a ou arm64-v8a). |
| A próxima tarefa na mesma conexão é rejeitada. | Confirme a rodada anterior recebida finalizada, e gere uma nova tarefa para a nova tarefa. |
Documentação relacionada
Para detalhes de parâmetros completos, campos de eventos e outras interfaces de plataforma, veja:
- [Consiga e configure uma chave API] (/api-reference/preparation/api-key)
- [ Introdução SDK] (/api-reference/realtime-api/aoq-sdk-intro)
- [SDK download] (/api-reference/realtime-api/sdk-download)
- [Autenticação do token] (/api-reference/realtime-api/token-auth)
- [Reconhecimento de fala em tempo real] (/api-reference/speech-recognition/fun-asr-realtime/python-sdk)
- [Acontecimentos do cliente] (/api-reference/qwen-audio-realtime/client-events)
- [Eventos de servidor] (/api-reference/qwen-audio-realtime/server-events)