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

Captura de áudio personalizada

Use uma fonte de áudio externa em vez do microfone do dispositivo

Descreve como implementar a captura de áudio personalizada com o SDK do cliente AOQ, incluindo a adição de streams de áudio externos, envio de dados PCM e gerenciamento do ciclo de vida do stream.

Visão geral

O módulo de áudio integrado do SDK do cliente AOQ cobre necessidades básicas de áudio, mas em alguns cenários o módulo de captura integrado pode não ser suficiente. A captura de áudio personalizada é útil quando você precisa:

O AOQ Client SDK oferece suporte flexível à captura personalizada, permitindo que você gerencie seus próprios dispositivos e fontes de áudio com base no seu caso de uso. Os dados de fluxo de áudio externo são misturados com áudio capturado internamente antes de serem publicados.

Código de exemplo

Em breve.

Pré-requisitos

Implementação

1. Iniciar ou parar a captura de áudio

Comece a captura de áudio primeiro. Os dados de fluxo de áudio externo são misturados com dados de captura interna antes de serem publicados. Se você não precisar de captura de microfone interno, defina isExternal=true para desativar o dispositivo de captura interno.

// Option 1: Internal capture — external audio stream data is mixed with microphone data
AoqClientEngine.AoqAudioCaptureConfig config = new AoqClientEngine.AoqAudioCaptureConfig();
config.isExternal = false; // Use internal microphone capture
config.isVoipMode = false;
engine.startAudioCapture(config);
// Option 2: No internal capture — only external audio stream data is published
AoqClientEngine.AoqAudioCaptureConfig config = new AoqClientEngine.AoqAudioCaptureConfig();
config.isExternal = true; // Do not open the microphone; external audio stream provides the data
engine.startAudioCapture(config);

2. Após conectar, adicione o fluxo de áudio externo

Uma vez que onConnectionStatusChange relatórios de retorno de chamada AoqConnectionStatusConnected, ligue addAudioExternalStream para adicionar o fluxo de áudio externo. Atribuir um único streamId que você usará para enviar dados e gerenciar o fluxo.

Se você precisar de processamento 3A (cancelamento de eco, supressão de ruído, controle automático de ganho), defina o enable3A parâmetro em AoqAudioExternalStreamConfig.

// Add the stream after confirming connection in the onConnectionStatusChange callback
@Override
public void onConnectionStatusChange(AoqClientEngine.AoqConnectionStatus status) {
  if (status == AoqClientEngine.AoqConnectionStatus.AoqConnectionStatusConnected) {
    addExternalAudioStream();
  }
}
private void addExternalAudioStream() {
  AoqClientEngine.AoqAudioExternalStreamConfig config = new AoqClientEngine.AoqAudioExternalStreamConfig();
  config.sampleRate = 48000;       // Sample rate — must match the actual audio data
  config.channels = 1;             // Channel count
  config.publishVolume = 100;      // Publishing volume [0-100]
  config.playoutVolume = 0;        // Local playback volume [0-100]; 0 = no local playback
  config.maxBufferDuration = 1000; // Maximum buffer duration (milliseconds)
  config.enable3A = true;          // Whether to apply 3A processing to input PCM
  String streamId = "external_audio_1";
  int ret = engine.addAudioExternalStream(streamId, config);
  if (ret == 0) {
    mExternalStreamId = streamId;
  }
}

Parâmetros:

Parâmetro Tipo Padrão Descrição
trackType AoqTrackType AoqTrackTypeÁudio Tipo de faixa de áudio
tipo de codec AoqEncoderType AoqEncoderTypeAudioPCM Formato de fluxo de áudio
canais interno 1 Contagem de canais
taxa de amostra interno 48.000 Taxa de amostragem (Hz)
volume de reprodução interno 100 Volume de reprodução [0-100]
publicarVolume interno 100 Volume de publicação [0-100]
maxBufferDuration interno 1000 Duração máxima do buffer (milissegundos)
habilitar3A booleano falso Se deve aplicar o processamento 3A ao PCM de entrada

3. Capture ou obtenha dados PCM

Implemente sua própria captura de áudio ou fonte de dados para seu caso de uso e, em seguida, alimente os dados no SDK. As fontes de dados comuns incluem:

Os dados de áudio devem estar no formato PCM. Grave a taxa de amostragem, contagem de canais e outros parâmetros para construir o AoqAudioFrameData objeto.

4. Envie dados de áudio para o SDK por meio do ID do stream

Ligar pushAudioExternalStreamData para alimentar os dados PCM capturados no SDK.

// Member variable: flag to control the push loop
private volatile boolean mPushRunning = false;
// Push a single audio frame
private void pushAudioData(byte[] audioData, int bytesRead) {
  if (engine == null || mExternalStreamId == null || bytesRead <= 0) {
    return;
  }
  int channels = 1;
  int bytesPerSample = 2; // 16-bit PCM
  int sampleRate = 48000;
  // Build the audio frame data object
  AoqClientEngine.AoqAudioFrameData frameData = new AoqClientEngine.AoqAudioFrameData();
  frameData.dataPtr = audioData;
  frameData.dataSize = bytesRead;
  frameData.numOfSamples = bytesRead / (channels * bytesPerSample);
  frameData.bytesPerSample = bytesPerSample;
  frameData.numOfChannels = channels;
  frameData.samplesPerSec = sampleRate;
  // Push data and handle buffer-full errors
  int ret;
  final int WAIT_MS = 30;
  do {
    // Check whether the running flag and stream ID are still valid
    if (!mPushRunning || mExternalStreamId == null) {
      break;
    }
    ret = engine.pushAudioExternalStreamData(mExternalStreamId, frameData);
    if (ret == 110) { // AoqErrorCodeAudioExternalBufferFull
      try {
        Thread.sleep(WAIT_MS);
      } catch (InterruptedException e) {
        break;
      }
    } else {
      break;
    }
  } while (true);
}

Notas importantes:

5. Remova o fluxo de áudio externo

Quando a captura personalizada não for mais necessária, interrompa o push loop primeiro e depois chame removeAudioExternalStream para remover o fluxo de áudio externo.

// Stop pushing first
stopPushAudio();
// Then remove the external audio stream
engine.removeAudioExternalStream(mExternalStreamId);
mExternalStreamId = null;