QwenCloudBRASIL
Tradução de apoio para consulta. Código e identificadores técnicos preservados. Consultar referência original ↗

Construir conversas de voz com qwen3.8-omni-flash-realtime sobre o AOQ

Use o QOA para se conectar qwen3.8-omni-flash-realtime E deixar o cliente controlar os limites para conversas de push-to-talk e perguntas de imagem opcionais. O código do cliente usa iOS Swift.

Visão geral da solução

Qwen-Omni-Realtime suporta VAD do lado do servidor e modo manual controlado pelo cliente. Este tutorial define sessão.turn_detection como null. O cliente envia áudio enquanto o usuário segura um botão, e comprime o áudio e explicitamente solicita uma resposta quando o usuário libera o botão.

Modo manual é adequado para botões de hardware intercomunicadores, controles de pressão e retenção, ambientes barulhentos em que a aplicação determina limites de giro, e gira que opcionalmente incluem uma imagem. O áudio é transportado pela faixa de áudio do AOQ. Não envie entrada, entrada, entrada, entrada, entrada.

Item Modo VAD Modo manual
Vire o limite. Detectado por servidor_vad ou semântica_vad Controlado por um botão ou estado de aplicação
Sessão de configuração Turn_Detection contém configurações de DAV A detecção de turnos é nula.
Commit de áudio Realizado automaticamente pelo serviço O cliente envia entrada_audio_buffer.commit
- Ativador de resposta. Acionado automaticamente pelo serviço. O cliente envia resposta.
Entrada da imagem Track vídeo contínuo ou uma imagem sobre a faixa de dados Track vídeo contínuo ou uma imagem sobre a faixa de dados

Pré-requisitos

  1. Ativar QwenCloud e obter uma chave API seguindo [Obter e configurar uma chave API] (/api-reference/preparation/api-key). Guarde a chave da API apenas no servidor de aplicativos. Não inclua em código de cliente ou o entregue em um repositório de códigos.
  2. Baixe o mais recente cliente do AOQ SDK como descrito em [SDK download] (/api-reference/realtime-api/sdk-download).
  3. Construa um servidor de aplicativos e implemente a autenticação proxy como descrito em Autenticação do Token. Antes de cada nova conexão, o cliente deve obter novas credenciais de conexão do servidor de aplicativos.

Importar o SDK

Importar o SDK para sua plataforma de desenvolvimento. A implementação do cliente usa iOS Swift. Outras plataformas fornecem as mesmas interfaces e fluxo de eventos. Este tutorial usa fluxos de áudio Opus. Importar o plugin Opus antes de prosseguir.

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 em app/libs, e configure a dependência e ABIs suportados por SDK em app/build.gradle:

```groovy
android {
  defaultConfig {
    minSdk 21
    ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' }
  }
}
dependencies {
  implementation fileTree(dir: 'libs', include: ['*.aar'])
}
```

