view release on metacpan or search on metacpan
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
void* pIntermediaryBuffer; /* For implementing fixed sized buffer callbacks. Will be null if using variable sized callbacks. */
ma_uint32 intermediaryBufferCap;
ma_uint32 intermediaryBufferLen; /* How many valid frames are sitting in the intermediary buffer. */
} capture;
union
{
#ifdef MA_SUPPORT_WASAPI
struct
{
/*IAudioClient**/ ma_ptr pAudioClientPlayback;
/*IAudioClient**/ ma_ptr pAudioClientCapture;
/*IAudioRenderClient**/ ma_ptr pRenderClient;
/*IAudioCaptureClient**/ ma_ptr pCaptureClient;
/*IMMDeviceEnumerator**/ ma_ptr pDeviceEnumerator; /* Used for IMMNotificationClient notifications. Required for detecting default device changes. */
ma_IMMNotificationClient notificationClient;
/*HANDLE*/ ma_handle hEventPlayback; /* Auto reset. Initialized to signaled. */
/*HANDLE*/ ma_handle hEventCapture; /* Auto reset. Initialized to unsignaled. */
ma_uint32 actualBufferSizeInFramesPlayback; /* Value from GetBufferSize(). internalPeriodSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works...
ma_uint32 actualBufferSizeInFramesCapture;
ma_uint32 originalPeriodSizeInFrames;
ma_uint32 originalPeriodSizeInMilliseconds;
ma_uint32 originalPeriods;
ma_performance_profile originalPerformanceProfile;
ma_uint32 periodSizeInFramesPlayback;
ma_uint32 periodSizeInFramesCapture;
void* pMappedBufferCapture;
ma_uint32 mappedBufferCaptureCap;
ma_uint32 mappedBufferCaptureLen;
void* pMappedBufferPlayback;
ma_uint32 mappedBufferPlaybackCap;
ma_uint32 mappedBufferPlaybackLen;
MA_ATOMIC(4, ma_bool32) isStartedCapture; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
MA_ATOMIC(4, ma_bool32) isStartedPlayback; /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
ma_bool8 noAutoConvertSRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */
ma_bool8 noDefaultQualitySRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */
ma_bool8 noHardwareOffloading;
ma_bool8 allowCaptureAutoStreamRouting;
ma_bool8 allowPlaybackAutoStreamRouting;
ma_bool8 isDetachedPlayback;
ma_bool8 isDetachedCapture;
} wasapi;
#endif
#ifdef MA_SUPPORT_DSOUND
struct
{
/*LPDIRECTSOUND*/ ma_ptr pPlayback;
/*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackPrimaryBuffer;
/*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackBuffer;
/*LPDIRECTSOUNDCAPTURE*/ ma_ptr pCapture;
/*LPDIRECTSOUNDCAPTUREBUFFER*/ ma_ptr pCaptureBuffer;
} dsound;
#endif
#ifdef MA_SUPPORT_WINMM
struct
{
/*HWAVEOUT*/ ma_handle hDevicePlayback;
/*HWAVEIN*/ ma_handle hDeviceCapture;
/*HANDLE*/ ma_handle hEventPlayback;
/*HANDLE*/ ma_handle hEventCapture;
ma_uint32 fragmentSizeInFrames;
ma_uint32 iNextHeaderPlayback; /* [0,periods). Used as an index into pWAVEHDRPlayback. */
ma_uint32 iNextHeaderCapture; /* [0,periods). Used as an index into pWAVEHDRCapture. */
ma_uint32 headerFramesConsumedPlayback; /* The number of PCM frames consumed in the buffer in pWAVEHEADER[iNextHeader]. */
ma_uint32 headerFramesConsumedCapture; /* ^^^ */
/*WAVEHDR**/ ma_uint8* pWAVEHDRPlayback; /* One instantiation for each period. */
/*WAVEHDR**/ ma_uint8* pWAVEHDRCapture; /* One instantiation for each period. */
ma_uint8* pIntermediaryBufferPlayback;
ma_uint8* pIntermediaryBufferCapture;
ma_uint8* _pHeapData; /* Used internally and is used for the heap allocated data for the intermediary buffer and the WAVEHDR structures. */
} winmm;
#endif
#ifdef MA_SUPPORT_ALSA
struct
{
/*snd_pcm_t**/ ma_ptr pPCMPlayback;
/*snd_pcm_t**/ ma_ptr pPCMCapture;
/*struct pollfd**/ void* pPollDescriptorsPlayback;
/*struct pollfd**/ void* pPollDescriptorsCapture;
int pollDescriptorCountPlayback;
int pollDescriptorCountCapture;
int wakeupfdPlayback; /* eventfd for waking up from poll() when the playback device is stopped. */
int wakeupfdCapture; /* eventfd for waking up from poll() when the capture device is stopped. */
ma_bool8 isUsingMMapPlayback;
ma_bool8 isUsingMMapCapture;
} alsa;
#endif
#ifdef MA_SUPPORT_PULSEAUDIO
struct
{
/*pa_mainloop**/ ma_ptr pMainLoop;
/*pa_context**/ ma_ptr pPulseContext;
/*pa_stream**/ ma_ptr pStreamPlayback;
/*pa_stream**/ ma_ptr pStreamCapture;
} pulse;
#endif
#ifdef MA_SUPPORT_JACK
struct
{
/*jack_client_t**/ ma_ptr pClient;
/*jack_port_t**/ ma_ptr* ppPortsPlayback;
/*jack_port_t**/ ma_ptr* ppPortsCapture;
float* pIntermediaryBufferPlayback; /* Typed as a float because JACK is always floating point. */
float* pIntermediaryBufferCapture;
} jack;
#endif
#ifdef MA_SUPPORT_COREAUDIO
struct
{
ma_uint32 deviceObjectIDPlayback;
ma_uint32 deviceObjectIDCapture;
/*AudioUnit*/ ma_ptr audioUnitPlayback;
/*AudioUnit*/ ma_ptr audioUnitCapture;
/*AudioBufferList**/ ma_ptr pAudioBufferList; /* Only used for input devices. */
ma_uint32 audioBufferCapInFrames; /* Only used for input devices. The capacity in frames of each buffer in pAudioBufferList. */
ma_event stopEvent;
ma_uint32 originalPeriodSizeInFrames;
ma_uint32 originalPeriodSizeInMilliseconds;
ma_uint32 originalPeriods;
ma_performance_profile originalPerformanceProfile;
ma_bool32 isDefaultPlaybackDevice;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Safe. It's safe to call this from any thread with the exception of the callback thread.
Callback Safety
---------------
Unsafe. It is not safe to call this inside any callback.
Remarks
-------
For a playback device, this will retrieve an initial chunk of audio data from the client before returning. The reason for this is to ensure there is valid
audio data in the buffer, which needs to be done before the device begins playback.
This API waits until the backend device has been started for real by the worker thread. It also waits on a mutex for thread-safety.
Do not call this in any callback.
See Also
--------
ma_device_stop()
*/
MA_API ma_result ma_device_start(ma_device* pDevice);
/*
Stops the device. For playback devices this stops playback. For capture devices it stops recording.
Use `ma_device_start()` to start the device again.
Parameters
----------
pDevice (in)
A pointer to the device to stop.
Return Value
------------
MA_SUCCESS if successful; any other error code otherwise.
Thread Safety
-------------
Safe. It's safe to call this from any thread with the exception of the callback thread.
Callback Safety
---------------
Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock.
Remarks
-------
This API needs to wait on the worker thread to stop the backend device properly before returning. It also waits on a mutex for thread-safety. In addition, some
backends need to wait for the device to finish playback/recording of the current fragment which can take some time (usually proportionate to the buffer size
that was specified at initialization time).
Backends are required to either pause the stream in-place or drain the buffer if pausing is not possible. The reason for this is that stopping the device and
the resuming it with ma_device_start() (which you might do when your program loses focus) may result in a situation where those samples are never output to the
speakers or received from the microphone which can in turn result in de-syncs.
Do not call this in any callback.
This will be called implicitly by `ma_device_uninit()`.
See Also
--------
ma_device_start()
*/
MA_API ma_result ma_device_stop(ma_device* pDevice);
/*
Determines whether or not the device is started.
Parameters
----------
pDevice (in)
A pointer to the device whose start state is being retrieved.
Return Value
------------
True if the device is started, false otherwise.
Thread Safety
-------------
Safe. If another thread calls `ma_device_start()` or `ma_device_stop()` at this same time as this function is called, there's a very small chance the return
value will be out of sync.
Callback Safety
---------------
Safe. This is implemented as a simple accessor.
See Also
--------
ma_device_start()
ma_device_stop()
*/
MA_API ma_bool32 ma_device_is_started(const ma_device* pDevice);
/*
Retrieves the state of the device.
Parameters
----------
pDevice (in)
A pointer to the device whose state is being retrieved.
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
CloseHandle((HANDLE)pDevice->winmm.hEventPlayback);
}
ma_free(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks);
MA_ZERO_OBJECT(&pDevice->winmm); /* Safety. */
return MA_SUCCESS;
}
static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__winmm(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile)
{
/* WinMM has a minimum period size of 40ms. */
ma_uint32 minPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(40, nativeSampleRate);
ma_uint32 periodSizeInFrames;
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, nativeSampleRate, performanceProfile);
if (periodSizeInFrames < minPeriodSizeInFrames) {
periodSizeInFrames = minPeriodSizeInFrames;
}
return periodSizeInFrames;
}
static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
{
const char* errorMsg = "";
ma_result errorCode = MA_ERROR;
ma_result result = MA_SUCCESS;
ma_uint32 heapSize;
UINT winMMDeviceIDPlayback = 0;
UINT winMMDeviceIDCapture = 0;
MA_ASSERT(pDevice != NULL);
MA_ZERO_OBJECT(&pDevice->winmm);
if (pConfig->deviceType == ma_device_type_loopback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED;
}
/* No exlusive mode with WinMM. */
if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive)) {
return MA_SHARE_MODE_NOT_SUPPORTED;
}
if (pDescriptorPlayback->pDeviceID != NULL) {
winMMDeviceIDPlayback = (UINT)pDescriptorPlayback->pDeviceID->winmm;
}
if (pDescriptorCapture->pDeviceID != NULL) {
winMMDeviceIDCapture = (UINT)pDescriptorCapture->pDeviceID->winmm;
}
/* The capture device needs to be initialized first. */
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
WAVEINCAPSA caps;
WAVEFORMATEX wf;
MMRESULT resultMM;
/* We use an event to know when a new fragment needs to be enqueued. */
pDevice->winmm.hEventCapture = (ma_handle)CreateEventW(NULL, TRUE, TRUE, NULL);
if (pDevice->winmm.hEventCapture == NULL) {
errorMsg = "[WinMM] Failed to create event for fragment enqueing for the capture device.", errorCode = ma_result_from_GetLastError(GetLastError());
goto on_error;
}
/* The format should be based on the device's actual format. */
if (((MA_PFN_waveInGetDevCapsA)pDevice->pContext->winmm.waveInGetDevCapsA)(winMMDeviceIDCapture, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
goto on_error;
}
result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf);
if (result != MA_SUCCESS) {
errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result;
goto on_error;
}
resultMM = ((MA_PFN_waveInOpen)pDevice->pContext->winmm.waveInOpen)((LPHWAVEIN)&pDevice->winmm.hDeviceCapture, winMMDeviceIDCapture, &wf, (DWORD_PTR)pDevice->winmm.hEventCapture, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
if (resultMM != MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to open capture device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
goto on_error;
}
pDescriptorCapture->format = ma_format_from_WAVEFORMATEX(&wf);
pDescriptorCapture->channels = wf.nChannels;
pDescriptorCapture->sampleRate = wf.nSamplesPerSec;
ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels);
pDescriptorCapture->periodCount = pDescriptorCapture->periodCount;
pDescriptorCapture->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile);
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
WAVEOUTCAPSA caps;
WAVEFORMATEX wf;
MMRESULT resultMM;
/* We use an event to know when a new fragment needs to be enqueued. */
pDevice->winmm.hEventPlayback = (ma_handle)CreateEventW(NULL, TRUE, TRUE, NULL);
if (pDevice->winmm.hEventPlayback == NULL) {
errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError());
goto on_error;
}
/* The format should be based on the device's actual format. */
if (((MA_PFN_waveOutGetDevCapsA)pDevice->pContext->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
goto on_error;
}
result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf);
if (result != MA_SUCCESS) {
errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result;
goto on_error;
}
resultMM = ((MA_PFN_waveOutOpen)pDevice->pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevicePlayback, winMMDeviceIDPlayback, &wf, (DWORD_PTR)pDevice->winmm.hEventPlayback, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
if (resultMM != MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to open playback device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
goto on_error;
}
pDescriptorPlayback->format = ma_format_from_WAVEFORMATEX(&wf);
pDescriptorPlayback->channels = wf.nChannels;
pDescriptorPlayback->sampleRate = wf.nSamplesPerSec;
ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels);
pDescriptorPlayback->periodCount = pDescriptorPlayback->periodCount;
pDescriptorPlayback->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
}
/*
The heap allocated data is allocated like so:
[Capture WAVEHDRs][Playback WAVEHDRs][Capture Intermediary Buffer][Playback Intermediary Buffer]
*/
heapSize = 0;
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
heapSize += sizeof(WAVEHDR)*pDescriptorCapture->periodCount + (pDescriptorCapture->periodSizeInFrames * pDescriptorCapture->periodCount * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels));
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
heapSize += sizeof(WAVEHDR)*pDescriptorPlayback->periodCount + (pDescriptorPlayback->periodSizeInFrames * pDescriptorPlayback->periodCount * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels));
}
pDevice->winmm._pHeapData = (ma_uint8*)ma_calloc(heapSize, &pDevice->pContext->allocationCallbacks);
if (pDevice->winmm._pHeapData == NULL) {
errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MA_OUT_OF_MEMORY;
goto on_error;
}
MA_ZERO_MEMORY(pDevice->winmm._pHeapData, heapSize);
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
ma_uint32 iPeriod;
if (pConfig->deviceType == ma_device_type_capture) {
pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData;
pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount));
} else {
pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData;
pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount + pDescriptorPlayback->periodCount));
}
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
#define MA_PA_CHANNEL_POSITION_AUX22 34
#define MA_PA_CHANNEL_POSITION_AUX23 35
#define MA_PA_CHANNEL_POSITION_AUX24 36
#define MA_PA_CHANNEL_POSITION_AUX25 37
#define MA_PA_CHANNEL_POSITION_AUX26 38
#define MA_PA_CHANNEL_POSITION_AUX27 39
#define MA_PA_CHANNEL_POSITION_AUX28 40
#define MA_PA_CHANNEL_POSITION_AUX29 41
#define MA_PA_CHANNEL_POSITION_AUX30 42
#define MA_PA_CHANNEL_POSITION_AUX31 43
#define MA_PA_CHANNEL_POSITION_TOP_CENTER 44
#define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT 45
#define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT 46
#define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER 47
#define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT 48
#define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT 49
#define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER 50
#define MA_PA_CHANNEL_POSITION_LEFT MA_PA_CHANNEL_POSITION_FRONT_LEFT
#define MA_PA_CHANNEL_POSITION_RIGHT MA_PA_CHANNEL_POSITION_FRONT_RIGHT
#define MA_PA_CHANNEL_POSITION_CENTER MA_PA_CHANNEL_POSITION_FRONT_CENTER
#define MA_PA_CHANNEL_POSITION_SUBWOOFER MA_PA_CHANNEL_POSITION_LFE
typedef int ma_pa_channel_map_def_t;
#define MA_PA_CHANNEL_MAP_AIFF 0
#define MA_PA_CHANNEL_MAP_ALSA 1
#define MA_PA_CHANNEL_MAP_AUX 2
#define MA_PA_CHANNEL_MAP_WAVEEX 3
#define MA_PA_CHANNEL_MAP_OSS 4
#define MA_PA_CHANNEL_MAP_DEFAULT MA_PA_CHANNEL_MAP_AIFF
typedef int ma_pa_sample_format_t;
#define MA_PA_SAMPLE_INVALID -1
#define MA_PA_SAMPLE_U8 0
#define MA_PA_SAMPLE_ALAW 1
#define MA_PA_SAMPLE_ULAW 2
#define MA_PA_SAMPLE_S16LE 3
#define MA_PA_SAMPLE_S16BE 4
#define MA_PA_SAMPLE_FLOAT32LE 5
#define MA_PA_SAMPLE_FLOAT32BE 6
#define MA_PA_SAMPLE_S32LE 7
#define MA_PA_SAMPLE_S32BE 8
#define MA_PA_SAMPLE_S24LE 9
#define MA_PA_SAMPLE_S24BE 10
#define MA_PA_SAMPLE_S24_32LE 11
#define MA_PA_SAMPLE_S24_32BE 12
typedef struct ma_pa_mainloop ma_pa_mainloop;
typedef struct ma_pa_threaded_mainloop ma_pa_threaded_mainloop;
typedef struct ma_pa_mainloop_api ma_pa_mainloop_api;
typedef struct ma_pa_context ma_pa_context;
typedef struct ma_pa_operation ma_pa_operation;
typedef struct ma_pa_stream ma_pa_stream;
typedef struct ma_pa_spawn_api ma_pa_spawn_api;
typedef struct
{
ma_uint32 maxlength;
ma_uint32 tlength;
ma_uint32 prebuf;
ma_uint32 minreq;
ma_uint32 fragsize;
} ma_pa_buffer_attr;
typedef struct
{
ma_uint8 channels;
ma_pa_channel_position_t map[MA_PA_CHANNELS_MAX];
} ma_pa_channel_map;
typedef struct
{
ma_uint8 channels;
ma_uint32 values[MA_PA_CHANNELS_MAX];
} ma_pa_cvolume;
typedef struct
{
ma_pa_sample_format_t format;
ma_uint32 rate;
ma_uint8 channels;
} ma_pa_sample_spec;
typedef struct
{
const char* name;
ma_uint32 index;
const char* description;
ma_pa_sample_spec sample_spec;
ma_pa_channel_map channel_map;
ma_uint32 owner_module;
ma_pa_cvolume volume;
int mute;
ma_uint32 monitor_source;
const char* monitor_source_name;
ma_uint64 latency;
const char* driver;
ma_pa_sink_flags_t flags;
void* proplist;
ma_uint64 configured_latency;
ma_uint32 base_volume;
ma_pa_sink_state_t state;
ma_uint32 n_volume_steps;
ma_uint32 card;
ma_uint32 n_ports;
void** ports;
void* active_port;
ma_uint8 n_formats;
void** formats;
} ma_pa_sink_info;
typedef struct
{
const char *name;
ma_uint32 index;
const char *description;
ma_pa_sample_spec sample_spec;
ma_pa_channel_map channel_map;
ma_uint32 owner_module;
ma_pa_cvolume volume;
int mute;
ma_uint32 monitor_of_sink;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (deviceType == ma_device_type_playback) {
pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceName, ma_context_get_device_info_sink_callback__pulse, &callbackData);
} else {
pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceName, ma_context_get_device_info_source_callback__pulse, &callbackData);
}
if (pOP != NULL) {
ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP);
} else {
result = MA_ERROR;
goto done;
}
if (!callbackData.foundDevice) {
result = MA_NO_DEVICE;
goto done;
}
done:
return result;
}
static ma_result ma_device_uninit__pulse(ma_device* pDevice)
{
ma_context* pContext;
MA_ASSERT(pDevice != NULL);
pContext = pDevice->pContext;
MA_ASSERT(pContext != NULL);
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
}
if (pDevice->type == ma_device_type_duplex) {
ma_duplex_rb_uninit(&pDevice->duplexRB);
}
((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pDevice->pulse.pPulseContext);
((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pDevice->pulse.pPulseContext);
((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pDevice->pulse.pMainLoop);
return MA_SUCCESS;
}
static ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 periodSizeInFrames, ma_uint32 periods, const ma_pa_sample_spec* ss)
{
ma_pa_buffer_attr attr;
attr.maxlength = periodSizeInFrames * periods * ma_get_bytes_per_frame(ma_format_from_pulse(ss->format), ss->channels);
attr.tlength = attr.maxlength / periods;
attr.prebuf = (ma_uint32)-1;
attr.minreq = (ma_uint32)-1;
attr.fragsize = attr.maxlength / periods;
return attr;
}
static ma_pa_stream* ma_device__pa_stream_new__pulse(ma_device* pDevice, const char* pStreamName, const ma_pa_sample_spec* ss, const ma_pa_channel_map* cmap)
{
static int g_StreamCounter = 0;
char actualStreamName[256];
if (pStreamName != NULL) {
ma_strncpy_s(actualStreamName, sizeof(actualStreamName), pStreamName, (size_t)-1);
} else {
ma_strcpy_s(actualStreamName, sizeof(actualStreamName), "miniaudio:");
ma_itoa_s(g_StreamCounter, actualStreamName + 8, sizeof(actualStreamName)-8, 10); /* 8 = strlen("miniaudio:") */
}
g_StreamCounter += 1;
return ((ma_pa_stream_new_proc)pDevice->pContext->pulse.pa_stream_new)((ma_pa_context*)pDevice->pulse.pPulseContext, actualStreamName, ss, cmap);
}
static void ma_device_on_read__pulse(ma_pa_stream* pStream, size_t byteCount, void* pUserData)
{
ma_device* pDevice = (ma_device*)pUserData;
ma_uint32 bpf;
ma_uint32 deviceState;
ma_uint64 frameCount;
ma_uint64 framesProcessed;
MA_ASSERT(pDevice != NULL);
/*
Don't do anything if the device isn't initialized yet. Yes, this can happen because PulseAudio
can fire this callback before the stream has even started. Ridiculous.
*/
deviceState = ma_device_get_state(pDevice);
if (deviceState != ma_device_state_starting && deviceState != ma_device_state_started) {
return;
}
bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
MA_ASSERT(bpf > 0);
frameCount = byteCount / bpf;
framesProcessed = 0;
while (ma_device_get_state(pDevice) == ma_device_state_started && framesProcessed < frameCount) {
const void* pMappedPCMFrames;
size_t bytesMapped;
ma_uint64 framesMapped;
int pulseResult = ((ma_pa_stream_peek_proc)pDevice->pContext->pulse.pa_stream_peek)(pStream, &pMappedPCMFrames, &bytesMapped);
if (pulseResult < 0) {
break; /* Failed to map. Abort. */
}
framesMapped = bytesMapped / bpf;
if (framesMapped > 0) {
if (pMappedPCMFrames != NULL) {
ma_device_handle_backend_data_callback(pDevice, NULL, pMappedPCMFrames, framesMapped);
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
if (pDescriptorPlayback->pDeviceID != NULL) {
devPlayback = pDescriptorPlayback->pDeviceID->pulse;
}
format = pDescriptorPlayback->format;
channels = pDescriptorPlayback->channels;
sampleRate = pDescriptorPlayback->sampleRate;
}
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
if (pDescriptorCapture->pDeviceID != NULL) {
devCapture = pDescriptorCapture->pDeviceID->pulse;
}
format = pDescriptorCapture->format;
channels = pDescriptorCapture->channels;
sampleRate = pDescriptorCapture->sampleRate;
}
result = ma_init_pa_mainloop_and_pa_context__pulse(pDevice->pContext, pDevice->pContext->pulse.pApplicationName, pDevice->pContext->pulse.pServerName, MA_FALSE, &pDevice->pulse.pMainLoop, &pDevice->pulse.pPulseContext);
if (result != MA_SUCCESS) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize PA mainloop and context for device.\n");
return result;
}
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
result = ma_context_get_source_info__pulse(pDevice->pContext, devCapture, &sourceInfo);
if (result != MA_SUCCESS) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve source info for capture device.");
goto on_error0;
}
ss = sourceInfo.sample_spec;
cmap = sourceInfo.channel_map;
if (ma_format_from_pulse(ss.format) == ma_format_unknown) {
if (ma_is_little_endian()) {
ss.format = MA_PA_SAMPLE_FLOAT32LE;
} else {
ss.format = MA_PA_SAMPLE_FLOAT32BE;
}
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_FLOAT32.\n");
}
if (ss.rate == 0) {
ss.rate = MA_DEFAULT_SAMPLE_RATE;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.rate = 0. Defaulting to %d.\n", ss.rate);
}
if (ss.channels == 0) {
ss.channels = MA_DEFAULT_CHANNELS;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.channels = 0. Defaulting to %d.\n", ss.channels);
}
/* We now have enough information to calculate our actual period size in frames. */
pDescriptorCapture->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__pulse(pDescriptorCapture, ss.rate, pConfig->performanceProfile);
attr = ma_device__pa_buffer_attr_new(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->periodCount, &ss);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsi...
pDevice->pulse.pStreamCapture = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNameCapture, &ss, &cmap);
if (pDevice->pulse.pStreamCapture == NULL) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream.\n");
result = MA_ERROR;
goto on_error0;
}
/* The callback needs to be set before connecting the stream. */
((ma_pa_stream_set_read_callback_proc)pDevice->pContext->pulse.pa_stream_set_read_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_read__pulse, pDevice);
/* State callback for checking when the device has been corked. */
((ma_pa_stream_set_suspended_callback_proc)pDevice->pContext->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_suspended__pulse, pDevice);
/* Rerouting notification. */
((ma_pa_stream_set_moved_callback_proc)pDevice->pContext->pulse.pa_stream_set_moved_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_rerouted__pulse, pDevice);
/* Connect after we've got all of our internal state set up. */
streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS;
if (devCapture != NULL) {
streamFlags |= MA_PA_STREAM_DONT_MOVE;
}
error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags);
if (error != MA_PA_OK) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream.");
result = ma_result_from_pulse(error);
goto on_error1;
}
result = ma_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, (ma_pa_stream*)pDevice->pulse.pStreamCapture);
if (result != MA_SUCCESS) {
goto on_error2;
}
/* Internal format. */
pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
if (pActualSS != NULL) {
ss = *pActualSS;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture sample spec: format=%s, channels=%d, rate=%d\n", ma_get_format_name(ma_format_from_pulse(ss.format)), ss.channels, ss.rate);
} else {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Failed to retrieve capture sample spec.\n");
}
pDescriptorCapture->format = ma_format_from_pulse(ss.format);
pDescriptorCapture->channels = ss.channels;
pDescriptorCapture->sampleRate = ss.rate;
if (pDescriptorCapture->format == ma_format_unknown || pDescriptorCapture->channels == 0 || pDescriptorCapture->sampleRate == 0) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Capture sample spec is invalid. Device unusable by miniaudio. format=%s, channels=%d, sampleRate=%d.\n", ma_get_format_name(pDescriptorCapture->format), pDescripto...
result = MA_ERROR;
goto on_error4;
}
/* Internal channel map. */
/*
Bug in PipeWire. There have been reports that PipeWire is returning AUX channels when reporting
the channel map. To somewhat workaround this, I'm hacking in a hard coded channel map for mono
and stereo. In this case it should be safe to assume mono = MONO and stereo = LEFT/RIGHT. For
all other channel counts we need to just put up with whatever PipeWire reports and hope it gets
fixed sooner than later. I might remove this hack later.
*/
if (pDescriptorCapture->channels > 2) {
pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
if (pActualCMap != NULL) {
cmap = *pActualCMap;
}
for (iChannel = 0; iChannel < pDescriptorCapture->channels; ++iChannel) {
pDescriptorCapture->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]);
}
} else {
/* Hack for mono and stereo. */
if (pDescriptorCapture->channels == 1) {
pDescriptorCapture->channelMap[0] = MA_CHANNEL_MONO;
} else if (pDescriptorCapture->channels == 2) {
pDescriptorCapture->channelMap[0] = MA_CHANNEL_FRONT_LEFT;
pDescriptorCapture->channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
} else {
MA_ASSERT(MA_FALSE); /* Should never hit this. */
}
}
/* Buffer. */
pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pDevice->pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
if (pActualAttr != NULL) {
attr = *pActualAttr;
}
if (attr.fragsize > 0) {
pDescriptorCapture->periodCount = ma_max(attr.maxlength / attr.fragsize, 1);
} else {
pDescriptorCapture->periodCount = 1;
}
pDescriptorCapture->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / pDescriptorCapture->periodCount;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr...
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
result = ma_context_get_sink_info__pulse(pDevice->pContext, devPlayback, &sinkInfo);
if (result != MA_SUCCESS) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device.\n");
goto on_error2;
}
ss = sinkInfo.sample_spec;
cmap = sinkInfo.channel_map;
if (ma_format_from_pulse(ss.format) == ma_format_unknown) {
if (ma_is_little_endian()) {
ss.format = MA_PA_SAMPLE_FLOAT32LE;
} else {
ss.format = MA_PA_SAMPLE_FLOAT32BE;
}
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_FLOAT32.\n");
}
if (ss.rate == 0) {
ss.rate = MA_DEFAULT_SAMPLE_RATE;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.rate = 0. Defaulting to %d.\n", ss.rate);
}
if (ss.channels == 0) {
ss.channels = MA_DEFAULT_CHANNELS;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] sample_spec.channels = 0. Defaulting to %d.\n", ss.channels);
}
/* We now have enough information to calculate the actual buffer size in frames. */
pDescriptorPlayback->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__pulse(pDescriptorPlayback, ss.rate, pConfig->performanceProfile);
attr = ma_device__pa_buffer_attr_new(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->periodCount, &ss);
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.frags...
pDevice->pulse.pStreamPlayback = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNamePlayback, &ss, &cmap);
if (pDevice->pulse.pStreamPlayback == NULL) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream.\n");
result = MA_ERROR;
goto on_error2;
}
/*
Note that this callback will be fired as soon as the stream is connected, even though it's started as corked. The callback needs to handle a
device state of ma_device_state_uninitialized.
*/
((ma_pa_stream_set_write_callback_proc)pDevice->pContext->pulse.pa_stream_set_write_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_write__pulse, pDevice);
/* State callback for checking when the device has been corked. */
((ma_pa_stream_set_suspended_callback_proc)pDevice->pContext->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_suspended__pulse, pDevice);
/* Rerouting notification. */
((ma_pa_stream_set_moved_callback_proc)pDevice->pContext->pulse.pa_stream_set_moved_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_rerouted__pulse, pDevice);
/* Connect after we've got all of our internal state set up. */
streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS;
if (devPlayback != NULL) {
streamFlags |= MA_PA_STREAM_DONT_MOVE;
}
error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL);
if (error != MA_PA_OK) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream.");
result = ma_result_from_pulse(error);
goto on_error3;
}
result = ma_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, (ma_pa_stream*)pDevice->pulse.pStreamPlayback);
if (result != MA_SUCCESS) {
goto on_error3;
}
/* Internal format. */
pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
if (pActualSS != NULL) {
ss = *pActualSS;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback sample spec: format=%s, channels=%d, rate=%d\n", ma_get_format_name(ma_format_from_pulse(ss.format)), ss.channels, ss.rate);
} else {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Failed to retrieve playback sample spec.\n");
}
pDescriptorPlayback->format = ma_format_from_pulse(ss.format);
pDescriptorPlayback->channels = ss.channels;
pDescriptorPlayback->sampleRate = ss.rate;
if (pDescriptorPlayback->format == ma_format_unknown || pDescriptorPlayback->channels == 0 || pDescriptorPlayback->sampleRate == 0) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Playback sample spec is invalid. Device unusable by miniaudio. format=%s, channels=%d, sampleRate=%d.\n", ma_get_format_name(pDescriptorPlayback->format), pDescrip...
result = MA_ERROR;
goto on_error4;
}
/* Internal channel map. */
/*
Bug in PipeWire. There have been reports that PipeWire is returning AUX channels when reporting
the channel map. To somewhat workaround this, I'm hacking in a hard coded channel map for mono
and stereo. In this case it should be safe to assume mono = MONO and stereo = LEFT/RIGHT. For
all other channel counts we need to just put up with whatever PipeWire reports and hope it gets
fixed sooner than later. I might remove this hack later.
*/
if (pDescriptorPlayback->channels > 2) {
pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
if (pActualCMap != NULL) {
cmap = *pActualCMap;
}
for (iChannel = 0; iChannel < pDescriptorPlayback->channels; ++iChannel) {
pDescriptorPlayback->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]);
}
} else {
/* Hack for mono and stereo. */
if (pDescriptorPlayback->channels == 1) {
pDescriptorPlayback->channelMap[0] = MA_CHANNEL_MONO;
} else if (pDescriptorPlayback->channels == 2) {
pDescriptorPlayback->channelMap[0] = MA_CHANNEL_FRONT_LEFT;
pDescriptorPlayback->channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
} else {
MA_ASSERT(MA_FALSE); /* Should never hit this. */
}
}
/* Buffer. */
pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pDevice->pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
if (pActualAttr != NULL) {
attr = *pActualAttr;
}
if (attr.tlength > 0) {
pDescriptorPlayback->periodCount = ma_max(attr.maxlength / attr.tlength, 1);
} else {
pDescriptorPlayback->periodCount = 1;
}
pDescriptorPlayback->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) / pDescriptorPlayback->periodCount;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.min...
}
/*
We need a ring buffer for handling duplex mode. We can use the main duplex ring buffer in the main
part of the ma_device struct. We cannot, however, depend on ma_device_init() initializing this for
us later on because that will only do it if it's a fully asynchronous backend - i.e. the
onDeviceDataLoop callback is NULL, which is not the case for PulseAudio.
*/
if (pConfig->deviceType == ma_device_type_duplex) {
ma_format rbFormat = (format != ma_format_unknown) ? format : pDescriptorCapture->format;
ma_uint32 rbChannels = (channels > 0) ? channels : pDescriptorCapture->channels;
ma_uint32 rbSampleRate = (sampleRate > 0) ? sampleRate : pDescriptorCapture->sampleRate;
result = ma_duplex_rb_init(rbFormat, rbChannels, rbSampleRate, pDescriptorCapture->sampleRate, pDescriptorCapture->periodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB);
if (result != MA_SUCCESS) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize ring buffer. %s.\n", ma_result_description(result));
goto on_error4;
}
}
return MA_SUCCESS;
on_error4:
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
((ma_pa_stream_disconnect_proc)pDevice->pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
}
on_error3:
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
((ma_pa_stream_unref_proc)pDevice->pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
}
on_error2:
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
((ma_pa_stream_disconnect_proc)pDevice->pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
}
on_error1:
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
((ma_pa_stream_unref_proc)pDevice->pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
}
on_error0:
return result;
}
static void ma_pulse_operation_complete_callback(ma_pa_stream* pStream, int success, void* pUserData)
{
ma_bool32* pIsSuccessful = (ma_bool32*)pUserData;
MA_ASSERT(pIsSuccessful != NULL);
*pIsSuccessful = (ma_bool32)success;
(void)pStream; /* Unused. */
}
static ma_result ma_device__cork_stream__pulse(ma_device* pDevice, ma_device_type deviceType, int cork)
{
ma_context* pContext = pDevice->pContext;
ma_bool32 wasSuccessful;
ma_pa_stream* pStream;
share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h view on Meta::CPAN
ma_result result;
int ossResult;
int fd;
const ma_device_id* pDeviceID = NULL;
ma_share_mode shareMode;
int ossFormat;
int ossChannels;
int ossSampleRate;
int ossFragment;
MA_ASSERT(pDevice != NULL);
MA_ASSERT(pConfig != NULL);
MA_ASSERT(deviceType != ma_device_type_duplex);
pDeviceID = pDescriptor->pDeviceID;
shareMode = pDescriptor->shareMode;
ossFormat = ma_format_to_oss((pDescriptor->format != ma_format_unknown) ? pDescriptor->format : ma_format_s16); /* Use s16 by default because OSS doesn't like floating point. */
ossChannels = (int)(pDescriptor->channels > 0) ? pDescriptor->channels : MA_DEFAULT_CHANNELS;
ossSampleRate = (int)(pDescriptor->sampleRate > 0) ? pDescriptor->sampleRate : MA_DEFAULT_SAMPLE_RATE;
result = ma_context_open_device__oss(pDevice->pContext, deviceType, pDeviceID, shareMode, &fd);
if (result != MA_SUCCESS) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.");
return result;
}
/*
The OSS documantation is very clear about the order we should be initializing the device's properties:
1) Format
2) Channels
3) Sample rate.
*/
/* Format. */
ossResult = ioctl(fd, SNDCTL_DSP_SETFMT, &ossFormat);
if (ossResult == -1) {
close(fd);
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set format.");
return ma_result_from_errno(errno);
}
/* Channels. */
ossResult = ioctl(fd, SNDCTL_DSP_CHANNELS, &ossChannels);
if (ossResult == -1) {
close(fd);
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set channel count.");
return ma_result_from_errno(errno);
}
/* Sample Rate. */
ossResult = ioctl(fd, SNDCTL_DSP_SPEED, &ossSampleRate);
if (ossResult == -1) {
close(fd);
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set sample rate.");
return ma_result_from_errno(errno);
}
/*
Buffer.
The documentation says that the fragment settings should be set as soon as possible, but I'm not sure if
it should be done before or after format/channels/rate.
OSS wants the fragment size in bytes and a power of 2. When setting, we specify the power, not the actual
value.
*/
{
ma_uint32 periodSizeInFrames;
ma_uint32 periodSizeInBytes;
ma_uint32 ossFragmentSizePower;
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, (ma_uint32)ossSampleRate, pConfig->performanceProfile);
periodSizeInBytes = ma_round_to_power_of_2(periodSizeInFrames * ma_get_bytes_per_frame(ma_format_from_oss(ossFormat), ossChannels));
if (periodSizeInBytes < 16) {
periodSizeInBytes = 16;
}
ossFragmentSizePower = 4;
periodSizeInBytes >>= 4;
while (periodSizeInBytes >>= 1) {
ossFragmentSizePower += 1;
}
ossFragment = (int)((pConfig->periods << 16) | ossFragmentSizePower);
ossResult = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &ossFragment);
if (ossResult == -1) {
close(fd);
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set fragment size and period count.");
return ma_result_from_errno(errno);
}
}
/* Internal settings. */
if (deviceType == ma_device_type_capture) {
pDevice->oss.fdCapture = fd;
} else {
pDevice->oss.fdPlayback = fd;
}
pDescriptor->format = ma_format_from_oss(ossFormat);
pDescriptor->channels = ossChannels;
pDescriptor->sampleRate = ossSampleRate;
ma_channel_map_init_standard(ma_standard_channel_map_sound4, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels);
pDescriptor->periodCount = (ma_uint32)(ossFragment >> 16);
pDescriptor->periodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDescriptor->format, pDescriptor->channels);
if (pDescriptor->format == ma_format_unknown) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.");
return MA_FORMAT_NOT_SUPPORTED;
}
return MA_SUCCESS;
}
static ma_result ma_device_init__oss(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
{
MA_ASSERT(pDevice != NULL);
MA_ASSERT(pConfig != NULL);
MA_ZERO_OBJECT(&pDevice->oss);
if (pConfig->deviceType == ma_device_type_loopback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED;
}
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
if (result != MA_SUCCESS) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.");
return result;
}
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
if (result != MA_SUCCESS) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.");
return result;
}
}
return MA_SUCCESS;
}
/*
Note on Starting and Stopping
=============================
In the past I was using SNDCTL_DSP_HALT to stop the device, however this results in issues when