Driver de áudio personalizado (Android)

Visão geral

O SDK do OpenTok para Android permite configurar um driver de áudio personalizado para emissores e assinantes. Você pode usar um driver de áudio personalizado para personalizar o áudio enviado ao fluxo de um emissor. Também é possível personalizar a reprodução do áudio dos fluxos assinados.

Configurando seu projeto

O código desta seção está disponível no projeto Basic-Audio-Driver-Java do exemplos-do-opentok-android-sdk repositório. Caso ainda não tenha feito isso, você precisará clonar o repositório em um diretório local. Na linha de comando, execute:

git clone git@github.com:Vonage/vonage-video-android-sdk-samples.git

Abra o Áudio Básico em Java projeto no Android Studio para acompanhar.

Observação: Este tutorial aborda a versão em Java do aplicativo de exemplo do Android. Para uma versão em Kotlin com documentação, consulte o Repositório de aplicativos de exemplo para Android.

Etapa 1: Adicionar um driver de áudio personalizado

Este aplicativo de exemplo utiliza o driver de áudio personalizado para transmitir ruído branco (um sinal de áudio aleatório) em seu fluxo de áudio. Ele também utiliza o driver de áudio personalizado para capturar o áudio de fluxos assinados e salvá-lo em um arquivo.

Configurando o dispositivo de áudio e o barramento de áudio

Ao utilizar um driver de áudio personalizado, você define um driver de áudio personalizado e um barramento de áudio a ser usado pelo aplicativo.

O NoiseAudioDevice A classe define uma interface básica de dispositivo de áudio a ser utilizada pelo aplicativo. Ela estende a BaseAudioDevice classe, definida pelo SDK do OpenTok para Android. Para usar um driver de áudio personalizado, chame o AudioDeviceManager.setAudioDevice() método. Este exemplo configura o dispositivo de áudio como uma instância do NoiseAudioDevice classe:

AudioDeviceManager.setAudioDevice(noiseAudioDevice);

Use o AudioSettings classe, definida no SDK do OpenTok para Android, para definir o formato de áudio utilizado pelo driver de áudio personalizado. A NoiseAudioDevice() O construtor instancia dois AudioSettings instâncias — uma para o capturador de áudio personalizado e outra para o renderizador de áudio personalizado. Ele define a taxa de amostragem e o número de canais para cada um:

public NoiseAudioDevice(Context context) {
    this.context = context;

    captureSettings = new AudioSettings(SAMPLING_RATE, NUM_CHANNELS_CAPTURING);
    rendererSettings = new AudioSettings(SAMPLING_RATE, NUM_CHANNELS_RENDERING);

    capturerStarted = false;
    rendererStarted = false;

    audioDriverPaused = false;

    capturerHandler = new Handler();
    rendererHandler = new Handler();
}

O construtor também define algumas propriedades locais que indicam se o dispositivo está capturando ou renderizando. Além disso, ele define uma instância de Handler para processar o capturer Objeto executável.

O NoiseAudioDevice.getAudioBus() O método obtém o AudioBus instância utilizada por esse dispositivo de áudio, definida pelo NoiseAudioDevice.AudioBus classe. Use o AudioBus instância para enviar e receber amostras de áudio de e para uma sessão. O editor acessará o AudioBus objeto para obter as amostras de áudio. Os assinantes enviarão amostras de áudio (de fluxos assinados) para o objeto AudioBus.

Gravação de áudio para uso por uma editora

O BaseAudioDevice.startCapturer() O método é chamado quando o dispositivo de áudio deve começar a capturar o áudio a ser publicado. O NoiseAudioDevice A implementação desse método inicia o capturer thread a ser executado na fila após 1 segundo:

public boolean startCapturer() {
    capturerStarted = true;
    capturerHandler.postDelayed(capturer, capturerIntervalMillis);
    return true;
}