2. Declare as seguintes permissões 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" />
<uses-permission android:name="android.permission.CAMERA" />
```

3.  Solicitar permissão de registro e câmera antes de usar os dispositivos correspondentes.

iOS

1.  Adicione AoqClientSdk.framework e PluginOpus.framework ao projeto Xcode e selecione Incorporar e assinar em Target > General > Frameworks, Bibliotecas e Conteúdo Incorporado. O SDK suporta dispositivos arm64 rodando iOS 13.0 ou posterior.
2.  Adicione NSMicrophoneUsageDescription e NSCameraUsageDescription para Info.plist e solicite autorização antes dos dispositivos correspondentes serem usados.
3. Use `import AoqClientSdk` em Swift ou `#import <AoqClientSdk/AoqClientSdk.h>` no Objetivo-C.

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 as seguintes permissões 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" } },
  { "name": "ohos.permission.CAMERA",
    "reason": "$string:perm_camera_reason",
    "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" } }
]
```

3.  Antes que os dispositivos correspondentes sejam usados, ligue para `abilityAccessCtrl.createAtManager().requestPermissionsFromUser` para pedir `ohos.permission.MICROPHONE` e `ohos.permission.CAMERA`.

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. Use `import aoq_client_sdk` em Python.  Você também pode especificar o caminho absoluto da libAoqClientSdk.so usando `AOQ_CLIENT_SDK_LIB`.

Fluxo de implementação

  1. O servidor de aplicativos obtém parâmetros de conexão AOQ para qwen3.8-omni-flash-realtime da URL do símbolo em tempo real.
  2. O cliente cria o motor e configura codecs e faixas de áudio. Também configura a faixa de vídeo se for necessário um entendimento visual contínuo.
  3. O cliente inicia a captura e reprodução local, desativa o envio de áudio por padrão, conecta-se ao AOQ e envia session.update.
  4. Após a sessão. A atualização é recebida, a opção de vídeo contínuo permite a faixa de vídeo. A faixa de áudio permanece desativada até o usuário apertar o botão de falar.
  5. Quando o usuário aperta o botão, o cliente ativa a faixa de áudio. Quando é lançado, ele desativa a faixa de áudio, envia uma imagem opcionalmente, e então envia entrada_audio_buffer.commit e response.create.
  6. Depois da resposta. Feito é recebido, outra volta pode começar. Para terminar, pare os dispositivos, desligue e destrua o motor.

Continuous Video track

Publique a faixa de vídeo e habilite o envio de vídeo após a sessão. O modelo vê continuamente as últimas molduras.  Cada voz gira só precisa fazer áudio e pedir uma resposta.

[Diagrama de sequência para modo manual AOQ com transmissão contínua de vídeo] (http://icms-x-dita-hz.oss-cn-hangzhou.aliyuncs.com/en-US/images/p1094863.png)

Send an image over the Data track

 Não publique a faixa de vídeo.  Quando uma imagem é necessária, envie entrada\_image\_buffer.append após o botão ser liberado, e então commita o áudio e peça uma resposta.

[Diagrama de sequência para enviar imagens sob demanda no modo manual AOQ] (http://icms-x-dita-hz.oss-cn-hangzhou.aliyuncs.com/en-US/images/p1094864.png)

Obter um token do servidor de aplicativos

Defina DASHSCOPE_API_KEY no servidor de aplicativos e envie o pedido para o ponto final. clientIp é o endereço IP público do cliente. Este campo é opcional, mas especificando que ajuda o serviço alocar um ponto final adequado.

curl -X POST \
  "https://maas.qwencloudapi.com/api/v1/webrtc/realtime?model=qwen3.8-omni-flash-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 servidor de aplicativos não conseguir o endereço IP público do cliente, omita. clientIp em vez de passar uma corda vazia.

O servidor de aplicativos devolve os seguintes campos de resposta ao cliente. Nunca devolva a chave da API para um cliente em produção. Para todos os campos de solicitação e resposta, veja [Autenticação do Token] (/api-reference/realtime-api/token-auth).

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 iOS

Depois que o cliente obter AoqConnectConfig do servidor de aplicativos, siga estes passos para implementar conversas de voz push-to-talk no iOS.

1. Crie o motor e registre chamadas de retorno

Crie o motor de som único e registre o objeto de aplicação como o receptor de retorno. Lide com estados de conexão, eventos de servidores, erros e avisos nas chamadas.

let createConfig = AoqCreateConfig()
createConfig.workDir = workDir
engine = AoqClientEngine.createEngine(createConfig, delegate: self)

- Dois. Iniciem os dispositivos de áudio e vídeo.

Inicialize a captura e reprodução de áudio. Ligue a câmera apenas para a opção de vídeo contínuo. Obter permissão de microfone e câmera antes que esses métodos sejam chamados.

let captureConfig = AoqAudioCaptureConfig()
captureConfig.channel = 1
captureConfig.isExternal = false
engine.startAudioCapture(captureConfig)
let playbackConfig = AoqAudioPlaybackConfig()
playbackConfig.channel = 1
playbackConfig.isExternal = false
playbackConfig.isDefaultSpeaker = true
engine.startAudioPlayer(playbackConfig)

3. Configure codecs e facas

Configure os codecs de áudio para o modelo selecionado e o formato de áudio do aplicativo, e selecione faixas para a opção de entrada de imagem. Os seguintes valores de áudio e vídeo são exemplos. Ajuste-os para os requisitos do modelo e cenário de aplicação. Desativar o envio de áudio antes da conexão ser estabelecida.

Continuous Video track

 Configure as faixas de áudio, vídeo e dados.  Ajuste as configurações de codificação de vídeo para a qualidade de imagem necessária e largura de banda disponível.

```swift
let audioEncoderConfig = AoqAudioCodecConfig()
audioEncoderConfig.trackType = .audio
audioEncoderConfig.codecType = .audioOpus
audioEncoderConfig.sampleRate = 16_000
audioEncoderConfig.channel = 1
engine.setAudioEncoderConfig(audioEncoderConfig)
let audioDecoderConfig = AoqAudioCodecConfig()
audioDecoderConfig.trackType = .audio
audioDecoderConfig.codecType = .audioOpus
audioDecoderConfig.sampleRate = 24_000
audioDecoderConfig.channel = 1
engine.setAudioDecoderConfig(audioDecoderConfig)
let videoEncoderConfig = AoqVideoCodecConfig()
videoEncoderConfig.trackType = .video
videoEncoderConfig.codecType = .videoJpeg
videoEncoderConfig.width = 960
videoEncoderConfig.height = 540
videoEncoderConfig.fps = 2
videoEncoderConfig.bitrate = 500_000
engine.setVideoEncoderConfig(videoEncoderConfig)
let publishAudioTrack = AoqTrackParam()
publishAudioTrack.trackType = .audio
let publishVideoTrack = AoqTrackParam()
publishVideoTrack.trackType = .video
let publishDataTrack = AoqTrackParam()
publishDataTrack.trackType = .data
let subscribeAudioTrack = AoqTrackParam()
subscribeAudioTrack.trackType = .audio
let subscribeDataTrack = AoqTrackParam()
subscribeDataTrack.trackType = .data
connectConfig.publishTracks = [publishAudioTrack, publishVideoTrack, publishDataTrack]
connectConfig.subscribeTracks = [subscribeAudioTrack, subscribeDataTrack]
```

Send an image over the Data track

 Configure apenas as faixas de áudio e dados.  Não configure um codificador de vídeo, que evite a captura, codificação e transmissão contínuas de vídeo.  Os valores de áudio são exemplos.

```swift
let audioEncoderConfig = AoqAudioCodecConfig()
audioEncoderConfig.trackType = .audio
audioEncoderConfig.codecType = .audioOpus
audioEncoderConfig.sampleRate = 16_000
audioEncoderConfig.channel = 1
engine.setAudioEncoderConfig(audioEncoderConfig)
let audioDecoderConfig = AoqAudioCodecConfig()
audioDecoderConfig.trackType = .audio
audioDecoderConfig.codecType = .audioOpus
audioDecoderConfig.sampleRate = 24_000
audioDecoderConfig.channel = 1
engine.setAudioDecoderConfig(audioDecoderConfig)
let publishAudioTrack = AoqTrackParam()
publishAudioTrack.trackType = .audio
let publishDataTrack = AoqTrackParam()
publishDataTrack.trackType = .data
let subscribeAudioTrack = AoqTrackParam()
subscribeAudioTrack.trackType = .audio
let subscribeDataTrack = AoqTrackParam()
subscribeDataTrack.trackType = .data
connectConfig.publishTracks = [publishAudioTrack, publishDataTrack]
connectConfig.subscribeTracks = [subscribeAudioTrack, subscribeDataTrack]
```

Depois que a conexão for estabelecida, ligue para enviar DataMsg para enviar um evento de atualização. Ajuste a volta para anular e selecione as modalidades de voz, instruções e saída para sua aplicação. Mantenha os parâmetros de áudio do exemplo consistentes com as configurações do codec SDK. Para todos os campos, veja [Eventos do cliente] (/api-reference/real-time-multimodal/client-events).

private func sendSessionUpdate() {
    let event: [String: Any] = [
        "type": "session.update",
        "session": [
            "modalities": ["text", "audio"],
            "voice": "Tina",
            "audio": [
                "input": ["format": ["type": "pcm", "sample_rate": 16_000]],
                "output": ["format": ["type": "pcm", "sample_rate": 24_000]]
            ],
            "turn_detection": NSNull()
        ]
    ]
    guard let data = try? JSONSerialization.data(withJSONObject: event) else { return }
    let dataMessage = AoqDataMsg()
    dataMessage.data = data
    engine.sendDataMsg(dataMessage)
}

- Cinco. Espere pela configuração da sessão.

Lide com a sessão. Atualizado evento na chamada onDataMsg. Não enviem a mídia até que este evento seja recebido. Para a opção de vídeo contínuo, ligue para ativar o sinal de vídeo neste momento, mas mantenha a faixa de áudio desativada para que o áudio antes que o usuário pressione o botão não entre no buffer de entrada.

func onDataMsg(_ msg: AoqDataMsg) {
    guard let event = try? JSONSerialization.jsonObject(with: msg.data) as? [String: Any],
          let type = event["type"] as? String else { return }
    if type == "session.updated", imageMode == .continuousVideo {
        engine.enableSendMediaStream(.video, enable: true)
    }
    // Keep Audio-track sending disabled until the talk button is pressed.
}

Seis. Implementar interação de push-to-talk

Quando o botão é pressionado, a chamada habilita o SendMediaStream para ativar a faixa de áudio. Na liberação, a chamada habilita oSendMediaStream para desativar a faixa de áudio, certifique-se de que a volta contenha áudio, envie uma imagem opcionalmente, e ligue para o sendDataMsg para enviar entrada_audio_buffer.commit seguido de resposta.criar.

func onPushToTalkPressed() {
    hasAudioInCurrentTurn = true
    engine.enableSendMediaStream(.audio, enable: true)
}
func onPushToTalkReleased(base64Jpeg: String? = nil) {
    engine.enableSendMediaStream(.audio, enable: false)
    guard hasAudioInCurrentTurn else { return }
    if imageMode == .singleImage, let base64Jpeg {
        let imageEvent: [String: Any] = [
            "type": "input_image_buffer.append",
            "image": base64Jpeg
        ]
        if let data = try? JSONSerialization.data(withJSONObject: imageEvent) {
            let dataMessage = AoqDataMsg()
            dataMessage.data = data
            engine.sendDataMsg(dataMessage)
        }
    }
    for event in [
        ["type": "input_audio_buffer.commit"],
        ["type": "response.create"]
    ] {
        guard let data = try? JSONSerialization.data(withJSONObject: event) else { continue }
        let dataMessage = AoqDataMsg()
        dataMessage.data = data
        engine.sendDataMsg(dataMessage)
    }
    hasAudioInCurrentTurn = false
}

- 7? - 7? Selecione uma opção de entrada de imagem

A compreensão visual contínua e as perguntas ocasionais de imagem usam diferentes configurações de trilhas e enviam comportamento. Selecione uma opção baseada em largura de banda, consumo de energia e design de interação.

Continuous Video track

Use esta opção para chamadas de vídeo, mudanças rápidas de cenas, ou contexto visual contínuo.  Depois que a faixa de vídeo for publicada, não envie entrada\_image\_buffer.append.

Send a single image over the Data track

Use esta opção para perguntas de imagem ou imagens ocasionais. Converta a imagem para JPG ou JPEG, base64-codificá-la, e enviá-la após o botão é liberado e antes que o áudio é committed:

```json
{
  "type": "input_image_buffer.append",
  "image": "<Base64-encoded JPEG data>"
}
```

- Use 480p ou 720p para melhor desempenho.  Não exceda 1080p.
- A imagem codificada pela Base64 não pode exceder 256 KB.  Mantenha a imagem de origem abaixo de 190 KB e reserve espaço para o papel JSON.
- A faixa de áudio deve ter enviado pelo menos um quadro de áudio na volta antes da imagem ser enviada. O evento de entrada seguinte\_audio\_buffer.commit commits both audio and image buffers.

Oito. Desligue e destrua o motor.

Quando a sessão terminar, desligue e destrua o motor. Desligue ou destrua automaticamente dispositivos de mídia, então não precisa chamar os métodos de parada separadamente. AoqClientEngine é um singleton e não pode ser criado de novo até que a destruição seja chamada.

engine.disconnect()
AoqClientEngine.destroy()

Exemplo completo.

A seguinte classe aceita um AoqConnectConfig que foi mapeado a partir da resposta do servidor de aplicativos. Adicione estado de UI, permissões, recuperação de erros e compressão de imagem na produção.

import Foundation
import AoqClientSdk
final class ManualPushToTalkClient: NSObject, AoqEngineDelegate {
    enum ImageMode: Equatable {
        case none
        case continuousVideo
        case singleImage
    }
    private var engine: AoqClientEngine!
    private let imageMode: ImageMode
    private var hasAudioInCurrentTurn = false
    init(workDir: String, connectConfig: AoqConnectConfig, imageMode: ImageMode) {
        self.imageMode = imageMode
        super.init()
        let createConfig = AoqCreateConfig()
        createConfig.workDir = workDir
        self.engine = AoqClientEngine.createEngine(createConfig, delegate: self)
        // Example values. Match these settings to the selected model and application format.
        let audioEncoderConfig = AoqAudioCodecConfig()
        audioEncoderConfig.trackType = .audio
        audioEncoderConfig.codecType = .audioOpus
        audioEncoderConfig.sampleRate = 16_000
        audioEncoderConfig.channel = 1
        engine.setAudioEncoderConfig(audioEncoderConfig)
        let audioDecoderConfig = AoqAudioCodecConfig()
        audioDecoderConfig.trackType = .audio
        audioDecoderConfig.codecType = .audioOpus
        audioDecoderConfig.sampleRate = 24_000
        audioDecoderConfig.channel = 1
        engine.setAudioDecoderConfig(audioDecoderConfig)
        let publishAudioTrack = AoqTrackParam()
        publishAudioTrack.trackType = .audio
        let publishDataTrack = AoqTrackParam()
        publishDataTrack.trackType = .data
        let subscribeAudioTrack = AoqTrackParam()
        subscribeAudioTrack.trackType = .audio
        let subscribeDataTrack = AoqTrackParam()
        subscribeDataTrack.trackType = .data
        connectConfig.publishTracks = [publishAudioTrack, publishDataTrack]
        connectConfig.subscribeTracks = [subscribeAudioTrack, subscribeDataTrack]
        if imageMode == .continuousVideo {
            let videoEncoderConfig = AoqVideoCodecConfig()
            videoEncoderConfig.trackType = .video
            videoEncoderConfig.codecType = .videoJpeg
            videoEncoderConfig.width = 960
            videoEncoderConfig.height = 540
            videoEncoderConfig.fps = 2
            videoEncoderConfig.bitrate = 500_000
            engine.setVideoEncoderConfig(videoEncoderConfig)
            let publishVideoTrack = AoqTrackParam()
            publishVideoTrack.trackType = .video
            connectConfig.publishTracks = [publishAudioTrack, publishVideoTrack, publishDataTrack]
        }
        let captureConfig = AoqAudioCaptureConfig()
        captureConfig.channel = 1
        captureConfig.isExternal = false
        engine.startAudioCapture(captureConfig)
        let playbackConfig = AoqAudioPlaybackConfig()
        playbackConfig.channel = 1
        playbackConfig.isExternal = false
        playbackConfig.isDefaultSpeaker = true
        engine.startAudioPlayer(playbackConfig)
        if imageMode == .continuousVideo {
            let videoCaptureConfig = AoqVideoCaptureConfig()
            videoCaptureConfig.width = 1280
            videoCaptureConfig.height = 720
            videoCaptureConfig.fps = 15
            engine.startVideoCapture(videoCaptureConfig)
        }
        engine.enableSendMediaStream(.audio, enable: false)
        if imageMode == .continuousVideo {
            engine.enableSendMediaStream(.video, enable: false)
        }
        engine.connect(connectConfig)
    }
    func onPushToTalkPressed() {
        hasAudioInCurrentTurn = true
        engine.enableSendMediaStream(.audio, enable: true)
    }
    func onPushToTalkReleased(base64Jpeg: String? = nil) {
        engine.enableSendMediaStream(.audio, enable: false)
        guard hasAudioInCurrentTurn else { return }
        if imageMode == .singleImage, let base64Jpeg {
            let imageEvent: [String: Any] = [
                "type": "input_image_buffer.append",
                "image": base64Jpeg
            ]
            if let data = try? JSONSerialization.data(withJSONObject: imageEvent) {
                let dataMessage = AoqDataMsg()
                dataMessage.data = data
                engine.sendDataMsg(dataMessage)
            }
        }
        for event in [
            ["type": "input_audio_buffer.commit"],
            ["type": "response.create"]
        ] {
            guard let data = try? JSONSerialization.data(withJSONObject: event) else { continue }
            let dataMessage = AoqDataMsg()
            dataMessage.data = data
            engine.sendDataMsg(dataMessage)
        }
        hasAudioInCurrentTurn = false
    }
    private func sendSessionUpdate() {
        let event: [String: Any] = [
            "type": "session.update",
            "session": [
                "modalities": ["text", "audio"],
                "voice": "Tina",
                "audio": [
                    "input": ["format": ["type": "pcm", "sample_rate": 16_000]],
                    "output": ["format": ["type": "pcm", "sample_rate": 24_000]]
                ],
                "turn_detection": NSNull()
            ]
        ]
        guard let data = try? JSONSerialization.data(withJSONObject: event) else { return }
        let dataMessage = AoqDataMsg()
        dataMessage.data = data
        engine.sendDataMsg(dataMessage)
    }
    func close() {
        engine.disconnect()
        AoqClientEngine.destroy()
    }
    func onConnectionStatusChange(_ status: AoqConnectionStatus) {
        if status == .connected { sendSessionUpdate() }
    }
    func onDataMsg(_ msg: AoqDataMsg) {
        guard let event = try? JSONSerialization.jsonObject(with: msg.data) as? [String: Any],
              let type = event["type"] as? String else { return }
        if type == "session.updated", imageMode == .continuousVideo {
            engine.enableSendMediaStream(.video, enable: true)
        }
    }
    func onError(_ code: Int, message: String) {}
    func onWarning(_ code: Int, message: String) {}
    func onStats(_ stats: AoqStats) {}
    func onAudioDeviceStateChanged(_ state: AoqAudioDeviceState) {}
    func onAudioDeviceRouteChanged(_ routeType: Int) {}
    func onAudioDeviceInterrupted(_ interrupt: Bool) {}
    func onAudioFileState(_ state: AoqAudioFileState) {}
    func onVideoDeviceStateChanged(_ state: AoqVideoDeviceState) {}
}

Corra e verifique.

Complete uma volta de áudio e uma volta com uma imagem. Resultados esperados:

  1. A faixa de áudio está desativada antes do botão ser pressionado e enviar áudio continuamente enquanto o botão é mantido.
  2. Após a liberação, input_audio_buffer.committed, response.created, and response.done são recebidos em sequência, e áudio modelo é reproduzido sobre a faixa de áudio subscrito.
  3. Com a opção de uma única imagem, o modelo responde usando a imagem e áudio da curva. Com vídeo contínuo, usa as últimas molduras de vídeo.

Para os campos de eventos do servidor e esquemas de resposta completos, veja Eventos de servidor.

Considerações importantes.

  1. O AOQ transporta áudio pela faixa de áudio. Não envie também entrada, áudio, buffer, append.
  2. Input_audio_buffer.commit só commite a volta e não desencadeia uma resposta modelo. Envie resposta. Crie depois.
  3. Não commita um buffer de áudio vazio. O serviço devolve um erro.
  4. Não habilite o envio de mídia antes da sessão. No modo manual, não habilite a faixa de áudio antes do usuário pressionar o botão.

Informação relacionada

Para todos os parâmetros, campos de eventos e interfaces para outras plataformas, veja: