PipeWire: Finish work on removing the SPA dependency.

This commit is contained in:
David Reid
2025-12-31 18:18:17 +10:00
parent e1dfc9d77f
commit 114b9594c1
2 changed files with 196 additions and 60 deletions
+196 -40
View File
@@ -3,6 +3,119 @@
#include "miniaudio_pipewire.h" #include "miniaudio_pipewire.h"
/* This is temporary until this is merged into miniaudio proper. */
MA_API MA_NO_INLINE int ma_pipewire_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix)
{
int sign;
unsigned int valueU;
char* dstEnd;
if (dst == NULL || dstSizeInBytes == 0) {
return 22;
}
if (radix < 2 || radix > 36) {
dst[0] = '\0';
return 22;
}
sign = (value < 0 && radix == 10) ? -1 : 1; /* The negative sign is only used when the base is 10. */
if (value < 0) {
valueU = -value;
} else {
valueU = value;
}
dstEnd = dst;
do
{
int remainder = valueU % radix;
if (remainder > 9) {
*dstEnd = (char)((remainder - 10) + 'a');
} else {
*dstEnd = (char)(remainder + '0');
}
dstEnd += 1;
dstSizeInBytes -= 1;
valueU /= radix;
} while (dstSizeInBytes > 0 && valueU > 0);
if (dstSizeInBytes == 0) {
dst[0] = '\0';
return 22; /* Ran out of room in the output buffer. */
}
if (sign < 0) {
*dstEnd++ = '-';
dstSizeInBytes -= 1;
}
if (dstSizeInBytes == 0) {
dst[0] = '\0';
return 22; /* Ran out of room in the output buffer. */
}
*dstEnd = '\0';
/* At this point the string will be reversed. */
dstEnd -= 1;
while (dst < dstEnd) {
char temp = *dst;
*dst = *dstEnd;
*dstEnd = temp;
dst += 1;
dstEnd -= 1;
}
return 0;
}
MA_API MA_NO_INLINE int ma_pipewire_strcat_s(char* dst, size_t dstSizeInBytes, const char* src)
{
char* dstorig;
if (dst == 0) {
return 22;
}
if (dstSizeInBytes == 0) {
return 34;
}
if (src == 0) {
dst[0] = '\0';
return 22;
}
dstorig = dst;
while (dstSizeInBytes > 0 && dst[0] != '\0') {
dst += 1;
dstSizeInBytes -= 1;
}
if (dstSizeInBytes == 0) {
return 22; /* Unterminated. */
}
while (dstSizeInBytes > 0 && src[0] != '\0') {
*dst++ = *src++;
dstSizeInBytes -= 1;
}
if (dstSizeInBytes > 0) {
dst[0] = '\0';
} else {
dstorig[0] = '\0';
return 34;
}
return 0;
}
#include <string.h> /* memset() */ #include <string.h> /* memset() */
#include <assert.h> /* assert() */ #include <assert.h> /* assert() */
@@ -34,6 +147,7 @@
#endif #endif
#if defined(MA_HAS_PIPEWIRE) #if defined(MA_HAS_PIPEWIRE)
#if 0
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic" #pragma GCC diagnostic ignored "-Wpedantic"
@@ -43,9 +157,10 @@
#pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" #pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#endif #endif
#endif #endif
#endif
/*#include <pipewire/pipewire.h>*/ /*#include <pipewire/pipewire.h>*/
#include <spa/param/audio/format-utils.h> /* For spa_format_audio_raw_build() */ /*#include <spa/param/audio/format-utils.h>*/
/*#include <spa/param/audio/raw.h>*/ /*#include <spa/param/audio/raw.h>*/
/*#include <spa/utils/dict.h>*/ /*#include <spa/utils/dict.h>*/
/*#include <spa/pod/command.h>*/ /*#include <spa/pod/command.h>*/
@@ -395,6 +510,36 @@ struct ma_spa_hook
/* spa_pod is the most complicated part of SPA that we use. We're only implementing specifically what we need. */ /* spa_pod is the most complicated part of SPA that we use. We're only implementing specifically what we need. */
#define MA_SPA_TYPE_Id 3
#define MA_SPA_TYPE_Int 4
#define MA_SPA_TYPE_Array 13
#define MA_SPA_TYPE_Object 15
#define MA_SPA_TYPE_Choice 19
#define MA_SPA_TYPE_OBJECT_Format 262147
#define MA_SPA_TYPE_OBJECT_ParamBuffers 262148
#define MA_SPA_PARAM_EnumFormat 3
#define MA_SPA_PARAM_Format 4
#define MA_SPA_PARAM_Buffers 5
#define MA_SPA_PARAM_BUFFERS_buffers 1
#define MA_SPA_PARAM_BUFFERS_blocks 2
#define MA_SPA_PARAM_BUFFERS_size 3
#define MA_SPA_PARAM_BUFFERS_stride 4
#define MA_SPA_FORMAT_mediaType 1
#define MA_SPA_FORMAT_mediaSubtype 2
#define MA_SPA_MEDIA_TYPE_audio 1
#define MA_SPA_MEDIA_SUBTYPE_raw 1
#define MA_SPA_FORMAT_AUDIO_format 65537
#define MA_SPA_FORMAT_AUDIO_rate 65539
#define MA_SPA_FORMAT_AUDIO_channels 65540
#define MA_SPA_FORMAT_AUDIO_position 65541
struct ma_spa_pod struct ma_spa_pod
{ {
ma_uint32 size; ma_uint32 size;
@@ -415,7 +560,7 @@ static MA_INLINE struct ma_spa_pod_id ma_spa_pod_id_init(ma_uint32 value)
MA_PIPEWIRE_ZERO_OBJECT(&pod); MA_PIPEWIRE_ZERO_OBJECT(&pod);
pod.pod.size = 4; /* Does not include the header or padding. */ pod.pod.size = 4; /* Does not include the header or padding. */
pod.pod.type = SPA_TYPE_Id; pod.pod.type = MA_SPA_TYPE_Id;
pod.value = value; pod.value = value;
return pod; return pod;
@@ -435,7 +580,7 @@ static MA_INLINE struct ma_spa_pod_int ma_spa_pod_int_init(ma_int32 value)
MA_PIPEWIRE_ZERO_OBJECT(&pod); MA_PIPEWIRE_ZERO_OBJECT(&pod);
pod.pod.size = 4; /* Does not include the header or padding. */ pod.pod.size = 4; /* Does not include the header or padding. */
pod.pod.type = SPA_TYPE_Int; pod.pod.type = MA_SPA_TYPE_Int;
pod.value = value; pod.value = value;
return pod; return pod;
@@ -578,14 +723,14 @@ static MA_INLINE struct ma_spa_pod_buffer_params ma_spa_pod_buffer_params_init(m
MA_PIPEWIRE_ZERO_OBJECT(&pod); MA_PIPEWIRE_ZERO_OBJECT(&pod);
pod.object.pod.size = sizeof(struct ma_spa_pod_buffer_params) - sizeof(struct ma_spa_pod); /* Don't include the header in the size. */ pod.object.pod.size = sizeof(struct ma_spa_pod_buffer_params) - sizeof(struct ma_spa_pod); /* Don't include the header in the size. */
pod.object.pod.type = SPA_TYPE_Object; pod.object.pod.type = MA_SPA_TYPE_Object;
pod.object.body.type = SPA_TYPE_OBJECT_ParamBuffers; pod.object.body.type = MA_SPA_TYPE_OBJECT_ParamBuffers;
pod.object.body.id = SPA_PARAM_Buffers; pod.object.body.id = MA_SPA_PARAM_Buffers;
pod.buffers = ma_spa_pod_prop_int_init(SPA_PARAM_BUFFERS_buffers, 2); pod.buffers = ma_spa_pod_prop_int_init(MA_SPA_PARAM_BUFFERS_buffers, 2);
pod.blocks = ma_spa_pod_prop_int_init(SPA_PARAM_BUFFERS_blocks, 1); pod.blocks = ma_spa_pod_prop_int_init(MA_SPA_PARAM_BUFFERS_blocks, 1);
pod.stride = ma_spa_pod_prop_int_init(SPA_PARAM_BUFFERS_stride, (ma_int32)strideInBytes); pod.stride = ma_spa_pod_prop_int_init(MA_SPA_PARAM_BUFFERS_stride, (ma_int32)strideInBytes);
pod.size = ma_spa_pod_prop_int_init(SPA_PARAM_BUFFERS_size, (ma_int32)(strideInBytes * bufferSizeInFrames)); pod.size = ma_spa_pod_prop_int_init(MA_SPA_PARAM_BUFFERS_size, (ma_int32)(strideInBytes * bufferSizeInFrames));
return pod; return pod;
} }
@@ -625,27 +770,27 @@ static MA_INLINE struct ma_spa_pod_audio_info_raw ma_spa_pod_audio_info_raw_init
MA_PIPEWIRE_ZERO_OBJECT(&pod); MA_PIPEWIRE_ZERO_OBJECT(&pod);
pod.object.pod.size = sizeof(struct ma_spa_pod_object) - sizeof(struct ma_spa_pod); /* Don't include the header in the size. */ pod.object.pod.size = sizeof(struct ma_spa_pod_object) - sizeof(struct ma_spa_pod); /* Don't include the header in the size. */
pod.object.pod.type = SPA_TYPE_Object; pod.object.pod.type = MA_SPA_TYPE_Object;
pod.object.body.type = SPA_TYPE_OBJECT_Format; pod.object.body.type = MA_SPA_TYPE_OBJECT_Format;
pod.object.body.id = SPA_PARAM_EnumFormat; pod.object.body.id = MA_SPA_PARAM_EnumFormat;
pod.mediaType = ma_spa_pod_prop_id_init(SPA_FORMAT_mediaType, SPA_MEDIA_TYPE_audio); pod.mediaType = ma_spa_pod_prop_id_init(MA_SPA_FORMAT_mediaType, MA_SPA_MEDIA_TYPE_audio);
pod.object.pod.size += sizeof(struct ma_spa_pod_prop_id); pod.object.pod.size += sizeof(struct ma_spa_pod_prop_id);
pod.mediaSubtype = ma_spa_pod_prop_id_init(SPA_FORMAT_mediaSubtype, SPA_MEDIA_SUBTYPE_raw); pod.mediaSubtype = ma_spa_pod_prop_id_init(MA_SPA_FORMAT_mediaSubtype, MA_SPA_MEDIA_SUBTYPE_raw);
pod.object.pod.size += sizeof(struct ma_spa_pod_prop_id); pod.object.pod.size += sizeof(struct ma_spa_pod_prop_id);
pod.format = ma_spa_pod_prop_id_init(SPA_FORMAT_AUDIO_format, (ma_uint32)format); pod.format = ma_spa_pod_prop_id_init(MA_SPA_FORMAT_AUDIO_format, (ma_uint32)format);
pod.object.pod.size += sizeof(struct ma_spa_pod_prop_id); pod.object.pod.size += sizeof(struct ma_spa_pod_prop_id);
if (channels > 0) { if (channels > 0) {
pod.extra[extraIndex] = ma_spa_pod_prop_int_init(SPA_FORMAT_AUDIO_channels, (ma_int32)channels); pod.extra[extraIndex] = ma_spa_pod_prop_int_init(MA_SPA_FORMAT_AUDIO_channels, (ma_int32)channels);
pod.object.pod.size += sizeof(struct ma_spa_pod_prop_int); pod.object.pod.size += sizeof(struct ma_spa_pod_prop_int);
extraIndex += 1; extraIndex += 1;
} }
if (sampleRate > 0) { if (sampleRate > 0) {
pod.extra[extraIndex] = ma_spa_pod_prop_int_init(SPA_FORMAT_AUDIO_rate, (ma_int32)sampleRate); pod.extra[extraIndex] = ma_spa_pod_prop_int_init(MA_SPA_FORMAT_AUDIO_rate, (ma_int32)sampleRate);
pod.object.pod.size += sizeof(struct ma_spa_pod_prop_int); pod.object.pod.size += sizeof(struct ma_spa_pod_prop_int);
extraIndex += 1; extraIndex += 1;
} }
@@ -663,13 +808,13 @@ static MA_INLINE ma_uint32 ma_spa_pod_get_id_value(const struct ma_spa_pod* pod)
switch (pod->type) switch (pod->type)
{ {
case SPA_TYPE_Id: case MA_SPA_TYPE_Id:
{ {
const struct ma_spa_pod_id* pPodID = (const struct ma_spa_pod_id*)pod; const struct ma_spa_pod_id* pPodID = (const struct ma_spa_pod_id*)pod;
return pPodID->value; return pPodID->value;
} }
case SPA_TYPE_Choice: case MA_SPA_TYPE_Choice:
{ {
const struct ma_spa_pod_choice* pPodChoice = (const struct ma_spa_pod_choice*)pod; const struct ma_spa_pod_choice* pPodChoice = (const struct ma_spa_pod_choice*)pod;
const void* pValues = ma_spa_pod_choice_get_values(pPodChoice); const void* pValues = ma_spa_pod_choice_get_values(pPodChoice);
@@ -692,13 +837,13 @@ static MA_INLINE ma_int32 ma_spa_pod_get_int_value(const struct ma_spa_pod* pod)
switch (pod->type) switch (pod->type)
{ {
case SPA_TYPE_Id: case MA_SPA_TYPE_Id:
{ {
const struct ma_spa_pod_int* pPodInt = (const struct ma_spa_pod_int*)pod; const struct ma_spa_pod_int* pPodInt = (const struct ma_spa_pod_int*)pod;
return pPodInt->value; return pPodInt->value;
} }
case SPA_TYPE_Choice: case MA_SPA_TYPE_Choice:
{ {
const struct ma_spa_pod_choice* pPodChoice = (const struct ma_spa_pod_choice*)pod; const struct ma_spa_pod_choice* pPodChoice = (const struct ma_spa_pod_choice*)pod;
const void* pValues = ma_spa_pod_choice_get_values(pPodChoice); const void* pValues = ma_spa_pod_choice_get_values(pPodChoice);
@@ -854,7 +999,7 @@ struct ma_pw_stream_events
void (* state_changed)(void* data, enum ma_pw_stream_state oldState, enum ma_pw_stream_state newState, const char* error); void (* state_changed)(void* data, enum ma_pw_stream_state oldState, enum ma_pw_stream_state newState, const char* error);
void (* control_info )(void* data, ma_uint32 id, const struct ma_pw_stream_control* control); void (* control_info )(void* data, ma_uint32 id, const struct ma_pw_stream_control* control);
void (* io_changed )(void* data, ma_uint32 id, void* area, ma_uint32 size); void (* io_changed )(void* data, ma_uint32 id, void* area, ma_uint32 size);
void (* param_changed)(void* data, ma_uint32 id, const struct spa_pod* param); void (* param_changed)(void* data, ma_uint32 id, const struct ma_spa_pod* param);
void (* add_buffer )(void* data, struct ma_pw_buffer* buffer); void (* add_buffer )(void* data, struct ma_pw_buffer* buffer);
void (* remove_buffer)(void* data, struct ma_pw_buffer* buffer); void (* remove_buffer)(void* data, struct ma_pw_buffer* buffer);
void (* process )(void* data); void (* process )(void* data);
@@ -1316,7 +1461,7 @@ typedef struct
} ma_enumerate_devices_data_pipewire; } ma_enumerate_devices_data_pipewire;
static void ma_on_core_done__pipewire(void* pUserData, uint32_t id, int seq) static void ma_on_core_done__pipewire(void* pUserData, ma_uint32 id, int seq)
{ {
ma_enumerate_devices_data_pipewire* pEnumData = (ma_enumerate_devices_data_pipewire*)pUserData; ma_enumerate_devices_data_pipewire* pEnumData = (ma_enumerate_devices_data_pipewire*)pUserData;
@@ -1454,7 +1599,7 @@ static struct ma_pw_metadata_events ma_gMetadataEventsPipeWire =
}; };
static void ma_registry_event_global_add_enumeration_by_type__pipewire(ma_enumerate_devices_data_pipewire* pEnumData, uint32_t id, uint32_t permissions, const char* type, uint32_t version, const struct ma_spa_dict* props, ma_device_type deviceType) static void ma_registry_event_global_add_enumeration_by_type__pipewire(ma_enumerate_devices_data_pipewire* pEnumData, ma_uint32 id, ma_uint32 permissions, const char* type, ma_uint32 version, const struct ma_spa_dict* props, ma_device_type deviceType)
{ {
ma_device_info deviceInfo; ma_device_info deviceInfo;
const char* pNodeName; /* <-- This is the ID. */ const char* pNodeName; /* <-- This is the ID. */
@@ -1498,7 +1643,7 @@ static void ma_registry_event_global_add_enumeration_by_type__pipewire(ma_enumer
/*printf("Registry Global Added By Type: ID=%u, Type=%s, DeviceType=%d, NiceName=%s\n", id, type, deviceType, pNiceName);*/ /*printf("Registry Global Added By Type: ID=%u, Type=%s, DeviceType=%d, NiceName=%s\n", id, type, deviceType, pNiceName);*/
} }
static void ma_registry_event_global_add_enumeration__pipewire(void* pUserData, uint32_t id, uint32_t permissions, const char* type, uint32_t version, const struct ma_spa_dict* props) static void ma_registry_event_global_add_enumeration__pipewire(void* pUserData, ma_uint32 id, ma_uint32 permissions, const char* type, ma_uint32 version, const struct ma_spa_dict* props)
{ {
ma_enumerate_devices_data_pipewire* pEnumData = (ma_enumerate_devices_data_pipewire*)pUserData; ma_enumerate_devices_data_pipewire* pEnumData = (ma_enumerate_devices_data_pipewire*)pUserData;
const char* pMediaClass; const char* pMediaClass;
@@ -1516,7 +1661,7 @@ static void ma_registry_event_global_add_enumeration__pipewire(void* pUserData,
if (pName != NULL && strcmp(pName, "default") == 0) { if (pName != NULL && strcmp(pName, "default") == 0) {
pEnumData->pMetadata = (struct ma_pw_metadata*)pEnumData->pContextStatePipeWire->pw_registry_bind(pEnumData->pRegistry, id, MA_PW_TYPE_INTERFACE_Metadata, MA_PW_VERSION_METADATA, 0); pEnumData->pMetadata = (struct ma_pw_metadata*)pEnumData->pContextStatePipeWire->pw_registry_bind(pEnumData->pRegistry, id, MA_PW_TYPE_INTERFACE_Metadata, MA_PW_VERSION_METADATA, 0);
if (pEnumData->pMetadata != NULL) { if (pEnumData->pMetadata != NULL) {
spa_zero(pEnumData->metadataListener); MA_PIPEWIRE_ZERO_OBJECT(&pEnumData->metadataListener);
/* Not using pw_metadata_add_listener() because it appears to be an inline function and thus not exported by libpipewire. */ /* Not using pw_metadata_add_listener() because it appears to be an inline function and thus not exported by libpipewire. */
((struct ma_pw_metadata_methods*)((struct ma_spa_interface*)pEnumData->pMetadata)->cb.funcs)->add_listener(pEnumData->pMetadata, &pEnumData->metadataListener, &ma_gMetadataEventsPipeWire, pEnumData); ((struct ma_pw_metadata_methods*)((struct ma_spa_interface*)pEnumData->pMetadata)->cb.funcs)->add_listener(pEnumData->pMetadata, &pEnumData->metadataListener, &ma_gMetadataEventsPipeWire, pEnumData);
@@ -1604,7 +1749,7 @@ static ma_result ma_context_enumerate_devices__pipewire(ma_context* pContext, ma
ma_enumerate_devices_data_pipewire_init(&enumData, pContextStatePipeWire, pLoop, pCore, pRegistry, ma_context_get_allocation_callbacks(pContext)); ma_enumerate_devices_data_pipewire_init(&enumData, pContextStatePipeWire, pLoop, pCore, pRegistry, ma_context_get_allocation_callbacks(pContext));
spa_zero(registeryListener); MA_PIPEWIRE_ZERO_OBJECT(&registeryListener);
pContextStatePipeWire->pw_registry_add_listener(pRegistry, &registeryListener, &ma_gRegistryEventsPipeWire_Enumeration, &enumData); pContextStatePipeWire->pw_registry_add_listener(pRegistry, &registeryListener, &ma_gRegistryEventsPipeWire_Enumeration, &enumData);
/* /*
@@ -1689,12 +1834,12 @@ static ma_result ma_context_enumerate_devices__pipewire(ma_context* pContext, ma
} }
static void ma_stream_event_param_changed__pipewire(void* pUserData, ma_uint32 id, const struct spa_pod* pParam, ma_device_type deviceType) static void ma_stream_event_param_changed__pipewire(void* pUserData, ma_uint32 id, const struct ma_spa_pod* pParam, ma_device_type deviceType)
{ {
ma_device_state_pipewire* pDeviceStatePipeWire = (ma_device_state_pipewire*)pUserData; ma_device_state_pipewire* pDeviceStatePipeWire = (ma_device_state_pipewire*)pUserData;
ma_context_state_pipewire* pContextStatePipeWire = pDeviceStatePipeWire->pContextStatePipeWire; ma_context_state_pipewire* pContextStatePipeWire = pDeviceStatePipeWire->pContextStatePipeWire;
if (id == SPA_PARAM_Format) { if (id == MA_SPA_PARAM_Format) {
ma_pipewire_stream_state* pStreamState; ma_pipewire_stream_state* pStreamState;
struct ma_spa_pod_buffer_params bufferParams; struct ma_spa_pod_buffer_params bufferParams;
const struct ma_spa_pod* pBufferParameters[1]; const struct ma_spa_pod* pBufferParameters[1];
@@ -1738,7 +1883,7 @@ static void ma_stream_event_param_changed__pipewire(void* pUserData, ma_uint32 i
ma_uint32 cursor = 0; ma_uint32 cursor = 0;
ma_uint32 size; ma_uint32 size;
if (pParam->type != SPA_TYPE_Object || pParam->size < sizeof(struct ma_spa_pod_object_body)) { if (pParam->type != MA_SPA_TYPE_Object || pParam->size < sizeof(struct ma_spa_pod_object_body)) {
ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "Failed to parse PipeWire format parameter (invalid pod type)."); ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "Failed to parse PipeWire format parameter (invalid pod type).");
return; return;
} }
@@ -1749,7 +1894,7 @@ static void ma_stream_event_param_changed__pipewire(void* pUserData, ma_uint32 i
size = pParam->size + sizeof(struct ma_spa_pod); size = pParam->size + sizeof(struct ma_spa_pod);
cursor += sizeof(struct ma_spa_pod); cursor += sizeof(struct ma_spa_pod);
if (pObject->body.type != SPA_TYPE_OBJECT_Format) { if (pObject->body.type != MA_SPA_TYPE_OBJECT_Format) {
ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "Failed to parse PipeWire format parameter (invalid body type)."); ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "Failed to parse PipeWire format parameter (invalid body type).");
return; return;
} }
@@ -1772,27 +1917,27 @@ static void ma_stream_event_param_changed__pipewire(void* pUserData, ma_uint32 i
switch (pNextProp->key) switch (pNextProp->key)
{ {
case SPA_FORMAT_AUDIO_format: case MA_SPA_FORMAT_AUDIO_format:
{ {
formatPA = (enum ma_spa_audio_format)ma_spa_pod_get_id_value(pPropValue); formatPA = (enum ma_spa_audio_format)ma_spa_pod_get_id_value(pPropValue);
} break; } break;
case SPA_FORMAT_AUDIO_channels: case MA_SPA_FORMAT_AUDIO_channels:
{ {
channels = ma_spa_pod_get_int_value(pPropValue); channels = ma_spa_pod_get_int_value(pPropValue);
} break; } break;
case SPA_FORMAT_AUDIO_rate: case MA_SPA_FORMAT_AUDIO_rate:
{ {
sampleRate = ma_spa_pod_get_int_value(pPropValue); sampleRate = ma_spa_pod_get_int_value(pPropValue);
} break; } break;
case SPA_FORMAT_AUDIO_position: case MA_SPA_FORMAT_AUDIO_position:
{ {
ma_uint32 positionCount; ma_uint32 positionCount;
/* I'm assuming we can only get an array back for this. */ /* I'm assuming we can only get an array back for this. */
if (pPropValue->type != SPA_TYPE_Array) { if (pPropValue->type != MA_SPA_TYPE_Array) {
ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "Failed to parse PipeWire format parameter (invalid type for position property)."); ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "Failed to parse PipeWire format parameter (invalid type for position property).");
return; return;
} }
@@ -1830,9 +1975,18 @@ static void ma_stream_event_param_changed__pipewire(void* pUserData, ma_uint32 i
{ {
struct ma_spa_dict_item items[1]; struct ma_spa_dict_item items[1];
struct ma_spa_dict dict; struct ma_spa_dict dict;
char bufferSizeInFramesStr[32];
char sampleRateStr[32];
char latencyStr[32]; char latencyStr[32];
snprintf(latencyStr, sizeof(latencyStr), "%u/%u", (unsigned int)pStreamState->bufferSizeInFrames, pStreamState->sampleRate); ma_pipewire_itoa_s(pStreamState->bufferSizeInFrames, bufferSizeInFramesStr, sizeof(bufferSizeInFramesStr), 10);
ma_pipewire_itoa_s(pStreamState->sampleRate, sampleRateStr, sizeof(sampleRateStr), 10);
latencyStr[0] = '\0';
ma_pipewire_strcat_s(latencyStr, sizeof(latencyStr), bufferSizeInFramesStr);
ma_pipewire_strcat_s(latencyStr, sizeof(latencyStr), "/");
ma_pipewire_strcat_s(latencyStr, sizeof(latencyStr), sampleRateStr);
items[0] = MA_SPA_DICT_ITEM_INIT(MA_PW_KEY_NODE_LATENCY, latencyStr); items[0] = MA_SPA_DICT_ITEM_INIT(MA_PW_KEY_NODE_LATENCY, latencyStr);
dict = MA_SPA_DICT_INIT(items, 1); dict = MA_SPA_DICT_INIT(items, 1);
@@ -2010,12 +2164,12 @@ static void ma_stream_event_process__pipewire(void* pUserData, ma_device_type de
} }
static void ma_stream_event_param_changed_playback__pipewire(void* pUserData, ma_uint32 id, const struct spa_pod* pParam) static void ma_stream_event_param_changed_playback__pipewire(void* pUserData, ma_uint32 id, const struct ma_spa_pod* pParam)
{ {
ma_stream_event_param_changed__pipewire(pUserData, id, pParam, ma_device_type_playback); ma_stream_event_param_changed__pipewire(pUserData, id, pParam, ma_device_type_playback);
} }
static void ma_stream_event_param_changed_capture__pipewire(void* pUserData, ma_uint32 id, const struct spa_pod* pParam) static void ma_stream_event_param_changed_capture__pipewire(void* pUserData, ma_uint32 id, const struct ma_spa_pod* pParam)
{ {
ma_stream_event_param_changed__pipewire(pUserData, id, pParam, ma_device_type_capture); ma_stream_event_param_changed__pipewire(pUserData, id, pParam, ma_device_type_capture);
} }
@@ -2436,9 +2590,11 @@ static ma_device_backend_vtable ma_gDeviceBackendVTable_PipeWire =
ma_device_backend_vtable* ma_device_backend_pipewire = &ma_gDeviceBackendVTable_PipeWire; ma_device_backend_vtable* ma_device_backend_pipewire = &ma_gDeviceBackendVTable_PipeWire;
#if 0
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
#endif
#else #else
ma_device_backend_vtable* ma_device_backend_pipewire = NULL; ma_device_backend_vtable* ma_device_backend_pipewire = NULL;
#endif /* MA_HAS_PIPEWIRE */ #endif /* MA_HAS_PIPEWIRE */
@@ -1,23 +1,3 @@
/*
The PipeWire backend depends on the libspa development packages. On Debian-based distributions,
this can be installed with:
sudo apt install libspa-0.2-dev
If using Ubuntu, this may install it in a "spa-0.2" subfolder. In this case, you might need
to add the following to your build command:
-I/usr/include/spa-0.2
Unfortunately PipeWire has a hard dependency on the above package, and because it's made up
entirely of non-trivial inlined code, it's not practical to avoid this dependency. It's for
this reason the PipeWire backend cannot be included in miniaudio.h since it has a requirement
that it does not depend on external development packages. To use the PipeWire backend, you
need to plug it in as a custom backend. See the custom_backend example for how to do this.
The PipeWire backend cannot be used with `-std=c89`. This is because the SPA headers do not
support it.
*/
#ifndef miniaudio_backend_pipewire_h #ifndef miniaudio_backend_pipewire_h
#define miniaudio_backend_pipewire_h #define miniaudio_backend_pipewire_h