Cette rubrique explique comment mettre en œuvre une capture audio personnalisée avec le SDK client AOQ. Elle couvre l'ajout de flux audio externes, l'injection de données PCM et la gestion du cycle de vie des flux.
Présentation
Le module audio intégré du SDK client AOQ répond aux besoins fondamentaux, mais peut s'avérer insuffisant dans certains scénarios. La capture audio personnalisée est particulièrement utile pour :
- Contourner les conflits de périphériques de capture audio.
- Transmettre au SDK des données audio issues d'un système de capture spécifique ou d'un fichier.
- Publier via le SDK de l'audio généré par synthèse vocale IA (TTS).
Le SDK client AOQ offre une prise en charge flexible de la capture personnalisée, permettant de gérer vos propres périphériques et sources audio selon votre cas d'usage. Les données du flux audio externe sont mixées avec l'audio capturé en interne avant publication.
Exemple de code
Bientôt disponible.
Prérequis
- Vous avez créé une instance de moteur en appelant
createEngine. - La connexion au serveur est établie (le callback
onConnectionStatusChangea signalé l'étatAoqConnectionStatusConnected).
Mise en œuvre
1. Démarrer ou arrêter la capture audio
Commencez par lancer la capture audio. Les données du flux audio externe sont mixées avec celles de la capture interne avant publication. Si la capture par le microphone interne n'est pas nécessaire, définissez isExternal=true pour désactiver le périphérique de capture interne.
// 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. Ajouter le flux audio externe après la connexion
Dès que le callback onConnectionStatusChange signale l'état AoqConnectionStatusConnected, appelez addAudioExternalStream pour ajouter le flux audio externe. Attribuez-lui un identifiant streamId unique pour injecter les données et gérer le flux.
Si un traitement 3A (annulation d'écho, suppression du bruit, contrôle automatique du gain) est requis, activez le paramètre enable3A dans 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;
}
}
Paramètres :
Paramètre | Type | Valeur par défaut | Description |
|---|---|---|---|
trackType | AoqTrackType | AoqTrackTypeAudio | Type de piste audio |
codecType | AoqEncoderType | AoqEncoderTypeAudioPCM | Format du flux audio |
channels | int | 1 | Nombre de canaux |
sampleRate | int | 48000 | Fréquence d'échantillonnage (Hz) |
playoutVolume | int | 100 | Volume de lecture locale [0–100] |
publishVolume | int | 100 | Volume de publication [0–100] |
maxBufferDuration | int | 1000 | Durée maximale du tampon (millisecondes) |
enable3A | boolean | false | Activation du traitement 3A sur les données PCM entrantes |
3. Capturer ou obtenir des données PCM
Implémentez votre propre mécanisme de capture audio ou source de données adapté à votre cas d'usage, puis injectez ces données dans le SDK. Les sources courantes incluent :
- Capture microphone : utilisez l'API AudioRecord d'Android pour capturer des données PCM.
- Lecture de fichier : extrayez les données PCM depuis un fichier audio local au format PCM ou WAV.
- Synthèse vocale IA : récupérez les données PCM produites par un moteur de synthèse vocale.
- Flux réseau : décodez les données PCM issues d'un flux audio réseau.
Les données audio doivent être au format PCM. Notez la fréquence d'échantillonnage, le nombre de canaux et les autres paramètres pour construire l'objet AoqAudioFrameData.
4. Injecter les données audio dans le SDK via l'identifiant de flux
Appelez pushAudioExternalStreamData pour transmettre les données PCM capturées au SDK.
- Pour une capture matérielle : utilisez des trames de 10 ms et lancez l'injection dès que des données sont disponibles.
- Pour une entrée sur fichier : utilisez des trames de 40 ms et insérez une pause de 30 ms entre chaque injection.
- Gérez un indicateur
runningpour contrôler la boucle d'injection. Interrompez cette boucle lorsque le moteur s'arrête ou que l'identifiant de flux est supprimé.
// 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);
}
Remarques importantes :
- N'injectez des données qu'après l'établissement de la connexion et l'ajout du flux audio externe.
- Assurez-vous que la propriété
numOfSamplesde l'objetAoqAudioFrameDatacorrespond à la longueur réelle des données. - L'appel à
pushAudioExternalStreamDatapeut échouer si le tampon interne est plein (code d'erreur 110). Réessayez après un court délai. - En capture temps réel, privilégiez des trames de 10 ms et injectez les données dès qu'elles sont disponibles, tout en gérant le code d'erreur 110.
- Pour une entrée sur fichier, optez pour des trames de 40 ms avec une injection toutes les 30 ms, en prévoyant la gestion du code d'erreur 110.
- Avant l'arrêt du moteur (
destroy) ou la suppression d'un identifiant de flux, passezmPushRunning = falseafin d'interrompre la boucle d'injection et d'éviter tout accès à des ressources déjà libérées.
5. Supprimer le flux audio externe
Lorsque la capture personnalisée n'est plus nécessaire, arrêtez d'abord la boucle d'injection, puis appelez removeAudioExternalStream pour supprimer le flux audio externe.
// Stop pushing first
stopPushAudio();
// Then remove the external audio stream
engine.removeAudioExternalStream(mExternalStreamId);
mExternalStreamId = null;