diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-06-26 14:18:07 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-06-26 14:18:07 -0400 |
| commit | 1c87a0e431d30aaf19195f8a45c7607add21018a (patch) | |
| tree | dcae1b86647e87757a0e2c6804fa6ac7de0862b9 /src | |
| parent | 73795506229111ac8b65082921d563e53b5bdecd (diff) | |
pke: audio: auto-connect to default sink
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio-impl-pw.cpp | 77 | ||||
| -rw-r--r-- | src/audio-impl-pw.hpp | 1 | ||||
| -rw-r--r-- | src/audio.cpp | 8 | ||||
| -rw-r--r-- | src/audio.hpp | 2 | ||||
| -rw-r--r-- | src/game.cpp | 2 |
5 files changed, 87 insertions, 3 deletions
diff --git a/src/audio-impl-pw.cpp b/src/audio-impl-pw.cpp index ba6760e..4c0d909 100644 --- a/src/audio-impl-pw.cpp +++ b/src/audio-impl-pw.cpp @@ -1,6 +1,7 @@ #include "audio-impl-pw.hpp" #include "audio-types.hpp" +#include "game-settings.hpp" #include "pipewire/keys.h" #include "pipewire/thread-loop.h" #include "pk.h" @@ -176,6 +177,80 @@ void pke_audio_pw_teardown() { pke_audio_mstr.mtx_buffer.unlock(); } +bool pke_audio_pw_remap_outputs() { + uint32_t stream_id; + uint32_t i; + uint32_t port_count = {0}; + void *created_obj = {0}; + pw_properties *props = pw_properties_new(NULL, NULL); + pke_audio_pw_object *objs = (pke_audio_pw_object *)pke_audio_pw.pw_objects.data; + const char *str; + uint32_t *out_ports = pk_new<uint32_t>(pke_audio_mstr.channel_count, pkeSettings.mem_bkt.game_transient); + uint32_t *in_ports = pk_new<uint32_t>(pke_audio_mstr.channel_count, pkeSettings.mem_bkt.game_transient); + + pw_thread_loop_lock(pke_audio_pw.loop); + + // remove all existing links + { + for (i = pke_audio_pw.created_objects.next; i > 0; --i) { + pw_core_destroy(pke_audio_pw.core, pke_audio_pw.created_objects[i - 1]); + } + pk_arr_clear(&pke_audio_pw.created_objects); + } + + // find node we're going to connect to + // + build out_ports and in_ports + { + stream_id = pw_stream_get_node_id(pke_audio_pw.stream); + for (i = 0; i < pke_audio_pw.pw_objects.next; ++i) { + if (objs[i].type != PKE_AUDIO_PW_OBJECT_TYPE_NODE) continue; + if ((str = spa_dict_lookup(&objs[i].props->dict, "node.name")), str == NULL) continue; + if (strcmp(pke_audio_pw.default_sink_name, str) == 0) { + pke_audio_pw.default_sink_id = objs[i].id; + break; + } + } + // assert(stream_id != 0); + if (stream_id == 0) { + pw_properties_free(props); + pw_thread_loop_unlock(pke_audio_pw.loop); + return false; + } + for (i = 0; i < pke_audio_pw.pw_objects.next; ++i) { + if (objs[i].type != PKE_AUDIO_PW_OBJECT_TYPE_PORT) continue; + if (objs[i].data.port.node != pke_audio_pw.default_sink_id && objs[i].data.port.node != stream_id) continue; + if (objs[i].data.port.node == pke_audio_pw.default_sink_id && objs[i].data.port.direction == PW_DIRECTION_OUTPUT) continue; + if (objs[i].data.port.node == stream_id) { + out_ports[objs[i].data.port.id] = objs[i].id; + } else { + port_count++; + in_ports[objs[i].data.port.id] = objs[i].id; + } + } + } + // assert(port_count != 0); + if (port_count == 0) { + pw_properties_free(props); + pw_thread_loop_unlock(pke_audio_pw.loop); + return false; + } + + // do links + { + for (i = 0; i < pke_audio_mstr.channel_count; ++i) { + pw_properties_clear(props); + pw_properties_setf(props, PW_KEY_LINK_OUTPUT_PORT, "%d", out_ports[i]); + pw_properties_setf(props, PW_KEY_LINK_INPUT_PORT, "%d", in_ports[i % port_count]); + created_obj = pw_core_create_object(pke_audio_pw.core, "link-factory", PW_TYPE_INTERFACE_Link, PW_VERSION_LINK, &props->dict, 0); + if (created_obj != NULL) pk_arr_append(&pke_audio_pw.created_objects, created_obj); + } + } + + pw_properties_free(props); + pw_thread_loop_unlock(pke_audio_pw.loop); + return true; +} + void on_pipewire_process(void *user_data) { (void)user_data; pw_buffer *b; @@ -242,7 +317,7 @@ int metadata_event_property(void *data, uint32_t subject, const char *key, const // the default just changed?? pke_audio_pw.is_needing_output_remapped = true; } - if (value == NULL || spa_json_str_object_find(value, strlen(value), "name", pke_audio_pw.default_sink_name, sizeof(pke_audio_pw.default_sink_name)) < 0) { + if (value == NULL || spa_json_str_object_find(value, strlen(value), "name", pke_audio_pw.default_sink_name, PKE_AUDIO_PW_NAME_RESERVE_LEN) < 0) { pke_audio_pw.default_sink_name[0] = '\0'; } } diff --git a/src/audio-impl-pw.hpp b/src/audio-impl-pw.hpp index 2eb9916..d9bac99 100644 --- a/src/audio-impl-pw.hpp +++ b/src/audio-impl-pw.hpp @@ -63,6 +63,7 @@ struct pke_audio_implementation_pipewire { extern struct pke_audio_implementation_pipewire pke_audio_pw; void pke_audio_pw_init(); void pke_audio_pw_teardown(); +bool pke_audio_pw_remap_outputs(); void on_pipewire_process(void *user_data); void on_pipewire_stream_param_changed(void *, uint32_t id, const struct spa_pod *param); void on_registry_event_global(void *data, uint32_t id, uint32_t permissions, const char *type, uint32_t version, const struct spa_dict *props); diff --git a/src/audio.cpp b/src/audio.cpp index 002d1be..c3f152e 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -17,7 +17,13 @@ void pke_audio_teardown() { pke_audio_pw_teardown(); #endif } -void pke_audio_tick() { +void pke_audio_tick(double delta) { + (void)delta; +#ifdef PKE_AUDIO_IMPL_PIPEWIRE + if (pke_audio_pw.is_needing_output_remapped == true) { + pke_audio_pw.is_needing_output_remapped = !pke_audio_pw_remap_outputs(); + } +#endif } float pke_audio_get_volume(pke_audio_source source) { diff --git a/src/audio.hpp b/src/audio.hpp index 7ba0f1d..3084c84 100644 --- a/src/audio.hpp +++ b/src/audio.hpp @@ -7,7 +7,7 @@ void pke_audio_init(); void pke_audio_teardown(); -void pke_audio_tick(); +void pke_audio_tick(double delta); float pke_audio_get_volume(pke_audio_source source); void pke_audio_set_volume(pke_audio_source source, float volume); diff --git a/src/game.cpp b/src/game.cpp index 25473ed..67ca5fb 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -110,6 +110,8 @@ void Game_Tick(double delta) { PkeCamera_Tick(delta); + pke_audio_tick(delta); + EntityType_Tick_Late(delta); ECS_Tick_Late(delta); } |