O capturer A thread gera um buffer contendo amostras de dados aleatórios (ruído branco). Em seguida, ela chama a writeCaptureData() método do AudioBus objeto, que envia os samples para o barramento de áudio. O editor no aplicativo usa os samples enviados para o barramento de áudio para transmiti-los como áudio no fluxo publicado. Então, se uma captura ainda estiver em andamento (se o aplicativo estiver publicando), o capturer a thread é executada novamente após mais um segundo:

private Runnable capturer = new Runnable() {
    @Override
    public void run() {
        capturerBuffer.rewind();

        Random rand = new Random();
        rand.nextBytes(capturerBuffer.array());

        getAudioBus().writeCaptureData(capturerBuffer, SAMPLING_RATE);

        if(capturerStarted && !audioDriverPaused) {
            capturerHandler.postDelayed(capturer, capturerIntervalMillis);
        }
    }
};

A classe `AudioDevice` inclui outros métodos que são implementados pela classe `NoiseAudioDevice`. No entanto, este exemplo não realiza nenhuma ação relevante nesses métodos; portanto, eles não serão abordados nesta discussão.

Etapa 2: Adicionando um renderizador de áudio personalizado

Você implementará um renderizador de áudio simples para o áudio dos fluxos aos quais está inscrito.

O NoiseAudioDevice() O método construtor configura um arquivo para salvar o áudio recebido. Isso é feito simplesmente para ilustrar um uso do renderizador de áudio do driver de áudio personalizado. O aplicativo requer as seguintes permissões, definidas no AndroidManifest.xml arquivo:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

O BaseAudioDevice.initRenderer() O método é chamado quando o aplicativo inicializa o renderizador de áudio. O NoiseAudioDevice A implementação desse método instancia um novo objeto `File`, no qual o aplicativo gravará os dados de áudio:

@Override
public boolean initRenderer() {
    rendererBuffer = ByteBuffer.allocateDirect(SAMPLING_RATE * 2); // Each sample has 2 bytes
    File documentsDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
    rendererFile = new File(documentsDirectory, "output.raw");

    if (!rendererFile.exists()) {
        try {
            rendererFile.getParentFile().mkdirs();
            rendererFile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return true;
}

O BaseAudioDevice.startRendering() O método é chamado quando o dispositivo de áudio deve começar a reproduzir o áudio dos fluxos aos quais está inscrito. O NoiseAudioDevice A implementação desse método inicia o capturer thread a ser executado na fila após 1 segundo:

 @Override
 public boolean startRenderer() {
     rendererStarted = true;
     rendererHandler.postDelayed(renderer, rendererIntervalMillis);
     return true;
 }

O renderer O thread obtém 1 segundo de áudio do barramento de áudio chamando a função readRenderData() método do AudioBus objeto. Em seguida, ele grava os dados de áudio no arquivo (para fins de amostragem). E, se o dispositivo de áudio ainda estiver sendo usado para reproduzir amostras de áudio, ele define um temporizador para executar o rendererHandler retomar o thread após 0,1 segundos:

private Handler rendererHandler;

private Runnable renderer = new Runnable() {
    @Override
    public void run() {
        rendererBuffer.clear();
        getAudioBus().readRenderData(rendererBuffer, SAMPLING_RATE);

        try {
            FileOutputStream stream = new FileOutputStream(rendererFile);
            stream.write(rendererBuffer.array());
            stream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (rendererStarted && !audioDriverPaused) {
            rendererHandler.postDelayed(renderer, rendererIntervalMillis);
        }
    }
};

Este exemplo é intencionalmente simples para fins didáticos — ele apenas grava os dados de áudio em um arquivo. Em uma aplicação mais prática de um driver de áudio personalizado, você poderia usá-lo para reproduzir áudio em um dispositivo Bluetooth ou para processar o áudio antes de reproduzi-lo.

Parabéns! Você concluiu o tutorial sobre drivers de áudio personalizados para Android.
Você pode continuar experimentando e ajustando o código que desenvolveu aqui, ou conferir o Próximos passos abaixo.

Próximos passos

Quando terminar esta seção, continue desenvolvendo e aprimorando seu aplicativo OpenTok com estes recursos úteis: