Configurez l'encodage audio, gérez la capture et la lecture, activez le retour oreillette et définissez le routage audio dans le SDK ARTC.
Présentation
Le SDK ARTC prend en charge l'encodage audio, la sélection du mode de scénario, la gestion de la capture et de la lecture audio locales, le contrôle de la lecture audio distante, le retour oreillette ainsi que la configuration du routage audio.
Exemples de code
Android : Android/ARTCExample/BasicUsage/src/main/java/com/aliyun/artc/api/basicusage/AudioBasicUsage/AudioBasicUsageActivity.java.
iOS : iOS/ARTCExample/BasicUsage/AudioBasicUsage/AudioBasicUsageVC.swift.
Harmony : Harmony/ARTCExample/entry/src/main/ets/pages/basicusage/AudioBasicUsage.ets.
Prérequis
Vous disposez d'un compte Alibaba Cloud valide et avez créé une application ApsaraVideo for RTC. Pour plus d'informations, consultez la rubrique Créer une application. Récupérez l'AppID et l'AppKey depuis la console ApsaraVideo Live.
Vous avez intégré le SDK ARTC à votre projet et implémenté les fonctionnalités audio et vidéo en temps réel de base. Pour plus d'informations sur l'intégration du SDK, consultez la rubrique Télécharger et intégrer le SDK. Pour mettre en œuvre un appel audio et vidéo, reportez-vous à la section Mettre en œuvre un appel audio et vidéo.
Implémentation
1. Définir les modes d'encodage audio et de scénario (avant de rejoindre un canal)
Le SDK ARTC vous permet de définir le mode d'encodage audio et le mode de scénario audio à l'aide de la méthode setAudioProfile afin d'optimiser la qualité audio selon différents scénarios.
Appelez
setAudioProfileuniquement avant de rejoindre un canal. Les paramètres ne peuvent pas être modifiés après la connexion.Le SDK ARTC recommande d'utiliser le mode d'encodage audio haute qualité
AliRtcEngineHighQualityModeet le mode de scénario musicalAliRtcSceneMusicMode.
1,1. Modes d'encodage audio (AliRtcAudioProfile)
Utilisez le mode haute qualité (
AliRtcEngineHighQualityMode).Pour assurer l'interopérabilité avec les clients web, sélectionnez un mode avec une fréquence d'échantillonnage de 48 kHz.
Pour un son stéréo, définissez le mode sur
AliRtcEngineStereoHighQualityMode.
|
Énumération |
Description |
Fréquence d'échantillonnage |
Canaux |
Débit maximal |
|
AliRtcEngineLowQualityMode |
Mode audio basse qualité |
8000 Hz |
Mono |
12 kbps |
|
AliRtcEngineBasicQualityMode |
Mode audio qualité standard |
16000 Hz |
Mono |
24 kbps |
|
AliRtcEngineHighQualityMode |
Mode audio haute qualité |
48000 Hz |
Mono |
64 kbps |
|
AliRtcEngineStereoHighQualityMode |
Mode audio stéréo haute qualité |
48000 Hz |
Stéréo |
80 kbps |
|
AliRtcEngineSuperHighQualityMode |
Mode audio très haute qualité |
48000 Hz |
Mono |
96 kbps |
|
AliRtcEngineStereoSuperHighQualityMode |
Mode audio stéréo très haute qualité |
48000 Hz |
Stéréo |
128 kbps |
1,2. Modes de scénario audio (AliRtcAudioScenario)
|
Énumération |
Description |
|
AliRtcSceneDefaultMode |
Mode par défaut. Utilise le traitement 3A matériel et prend en charge la capture audio depuis un appareil Bluetooth. Utilisez ce mode pour capturer l'audio via un casque Bluetooth. |
|
AliRtcSceneMusicMode |
(Recommandé) Scénario musical. Utilise le traitement 3A logiciel et capture l'audio via le microphone intégré de l'appareil pour une meilleure fidélité sonore. |
1,3. Exemple de code
Les exemples suivants illustrent la configuration des modes d'encodage audio et de scénario pour des cas d'utilisation courants.
Pour la capture Bluetooth
Android
// Set the audio scenario to AliRtcSceneDefaultMode.
mAliRtcEngine.setAudioProfile(AliRtcEngineHighQualityMode, AliRtcSceneDefaultMode);
iOS
// Set the audio scenario to AliRtcSceneDefaultMode.
engine.setAudioProfile(AliRtcAudioProfile.engineHighQualityMode, audio_scene: AliRtcAudioScenario.sceneDefaultMode)
Harmony
this.rtcEngine.setAudioProfile(AliRtcAudioProfile.AliRtcHighQualityMode, AliRtcAudioScenario.AliRtcSceneDefaultMode);
Mac
[self.engine setAudioProfile:AliRtcEngineHighQualityMode audio_scene:AliRtcSceneDefaultMode];
Windows
mAliRtcEngine->SetAudioProfile(AliEngineHighQualityMode, AliEngineSceneDefaultMode);
Pour l'interopérabilité avec les clients web
Android
// Select an encoding mode with a 48 kHz sample rate, such as AliRtcEngineHighQualityMode.
mAliRtcEngine.setAudioProfile(AliRtcEngineHighQualityMode, AliRtcSceneMusicMode);
iOS
// Select an encoding mode with a 48 kHz sample rate, such as AliRtcEngineHighQualityMode.
engine.setAudioProfile(AliRtcAudioProfile.engineHighQualityMode, audio_scene: AliRtcAudioScenario.sceneMusicMode)
Harmony
this.rtcEngine.setAudioProfile(AliRtcAudioProfile.AliRtcHighQualityMode, AliRtcAudioScenario.AliRtcSceneMusicMode);
Mac
[self.engine setAudioProfile:AliRtcEngineHighQualityMode audio_scene:AliRtcSceneMusicMode];
Windows
mAliRtcEngine->SetAudioProfile(AliEngineHighQualityMode, AliEngineSceneMusicMode);
Pour un son stéréo
Android
// Set the mode to one that supports stereo, such as AliRtcEngineStereoHighQualityMode.
mAliRtcEngine.setAudioProfile(AliRtcEngineStereoHighQualityMode, AliRtcSceneMusicMode);
iOS
// Set the mode to one that supports stereo, such as AliRtcEngineStereoHighQualityMode.
engine.setAudioProfile(AliRtcAudioProfile.engineStereoHighQualityMode, audio_scene: AliRtcAudioScenario.sceneMusicMode)
Harmony
this.rtcEngine.setAudioProfile(AliRtcAudioProfile.AliRtcStereoHighQualityMode, AliRtcAudioScenario.AliRtcSceneMusicMode);
Mac
[self.engine setAudioProfile:AliRtcEngineStereoHighQualityMode audio_scene:AliRtcSceneMusicMode];
Windows
mAliRtcEngine->SetAudioProfile(AliEngineStereoHighQualityMode, AliEngineSceneMusicMode);
2. Capture audio locale
Contrôlez la capture audio locale en coupant le microphone ou en arrêtant la capture microphonique. Le tableau suivant compare ces deux approches.
|
Méthode |
|
|
|
Fonctionnement |
Envoie des trames silencieuses. |
Arrête ou démarre la capture du microphone. |
|
Moment de l'appel |
Peut être appelé avant ou après avoir rejoint un canal. |
Doit être appelé après avoir rejoint un canal. |
|
Libère les ressources du microphone |
Non |
Oui |
2,1. Couper le microphone local
Utilisez la méthode muteLocalMic pour couper le microphone local et l'entrée audio externe. Vous pouvez appeler cette méthode avant ou après avoir rejoint un canal.
Contrairement à stopAudioCapture, la méthode muteLocalMic ne libère pas la ressource du microphone. Les modules de capture et d'encodage continuent de fonctionner mais envoient des trames silencieuses à un débit extrêmement faible.
Les modes AliRtcMuteLocalAudioMode suivants sont pris en charge :
|
|
Mode par défaut. Même comportement que |
|
|
Coupe tout l'audio. Arrête la publication de l'audio provenant à la fois du microphone et de l'entrée PCM externe. |
|
|
Coupe uniquement le microphone. Arrête la publication de l'audio capturé par le microphone. |
Exemple de code :
Android
// Mute all audio
mAliRtcEngine.muteLocalMic(true, AliRtcEngine.AliRtcMuteLocalAudioMode.AliRtcMuteAllAudioMode);
// Unmute all audio
mAliRtcEngine.muteLocalMic(false, AliRtcEngine.AliRtcMuteLocalAudioMode.AliRtcMuteAllAudioMode);
// Mute only the microphone
mAliRtcEngine.muteLocalMic(true, AliRtcEngine.AliRtcMuteLocalAudioMode.AliRtcMuteOnlyMicAudioMode);
iOS
// Mute all audio
self.rtcEngine?.muteLocalMic(true, mode: .allAudioMode)
// Unmute all audio
self.rtcEngine?.muteLocalMic(false, mode: .allAudioMode)
// Mute only the microphone
self.rtcEngine?.muteLocalMic(true, mode: .onlyMicAudioMode)
Harmony
// Mute all audio
this.rtcEngine.muteLocalMic(true, AliRtcMuteLocalAudioMode.AliRtcMuteLocalAudioModeMuteAll);
// Unmute all audio
this.rtcEngine.muteLocalMic(false, AliRtcMuteLocalAudioMode.AliRtcMuteLocalAudioModeMuteAll);
// Mute only the microphone
this.rtcEngine.muteLocalMic(true, AliRtcMuteLocalAudioMode.AliRtcMuteLocalAudioModeMuteOnlyMic);
Mac
// Mute all audio
[self.engine muteLocalMic:TRUE mode:AliRtcMuteAllAudioMode];
// Unmute all audio
[self.engine muteLocalMic:FALSE mode:AliRtcMuteAllAudioMode];
// Mute only the microphone
[self.engine muteLocalMic:TRUE mode:AliRtcMuteOnlyMicAudioMode];
Windows
// Mute all audio
mAliRtcEngine->MuteLocalMic(true, AliEngineMuteLocalAudioModeMuteAll);
// Unmute all audio
mAliRtcEngine->MuteLocalMic(false, AliEngineMuteLocalAudioModeMuteAll);
// Mute only the microphone
mAliRtcEngine->MuteLocalMic(true, AliEngineMuteLocalAudioModeMuteOnlyMic);
2,2. Arrêter ou reprendre la capture du microphone
Par défaut, le SDK active la capture du microphone lors de la connexion à un canal. Pour arrêter la capture, appelez stopAudioCapture. Cet appel interrompt la capture audio et libère la ressource du microphone. Pour reprendre la capture, appelez startAudioCapture.
Android
// Stop microphone capture.
mAliRtcEngine.stopAudioCapture();
// Resume microphone capture.
mAliRtcEngine.startAudioCapture();
iOS
// Stop microphone capture.
self.rtcEngine?.stopAudioCapture()
// Resume microphone capture.
self.rtcEngine?.startAudioCapture()
Harmony
// Stop microphone capture.
this.rtcEngine.stopAudioCapture();
// Resume microphone capture.
this.rtcEngine.startAudioCapture();
Mac
// Stop microphone capture.
[self.engine stopAudioCapture];
// Resume microphone capture.
[self.engine startAudioCapture];
Windows
// Stop microphone capture.
mAliRtcEngine->StopAudioCapture();
// Resume microphone capture.
mAliRtcEngine->StartAudioCapture();
3. Paramètres de lecture audio distante
Contrôlez le volume de lecture audio distante et son état de mise en sourdine.
3,1. Mettre en sourdine un utilisateur distant
Utilisez la méthode muteRemoteAudioPlaying pour arrêter ou reprendre la lecture audio d'un utilisateur distant spécifique.
public abstract int muteRemoteAudioPlaying(String uid, boolean mute);
La mise en sourdine n'affecte pas la réception ni le décodage du flux audio. Ce paramètre peut être configuré avant ou après la connexion à une session.
La mise en sourdine affecte uniquement la lecture locale de l'audio de l'utilisateur distant. Elle n'influence pas la capture audio de cet utilisateur distant.
3,2. Définir le volume de lecture pour un utilisateur distant spécifique
Utilisez la méthode setPlayoutVolume pour contrôler le volume de lecture local.
/**
* @brief Sets the playback volume.
* @param volume The playback volume. The value ranges from 0 to 400.
* - 0: Mute.
* - <100: Decreases the volume.
* - >100: Increases the volume.
* @return
* - 0: Success.
* - A non-zero value: Failure.
*/
public abstract int setPlayoutVolume(int volume);
Utilisez la méthode setRemoteAudioVolume pour contrôler le volume de lecture audio d'un utilisateur distant spécifique. Définir le volume sur 0 produit le même effet que muteRemoteAudioPlaying.
/**
* @brief Adjusts the volume of a specific remote user for local playback.
* @param uid The user ID. This is a unique identifier assigned by your app server.
* @param volume The playback volume. The value ranges from 0 to 100, where 0 means mute and 100 means the original volume.
* @return
* - 0: Success.
* - A non-zero value: Failure.
*/
public abstract int setRemoteAudioVolume(String uid, int volume);
4. Retour oreillette
Le retour oreillette vous permet d'entendre l'audio de votre microphone via votre casque en temps réel.
4,1. Activer le retour oreillette
Appelez la méthode enableEarBack avant ou après avoir rejoint un canal pour activer le retour oreillette. Pour le désactiver, rappelez enableEarBack en définissant le paramètre sur false.
Utilisez un casque lorsque le retour oreillette est activé.
Android
rtcEngine.enableEarBack(true);
iOS
engine.enableEarBack(true)
Harmony
this.rtcEngine.enableEarBack(true);
Mac
[self.engine enableEarBack:YES];
Windows
mAliRtcEngine->EnableEarBack(TRUE);
4.2. Définir le volume du retour oreillette
Appelez la méthode setEarBackVolume pour ajuster le volume du retour oreillette. Le paramètre volume définit le volume sur une échelle de 0 à 100, où 0 correspond au mode muet et 100 au volume original. La valeur par défaut est 100.
Android
rtcEngine.setEarBackVolume(60);
iOS
rtcEngine?.setEarBackVolume(volume)
Harmony
this.rtcEngine.setEarBackVolume(value);
Mac
[self.engine setEarBackVolume:60];
Windows
mAliRtcEngine->SetEarBackVolume(volume);
5. Callbacks de volume utilisateur et d'interlocuteur actif
ARTC fournit des callbacks de volume utilisateur et d'interlocuteur actif pour détecter l'état de parole en temps réel des utilisateurs.
Cette fonctionnalité est désactivée par défaut. Appelez enableAudioVolumeIndication pour l'activer. Une fois activée, le système signale périodiquement le volume en temps réel de chaque utilisateur et l'interlocuteur actif actuel à une fréquence spécifiée. Vous pouvez exploiter ces données pour piloter des interactions dans l'interface utilisateur.
5,1. Activer la fonctionnalité de callback
Appelez enableAudioVolumeIndication pour activer la fonctionnalité et configurer les paramètres suivants :
interval : Intervalle de callback en millisecondes (ms). La plage recommandée est de 300 ms à 500 ms. La valeur minimale est de 10 ms. Une valeur négative désactive cette fonctionnalité.
smooth : Facteur de lissage. Une valeur plus élevée assure des variations de volume plus douces, tandis qu'une valeur plus faible offre une meilleure réactivité en temps réel. La valeur recommandée est 3. La plage valide va de 0 à 9.
reportVad : Commutateur pour la détection d'interlocuteur actif. Définissez-le sur 0 pour désactiver cette fonctionnalité, ou sur 1 pour l'activer.
Android
mAliRtcEngine.enableAudioVolumeIndication(500, 3,1);
iOS
// User volume callback and active speaker detection
engine.enableAudioVolumeIndication(500, smooth: 3, reportVad: 1)
Harmony
// User volume callback and active speaker detection
this.rtcEngine.enableAudioVolumeIndication(1000, 3, 1);
Mac
// User volume callback and active speaker detection
[self.engine enableAudioVolumeIndication:500 smooth:3 reportVad:1];
Windows
// User volume callback and active speaker detection
mAliRtcEngine->EnableAudioVolumeIndication(500, 3, 1);
5,2. Implémenter et enregistrer les callbacks
Appelez la méthode registerAudioVolumeObserver pour enregistrer les callbacks. Le système déclenche alors les callbacks suivants à l'intervalle spécifié :
onAudioVolume: Signale périodiquement les informations de volume audio pour tous les utilisateurs détectés, y compris les utilisateurs locaux et distants. Utilisez cette fonction pour implémenter des retours visuels dans l'interface utilisateur, tels que des animations d'ondes sonores ou des indicateurs de volume. SimUserIdest « 0 », l'entrée concerne le volume capturé localement. SimUserIdest « 1 », l'entrée représente le volume mixé de tous les utilisateurs distants. Les autres valeurs indiquent le volume d'un utilisateur spécifique.totalVolumeindique le volume total mixé de tous les utilisateurs distants.onActiveSpeaker: Déclenché par la détection d'activité vocale (VAD) lorsqu'un utilisateur devient l'interlocuteur le plus actif en fonction du volume et de la durée de parole. Utilisez cette fonction pour implémenter des fonctionnalités telles que la mise au point automatique sur l'interlocuteur actif lors d'une conférence.
Android
private final AliRtcEngine.AliRtcAudioVolumeObserver mAliRtcAudioVolumeObserver = new AliRtcEngine.AliRtcAudioVolumeObserver() {
// User volume callback
@Override
public void onAudioVolume(List<AliRtcEngine.AliRtcAudioVolume> speakers, int totalVolume){
handler.post(() -> {
if(!speakers.isEmpty()) {
for(AliRtcEngine.AliRtcAudioVolume volume : speakers) {
if("0".equals(volume.mUserId)) {
// Volume of the local user
} else if ("1".equals(volume.mUserId)) {
// Overall volume of remote users
} else {
// Volume of a remote user
}
}
}
});
}
// Active speaker detection callback
@Override
public void onActiveSpeaker(String uid){
// Active speaker
handler.post(() -> {
String mag = "onActiveSpeaker uid:" + uid;
ToastHelper.showToast(AudioBasicUsageActivity.this, mag, Toast.LENGTH_SHORT);
});
}
};
// Register the callback
mAliRtcEngine.registerAudioVolumeObserver(mAliRtcAudioVolumeObserver);
iOS
Pour iOS, vous n'avez pas besoin d'appeler une méthode pour enregistrer les callbacks. Implémentez simplement les callbacks suivants :
onAudioVolumeCallback
onActiveSpeaker
func onAudioVolumeCallback(_ array: [AliRtcUserVolumeInfo]?, totalVolume: Int32) {
// User volume callback
"onAudioVolumeCallback, totalVolume: \(totalVolume)".printLog()
}
func onActiveSpeaker(_ uid: String) {
// Active speaker callback
"onActiveSpeaker, uid: \(uid)".printLog()
}
Harmony
this.rtcEngineEventListener.onAudioVolumeCallback(
(volumeInfo : AliRtcUserVolumeInfo[], volumeInfoCount : number, totalVolume : number) => {
console.info(`Volume callback: volumeInfo=${volumeInfo}, volumeInfoCount=${volumeInfoCount}, totalVolume=${totalVolume}`);
}
)
this.rtcEngineEventListener.onActiveSpeaker((uid: string) => {
console.info(`Current active user: uid=${uid}`);
});
Mac
- (void)onAudioVolumeCallback:(NSArray <AliRtcUserVolumeInfo *> *)array totalVolume:(int)totalVolume {
for(AliRtcUserVolumeInfo *info in array) {
NSString *uid = info.uid;
NSInteger volume = info.volume;
dispatch_async(dispatch_get_main_queue(), ^{
NSArray * volumeArray = [ _audioVolumeLabel.stringValue componentsSeparatedByString:@"\n"];
if ([uid isEqualToString:@"1"]) { // Volume of remote users
// Overall volume of remote users
}else if ([uid isEqualToString:@"0"] ){ // Volume of the local user
// Display the volume of the local user
} else {
// Overall volume of remote users
}
});
}
}
- (void)onActiveSpeaker:(NSString *)uid {
if ([uid isEqualToString:@"0"]) {
[self log:[@"Active speaker: Self" UTF8String]];
} else {
NSDictionary *dic = [self.engine getUserInfo:uid];
NSString *name = dic[@"displayName"];
MyLog(@"Active speaker: %@",name);
}
}
Windows
void CTutorialDlg::OnAudioVolumeCallback(const AliEngineUserVolumeInfo* volumeInfo, int volumeInfoCount, int totalVolume)
{
CArray<AliEngineUserVolumeInfo*>* pArray = new CArray<AliEngineUserVolumeInfo*>;
for (int i = 0; i < volumeInfoCount; i++)
{
AliEngineUserVolumeInfo* p = new AliEngineUserVolumeInfo;
p->uid = volumeInfo[i].uid;
p->volume = volumeInfo[i].volume;
p->speechState = volumeInfo[i].speechState;
p->sumVolume = volumeInfo[i].sumVolume;
pArray->Add(p);
}
/* Notify the UI to refresh */
PostMessage(MM_VOLUME_CALLBACK, (WPARAM)totalVolume, (LPARAM)pArray);
}
void CTutorialDlg::OnActiveSpeaker(const char *uid)
{
m_strCurSpeaker = CString(uid);
/* Notify the UI to refresh */
PostMessage(MM_ACTIVE_SPEAKER, NULL, NULL);
}
6. Configurer le routage audio
Le routage audio détermine le périphérique de lecture audio utilisé pendant un appel. Les types de périphériques incluent :
-
Périphériques de lecture internes : Ils comprennent généralement le haut-parleur et l'écouteur.
Lorsque l'audio est routé vers le haut-parleur, le volume est suffisamment élevé pour être entendu sans porter le téléphone à l'oreille. Cela permet d'utiliser la fonction mains libres.
Lorsque l'audio est routé vers l'écouteur, le volume est plus faible. Vous devez tenir le téléphone contre votre oreille pour entendre clairement. Cela offre une meilleure confidentialité et convient aux appels téléphoniques.
Périphériques externes : Ils incluent des dispositifs audio externes tels que des écouteurs filaires et des casques Bluetooth. Ils englobent également des interfaces audio professionnelles comme les cartes son externes.
Le SDK commute automatiquement les périphériques en fonction de l'état de connexion des périphériques externes. L'organigramme suivant illustre ce processus :
6,1. Route audio par défaut
Définissez la route audio par défaut sur l'écouteur ou le haut-parleur avant de rejoindre un canal. Si aucun paramètre n'est défini, le haut-parleur est utilisé.
Lorsque des périphériques externes tels que des casques Bluetooth ou des écouteurs filaires sont déconnectés, l'audio est lu via le périphérique défini par cette fonction.
Si aucun périphérique externe n'est connecté et que l'utilisateur n'a pas défini de périphérique actuel, le paramètre par défaut du SDK s'applique. Le SDK utilise le haut-parleur comme sortie par défaut. Pour modifier ce paramètre par défaut, appelez
setDefaultAudioRoutetoSpeakerphone.
/**
* @brief Sets whether the default audio output is the speaker. The default is the speaker.
* @param defaultToSpeakerphone
* - true: Speaker mode.
* - false: Earpiece mode.
* @return
* - 0: Success.
* - <0: Failure.
*/
public int setDefaultAudioRoutetoSpeakerphone(boolean defaultToSpeakerphone);
6,2. Route audio actuelle
Définissez la route audio actuelle sur l'écouteur ou le haut-parleur pendant un appel. Si aucun paramètre n'est défini, la route audio par défaut est utilisée.
Cette fonction n'a aucun effet lorsqu'un périphérique externe, tel que des écouteurs filaires ou un casque Bluetooth, est connecté.
Lorsqu'aucun périphérique externe n'est connecté, appelez enableSpeakerphone pour utiliser le haut-parleur. Définissez-le sur false pour utiliser l'écouteur. Pour vérifier si le périphérique audio actuel est le haut-parleur ou l'écouteur, appelez l'interface isSpeakerOn.
/**
* @brief Sets the audio output to the earpiece or the speaker.
* @param enable true: Speaker mode. false: Earpiece mode.
* @return
* - 0: Success.
* - <0: Failure.
*/
public int enableSpeakerphone(boolean enable);
/**
* @brief Gets whether the current audio output is the earpiece or the speaker.
* @return
* - true: Speaker mode.
* - false: Earpiece mode.
*/
public boolean isSpeakerOn();
6,3. Callback de changement de route audio
Enregistrez et écoutez le callback suivant pour recevoir des notifications lorsque le périphérique de lecture audio change.
public abstract class AliRtcEngineEventListener {
/**
* @brief Warning notification.
* @details Notifies the app through this callback if a warning occurs in the engine.
* @param warn The warning type.
* @param message The warning message.
*/
public void onOccurWarning(int warn, String message);
}
Le tableau suivant montre la correspondance entre les valeurs de retour warn et les types de périphériques.
|
Valeur de retour |
Périphérique |
|
1 |
Écouteurs filaires avec microphone |
|
2 |
Écouteur |
|
3 |
Écouteurs filaires sans microphone |
|
4 |
Haut-parleur |
|
6 |
Périphérique Bluetooth SCO |
|
7 |
Périphérique Bluetooth A2DP |