mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-23 00:34:03 +02:00
PipeWire: Improve sample rate detection for device enumeration.
This commit is contained in:
@@ -1672,12 +1672,22 @@ static void ma_context_uninit__pipewire(ma_context* pContext)
|
||||
}
|
||||
|
||||
|
||||
static ma_device_enumeration_result ma_context_enumerate_default_device_by_type__pipewire(ma_context* pContext, ma_device_type deviceType, ma_enum_devices_callback_proc callback, void* pUserData)
|
||||
static ma_device_enumeration_result ma_context_enumerate_default_device_by_type__pipewire(ma_context* pContext, ma_device_type deviceType, ma_uint32 sampleRate, ma_enum_devices_callback_proc callback, void* pUserData)
|
||||
{
|
||||
ma_device_info deviceInfo;
|
||||
ma_uint32 minSampleRate;
|
||||
ma_uint32 maxSampleRate;
|
||||
|
||||
(void)pContext;
|
||||
|
||||
if (sampleRate != 0) {
|
||||
minSampleRate = sampleRate;
|
||||
maxSampleRate = sampleRate;
|
||||
} else {
|
||||
minSampleRate = ma_standard_sample_rate_min;
|
||||
maxSampleRate = ma_standard_sample_rate_max;
|
||||
}
|
||||
|
||||
MA_PIPEWIRE_ZERO_OBJECT(&deviceInfo);
|
||||
|
||||
/* Default. */
|
||||
@@ -1693,12 +1703,8 @@ static ma_device_enumeration_result ma_context_enumerate_default_device_by_type_
|
||||
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "Default Capture Device", (size_t)-1);
|
||||
}
|
||||
|
||||
/* Data Format. PipeWire supports everything. Its maximum channel count is 64. */
|
||||
ma_device_info_add_native_data_format(&deviceInfo, ma_format_f32, 1, 64, ma_standard_sample_rate_min, ma_standard_sample_rate_max);
|
||||
ma_device_info_add_native_data_format(&deviceInfo, ma_format_s16, 1, 64, ma_standard_sample_rate_min, ma_standard_sample_rate_max);
|
||||
ma_device_info_add_native_data_format(&deviceInfo, ma_format_s32, 1, 64, ma_standard_sample_rate_min, ma_standard_sample_rate_max);
|
||||
ma_device_info_add_native_data_format(&deviceInfo, ma_format_s24, 1, 64, ma_standard_sample_rate_min, ma_standard_sample_rate_max);
|
||||
ma_device_info_add_native_data_format(&deviceInfo, ma_format_u8, 1, 64, ma_standard_sample_rate_min, ma_standard_sample_rate_max);
|
||||
/* Data Format. */
|
||||
ma_device_info_add_native_data_format(&deviceInfo, ma_format_f32, 1, 64, minSampleRate, maxSampleRate);
|
||||
|
||||
return callback(deviceType, &deviceInfo, pUserData);
|
||||
}
|
||||
@@ -1707,6 +1713,7 @@ static ma_device_enumeration_result ma_context_enumerate_default_device_by_type_
|
||||
|
||||
#define MA_PW_CORE_SYNC_FLAG_ENUM_DONE (1 << 0)
|
||||
#define MA_PW_CORE_SYNC_FLAG_DEFAULTS_DONE (1 << 1)
|
||||
#define MA_PW_CORE_SYNC_FLAG_SETTINGS_DONE (1 << 2)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -1714,11 +1721,15 @@ typedef struct
|
||||
struct ma_pw_loop* pLoop;
|
||||
struct ma_pw_core* pCore;
|
||||
struct ma_pw_registry* pRegistry;
|
||||
struct ma_pw_metadata* pMetadata;
|
||||
struct ma_spa_hook metadataListener;
|
||||
struct ma_pw_metadata* pMetadata; /* "default" metadata. */
|
||||
struct ma_pw_metadata* pMetadataSettings; /* "settings" metadata. */
|
||||
struct ma_spa_hook metadataListener; /* "default" metadata */
|
||||
struct ma_spa_hook metadataListenerSettings; /* "settings" metadata. */
|
||||
int seqDefaults;
|
||||
int seqSettings;
|
||||
int seqEnumeration;
|
||||
ma_uint32 syncFlags;
|
||||
ma_uint32 clockRate; /* "clock.rate" from the "settings" metadata. */
|
||||
const ma_allocation_callbacks* pAllocationCallbacks;
|
||||
struct
|
||||
{
|
||||
@@ -1873,6 +1884,33 @@ static struct ma_pw_metadata_events ma_gMetadataEventsPipeWire =
|
||||
};
|
||||
|
||||
|
||||
static int ma_on_metadata_property_settings__pipewire(void* data, ma_uint32 subject, const char* key, const char* type, const char* value)
|
||||
{
|
||||
ma_enumerate_devices_data_pipewire* pEnumData = (ma_enumerate_devices_data_pipewire*)data;
|
||||
|
||||
(void)pEnumData;
|
||||
(void)subject;
|
||||
(void)type;
|
||||
|
||||
if (key == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(key, "clock.rate") == 0) {
|
||||
pEnumData->clockRate = (ma_uint32)atoi(value);
|
||||
}
|
||||
|
||||
/*printf("Metadata Property: Subject=%u, Key=%s, Type=%s, Value=%s\n", subject, key, type, value);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ma_pw_metadata_events ma_gMetadataEventsPipeWire_Settings =
|
||||
{
|
||||
MA_PW_VERSION_METADATA_EVENTS,
|
||||
ma_on_metadata_property_settings__pipewire
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum ma_spa_audio_format format;
|
||||
@@ -2106,16 +2144,6 @@ static void ma_add_native_data_format__pipewire(ma_context_state_pipewire* pCont
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ma_add_native_data_format__pipewire(ma_context_state_pipewire* pContextStatePipeWire, struct ma_pw_core* pCore, struct ma_pw_loop* pLoop, ma_device_type deviceType, ma_device_info* pDeviceInfo)
|
||||
{
|
||||
(void)pContextStatePipeWire;
|
||||
(void)pCore;
|
||||
(void)pLoop;
|
||||
(void)deviceType;
|
||||
|
||||
ma_device_info_add_native_data_format(pDeviceInfo, ma_format_f32, 1, 64, ma_standard_sample_rate_min, ma_standard_sample_rate_max);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -2167,26 +2195,41 @@ static void ma_registry_event_global_add_enumeration__pipewire(void* pUserData,
|
||||
return;
|
||||
}
|
||||
|
||||
/* We need to check for our default devices. */
|
||||
/* Some device info needs to be retrieved from metadata. */
|
||||
if (strcmp(type, MA_PW_TYPE_INTERFACE_Metadata) == 0) {
|
||||
const char* pName;
|
||||
|
||||
pName = ma_spa_dict_lookup(props, MA_PW_KEY_METADATA_NAME);
|
||||
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);
|
||||
if (pEnumData->pMetadata != NULL) {
|
||||
MA_PIPEWIRE_ZERO_OBJECT(&pEnumData->metadataListener);
|
||||
if (pName != NULL) {
|
||||
/* Default devices. */
|
||||
if (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);
|
||||
if (pEnumData->pMetadata != NULL) {
|
||||
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. */
|
||||
((struct ma_pw_metadata_methods*)((struct ma_spa_interface*)pEnumData->pMetadata)->cb.funcs)->add_listener(pEnumData->pMetadata, &pEnumData->metadataListener, &ma_gMetadataEventsPipeWire, pEnumData);
|
||||
|
||||
/*spa_api_method_r(int, -ENOTSUP, ma_pw_metadata, (struct spa_interface*)pEnumData->pMetadata, add_listener, 0, &pEnumData->metadataListener, &ma_gMetadataEventsPipeWire, pEnumData);*/
|
||||
/*pEnumData->pContextStatePipeWire->pw_metadata_add_listener(pMetadata, &pEnumData->metadataListener, &ma_gMetadataEventsPipeWire, NULL);*/
|
||||
|
||||
/* 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);
|
||||
pEnumData->seqDefaults = pEnumData->pContextStatePipeWire->pw_core_sync(pEnumData->pCore, MA_PW_ID_CORE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*spa_api_method_r(int, -ENOTSUP, ma_pw_metadata, (struct spa_interface*)pEnumData->pMetadata, add_listener, 0, &pEnumData->metadataListener, &ma_gMetadataEventsPipeWire, pEnumData);*/
|
||||
/*pEnumData->pContextStatePipeWire->pw_metadata_add_listener(pMetadata, &pEnumData->metadataListener, &ma_gMetadataEventsPipeWire, NULL);*/
|
||||
/* Sample rate. */
|
||||
if (strcmp(pName, "settings") == 0) {
|
||||
pEnumData->pMetadataSettings = (struct ma_pw_metadata*)pEnumData->pContextStatePipeWire->pw_registry_bind(pEnumData->pRegistry, id, MA_PW_TYPE_INTERFACE_Metadata, MA_PW_VERSION_METADATA, 0);
|
||||
if (pEnumData->pMetadataSettings != NULL) {
|
||||
MA_PIPEWIRE_ZERO_OBJECT(&pEnumData->metadataListenerSettings);
|
||||
((struct ma_pw_metadata_methods*)((struct ma_spa_interface*)pEnumData->pMetadataSettings)->cb.funcs)->add_listener(pEnumData->pMetadataSettings, &pEnumData->metadataListenerSettings, &ma_gMetadataEventsPipeWire_Settings, pEnumData);
|
||||
|
||||
pEnumData->seqDefaults = pEnumData->pContextStatePipeWire->pw_core_sync(pEnumData->pCore, MA_PW_ID_CORE, 0);
|
||||
pEnumData->seqSettings = pEnumData->pContextStatePipeWire->pw_core_sync(pEnumData->pCore, MA_PW_ID_CORE, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2281,12 +2324,18 @@ static ma_result ma_context_enumerate_devices__pipewire(ma_context* pContext, ma
|
||||
for (;;) {
|
||||
pContextStatePipeWire->pw_loop_iterate(pLoop, -1);
|
||||
|
||||
if (enumData.syncFlags & MA_PW_CORE_SYNC_FLAG_ENUM_DONE) {
|
||||
if ((enumData.syncFlags & MA_PW_CORE_SYNC_FLAG_ENUM_DONE) != 0) {
|
||||
if (enumData.seqDefaults == 0) {
|
||||
break; /* We don't have a "default" metadata. */
|
||||
}
|
||||
if ((enumData.syncFlags & MA_PW_CORE_SYNC_FLAG_DEFAULTS_DONE) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (enumData.syncFlags & MA_PW_CORE_SYNC_FLAG_DEFAULTS_DONE) {
|
||||
if (enumData.seqSettings == 0) {
|
||||
break; /* We don't have a "settings" metadata. */
|
||||
}
|
||||
if ((enumData.syncFlags & MA_PW_CORE_SYNC_FLAG_SETTINGS_DONE) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2298,6 +2347,16 @@ static ma_result ma_context_enumerate_devices__pipewire(ma_context* pContext, ma
|
||||
size_t iDevice;
|
||||
ma_bool32 hasDefaultPlaybackDevice = MA_FALSE;
|
||||
ma_bool32 hasDefaultCaptureDevice = MA_FALSE;
|
||||
ma_uint32 minSampleRate;
|
||||
ma_uint32 maxSampleRate;
|
||||
|
||||
if (enumData.clockRate != 0) {
|
||||
minSampleRate = enumData.clockRate;
|
||||
maxSampleRate = enumData.clockRate;
|
||||
} else {
|
||||
minSampleRate = ma_standard_sample_rate_min;
|
||||
maxSampleRate = ma_standard_sample_rate_max;
|
||||
}
|
||||
|
||||
/* Playback devices. */
|
||||
for (iDevice = 0; iDevice < enumData.playback.deviceInfoCount; iDevice += 1) {
|
||||
@@ -2308,7 +2367,7 @@ static ma_result ma_context_enumerate_devices__pipewire(ma_context* pContext, ma
|
||||
}
|
||||
|
||||
/* Now we need to open the stream and get it's native data format. */
|
||||
ma_add_native_data_format__pipewire(pContextStatePipeWire, pCore, pLoop, ma_device_type_playback, &enumData.playback.pDeviceInfos[iDevice]);
|
||||
ma_device_info_add_native_data_format(&enumData.playback.pDeviceInfos[iDevice], ma_format_f32, 1, 64, minSampleRate, maxSampleRate);
|
||||
|
||||
cbResult = callback(ma_device_type_playback, &enumData.playback.pDeviceInfos[iDevice], pUserData);
|
||||
}
|
||||
@@ -2316,7 +2375,7 @@ static ma_result ma_context_enumerate_devices__pipewire(ma_context* pContext, ma
|
||||
|
||||
if (enumData.playback.deviceInfoCount > 0 && !hasDefaultPlaybackDevice) {
|
||||
if (cbResult == MA_DEVICE_ENUMERATION_CONTINUE) {
|
||||
cbResult = ma_context_enumerate_default_device_by_type__pipewire(pContext, ma_device_type_playback, callback, pUserData);
|
||||
cbResult = ma_context_enumerate_default_device_by_type__pipewire(pContext, ma_device_type_playback, enumData.clockRate, callback, pUserData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2330,7 +2389,7 @@ static ma_result ma_context_enumerate_devices__pipewire(ma_context* pContext, ma
|
||||
}
|
||||
|
||||
/* Now we need to open the stream and get it's native data format. */
|
||||
ma_add_native_data_format__pipewire(pContextStatePipeWire, pCore, pLoop, ma_device_type_capture, &enumData.capture.pDeviceInfos[iDevice]);
|
||||
ma_device_info_add_native_data_format(&enumData.capture.pDeviceInfos[iDevice], ma_format_f32, 1, 64, minSampleRate, maxSampleRate);
|
||||
|
||||
cbResult = callback(ma_device_type_capture, &enumData.capture.pDeviceInfos[iDevice], pUserData);
|
||||
}
|
||||
@@ -2338,7 +2397,7 @@ static ma_result ma_context_enumerate_devices__pipewire(ma_context* pContext, ma
|
||||
|
||||
if (enumData.capture.deviceInfoCount > 0 && !hasDefaultCaptureDevice) {
|
||||
if (cbResult == MA_DEVICE_ENUMERATION_CONTINUE) {
|
||||
cbResult = ma_context_enumerate_default_device_by_type__pipewire(pContext, ma_device_type_capture, callback, pUserData);
|
||||
cbResult = ma_context_enumerate_default_device_by_type__pipewire(pContext, ma_device_type_capture, enumData.clockRate, callback, pUserData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user