NVDA Helper
In-process and lite high-speed utilities for NVDA
wasapi.cpp File Reference
#include <thread>
#include <vector>
#include <windows.h>
#include <atlbase.h>
#include <atlcomcli.h>
#include <audioclient.h>
#include <audiopolicy.h>
#include <functiondiscoverykeys.h>
#include <Functiondiscoverykeys_devpkey.h>
#include <mmdeviceapi.h>
#include <common/log.h>
#include <random>

Go to the source code of this file.

Classes

class  AutoHandle
 C++ RAII class to manage the lifecycle of a standard Windows HANDLE closed with CloseHandle. More...
 
class  NotificationClient
 Listens for default device changes and device state changes. More...
 
class  WasapiPlayer
 Play a stream of audio using WASAPI. More...
 
class  SilencePlayer
 Asynchronously play silence for requested durations. More...
 

Functions

WasapiPlayerwasPlay_create (wchar_t *deviceName, WAVEFORMATEX format, WasapiPlayer::ChunkCompletedCallback callback)
 
void wasPlay_destroy (WasapiPlayer *player)
 
HRESULT wasPlay_open (WasapiPlayer *player)
 
HRESULT wasPlay_feed (WasapiPlayer *player, unsigned char *data, unsigned int size, unsigned int *id)
 
HRESULT wasPlay_stop (WasapiPlayer *player)
 
HRESULT wasPlay_sync (WasapiPlayer *player)
 
HRESULT wasPlay_idle (WasapiPlayer *player)
 
HRESULT wasPlay_pause (WasapiPlayer *player)
 
HRESULT wasPlay_resume (WasapiPlayer *player)
 
HRESULT wasPlay_setChannelVolume (WasapiPlayer *player, unsigned int channel, float level)
 
HRESULT wasPlay_startup ()
 This must be called once per session at startup before wasPlay_create is called.
 
HRESULT wasSilence_init (wchar_t *deviceName)
 
void wasSilence_playFor (DWORD ms, float volume)
 
void wasSilence_terminate ()
 

Variables

constexpr REFERENCE_TIME REFTIMES_PER_MILLISEC = 10000
 Support for audio playback using WASAPI.
 
constexpr DWORD BUFFER_MS = 400
 
constexpr REFERENCE_TIME BUFFER_SIZE = BUFFER_MS * REFTIMES_PER_MILLISEC
 
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator)
 
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator)
 
const IID IID_IAudioClient = __uuidof(IAudioClient)
 
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient)
 
const IID IID_IAudioClock = __uuidof(IAudioClock)
 
const IID IID_IMMNotificationClient = __uuidof(IMMNotificationClient)
 
const IID IID_IAudioStreamVolume = __uuidof(IAudioStreamVolume)
 
CComPtr< NotificationClientnotificationClient
 
SilencePlayersilence = nullptr
 

Function Documentation

◆ wasPlay_create()

WasapiPlayer * wasPlay_create ( wchar_t * deviceName,
WAVEFORMATEX format,
WasapiPlayer::ChunkCompletedCallback callback )

◆ wasPlay_destroy()

void wasPlay_destroy ( WasapiPlayer * player)

◆ wasPlay_open()

HRESULT wasPlay_open ( WasapiPlayer * player)

References WasapiPlayer::open().

◆ wasPlay_feed()

HRESULT wasPlay_feed ( WasapiPlayer * player,
unsigned char * data,
unsigned int size,
unsigned int * id )

References WasapiPlayer::feed().

◆ wasPlay_stop()

HRESULT wasPlay_stop ( WasapiPlayer * player)

References WasapiPlayer::stop().

◆ wasPlay_sync()

HRESULT wasPlay_sync ( WasapiPlayer * player)

References WasapiPlayer::sync().

◆ wasPlay_idle()

HRESULT wasPlay_idle ( WasapiPlayer * player)

References WasapiPlayer::idle().

◆ wasPlay_pause()

HRESULT wasPlay_pause ( WasapiPlayer * player)

References WasapiPlayer::pause().

◆ wasPlay_resume()

HRESULT wasPlay_resume ( WasapiPlayer * player)

◆ wasPlay_setChannelVolume()

HRESULT wasPlay_setChannelVolume ( WasapiPlayer * player,
unsigned int channel,
float level )

◆ wasPlay_startup()

HRESULT wasPlay_startup ( )

This must be called once per session at startup before wasPlay_create is called.

References CLSID_MMDeviceEnumerator, HRESULT(), and notificationClient.

◆ wasSilence_init()

HRESULT wasSilence_init ( wchar_t * deviceName)

References SilencePlayer::init(), and silence.

◆ wasSilence_playFor()

void wasSilence_playFor ( DWORD ms,
float volume )

◆ wasSilence_terminate()

void wasSilence_terminate ( )

Variable Documentation

◆ REFTIMES_PER_MILLISEC

REFERENCE_TIME REFTIMES_PER_MILLISEC = 10000
constexpr

Support for audio playback using WASAPI.

Most of the core work happens in the WasapiPlayer class. Because Python ctypes can't call C++ classes, NVDA interfaces with this using the wasPlay_* and wasSilence_* functions.

◆ BUFFER_MS

DWORD BUFFER_MS = 400
constexpr

◆ BUFFER_SIZE

REFERENCE_TIME BUFFER_SIZE = BUFFER_MS * REFTIMES_PER_MILLISEC
constexpr

Referenced by WasapiPlayer::open().

◆ CLSID_MMDeviceEnumerator

const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator)

◆ IID_IMMDeviceEnumerator

const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator)

◆ IID_IAudioClient

const IID IID_IAudioClient = __uuidof(IAudioClient)

Referenced by WasapiPlayer::open().

◆ IID_IAudioRenderClient

const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient)

Referenced by WasapiPlayer::open().

◆ IID_IAudioClock

const IID IID_IAudioClock = __uuidof(IAudioClock)

Referenced by WasapiPlayer::open().

◆ IID_IMMNotificationClient

const IID IID_IMMNotificationClient = __uuidof(IMMNotificationClient)

◆ IID_IAudioStreamVolume

const IID IID_IAudioStreamVolume = __uuidof(IAudioStreamVolume)

◆ notificationClient

CComPtr<NotificationClient> notificationClient

◆ silence