mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-24 09:14:04 +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_device_info deviceInfo;
|
||||||
|
ma_uint32 minSampleRate;
|
||||||
|
ma_uint32 maxSampleRate;
|
||||||
|
|
||||||
(void)pContext;
|
(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);
|
MA_PIPEWIRE_ZERO_OBJECT(&deviceInfo);
|
||||||
|
|
||||||
/* Default. */
|
/* 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);
|
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. */
|
/* Data Format. */
|
||||||
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_f32, 1, 64, minSampleRate, maxSampleRate);
|
||||||
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);
|
|
||||||
|
|
||||||
return callback(deviceType, &deviceInfo, pUserData);
|
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_ENUM_DONE (1 << 0)
|
||||||
#define MA_PW_CORE_SYNC_FLAG_DEFAULTS_DONE (1 << 1)
|
#define MA_PW_CORE_SYNC_FLAG_DEFAULTS_DONE (1 << 1)
|
||||||
|
#define MA_PW_CORE_SYNC_FLAG_SETTINGS_DONE (1 << 2)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -1714,11 +1721,15 @@ typedef struct
|
|||||||
struct ma_pw_loop* pLoop;
|
struct ma_pw_loop* pLoop;
|
||||||
struct ma_pw_core* pCore;
|
struct ma_pw_core* pCore;
|
||||||
struct ma_pw_registry* pRegistry;
|
struct ma_pw_registry* pRegistry;
|
||||||
struct ma_pw_metadata* pMetadata;
|
struct ma_pw_metadata* pMetadata; /* "default" metadata. */
|
||||||
struct ma_spa_hook metadataListener;
|
struct ma_pw_metadata* pMetadataSettings; /* "settings" metadata. */
|
||||||
|
struct ma_spa_hook metadataListener; /* "default" metadata */
|
||||||
|
struct ma_spa_hook metadataListenerSettings; /* "settings" metadata. */
|
||||||
int seqDefaults;
|
int seqDefaults;
|
||||||
|
int seqSettings;
|
||||||
int seqEnumeration;
|
int seqEnumeration;
|
||||||
ma_uint32 syncFlags;
|
ma_uint32 syncFlags;
|
||||||
|
ma_uint32 clockRate; /* "clock.rate" from the "settings" metadata. */
|
||||||
const ma_allocation_callbacks* pAllocationCallbacks;
|
const ma_allocation_callbacks* pAllocationCallbacks;
|
||||||
struct
|
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
|
typedef struct
|
||||||
{
|
{
|
||||||
enum ma_spa_audio_format format;
|
enum ma_spa_audio_format format;
|
||||||
@@ -2106,16 +2144,6 @@ static void ma_add_native_data_format__pipewire(ma_context_state_pipewire* pCont
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
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;
|
||||||
@@ -2167,26 +2195,41 @@ static void ma_registry_event_global_add_enumeration__pipewire(void* pUserData,
|
|||||||
return;
|
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) {
|
if (strcmp(type, MA_PW_TYPE_INTERFACE_Metadata) == 0) {
|
||||||
const char* pName;
|
const char* pName;
|
||||||
|
|
||||||
pName = ma_spa_dict_lookup(props, MA_PW_KEY_METADATA_NAME);
|
pName = ma_spa_dict_lookup(props, MA_PW_KEY_METADATA_NAME);
|
||||||
if (pName != NULL && strcmp(pName, "default") == 0) {
|
if (pName != NULL) {
|
||||||
pEnumData->pMetadata = (struct ma_pw_metadata*)pEnumData->pContextStatePipeWire->pw_registry_bind(pEnumData->pRegistry, id, MA_PW_TYPE_INTERFACE_Metadata, MA_PW_VERSION_METADATA, 0);
|
/* Default devices. */
|
||||||
if (pEnumData->pMetadata != NULL) {
|
if (strcmp(pName, "default") == 0) {
|
||||||
MA_PIPEWIRE_ZERO_OBJECT(&pEnumData->metadataListener);
|
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. */
|
/* 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);
|
||||||
|
|
||||||
/*spa_api_method_r(int, -ENOTSUP, ma_pw_metadata, (struct spa_interface*)pEnumData->pMetadata, add_listener, 0, &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);*/
|
/*pEnumData->pContextStatePipeWire->pw_metadata_add_listener(pMetadata, &pEnumData->metadataListener, &ma_gMetadataEventsPipeWire, NULL);*/
|
||||||
|
|
||||||
pEnumData->seqDefaults = pEnumData->pContextStatePipeWire->pw_core_sync(pEnumData->pCore, MA_PW_ID_CORE, 0);
|
pEnumData->seqDefaults = pEnumData->pContextStatePipeWire->pw_core_sync(pEnumData->pCore, MA_PW_ID_CORE, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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->seqSettings = pEnumData->pContextStatePipeWire->pw_core_sync(pEnumData->pCore, MA_PW_ID_CORE, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2281,12 +2324,18 @@ static ma_result ma_context_enumerate_devices__pipewire(ma_context* pContext, ma
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
pContextStatePipeWire->pw_loop_iterate(pLoop, -1);
|
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) {
|
if (enumData.seqDefaults == 0) {
|
||||||
break; /* We don't have a "default" metadata. */
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2298,6 +2347,16 @@ static ma_result ma_context_enumerate_devices__pipewire(ma_context* pContext, ma
|
|||||||
size_t iDevice;
|
size_t iDevice;
|
||||||
ma_bool32 hasDefaultPlaybackDevice = MA_FALSE;
|
ma_bool32 hasDefaultPlaybackDevice = MA_FALSE;
|
||||||
ma_bool32 hasDefaultCaptureDevice = 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. */
|
/* Playback devices. */
|
||||||
for (iDevice = 0; iDevice < enumData.playback.deviceInfoCount; iDevice += 1) {
|
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. */
|
/* 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);
|
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 (enumData.playback.deviceInfoCount > 0 && !hasDefaultPlaybackDevice) {
|
||||||
if (cbResult == MA_DEVICE_ENUMERATION_CONTINUE) {
|
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. */
|
/* 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);
|
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 (enumData.capture.deviceInfoCount > 0 && !hasDefaultCaptureDevice) {
|
||||||
if (cbResult == MA_DEVICE_ENUMERATION_CONTINUE) {
|
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