diff --git a/src/modules/module-roc-sink.c b/src/modules/module-roc-sink.c index 7b834e3eb..1cca69592 100644 --- a/src/modules/module-roc-sink.c +++ b/src/modules/module-roc-sink.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,10 @@ * * - \ref PW_KEY_NODE_NAME * - \ref PW_KEY_NODE_DESCRIPTION - * - \ref PW_KEY_MEDIA_NAME + * - \ref PW_KEY_NODE_VIRTUAL + * - \ref PW_KEY_MEDIA_CLASS + * - \ref SPA_KEY_AUDIO_POSITION + * * ## Example configuration *\code{.unparsed} @@ -70,6 +74,7 @@ * sink.props = { * node.name = "roc-sink" * } + * audio.position = [ FL FR ] * } * } *] @@ -264,18 +269,34 @@ static int roc_sink_setup(struct module_roc_sink_data *data) spa_zero(sender_config); sender_config.frame_encoding.rate = data->rate; - sender_config.frame_encoding.channels = ROC_CHANNEL_LAYOUT_STEREO; sender_config.frame_encoding.format = ROC_FORMAT_PCM_FLOAT32; - sender_config.packet_encoding = ROC_PACKET_ENCODING_AVP_L16_STEREO; sender_config.fec_encoding = data->fec_code; - info.rate = data->rate; - /* Fixed to be the same as ROC sender config above */ - info.channels = 2; + info.rate = data->rate; info.format = SPA_AUDIO_FORMAT_F32; - info.position[0] = SPA_AUDIO_CHANNEL_FL; - info.position[1] = SPA_AUDIO_CHANNEL_FR; + + const char* positions = pw_properties_get(data->capture_props, SPA_KEY_AUDIO_POSITION); + int channels = spa_audio_parse_position_n(positions, strlen(positions), info.position, SPA_N_ELEMENTS(info.position), &info.channels); + + if(channels == 2) { + sender_config.frame_encoding.channels = ROC_CHANNEL_LAYOUT_STEREO; + sender_config.packet_encoding = ROC_PACKET_ENCODING_AVP_L16_STEREO; + } else { + sender_config.frame_encoding.channels = ROC_CHANNEL_LAYOUT_MULTITRACK; + sender_config.frame_encoding.tracks = channels; + + res = roc_context_register_encoding(data->context, PW_ROC_MULTITRACK_ENCODING_ID, &sender_config.frame_encoding); + if(res) { + pw_log_error("failed to register encoding: %d", res); + return -EINVAL; + } + sender_config.packet_encoding = PW_ROC_MULTITRACK_ENCODING_ID; + + // As of v0.4.0, roc generates packets bigger than it can handle if many channels are used + // (see github.com/roc-streaming/roc-toolkit/issues/821) + sender_config.packet_length = PW_ROC_DEFAULT_PACKET_LENGTH * 2 / channels; + } pw_properties_setf(data->capture_props, PW_KEY_NODE_RATE, "1/%d", info.rate); @@ -360,6 +381,7 @@ static const struct spa_dict_item module_roc_sink_info[] = { "( remote.source.port= ) " "( remote.repair.port= ) " "( remote.control.port= ) " + "( audio.position= ) " "( sink.props= { key=val ... } ) " }, { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, }; @@ -418,6 +440,12 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) if ((str = pw_properties_get(capture_props, PW_KEY_MEDIA_CLASS)) == NULL) pw_properties_set(capture_props, PW_KEY_MEDIA_CLASS, "Audio/Sink"); + if ((str = pw_properties_get(props, SPA_KEY_AUDIO_POSITION)) != NULL) { + pw_properties_set(capture_props, SPA_KEY_AUDIO_POSITION, str); + } else { + pw_properties_set(capture_props, SPA_KEY_AUDIO_POSITION, PW_ROC_STEREO_POSITIONS); + } + data->rate = pw_properties_get_uint32(capture_props, PW_KEY_AUDIO_RATE, 0); if (data->rate == 0) data->rate = PW_ROC_DEFAULT_RATE; diff --git a/src/modules/module-roc-source.c b/src/modules/module-roc-source.c index 0da4560e7..6c67a037c 100644 --- a/src/modules/module-roc-source.c +++ b/src/modules/module-roc-source.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -62,7 +63,9 @@ * * - \ref PW_KEY_NODE_NAME * - \ref PW_KEY_NODE_DESCRIPTION - * - \ref PW_KEY_MEDIA_NAME + * - \ref PW_KEY_NODE_VIRTUAL + * - \ref PW_KEY_MEDIA_CLASS + * - \ref SPA_KEY_AUDIO_POSITION * * ## Example configuration *\code{.unparsed} @@ -85,6 +88,7 @@ * source.props = { * node.name = "roc-source" * } + * audio.position = [ FL FR ] * } * } *] @@ -285,20 +289,33 @@ static int roc_source_setup(struct module_roc_source_data *data) spa_zero(receiver_config); receiver_config.frame_encoding.rate = data->rate; - receiver_config.frame_encoding.channels = ROC_CHANNEL_LAYOUT_STEREO; receiver_config.frame_encoding.format = ROC_FORMAT_PCM_FLOAT32; receiver_config.resampler_profile = data->resampler_profile; receiver_config.resampler_backend = data->resampler_backend; receiver_config.latency_tuner_backend = data->latency_tuner_backend; receiver_config.latency_tuner_profile = data->latency_tuner_profile; - info.rate = data->rate; /* Fixed to be the same as ROC receiver config above */ - info.channels = 2; + info.rate = data->rate; info.format = SPA_AUDIO_FORMAT_F32; - info.position[0] = SPA_AUDIO_CHANNEL_FL; - info.position[1] = SPA_AUDIO_CHANNEL_FR; + + const char* positions = pw_properties_get(data->playback_props, SPA_KEY_AUDIO_POSITION); + int channels = spa_audio_parse_position_n(positions, strlen(positions), info.position, SPA_N_ELEMENTS(info.position), &info.channels); + + if(channels == 2) { + receiver_config.frame_encoding.channels = ROC_CHANNEL_LAYOUT_STEREO; + } else { + receiver_config.frame_encoding.channels = ROC_CHANNEL_LAYOUT_MULTITRACK; + receiver_config.frame_encoding.tracks = channels; + + res = roc_context_register_encoding(data->context, PW_ROC_MULTITRACK_ENCODING_ID, &receiver_config.frame_encoding); + if(res) { + pw_log_error("failed to register encoding: %d", res); + return -EINVAL; + } + } + data->stride = info.channels * sizeof(float); pw_properties_setf(data->playback_props, PW_KEY_NODE_RATE, "1/%d", info.rate); @@ -403,6 +420,7 @@ static const struct spa_dict_item module_roc_source_info[] = { "( local.source.port= ) " "( local.repair.port= ) " "( local.control.port= ) " + "( audio.position= ) " "( source.props= { key=value ... } ) " }, { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, }; @@ -459,6 +477,12 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) if (pw_properties_get(playback_props, PW_KEY_NODE_NETWORK) == NULL) pw_properties_set(playback_props, PW_KEY_NODE_NETWORK, "true"); + if ((str = pw_properties_get(props, SPA_KEY_AUDIO_POSITION)) != NULL) { + pw_properties_set(playback_props, SPA_KEY_AUDIO_POSITION, str); + } else { + pw_properties_set(playback_props, SPA_KEY_AUDIO_POSITION, PW_ROC_STEREO_POSITIONS); + } + data->rate = pw_properties_get_uint32(playback_props, PW_KEY_AUDIO_RATE, 0); if (data->rate == 0) data->rate = PW_ROC_DEFAULT_RATE; diff --git a/src/modules/module-roc/common.h b/src/modules/module-roc/common.h index 4b30f41d4..69153659e 100644 --- a/src/modules/module-roc/common.h +++ b/src/modules/module-roc/common.h @@ -13,6 +13,10 @@ #define PW_ROC_DEFAULT_SESS_LATENCY 200 #define PW_ROC_DEFAULT_RATE 44100 #define PW_ROC_DEFAULT_CONTROL_PROTO ROC_PROTO_RTCP +#define PW_ROC_DEFAULT_PACKET_LENGTH 5000000 // 5ms in ns + +#define PW_ROC_MULTITRACK_ENCODING_ID 100 +#define PW_ROC_STEREO_POSITIONS "[ FL FR ]" static inline int pw_roc_parse_fec_encoding(roc_fec_encoding *out, const char *str) {