mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-21 15:56:58 +02:00
PipeWire: Remove dependency on spa_format_audio_raw_parse().
This commit is contained in:
@@ -442,6 +442,59 @@ static MA_INLINE struct ma_spa_pod_int ma_spa_pod_int_init(ma_int32 value)
|
||||
}
|
||||
|
||||
|
||||
enum ma_spa_choice_type
|
||||
{
|
||||
MA_SPA_CHOICE_None = 0,
|
||||
MA_SPA_CHOICE_Range,
|
||||
MA_SPA_CHOICE_Step,
|
||||
MA_SPA_CHOICE_Enum,
|
||||
MA_SPA_CHOICE_Flags
|
||||
};
|
||||
|
||||
struct ma_spa_pod_choice_body
|
||||
{
|
||||
ma_uint32 type;
|
||||
ma_uint32 flags;
|
||||
struct ma_spa_pod child;
|
||||
};
|
||||
|
||||
struct ma_spa_pod_choice
|
||||
{
|
||||
struct ma_spa_pod pod;
|
||||
struct ma_spa_pod_choice_body body;
|
||||
};
|
||||
|
||||
static MA_INLINE void* ma_spa_pod_choice_get_values(const struct ma_spa_pod_choice* choice)
|
||||
{
|
||||
/* Values are stored as a flat array after the main struct. */
|
||||
return (void*)ma_offset_ptr(choice, sizeof(struct ma_spa_pod_choice));
|
||||
}
|
||||
|
||||
|
||||
struct ma_spa_pod_array_body
|
||||
{
|
||||
struct ma_spa_pod child;
|
||||
};
|
||||
|
||||
struct ma_spa_pod_array
|
||||
{
|
||||
struct ma_spa_pod pod;
|
||||
struct ma_spa_pod_array_body body;
|
||||
};
|
||||
|
||||
static MA_INLINE ma_uint32 ma_spa_pod_array_get_length(const struct ma_spa_pod_array* array)
|
||||
{
|
||||
return (array->pod.size - sizeof(struct ma_spa_pod_array_body)) / array->body.child.size;
|
||||
}
|
||||
|
||||
static MA_INLINE void* ma_spa_pod_array_get_values(const struct ma_spa_pod_array* array)
|
||||
{
|
||||
/* Values are stored as a flat array after the main struct. */
|
||||
return (void*)ma_offset_ptr(array, sizeof(struct ma_spa_pod_array));
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ma_spa_pod_object_body
|
||||
{
|
||||
ma_uint32 type;
|
||||
@@ -603,6 +656,65 @@ static MA_INLINE struct ma_spa_pod_audio_info_raw ma_spa_pod_audio_info_raw_init
|
||||
}
|
||||
|
||||
|
||||
/* Extracts the value of an ID from a pod, depending on its type. */
|
||||
static MA_INLINE ma_uint32 ma_spa_pod_get_id_value(const struct ma_spa_pod* pod)
|
||||
{
|
||||
MA_PIPEWIRE_ASSERT(pod != NULL);
|
||||
|
||||
switch (pod->type)
|
||||
{
|
||||
case SPA_TYPE_Id:
|
||||
{
|
||||
const struct ma_spa_pod_id* pPodID = (const struct ma_spa_pod_id*)pod;
|
||||
return pPodID->value;
|
||||
}
|
||||
|
||||
case SPA_TYPE_Choice:
|
||||
{
|
||||
const struct ma_spa_pod_choice* pPodChoice = (const struct ma_spa_pod_choice*)pod;
|
||||
const void* pValues = ma_spa_pod_choice_get_values(pPodChoice);
|
||||
|
||||
/* We're just going to return the first value. */
|
||||
return ((ma_uint32*)pValues)[0];
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
MA_PIPEWIRE_ASSERT(MA_FALSE); /* Unsupported type. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static MA_INLINE ma_int32 ma_spa_pod_get_int_value(const struct ma_spa_pod* pod)
|
||||
{
|
||||
MA_PIPEWIRE_ASSERT(pod != NULL);
|
||||
|
||||
switch (pod->type)
|
||||
{
|
||||
case SPA_TYPE_Id:
|
||||
{
|
||||
const struct ma_spa_pod_int* pPodInt = (const struct ma_spa_pod_int*)pod;
|
||||
return pPodInt->value;
|
||||
}
|
||||
|
||||
case SPA_TYPE_Choice:
|
||||
{
|
||||
const struct ma_spa_pod_choice* pPodChoice = (const struct ma_spa_pod_choice*)pod;
|
||||
const void* pValues = ma_spa_pod_choice_get_values(pPodChoice);
|
||||
|
||||
/* We're just going to return the first value. */
|
||||
return ((ma_int32*)pValues)[0];
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
MA_PIPEWIRE_ASSERT(MA_FALSE); /* Unsupported type. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
@@ -1584,11 +1696,14 @@ 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;
|
||||
struct ma_spa_pod_buffer_params bufferParams;
|
||||
const struct ma_spa_pod* pBufferParameters[1];
|
||||
ma_uint32 bytesPerFrame;
|
||||
ma_uint32 iChannel;
|
||||
enum ma_spa_audio_format formatPA;
|
||||
ma_uint32 channels;
|
||||
ma_uint32 sampleRate;
|
||||
const ma_uint32* pChannelPositionsPA;
|
||||
|
||||
/* It's possible for PipeWire to fire this callback with pParam set to NULL. I noticed it when tearing down a stream. Why does it do this? */
|
||||
if (pParam == NULL) {
|
||||
@@ -1608,38 +1723,106 @@ static void ma_stream_event_param_changed__pipewire(void* pUserData, ma_uint32 i
|
||||
|
||||
/*
|
||||
We can now determine the format/channels/rate which will let us configure the size of the buffer and set the
|
||||
internal format of the device.
|
||||
internal format of the device. To do this we need to parse the pParam pod.
|
||||
*/
|
||||
spa_format_audio_raw_parse(pParam, &audioInfo);
|
||||
|
||||
#if 0
|
||||
{
|
||||
printf("Format: %d\n", audioInfo.format);
|
||||
printf("Channels: %d\n", audioInfo.channels);
|
||||
printf("Rate: %d\n", audioInfo.rate);
|
||||
printf("Channel Map: {");
|
||||
for (iChannel = 0; iChannel < audioInfo.channels; iChannel += 1) {
|
||||
printf("%d", audioInfo.position[iChannel]);
|
||||
if (iChannel < audioInfo.channels - 1) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf("}\n");
|
||||
struct spa_audio_info_raw audioInfo;
|
||||
spa_format_audio_raw_parse(pParam, &audioInfo);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
struct ma_spa_pod_object* pObject;
|
||||
struct ma_spa_pod_prop* pNextProp;
|
||||
ma_uint8* ptr = (ma_uint8*)pParam;
|
||||
ma_uint32 cursor = 0;
|
||||
ma_uint32 size;
|
||||
|
||||
if (pParam->type != 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).");
|
||||
return;
|
||||
}
|
||||
|
||||
pObject = (struct ma_spa_pod_object*)pParam;
|
||||
|
||||
/* The size of the pod does not include the header which makes parsing kind of annoying for us. We'll add it here. */
|
||||
size = pParam->size + sizeof(struct ma_spa_pod);
|
||||
cursor += sizeof(struct ma_spa_pod);
|
||||
|
||||
if (pObject->body.type != SPA_TYPE_OBJECT_Format) {
|
||||
ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "Failed to parse PipeWire format parameter (invalid body type).");
|
||||
return;
|
||||
}
|
||||
|
||||
cursor += sizeof(struct ma_spa_pod_object_body);
|
||||
|
||||
/* At this point we have parsed the header part of the object, and what follows now should be a list of properties. */
|
||||
while (cursor < size) {
|
||||
struct ma_spa_pod* pPropValue;
|
||||
|
||||
pNextProp = (struct ma_spa_pod_prop*)(ptr + cursor);
|
||||
if (cursor + sizeof(struct ma_spa_pod_prop) > size) {
|
||||
ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "Failed to parse PipeWire format parameter (invalid size for property).");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Place the cursor on the prop value, which is a spa_pod. */
|
||||
cursor += 8; /* Size of the key and flags. */
|
||||
pPropValue = (struct ma_spa_pod*)(ptr + cursor);
|
||||
|
||||
switch (pNextProp->key)
|
||||
{
|
||||
case SPA_FORMAT_AUDIO_format:
|
||||
{
|
||||
formatPA = (enum ma_spa_audio_format)ma_spa_pod_get_id_value(pPropValue);
|
||||
} break;
|
||||
|
||||
case SPA_FORMAT_AUDIO_channels:
|
||||
{
|
||||
channels = ma_spa_pod_get_int_value(pPropValue);
|
||||
} break;
|
||||
|
||||
case SPA_FORMAT_AUDIO_rate:
|
||||
{
|
||||
sampleRate = ma_spa_pod_get_int_value(pPropValue);
|
||||
} break;
|
||||
|
||||
case SPA_FORMAT_AUDIO_position:
|
||||
{
|
||||
ma_uint32 positionCount;
|
||||
|
||||
/* I'm assuming we can only get an array back for this. */
|
||||
if (pPropValue->type != SPA_TYPE_Array) {
|
||||
ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "Failed to parse PipeWire format parameter (invalid type for position property).");
|
||||
return;
|
||||
}
|
||||
|
||||
positionCount = ma_spa_pod_array_get_length((const struct ma_spa_pod_array*)pPropValue);
|
||||
if (positionCount != channels) {
|
||||
ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "Failed to parse PipeWire format parameter (mismatched channel count for position property).");
|
||||
return;
|
||||
}
|
||||
|
||||
pChannelPositionsPA = (const ma_uint32*)ma_spa_pod_array_get_values((const struct ma_spa_pod_array*)pPropValue);
|
||||
} break;
|
||||
}
|
||||
|
||||
cursor += ma_align_64(8 + pPropValue->size); /* Size of the value pod header + the size of the pod itself. */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Now that we definitely know the sample rate, we can reliably configure the size of the buffer. */
|
||||
if (pStreamState->bufferSizeInFrames == 0) {
|
||||
pStreamState->bufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pStreamState->pDescriptor, (ma_uint32)audioInfo.rate);
|
||||
pStreamState->bufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pStreamState->pDescriptor, sampleRate);
|
||||
}
|
||||
|
||||
pStreamState->format = ma_format_from_pipewire((enum ma_spa_audio_format)audioInfo.format);
|
||||
pStreamState->channels = audioInfo.channels;
|
||||
pStreamState->sampleRate = audioInfo.rate;
|
||||
pStreamState->format = ma_format_from_pipewire(formatPA);
|
||||
pStreamState->channels = channels;
|
||||
pStreamState->sampleRate = sampleRate;
|
||||
|
||||
for (iChannel = 0; iChannel < MA_MAX_CHANNELS; iChannel += 1) {
|
||||
pStreamState->channelMap[iChannel] = ma_channel_from_pipewire(audioInfo.position[iChannel]);
|
||||
pStreamState->channelMap[iChannel] = ma_channel_from_pipewire(pChannelPositionsPA[iChannel]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user