mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
PipeWire: Remove dependency on spa_pod_builder.
This commit is contained in:
@@ -394,6 +394,216 @@ struct ma_spa_hook
|
||||
};
|
||||
|
||||
|
||||
/* spa_pod is the most complicated part of SPA that we use. We're only implementing specifically what we need. */
|
||||
struct ma_spa_pod
|
||||
{
|
||||
ma_uint32 size;
|
||||
ma_uint32 type;
|
||||
};
|
||||
|
||||
|
||||
struct ma_spa_pod_id
|
||||
{
|
||||
struct ma_spa_pod pod;
|
||||
ma_uint32 value;
|
||||
ma_int32 _padding;
|
||||
};
|
||||
|
||||
static MA_INLINE struct ma_spa_pod_id ma_spa_pod_id_init(ma_uint32 value)
|
||||
{
|
||||
struct ma_spa_pod_id pod;
|
||||
|
||||
MA_PIPEWIRE_ZERO_OBJECT(&pod);
|
||||
pod.pod.size = 4; /* Does not include the header or padding. */
|
||||
pod.pod.type = SPA_TYPE_Id;
|
||||
pod.value = value;
|
||||
|
||||
return pod;
|
||||
}
|
||||
|
||||
|
||||
struct ma_spa_pod_int
|
||||
{
|
||||
struct ma_spa_pod pod;
|
||||
ma_int32 value;
|
||||
ma_int32 _padding;
|
||||
};
|
||||
|
||||
static MA_INLINE struct ma_spa_pod_int ma_spa_pod_int_init(ma_int32 value)
|
||||
{
|
||||
struct ma_spa_pod_int pod;
|
||||
|
||||
MA_PIPEWIRE_ZERO_OBJECT(&pod);
|
||||
pod.pod.size = 4; /* Does not include the header or padding. */
|
||||
pod.pod.type = SPA_TYPE_Int;
|
||||
pod.value = value;
|
||||
|
||||
return pod;
|
||||
}
|
||||
|
||||
|
||||
struct ma_spa_pod_object_body
|
||||
{
|
||||
ma_uint32 type;
|
||||
ma_uint32 id;
|
||||
};
|
||||
|
||||
struct ma_spa_pod_object
|
||||
{
|
||||
struct ma_spa_pod pod;
|
||||
struct ma_spa_pod_object_body body;
|
||||
};
|
||||
|
||||
struct ma_spa_pod_prop
|
||||
{
|
||||
ma_uint32 key;
|
||||
ma_uint32 flags;
|
||||
struct ma_spa_pod value;
|
||||
};
|
||||
|
||||
struct ma_spa_pod_prop_id
|
||||
{
|
||||
ma_uint32 key;
|
||||
ma_uint32 flags;
|
||||
struct ma_spa_pod_id value;
|
||||
};
|
||||
|
||||
static MA_INLINE struct ma_spa_pod_prop_id ma_spa_pod_prop_id_init(ma_uint32 key, ma_uint32 value)
|
||||
{
|
||||
struct ma_spa_pod_prop_id prop;
|
||||
|
||||
prop.key = key;
|
||||
prop.flags = 0;
|
||||
prop.value = ma_spa_pod_id_init(value);
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
|
||||
struct ma_spa_pod_prop_int
|
||||
{
|
||||
ma_uint32 key;
|
||||
ma_uint32 flags;
|
||||
struct ma_spa_pod_int value;
|
||||
};
|
||||
|
||||
static MA_INLINE struct ma_spa_pod_prop_int ma_spa_pod_prop_int_init(ma_uint32 key, ma_int32 value)
|
||||
{
|
||||
struct ma_spa_pod_prop_int prop;
|
||||
|
||||
prop.key = key;
|
||||
prop.flags = 0;
|
||||
prop.value = ma_spa_pod_int_init(value);
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
|
||||
/* This is a custom pod for our buffer parameters. */
|
||||
struct ma_spa_pod_buffer_params
|
||||
{
|
||||
struct ma_spa_pod_object object;
|
||||
struct ma_spa_pod_prop_int buffers;
|
||||
struct ma_spa_pod_prop_int blocks;
|
||||
struct ma_spa_pod_prop_int stride;
|
||||
struct ma_spa_pod_prop_int size;
|
||||
};
|
||||
|
||||
static MA_INLINE struct ma_spa_pod_buffer_params ma_spa_pod_buffer_params_init(ma_uint32 strideInBytes, ma_uint32 bufferSizeInFrames)
|
||||
{
|
||||
struct ma_spa_pod_buffer_params pod;
|
||||
|
||||
/*
|
||||
spa_pod_builder_add_object(&podBuilder,
|
||||
SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
|
||||
SPA_PARAM_BUFFERS_buffers, SPA_POD_Int(2),
|
||||
SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
|
||||
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(bytesPerFrame),
|
||||
SPA_PARAM_BUFFERS_size, SPA_POD_Int(bytesPerFrame * pStreamState->bufferSizeInFrames));
|
||||
*/
|
||||
|
||||
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.type = SPA_TYPE_Object;
|
||||
pod.object.body.type = SPA_TYPE_OBJECT_ParamBuffers;
|
||||
pod.object.body.id = SPA_PARAM_Buffers;
|
||||
|
||||
pod.buffers = ma_spa_pod_prop_int_init(SPA_PARAM_BUFFERS_buffers, 2);
|
||||
pod.blocks = ma_spa_pod_prop_int_init(SPA_PARAM_BUFFERS_blocks, 1);
|
||||
pod.stride = ma_spa_pod_prop_int_init(SPA_PARAM_BUFFERS_stride, (ma_int32)strideInBytes);
|
||||
pod.size = ma_spa_pod_prop_int_init(SPA_PARAM_BUFFERS_size, (ma_int32)(strideInBytes * bufferSizeInFrames));
|
||||
|
||||
return pod;
|
||||
}
|
||||
|
||||
|
||||
/* A custom pod for audio info. */
|
||||
struct ma_spa_pod_audio_info_raw
|
||||
{
|
||||
struct ma_spa_pod_object object;
|
||||
struct ma_spa_pod_prop_id mediaType;
|
||||
struct ma_spa_pod_prop_id mediaSubtype;
|
||||
struct ma_spa_pod_prop_id format;
|
||||
struct ma_spa_pod_prop_int extra[2]; /* Channels and sample rate. Both are optional. */
|
||||
};
|
||||
|
||||
static MA_INLINE struct ma_spa_pod_audio_info_raw ma_spa_pod_audio_info_raw_init(enum ma_spa_audio_format format, ma_uint32 channels, ma_uint32 sampleRate)
|
||||
{
|
||||
struct ma_spa_pod_audio_info_raw pod;
|
||||
int extraIndex = 0;
|
||||
|
||||
/*
|
||||
struct spa_audio_info_raw audioInfo;
|
||||
char podBuilderBuffer[1024];
|
||||
struct spa_pod_builder podBuilder;
|
||||
|
||||
podBuilder = SPA_POD_BUILDER_INIT(podBuilderBuffer, sizeof(podBuilderBuffer));
|
||||
|
||||
memset(&audioInfo, 0, sizeof(audioInfo));
|
||||
audioInfo.flags = SPA_AUDIO_FLAG_UNPOSITIONED;
|
||||
audioInfo.format = (enum spa_audio_format)formatPA;
|
||||
audioInfo.channels = pDescriptor->channels;
|
||||
audioInfo.rate = pDescriptor->sampleRate;
|
||||
|
||||
pConnectionParameters[0] = spa_format_audio_raw_build(&podBuilder, SPA_PARAM_EnumFormat, &audioInfo);
|
||||
*/
|
||||
|
||||
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.type = SPA_TYPE_Object;
|
||||
pod.object.body.type = SPA_TYPE_OBJECT_Format;
|
||||
pod.object.body.id = SPA_PARAM_EnumFormat;
|
||||
|
||||
pod.mediaType = ma_spa_pod_prop_id_init(SPA_FORMAT_mediaType, SPA_MEDIA_TYPE_audio);
|
||||
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.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.object.pod.size += sizeof(struct ma_spa_pod_prop_id);
|
||||
|
||||
if (channels > 0) {
|
||||
pod.extra[extraIndex] = ma_spa_pod_prop_int_init(SPA_FORMAT_AUDIO_channels, (ma_int32)channels);
|
||||
pod.object.pod.size += sizeof(struct ma_spa_pod_prop_int);
|
||||
extraIndex += 1;
|
||||
}
|
||||
|
||||
if (sampleRate > 0) {
|
||||
pod.extra[extraIndex] = ma_spa_pod_prop_int_init(SPA_FORMAT_AUDIO_rate, (ma_int32)sampleRate);
|
||||
pod.object.pod.size += sizeof(struct ma_spa_pod_prop_int);
|
||||
extraIndex += 1;
|
||||
}
|
||||
|
||||
/* We're going to leave the channel map alone and just do a conversion ourselves if it differs from the native map. */
|
||||
|
||||
return pod;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Miscellaneous SPA references that we don't actively use but are required by structs or function parameters. */
|
||||
typedef struct ma_spa_command ma_spa_command;
|
||||
|
||||
@@ -573,11 +783,11 @@ typedef int (* ma_pw_properties_set_proc )(struct
|
||||
typedef struct ma_pw_stream* (* ma_pw_stream_new_proc )(struct ma_pw_core* core, const char* name, struct ma_pw_properties* props);
|
||||
typedef void (* ma_pw_stream_destroy_proc )(struct ma_pw_stream* stream);
|
||||
typedef void (* ma_pw_stream_add_listener_proc )(struct ma_pw_stream* stream, struct ma_spa_hook* listener, const struct ma_pw_stream_events* events, void* data);
|
||||
typedef int (* ma_pw_stream_connect_proc )(struct ma_pw_stream* stream, enum ma_spa_direction direction, ma_uint32 target_id, enum ma_pw_stream_flags flags, const struct spa_pod** params, ma_uint32 paramCount);
|
||||
typedef int (* ma_pw_stream_connect_proc )(struct ma_pw_stream* stream, enum ma_spa_direction direction, ma_uint32 target_id, enum ma_pw_stream_flags flags, const struct ma_spa_pod** params, ma_uint32 paramCount);
|
||||
typedef int (* ma_pw_stream_set_active_proc )(struct ma_pw_stream* stream, ma_bool8 active);
|
||||
typedef struct ma_pw_buffer* (* ma_pw_stream_dequeue_buffer_proc )(struct ma_pw_stream* stream);
|
||||
typedef int (* ma_pw_stream_queue_buffer_proc )(struct ma_pw_stream* stream, struct ma_pw_buffer* buffer);
|
||||
typedef int (* ma_pw_stream_update_params_proc )(struct ma_pw_stream* stream, const struct spa_pod** params, ma_uint32 paramCount);
|
||||
typedef int (* ma_pw_stream_update_params_proc )(struct ma_pw_stream* stream, const struct ma_spa_pod** params, ma_uint32 paramCount);
|
||||
typedef int (* ma_pw_stream_update_properties_proc)(struct ma_pw_stream* stream, const struct ma_spa_dict* dict);
|
||||
typedef int (* ma_pw_stream_get_time_n_proc )(struct ma_pw_stream* stream, struct ma_pw_time* time, ma_uint32 size);
|
||||
|
||||
@@ -1375,9 +1585,8 @@ static void ma_stream_event_param_changed__pipewire(void* pUserData, ma_uint32 i
|
||||
if (id == SPA_PARAM_Format) {
|
||||
ma_pipewire_stream_state* pStreamState;
|
||||
struct spa_audio_info_raw audioInfo;
|
||||
char podBuilderBuffer[1024];
|
||||
struct spa_pod_builder podBuilder;
|
||||
const struct spa_pod* pBufferParameters[1];
|
||||
struct ma_spa_pod_buffer_params bufferParams;
|
||||
const struct ma_spa_pod* pBufferParameters[1];
|
||||
ma_uint32 bytesPerFrame;
|
||||
ma_uint32 iChannel;
|
||||
|
||||
@@ -1451,15 +1660,12 @@ static void ma_stream_event_param_changed__pipewire(void* pUserData, ma_uint32 i
|
||||
|
||||
bytesPerFrame = ma_get_bytes_per_frame(pStreamState->format, pStreamState->channels);
|
||||
|
||||
/* Now update the PipeWire buffer properties. */
|
||||
podBuilder = SPA_POD_BUILDER_INIT(podBuilderBuffer, sizeof(podBuilderBuffer));
|
||||
|
||||
pBufferParameters[0] = (const struct spa_pod*)spa_pod_builder_add_object(&podBuilder,
|
||||
SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
|
||||
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 2, 8),
|
||||
SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
|
||||
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(bytesPerFrame),
|
||||
SPA_PARAM_BUFFERS_size, SPA_POD_Int(bytesPerFrame * pStreamState->bufferSizeInFrames));
|
||||
/*
|
||||
Now update the PipeWire buffer properties. Note that spa_pod_buffer_params_init() is not a standard SPA function. It's a
|
||||
custom function to eliminate the dependency on libspa for building miniaudio.
|
||||
*/
|
||||
bufferParams = ma_spa_pod_buffer_params_init(bytesPerFrame, pStreamState->bufferSizeInFrames);
|
||||
pBufferParameters[0] = (struct ma_spa_pod*)&bufferParams;
|
||||
|
||||
pContextStatePipeWire->pw_stream_update_params(pStreamState->pStream, pBufferParameters, sizeof(pBufferParameters) / sizeof(pBufferParameters[0]));
|
||||
|
||||
@@ -1679,12 +1885,11 @@ static const struct ma_pw_stream_events ma_gStreamEventsPipeWire_Capture =
|
||||
static ma_result ma_device_init_internal__pipewire(ma_device* pDevice, ma_context_state_pipewire* pContextStatePipeWire, ma_device_state_pipewire* pDeviceStatePipeWire, const ma_device_config_pipewire* pDeviceConfigPipeWire, ma_device_type deviceType, ma_device_descriptor* pDescriptor)
|
||||
{
|
||||
ma_pipewire_stream_state* pStreamState;
|
||||
struct spa_audio_info_raw audioInfo;
|
||||
struct ma_pw_properties* pProperties;
|
||||
const struct ma_pw_stream_events* pStreamEvents;
|
||||
char podBuilderBuffer[1024]; /* A random buffer for use by the POD builder. I have no idea what the purpose of this is and what an appropriate size it should be set to. Why is this even a thing? */
|
||||
struct spa_pod_builder podBuilder;
|
||||
const struct spa_pod* pConnectionParameters[1];
|
||||
enum ma_spa_audio_format formatPA;
|
||||
struct ma_spa_pod_audio_info_raw podAudioInfo;
|
||||
const struct ma_spa_pod* pConnectionParameters[1];
|
||||
enum ma_pw_stream_flags streamFlags;
|
||||
int connectResult;
|
||||
|
||||
@@ -1725,22 +1930,15 @@ static ma_result ma_device_init_internal__pipewire(ma_device* pDevice, ma_contex
|
||||
/* This installs callbacks for process and param_changed. "process" is for queuing audio data, and "param_changed" is for getting the internal format/channels/rate. */
|
||||
pContextStatePipeWire->pw_stream_add_listener(pStreamState->pStream, &pStreamState->eventListener, pStreamEvents, pDeviceStatePipeWire);
|
||||
|
||||
|
||||
podBuilder = SPA_POD_BUILDER_INIT(podBuilderBuffer, sizeof(podBuilderBuffer));
|
||||
|
||||
memset(&audioInfo, 0, sizeof(audioInfo));
|
||||
audioInfo.format = (enum spa_audio_format)ma_format_to_pipewire(pDescriptor->format);
|
||||
audioInfo.channels = pDescriptor->channels;
|
||||
audioInfo.rate = pDescriptor->sampleRate;
|
||||
|
||||
/* If the format is SPA_AUDIO_FORMAT_UNKNOWN, PipeWire can pick a planar data layout (de-interleaved) which breaks things for us. Just force interleaved F32 in this case. */
|
||||
if (audioInfo.format == (enum spa_audio_format)MA_SPA_AUDIO_FORMAT_UNKNOWN) {
|
||||
audioInfo.format = (enum spa_audio_format)MA_SPA_AUDIO_FORMAT_F32;
|
||||
formatPA = ma_format_to_pipewire(pDescriptor->format);
|
||||
if (formatPA == MA_SPA_AUDIO_FORMAT_UNKNOWN) {
|
||||
formatPA = MA_SPA_AUDIO_FORMAT_F32;
|
||||
}
|
||||
|
||||
/* We're going to leave the channel map alone and just do a conversion ourselves if it differs from the native map. */
|
||||
|
||||
pConnectionParameters[0] = spa_format_audio_raw_build(&podBuilder, SPA_PARAM_EnumFormat, &audioInfo);
|
||||
podAudioInfo = ma_spa_pod_audio_info_raw_init(formatPA, pDescriptor->channels, pDescriptor->sampleRate);
|
||||
pConnectionParameters[0] = (struct ma_spa_pod*)&podAudioInfo;
|
||||
|
||||
|
||||
/*
|
||||
I'm just using MAP_BUFFERS because it's what the PipeWire examples do. I don't know what this does. Also, what's the
|
||||
|
||||
Reference in New Issue
Block a user