All Products
Search
Document Center

Alibaba Cloud Model Studio:Custom audio capture

Last Updated:Sep 02, 2026

Menjelaskan cara mengimplementasikan custom audio capture dengan AOQ Client SDK, termasuk menambahkan aliran audio eksternal, mendorong data PCM, dan mengelola siklus hidup aliran.

Overview

Modul audio bawaan AOQ Client SDK mencakup kebutuhan audio dasar, tetapi dalam beberapa skenario modul capture bawaan mungkin tidak mencukupi. Custom audio capture berguna ketika Anda perlu:

  • Mengatasi konflik perangkat capture audio.
  • Memasukkan data audio dari sistem capture kustom atau file audio ke dalam SDK untuk transmisi.
  • Memublikasikan audio yang dihasilkan oleh AI TTS melalui SDK.

AOQ Client SDK menyediakan dukungan custom capture yang fleksibel, memungkinkan Anda mengelola perangkat dan sumber audio sendiri sesuai kasus penggunaan. Data aliran audio eksternal akan dicampur dengan audio yang ditangkap secara internal sebelum dipublikasikan.

Sample code

Segera hadir.

Prerequisites

  • Sebuah instans engine telah dibuat dengan memanggil createEngine.
  • Koneksi ke server telah terjalin (callback onConnectionStatusChange telah melaporkan AoqConnectionStatusConnected).

Implementation

1. Mulai atau hentikan perekaman audio

Mulailah audio capture terlebih dahulu. Data aliran audio eksternal akan dicampur dengan data capture internal sebelum dipublikasikan. Jika Anda tidak memerlukan capture mikrofon internal, atur isExternal=true untuk menonaktifkan perangkat capture internal.

// Opsi 1: Capture internal — data aliran audio eksternal dicampur dengan data mikrofon
AoqClientEngine.AoqAudioCaptureConfig config = new AoqClientEngine.AoqAudioCaptureConfig();
config.isExternal = false; // Gunakan capture mikrofon internal
config.isVoipMode = false;
engine.startAudioCapture(config);

// Opsi 2: Tanpa capture internal — hanya data aliran audio eksternal yang dipublikasikan
AoqClientEngine.AoqAudioCaptureConfig config = new AoqClientEngine.AoqAudioCaptureConfig();
config.isExternal = true; // Jangan buka mikrofon; data disediakan oleh aliran audio eksternal
engine.startAudioCapture(config);

2. Setelah terhubung, tambahkan aliran audio eksternal

Setelah callback onConnectionStatusChange melaporkan AoqConnectionStatusConnected, panggil addAudioExternalStream untuk menambahkan aliran audio eksternal. Tetapkan streamId unik yang akan Anda gunakan untuk mendorong data dan mengelola aliran tersebut.

Jika Anda memerlukan pemrosesan 3A (echo cancellation, noise suppression, automatic gain control), atur parameter enable3A dalam AoqAudioExternalStreamConfig.

// Tambahkan aliran setelah koneksi dikonfirmasi dalam callback onConnectionStatusChange
@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;       // Laju sampel — harus sesuai dengan data audio aktual
    config.channels = 1;             // Jumlah channel
    config.publishVolume = 100;      // Volume publikasi [0-100]
    config.playoutVolume = 0;        // Volume pemutaran lokal [0-100]; 0 = tanpa pemutaran lokal
    config.maxBufferDuration = 1000; // Durasi buffer maksimum (milidetik)
    config.enable3A = true;          // Apakah menerapkan pemrosesan 3A pada PCM input

    String streamId = "external_audio_1";
    int ret = engine.addAudioExternalStream(streamId, config);
    if (ret == 0) {
        mExternalStreamId = streamId;
    }
}
Parameter:

Parameter

Type

Default

Description

trackType

AoqTrackType

AoqTrackTypeAudio

Jenis track audio

codecType

AoqEncoderType

AoqEncoderTypeAudioPCM

Format aliran audio

channels

int

1

Jumlah channel

sampleRate

int

48000

Laju sampel (Hz)

playoutVolume

int

100

Volume pemutaran [0–100]

publishVolume

int

100

Volume publikasi [0–100]

maxBufferDuration

int

1000

Durasi buffer maksimum (milidetik)

enable3A

boolean

false

Apakah menerapkan pemrosesan 3A pada PCM input

3. Tangkap atau peroleh data PCM

Implementasikan capture audio atau sumber data Anda sendiri sesuai kasus penggunaan, lalu masukkan data tersebut ke dalam SDK. Sumber data umum meliputi:

  • Capture mikrofon: Gunakan Android AudioRecord untuk menangkap data PCM.
  • Pembacaan file: Parsing data PCM dari file audio PCM atau WAV lokal.
  • AI TTS: Peroleh data PCM dari mesin sintesis suara.
  • Aliran jaringan: Decode data PCM dari aliran audio jaringan.

Data audio harus dalam format PCM. Catat laju sampel, jumlah channel, dan parameter lainnya untuk membuat objek AoqAudioFrameData.

4. Dorong data audio ke SDK melalui stream ID

Panggil pushAudioExternalStreamData untuk memasukkan data PCM yang ditangkap ke dalam SDK.

  • Untuk capture perangkat keras: gunakan frame 10 ms dan panggil push setiap kali data tersedia.
  • Untuk input berbasis file: gunakan frame 40 ms dan tidur selama 30 ms di antara pemanggilan push.
  • Pertahankan flag running. Hentikan loop push saat engine keluar atau stream ID dihapus.
// Variabel anggota: flag untuk mengontrol loop push
private volatile boolean mPushRunning = false;

// Dorong satu frame audio

private void pushAudioData(byte[] audioData, int bytesRead) {

    if (engine == null || mExternalStreamId == null || bytesRead <= 0) {
        return;
    }

    int channels = 1;
    int bytesPerSample = 2; // PCM 16-bit
    int sampleRate = 48000;

    // Buat objek data frame audio
    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;

    // Dorong data dan tangani error buffer penuh
    int ret;
    final int WAIT_MS = 30;

    do {
        // Periksa apakah flag running dan stream ID masih 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);
}
Catatan penting:
  • Mulai mendorong data hanya setelah koneksi terjalin dan aliran audio eksternal telah ditambahkan.
  • Atur numOfSamples pada AoqAudioFrameData agar sesuai dengan panjang aktual data.
  • pushAudioExternalStreamData dapat gagal jika buffer internal penuh (kode kesalahan 110). Ulangi setelah penundaan singkat.
  • Untuk capture real-time, gunakan frame 10 ms dan panggil push setiap kali data tersedia. Tangani kode kesalahan 110.
  • Untuk input berbasis file, gunakan frame 40 ms dan panggil push setiap 30 ms. Tangani kode kesalahan 110.
  • Sebelum engine keluar (destroy) atau stream ID dihapus, atur mPushRunning = false untuk menghentikan loop push dan menghindari akses ke sumber daya yang telah dilepas.

5. Hapus aliran audio eksternal

Saat custom capture tidak lagi diperlukan, hentikan loop push terlebih dahulu, lalu panggil removeAudioExternalStream untuk menghapus aliran audio eksternal.

// Hentikan push terlebih dahulu
stopPushAudio();
// Lalu hapus aliran audio eksternal
engine.removeAudioExternalStream(mExternalStreamId);
mExternalStreamId = null;