Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Comme expliqué précédemment, si une application ouvre un flux en mode exclusif, l’application dispose d’une utilisation exclusive de l’appareil de point de terminaison audio qui lit ou enregistre le flux. En revanche, plusieurs applications peuvent partager un appareil de point de terminaison audio en ouvrant des flux en mode partagé sur l’appareil.
Tip
À compter de Windows 10, IAudioClient3 active les flux en mode partagé avec des tailles de période très faibles (aussi bas que la valeur retournée par GetSharedModeEnginePeriod). Cela offre une latence comparable au mode exclusif tout en préservant le mixage et l’interopérabilité du son système. Évaluez les flux à faible période en mode partagé avant de vous engager en mode exclusif, sauf si vous avez une exigence difficile pour la sortie bit-exact ou les taux d’échantillonnage personnalisés.
Avertissement
Les flux en mode exclusif prennent le contrôle du point de terminaison audio — tous les sons système, les notifications et l’audio des autres applications sont coupés. Bien que l’accès en mode exclusif soit activé par défaut dans les paramètres audio, les utilisateurs peuvent le désactiver par appareil. Fournissez toujours une option visible par l’utilisateur pour revenir en mode partagé et relâchez l’appareil rapidement lorsque votre application perd le focus.
L’accès en mode exclusif à un appareil audio peut bloquer les sons système essentiels, empêcher l’interopérabilité avec d’autres applications et dégrader l’expérience utilisateur. Pour atténuer ces problèmes, une application avec un flux en mode exclusif abandonne généralement le contrôle de l’appareil audio lorsque l’application n’est pas le processus de premier plan ou n’est pas activement en streaming.
La latence du flux est le délai inhérent au chemin de données qui connecte la mémoire tampon de point de terminaison d’une application avec un appareil de point de terminaison audio. Pour un flux de rendu, la latence est le délai maximal entre le moment où une application écrit un échantillon dans une mémoire tampon de point de terminaison au moment où l’exemple est entendu par le biais des haut-parleurs. Pour un flux de capture, la latence est le délai maximal entre le moment où un son entre dans le microphone jusqu’à l’heure à laquelle une application peut lire l’exemple pour ce son à partir de la mémoire tampon du point de terminaison.
Les applications qui utilisent des flux en mode exclusif le font souvent, car elles nécessitent des latences faibles dans les chemins d’accès aux données entre les périphériques de point de terminaison audio et les threads d’application qui accèdent aux mémoires tampons de point de terminaison. En règle générale, ces threads s’exécutent avec une priorité relativement élevée et se planifient eux-mêmes pour s’exécuter à des intervalles périodiques proches de, ou identiques à, l’intervalle périodique qui sépare deux passes de traitement successives effectuées par le matériel audio. Pendant chaque passe, le matériel audio traite les nouvelles données dans les mémoires tampons du point de terminaison.
Pour obtenir les latences de flux les plus petites, une application peut nécessiter à la fois du matériel audio spécial et un système informatique légèrement chargé. Pousser le matériel audio au-delà de ses limites de synchronisation ou surcharger le système avec des tâches concurrentes de haute priorité peut provoquer un décrochage dans un flux audio à faible latence. Par exemple, pour un flux de rendu, un problème peut se produire si l’application ne parvient pas à écrire dans une mémoire tampon de point de terminaison avant que le matériel audio lise la mémoire tampon, ou si le matériel ne parvient pas à lire la mémoire tampon avant le moment où la mémoire tampon est planifiée pour lire. En règle générale, une application destinée à s’exécuter sur un large éventail de matériel audio et dans un large éventail de systèmes doit assouplir ses exigences de minutage suffisantes pour éviter les problèmes dans tous les environnements cibles.
Windows Vista dispose de plusieurs fonctionnalités pour prendre en charge les applications qui nécessitent des flux audio à faible latence. Comme indiqué dans Composants audio en mode utilisateur, les applications qui effectuent des opérations critiques en termes de temps peuvent appeler les fonctions du service MMCSS (Multimedia Class Scheduler Service) pour augmenter la priorité des threads sans priver les applications de plus faible priorité de ressources processeur. En outre, la méthode IAudioClient ::Initialize prend en charge un indicateur AUDCLNT_STREAMFLAGS_EVENTCALLBACK qui permet au thread de maintenance de la mémoire tampon d’une application de planifier son exécution lorsqu’une nouvelle mémoire tampon devient disponible à partir de l’appareil audio. En utilisant ces fonctionnalités, un thread d’application peut réduire l’incertitude quant au moment où il s’exécutera, ce qui réduit le risque de glitches dans un flux audio à faible latence.
Les pilotes des cartes audio plus anciennes sont susceptibles d’utiliser l’interface de pilote de périphérique WaveCyclique ou WavePci (DDI), tandis que les pilotes pour les cartes audio plus récentes sont plus susceptibles de prendre en charge la DDI WaveRT. Pour les applications en mode exclusif, les pilotes WaveRT peuvent fournir de meilleures performances que les pilotes WaveCyclique ou WavePci, mais les pilotes WaveRT nécessitent des fonctionnalités matérielles supplémentaires. Ces fonctionnalités incluent la possibilité de partager des mémoires tampons matérielles directement avec des applications. Avec le partage direct, aucune intervention système n’est nécessaire pour transférer des données entre une application en mode exclusif et le matériel audio. En revanche, les pilotes WaveCyclique et WavePci conviennent aux adaptateurs audio plus anciens et moins compatibles. Ces adaptateurs s’appuient sur le logiciel système pour transporter des blocs de données (attachés à des paquets de requête d’E/S système ou des irps) entre les mémoires tampons d’application et les mémoires tampons matérielles. En outre, les périphériques audio USB s’appuient sur les logiciels système pour transporter les données entre les mémoires tampons d’application et les mémoires tampons matérielles. Pour améliorer les performances des applications en mode exclusif qui se connectent aux appareils audio qui s’appuient sur le système pour le transport de données, WASAPI augmente automatiquement la priorité des threads système qui transfèrent des données entre les applications et le matériel. WASAPI utilise MMCSS pour augmenter la priorité du thread. Dans Windows Vista, si un thread système gère le transport de données pour un flux de lecture audio en mode exclusif avec un format PCM et une période d’appareil inférieure à 10 millisecondes, WASAPI affecte le nom de tâche MMCSS « Pro Audio » au thread. Si la période du périphérique pour le flux est supérieure ou égale à 10 millisecondes, WASAPI affecte au thread le nom de tâche MMCSS « Audio ». Pour plus d’informations sur les DDIS WaveCyclique, WavePci et WaveRT, consultez la documentation Windows DDK. Pour plus d’informations sur la sélection d’une période d’appareil appropriée, consultez IAudioClient ::GetDevicePeriod.
Comme décrit dans Les contrôles de volume de session, WASAPI fournit les interfaces ISimpleAudioVolume, IChannelAudioVolume et IAudioStreamVolume pour contrôler les niveaux de volume des flux audio en mode partagé. Toutefois, les contrôles de ces interfaces n’ont aucun effet sur les flux en mode exclusif. Au lieu de cela, les applications qui gèrent des flux en mode exclusif utilisent généralement l’interface IAudioEndpointVolume dans l’API EndpointVolume pour contrôler les niveaux de volume de ces flux. Pour plus d’informations sur cette interface, consultez Contrôles de volume de point de terminaison.
Pour chaque appareil de lecture et appareil de capture dans le système, l’utilisateur peut contrôler si l’appareil peut être utilisé en mode exclusif. Si l’utilisateur désactive l’utilisation en mode exclusif de l’appareil, l’appareil peut être utilisé pour lire ou enregistrer uniquement des flux en mode partagé.
Si l’utilisateur active l’utilisation en mode exclusif de l’appareil, l’utilisateur peut également contrôler si une demande d’une application à utiliser l’appareil en mode exclusif préemptera l’utilisation de l’appareil par les applications susceptibles de lire ou d’enregistrer des flux en mode partagé via l’appareil. Si la préemption est activée, une demande par une application pour prendre le contrôle exclusif de l’appareil réussit si l’appareil n’est actuellement pas utilisé, ou si l’appareil est utilisé en mode partagé, mais la demande échoue si une autre application a déjà un contrôle exclusif de l’appareil. Si la préemption est désactivée, une demande par une application pour prendre le contrôle exclusif de l’appareil réussit si l’appareil n’est pas en cours d’utilisation, mais la demande échoue si l’appareil est déjà utilisé en mode partagé ou en mode exclusif.
Dans Windows Vista, les paramètres par défaut d’un appareil de point de terminaison audio sont les suivants :
- L’appareil peut être utilisé pour lire ou enregistrer des flux en mode exclusif.
- Une demande d’utilisation d’un appareil pour lire ou enregistrer un flux en mode exclusif préempt tout flux en mode partagé en cours de lecture ou d’enregistrement via l’appareil.
Pour modifier les paramètres en mode exclusif d’un appareil de lecture ou d’enregistrement
- Cliquez avec le bouton droit sur l’icône du haut-parleur dans la zone de notification, située sur le côté droit de la barre des tâches, puis sélectionnez Périphériques de lecture ou Appareils d’enregistrement. (Vous pouvez également exécuter le panneau de configuration Multimédia de Windows, Mmsys.cpl, à partir d’une fenêtre d’invite de commandes. Pour plus d’informations, consultez la section Remarques des constantes DEVICE_STATE_XXX.)
- Une fois la fenêtre audio affichée, sélectionnez Lecture ou Enregistrement. Ensuite, sélectionnez une entrée dans la liste des noms d’appareils, puis cliquez sur Propriétés.
- Une fois la fenêtre Propriétés affichée, cliquez sur Avancé.
- Pour permettre aux applications d’utiliser l’appareil en mode exclusif, cochez la case Intitulée Autoriser les applications à prendre le contrôle exclusif de cet appareil. Pour désactiver l’utilisation en mode exclusif de l’appareil, désactivez la case à cocher.
- Si l’utilisation en mode exclusif de l’appareil est activée, vous pouvez spécifier si une demande de contrôle exclusif de l’appareil réussit si l’appareil est en cours de lecture ou d’enregistrement de flux en mode partagé. Pour donner la priorité aux applications en mode exclusif par rapport aux applications en mode partagé, cochez la case Intitulée Donner la priorité aux applications en mode exclusif. Pour refuser la priorité des applications en mode exclusif sur les applications en mode partagé, désactivez la case à cocher.
L’exemple de code suivant montre comment lire un flux audio à faible latence sur un appareil de rendu audio configuré pour une utilisation en mode exclusif :
//-----------------------------------------------------------
// Play an exclusive-mode stream on the default audio
// rendering device. The PlayExclusiveStream function uses
// event-driven buffering and MMCSS to play the stream at
// the minimum latency supported by the device.
//-----------------------------------------------------------
// REFERENCE_TIME time units per second and per millisecond
#define REFTIMES_PER_SEC 10000000
#define REFTIMES_PER_MILLISEC 10000
#define EXIT_ON_ERROR(hres) \
if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk) \
if ((punk) != NULL) \
{ (punk)->Release(); (punk) = NULL; }
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
HRESULT PlayExclusiveStream(MyAudioSource *pMySource)
{
HRESULT hr;
REFERENCE_TIME hnsRequestedDuration = 0;
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDevice *pDevice = NULL;
IAudioClient *pAudioClient = NULL;
IAudioRenderClient *pRenderClient = NULL;
WAVEFORMATEX *pwfx = NULL;
HANDLE hEvent = NULL;
HANDLE hTask = NULL;
UINT32 bufferFrameCount;
BYTE *pData;
DWORD flags = 0;
DWORD taskIndex = 0;
hr = CoCreateInstance(
CLSID_MMDeviceEnumerator, NULL,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
(void**)&pEnumerator);
EXIT_ON_ERROR(hr)
hr = pEnumerator->GetDefaultAudioEndpoint(
eRender, eConsole, &pDevice);
EXIT_ON_ERROR(hr)
hr = pDevice->Activate(
IID_IAudioClient, CLSCTX_ALL,
NULL, (void**)&pAudioClient);
EXIT_ON_ERROR(hr)
// Call a helper function to negotiate with the audio
// device for an exclusive-mode stream format.
hr = GetStreamFormat(pAudioClient, &pwfx);
EXIT_ON_ERROR(hr)
// Initialize the stream to play at the minimum latency.
hr = pAudioClient->GetDevicePeriod(NULL, &hnsRequestedDuration);
EXIT_ON_ERROR(hr)
hr = pAudioClient->Initialize(
AUDCLNT_SHAREMODE_EXCLUSIVE,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
hnsRequestedDuration,
hnsRequestedDuration,
pwfx,
NULL);
if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) {
// Align the buffer if needed, see IAudioClient::Initialize() documentation
UINT32 nFrames = 0;
hr = pAudioClient->GetBufferSize(&nFrames);
EXIT_ON_ERROR(hr)
hnsRequestedDuration = (REFERENCE_TIME)((double)REFTIMES_PER_SEC / pwfx->nSamplesPerSec * nFrames + 0.5);
hr = pAudioClient->Initialize(
AUDCLNT_SHAREMODE_EXCLUSIVE,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
hnsRequestedDuration,
hnsRequestedDuration,
pwfx,
NULL);
}
EXIT_ON_ERROR(hr)
// Tell the audio source which format to use.
hr = pMySource->SetFormat(pwfx);
EXIT_ON_ERROR(hr)
// Create an event handle and register it for
// buffer-event notifications.
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent == NULL)
{
hr = E_FAIL;
goto Exit;
}
hr = pAudioClient->SetEventHandle(hEvent);
EXIT_ON_ERROR(hr);
// Get the actual size of the two allocated buffers.
hr = pAudioClient->GetBufferSize(&bufferFrameCount);
EXIT_ON_ERROR(hr)
hr = pAudioClient->GetService(
IID_IAudioRenderClient,
(void**)&pRenderClient);
EXIT_ON_ERROR(hr)
// To reduce latency, load the first buffer with data
// from the audio source before starting the stream.
hr = pRenderClient->GetBuffer(bufferFrameCount, &pData);
EXIT_ON_ERROR(hr)
hr = pMySource->LoadData(bufferFrameCount, pData, &flags);
EXIT_ON_ERROR(hr)
hr = pRenderClient->ReleaseBuffer(bufferFrameCount, flags);
EXIT_ON_ERROR(hr)
// Ask MMCSS to temporarily boost the thread priority
// to reduce glitches while the low-latency stream plays.
hTask = AvSetMmThreadCharacteristics(TEXT("Pro Audio"), &taskIndex);
if (hTask == NULL)
{
hr = E_FAIL;
EXIT_ON_ERROR(hr)
}
hr = pAudioClient->Start(); // Start playing.
EXIT_ON_ERROR(hr)
// Each loop fills one of the two buffers.
while (flags != AUDCLNT_BUFFERFLAGS_SILENT)
{
// Wait for next buffer event to be signaled.
DWORD retval = WaitForSingleObject(hEvent, 2000);
if (retval != WAIT_OBJECT_0)
{
// Event handle timed out after a 2-second wait.
pAudioClient->Stop();
hr = ERROR_TIMEOUT;
goto Exit;
}
// Grab the next empty buffer from the audio device.
hr = pRenderClient->GetBuffer(bufferFrameCount, &pData);
EXIT_ON_ERROR(hr)
// Load the buffer with data from the audio source.
hr = pMySource->LoadData(bufferFrameCount, pData, &flags);
EXIT_ON_ERROR(hr)
hr = pRenderClient->ReleaseBuffer(bufferFrameCount, flags);
EXIT_ON_ERROR(hr)
}
// Wait for the last buffer to play before stopping.
Sleep((DWORD)(hnsRequestedDuration/REFTIMES_PER_MILLISEC));
hr = pAudioClient->Stop(); // Stop playing.
EXIT_ON_ERROR(hr)
Exit:
if (hEvent != NULL)
{
CloseHandle(hEvent);
}
if (hTask != NULL)
{
AvRevertMmThreadCharacteristics(hTask);
}
CoTaskMemFree(pwfx);
SAFE_RELEASE(pEnumerator)
SAFE_RELEASE(pDevice)
SAFE_RELEASE(pAudioClient)
SAFE_RELEASE(pRenderClient)
return hr;
}
Dans l’exemple de code précédent, la fonction PlayExclusiveStream s’exécute dans le thread d’application qui gère les mémoires tampons de point de terminaison pendant qu’un flux de rendu est en cours de lecture. La fonction prend un paramètre unique, pMySource, qui est un pointeur vers un objet qui appartient à une classe définie par le client, MyAudioSource. Cette classe a deux fonctions membres, LoadData et SetFormat, appelées dans l’exemple de code. MyAudioSource est décrit dans Rendu d’un flux.
La fonction PlayExclusiveStream appelle une fonction d’assistance, GetStreamFormat, qui négocie avec l’appareil de rendu par défaut pour déterminer si l’appareil prend en charge un format de flux en mode exclusif adapté à l’utilisation par l’application. Le code de la fonction GetStreamFormat n’apparaît pas dans l’exemple de code ; c’est parce que les détails de son implémentation dépendent entièrement des exigences de l’application. Toutefois, l’opération de la fonction GetStreamFormat peut être décrite simplement : elle appelle la méthode IAudioClient ::IsFormatSupported une ou plusieurs fois pour déterminer si l’appareil prend en charge un format approprié. Les exigences de l’application déterminent quels formats GetStreamFormat présente à la méthode IsFormatSupported et l’ordre dans lequel elle les présente. Pour plus d’informations sur IsFormatSupported, consultez Formats d’appareil.
Après l’appel GetStreamFormat, la fonction PlayExclusiveStream appelle la méthode IAudioClient ::GetDevicePeriod pour obtenir la période minimale d’appareil prise en charge par le matériel audio. Ensuite, la fonction appelle la méthode IAudioClient ::Initialize pour demander une durée de mémoire tampon égale à la période minimale. Si l’appel réussit, la méthode Initialize alloue deux mémoires tampons de point de terminaison, chacune d’elles étant égale à la durée minimale. Plus tard, lorsque le flux audio commence à s’exécuter, l’application et le matériel audio partageront les deux mémoires tampons de la mode « ping-pong », c’est-à-dire, tandis que l’application écrit dans une mémoire tampon, le matériel lit à partir de l’autre mémoire tampon.
Avant de démarrer le flux, la fonction PlayExclusiveStream effectue les opérations suivantes :
- Crée et enregistre le descripteur d’événement grâce auquel il recevra des notifications lorsque les tampons seront prêts à être remplis.
- Remplit la première mémoire tampon avec des données de la source audio pour réduire le délai de début de l’exécution du flux jusqu’au moment où le son initial est entendu.
- Appelle la fonction AvSetMmThreadCharacteristics pour demander que MMCSS augmente la priorité du thread dans lequel PlayExclusiveStream s’exécute. (Lorsque le flux cesse d’être en cours d’exécution, l’appel de fonction AvRevertMmThreadCharacteristics restaure la priorité de thread d’origine.)
Pour plus d’informations sur AvSetMmThreadCharacteristics et AvRevertMmThreadCharacteristics, consultez la documentation Windows SDK.
Pendant l’exécution du flux, chaque itération de la boucle while dans l’exemple de code précédent remplit une mémoire tampon de point de terminaison. Entre les itérations, l’appel de fonction WaitForSingleObject attend que le handle d’événement soit signalé. Lorsque le handle est signalé, le corps de la boucle effectue les opérations suivantes :
- Appelle la méthode IAudioRenderClient ::GetBuffer pour obtenir la mémoire tampon suivante.
- Remplit la mémoire tampon.
- Appelle la méthode IAudioRenderClient ::ReleaseBuffer pour libérer la mémoire tampon.
Pour plus d’informations sur WaitForSingleObject, consultez la documentation Windows SDK.
Si l’adaptateur audio est contrôlé par un pilote WaveRT, la signalisation du descripteur d’événement est liée aux notifications de transfert DMA provenant du matériel audio. Pour un périphérique audio USB ou pour un périphérique audio contrôlé par un pilote WaveCyclique ou WavePci, la signalisation du handle d’événement est liée à des achèvements des IRPs qui transfèrent les données de la mémoire tampon d’application vers la mémoire tampon matérielle.
L’exemple de code précédent pousse le matériel audio et l’ordinateur jusqu’à leurs limites de performance. Tout d’abord, pour réduire la latence du flux, l’application configure son thread de gestion du tampon afin d’utiliser la période minimale du périphérique que le matériel audio peut prendre en charge. Ensuite, pour vous assurer que le thread s’exécute de manière fiable dans chaque période d’appareil, l’appel de fonction AvSetMmThreadCharacteristics définit le paramètre TaskName sur « Pro Audio », qui est, dans Windows Vista, le nom de tâche par défaut avec la priorité la plus élevée. Déterminez si les exigences temporelles de votre application peuvent être assouplies sans compromettre son utilité. Par exemple, l’application peut planifier son thread de maintenance de mémoire tampon pour utiliser une période plus longue que la valeur minimale. Une période plus longue peut autoriser en toute sécurité l’utilisation d’une priorité de thread inférieure.
Rubriques connexes