Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 22
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Thu Jan 26 20:45:06 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.65 + +------------------------------------------------------------------- Mon Jan 16 08:13:26 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> - Update to version 0.3.64
View file
pipewire-aptx.spec
Changed
@@ -7,7 +7,7 @@ %define soversion 0_2 Name: pipewire-aptx -Version: 0.3.64 +Version: 0.3.65 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
pipewire-0.3.64.tar.gz/NEWS -> pipewire-0.3.65.tar.gz/NEWS
Changed
@@ -1,3 +1,117 @@ +# PipeWire 0.3.65 (2023-01-26) + +This is a bugfix release that is API and ABI compatible with previous +0.3.x releases. + +## Highlights + - Add back the deprecated symbols but make sure a deprecated warning is + emitted for them. This fixes compilation issues in bindings. + - Fix an error in the AVX code that could cause crackling in filter-chain + when using the mixer. + - The convolver in filter-chain can now select an IR from a list of IRs + that best matches the current samplerate. Also resampling of the IR + has been improved. + - A new native module-combine-stream was added. You can use this to create + a 5.1 device from 3 stereo soundcards, for example, or direct the output + to multiple sinks at once. + - Support for Bluetooth MIDI was added. This requires a wireplumber + addition as well. + - An ALSA plugin rule was added to tweak the buffer settings in Davinci + Resolve so that it now runs with acceptable latency. (#1697) + - Support for compress offload was added using tinycompress. This allows + compressed formats to be decoded in hardware using ALSA on some devices. + - Many more buffixes and improvements. + + +## PipeWire + - Add back the deprecated symbols but make sure a deprecated warning is + emitted for them. (#2952) + - Fix a regression when running older servers and newer clients (such as + flatpaks on older server) where the server would run clients too soon, + causing crashes. (#2964) + - Ensure that environment variables override any config values. + +## Tools + - pw-cli has received some improvements in the output. + - pw-cat can now use ffmpeg to demux streams for compress offload. + +## modules + - The convolver IR volume is now preserved after resampling. + - Adapter ports can now have a custom prefix. + - module-rt now clamps the realtime priority to the user allowed one if + it is within an acceptable range. Before it would fall back to RTKit + immediately. + - The module-echo-cancel can now have per stream channel layouts which + makes it possible to link to specific audio ports on a device. (#2939) + - Fix an error in the AVX code that could cause crackling in filter-chain + when using the mixer. (#2965) + - The convolver in filter-chain can now select an IR from a list of IRs + that best matches the current sample-rate. + - module-pipe-* now better matches the pulseaudio properties. (#2973) + - A new combine-stream module was added to combine multiple sinks into + one sink. It is also possible to merge multiple sources into one. + - module-rtp-source now has match rules to select what SAP sessions + to stream from. There were also improvements to the buffering and + latency handling. + - module-rtp-sink now handles multicast loopback correctly. + - module-rtp-sink implements min-ptime and max-ptime to control the + send packet latency. + +## SPA + - A new modifier flag was added to the video format parser helper to + allow 0 (linear) as a valid modifier. (#2943) + - Params includes were reorganized to make it more scalable. Many compressed + audio formats were added. + - The alsa pcm plugin now handles invalid values from the driver + gracefully. (#2953) + - Fix some potential stuttering cause by wrong scaling and overflow + of the output buffers in audioconvert. (#2680) + - Debug output is now also sent to the log instead of stdout. (#2923) + - A debug context was added to debug macros to implement custom debug + handling. This is used to redirect the debug of pods to the debug log + instead of using some custom duplicated code. + - Fix some warnings for potentially undefined shifts in format + conversion. + - Support for compress offload was added using tinycompress. This is mostly + used on some embedded hardware where decoding of audio formats can be + done in hardware. + +## Bluetooth + - Some fixes for LE audio were added. + - Support for Bluetooth MIDI was added. This requires a wireplumber + addition as well. + - Reply OK to empty commands. + - Improve compatibility with some devices that send stray \n such as + the Sennheiser HD 350BT. (#2991) + +## pulse-server + - Devices with unsupported formats (by the pulseaudio API) are now also + listed in the pulseaudio API (with invalid formats). + - The native module-combine-stream is used for module-combine-sink. + +## JACK + - Make jack.merge-monitor default to true to better match the jack1/2 + behaviour. Add an exception for mixxx, which is more usable with + unmerged monitors. (#1760) + +## ALSA + - The property handling in the ALSA plugin was improved. alsa.properties + and alsa.rules can now be added to the config file. + - A rule was added to tweak the buffer settings in Davinci Resolve so that + it can run with acceptable latency. (#1697) + - ALSA volume will now also use cubic volumes, like pulseaudio. + - The ALSA ctl plugin now also uses the client-rt.conf file. + - A new alsa.volume-method was added to configure cubic or linear volume. + This can be set per application using the rules. + +## GStreamer + - pipewiresrc will now advertize DMABUF support if the pipeline suports + this. + - pipewiresrc will now always be a live source unless told otherwise. + +Older versions: + + # PipeWire 0.3.64 (2023-01-12) This is a bugfix release that is API and ABI compatible with previous @@ -85,9 +199,6 @@ to PipeWire sessions from the portal. - DMABuf support was re-enabled in gstpipewiresrc. - -Older versions: - # PipeWire 0.3.63 (2022-12-15) This is a quick bugfix release that is API and ABI compatible with previous
View file
pipewire-0.3.64.tar.gz/doc/Doxyfile.in -> pipewire-0.3.65.tar.gz/doc/Doxyfile.in
Changed
@@ -1,13 +1,12 @@ PROJECT_NAME = PipeWire PROJECT_NUMBER = @PACKAGE_VERSION@ -OUTPUT_DIRECTORY = doc +OUTPUT_DIRECTORY = "@output_directory@" FULL_PATH_NAMES = NO JAVADOC_AUTOBRIEF = YES TAB_SIZE = 8 OPTIMIZE_OUTPUT_FOR_C = YES EXTRACT_ALL = YES EXTRACT_STATIC = YES -FULL_PATH_NAMES = YES STRIP_FROM_PATH = @path_prefixes@ STRIP_FROM_INC_PATH = @path_prefixes@ SHOW_FILES = NO
View file
pipewire-0.3.64.tar.gz/doc/meson.build -> pipewire-0.3.65.tar.gz/doc/meson.build
Changed
@@ -3,6 +3,7 @@ doxyfile_conf.set('PACKAGE_VERSION', meson.project_version()) doxyfile_conf.set('top_srcdir', meson.project_source_root()) doxyfile_conf.set('top_builddir', meson.project_build_root()) +doxyfile_conf.set('output_directory', meson.current_build_dir()) dot_found = find_program('dot', required: false).found() summary({'dot (used with doxygen)': dot_found}, bool_yn: true, section: 'Optional programs')
View file
pipewire-0.3.64.tar.gz/doc/pipewire-modules.dox -> pipewire-0.3.65.tar.gz/doc/pipewire-modules.dox
Changed
@@ -54,6 +54,7 @@ - \subpage page_module_avb - \subpage page_module_client_device - \subpage page_module_client_node +- \subpage page_module_combine_stream - \subpage page_module_echo_cancel - \subpage page_module_example_sink - \subpage page_module_example_source
View file
pipewire-0.3.64.tar.gz/man/pw-cat.1.rst.in -> pipewire-0.3.65.tar.gz/man/pw-cat.1.rst.in
Changed
@@ -160,7 +160,7 @@ --volume=VALUE The stream volume, default 1.000. Depending on the locale you have configured, "," or "." may be - used as a decimal seperator. Check with **locale** command. + used as a decimal separator. Check with **locale** command. AUTHORS =======
View file
pipewire-0.3.64.tar.gz/man/pw-link.1.rst.in -> pipewire-0.3.65.tar.gz/man/pw-link.1.rst.in
Changed
@@ -65,7 +65,7 @@ CONNECTING PORTS ================ -Whithout any list option (-i, -o or -l), the given ports will be linked. +Without any list option (-i, -o or -l), the given ports will be linked. Valid port specifications are: *port-id*
View file
pipewire-0.3.64.tar.gz/meson.build -> pipewire-0.3.65.tar.gz/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '0.3.64', + version : '0.3.65', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.59.0', default_options : 'warning_level=3', @@ -266,6 +266,19 @@ readline_dep = cc.find_library('readline', required : get_option('readline')) endif +# Both the FFmpeg SPA plugin and the pw-cat FFmpeg integration use libavcodec. +# But only the latter also needs libavformat. +# Search for these libraries here, globally, so both of these subprojects can reuse the results. +pw_cat_ffmpeg = get_option('pw-cat-ffmpeg') +ffmpeg = get_option('ffmpeg') +if pw_cat_ffmpeg.allowed() or ffmpeg.allowed() + avcodec_dep = dependency('libavcodec', required: pw_cat_ffmpeg.enabled() or ffmpeg.enabled()) + avformat_dep = dependency('libavformat', required: pw_cat_ffmpeg.enabled()) +else + avcodec_dep = dependency('', required: false) +endif +cdata.set('HAVE_PW_CAT_FFMPEG_INTEGRATION', pw_cat_ffmpeg.allowed()) + summary({'readline (for pw-cli)': readline_dep.found()}, bool_yn: true, section: 'Misc dependencies') cdata.set('HAVE_READLINE', readline_dep.found()) ncurses_dep = dependency('ncursesw', required : false)
View file
pipewire-0.3.64.tar.gz/meson_options.txt -> pipewire-0.3.65.tar.gz/meson_options.txt
Changed
@@ -188,6 +188,10 @@ description: 'Build pw-cat/pw-play/pw-record', type: 'feature', value: 'auto') +option('pw-cat-ffmpeg', + description: 'Enable FFmpeg integration in pw-cat/pw-play/pw-record', + type: 'feature', + value: 'disabled') option('udev', description: 'Enable Udev integration', type: 'feature', @@ -273,3 +277,7 @@ description: 'Enable code that depends on gsettings', type: 'feature', value: 'auto') +option('compress-offload', + description: 'Enable ALSA Compress-Offload support', + type: 'feature', + value: 'disabled')
View file
pipewire-0.3.64.tar.gz/pipewire-alsa/alsa-plugins/ctl_pipewire.c -> pipewire-0.3.65.tar.gz/pipewire-alsa/alsa-plugins/ctl_pipewire.c
Changed
@@ -37,7 +37,10 @@ PW_LOG_TOPIC_STATIC(alsa_log_topic, "alsa.ctl"); #define PW_LOG_TOPIC_DEFAULT alsa_log_topic -#define VOLUME_MAX 65536 +#define DEFAULT_VOLUME_METHOD "cubic" + +#define VOLUME_MIN ((uint32_t) 0U) +#define VOLUME_MAX ((uint32_t) 0x10000U) struct volume { uint32_t channels; @@ -47,6 +50,8 @@ typedef struct { snd_ctl_ext_t ext; + struct pw_properties *props; + struct spa_system *system; struct pw_thread_loop *mainloop; @@ -74,6 +79,9 @@ struct volume source_volume; int subscribed; +#define VOLUME_METHOD_LINEAR (0) +#define VOLUME_METHOD_CUBIC (1) + int volume_method; #define UPDATE_SINK_VOL (1<<0) #define UPDATE_SINK_MUTE (1<<1) @@ -84,6 +92,32 @@ struct spa_list globals; } snd_ctl_pipewire_t; +static inline uint32_t volume_from_linear(float vol, int method) +{ + if (vol <= 0.0f) + vol = 0.0f; + + switch (method) { + case VOLUME_METHOD_CUBIC: + vol = cbrtf(vol); + break; + } + return SPA_CLAMP((uint64_t)lroundf(vol * VOLUME_MAX), + VOLUME_MIN, VOLUME_MAX); +} + +static inline float volume_to_linear(uint32_t vol, int method) +{ + float v = ((float)vol) / VOLUME_MAX; + + switch (method) { + case VOLUME_METHOD_CUBIC: + v = v * v * v; + break; + } + return v; +} + struct global; struct global_info { @@ -416,7 +450,7 @@ long *imax, long *istep) { *istep = 1; - *imin = 0; + *imin = VOLUME_MIN; *imax = VOLUME_MAX; return 0; @@ -476,7 +510,8 @@ return err; } -static struct spa_pod *build_volume_mute(struct spa_pod_builder *b, struct volume *volume, int *mute) +static struct spa_pod *build_volume_mute(struct spa_pod_builder *b, struct volume *volume, + int *mute, int volume_method) { struct spa_pod_frame f1; @@ -488,7 +523,7 @@ n_volumes = volume->channels; for (i = 0; i < n_volumes; i++) - volumesi = volume->valuesi / (float) VOLUME_MAX; + volumesi = volume_to_linear(volume->valuesi, volume_method); spa_pod_builder_prop(b, SPA_PROP_channelVolumes, 0); spa_pod_builder_array(b, sizeof(float), @@ -536,7 +571,7 @@ 0); spa_pod_builder_prop(&b, SPA_PARAM_ROUTE_props, 0); - build_volume_mute(&b, volume, mute); + build_volume_mute(&b, volume, mute, ctl->volume_method); param = spa_pod_builder_pop(&b, &f0); pw_log_debug("set device %d mute/volume for node %d", dg->id, g->id); @@ -546,7 +581,7 @@ if (!SPA_FLAG_IS_SET(g->permissions, PW_PERM_W | PW_PERM_X)) return -EPERM; - param = build_volume_mute(&b, volume, mute); + param = build_volume_mute(&b, volume, mute, ctl->volume_method); pw_log_debug("set node %d mute/volume", g->id); pw_node_set_param((struct pw_node*)g->proxy, @@ -761,6 +796,7 @@ spa_system_close(ctl->system, ctl->fd); if (ctl->mainloop) pw_thread_loop_destroy(ctl->mainloop); + pw_properties_free(ctl->props); free(ctl); } @@ -816,6 +852,7 @@ { struct spa_pod_prop *prop; struct spa_pod_object *obj = (struct spa_pod_object *) param; + snd_ctl_pipewire_t *ctl = g->ctl; SPA_POD_OBJECT_FOREACH(obj, prop) { switch (prop->key) { @@ -841,7 +878,8 @@ g->node.channel_volume.channels = n_volumes; for (i = 0; i < n_volumes; i++) - g->node.channel_volume.valuesi = volumesi * VOLUME_MAX; + g->node.channel_volume.valuesi = + volume_from_linear(volumesi, ctl->volume_method); SPA_FLAG_UPDATE(g->node.flags, NODE_FLAG_DEVICE_VOLUME, device); pw_log_debug("update node %d channelVolumes", g->id); @@ -1230,6 +1268,14 @@ .done = on_core_done, }; +static int execute_match(void *data, const char *location, const char *action, + const char *val, size_t len) +{ + snd_ctl_pipewire_t *ctl = data; + if (spa_streq(action, "update-props")) + pw_properties_update_string(ctl->props, val, len); + return 1; +} SPA_EXPORT SND_CTL_PLUGIN_DEFINE_FUNC(pipewire) @@ -1242,7 +1288,6 @@ const char *fallback_name = NULL; int err; const char *str; - struct pw_properties *props = NULL; snd_ctl_pipewire_t *ctl; struct pw_loop *loop; @@ -1305,10 +1350,6 @@ return -EINVAL; } - str = getenv("PIPEWIRE_REMOTE"); - if (str != NULL && str0 != '\0') - server = str; - if (fallback_name && name && spa_streq(name, fallback_name)) fallback_name = NULL; /* no fallback for the same name */ @@ -1343,30 +1384,57 @@ goto error; } - ctl->context = pw_context_new(loop, NULL, 0); + ctl->context = pw_context_new(loop, + pw_properties_new( + PW_KEY_CLIENT_API, "alsa", + PW_KEY_CONFIG_NAME, "client-rt.conf", + NULL), + 0); if (ctl->context == NULL) { err = -errno; goto error; } - props = pw_properties_new(NULL, NULL); - if (props == NULL) { + ctl->props = pw_properties_new(NULL, NULL); + if (ctl->props == NULL) { err = -errno; goto error; } - pw_properties_setf(props, PW_KEY_APP_NAME, "PipeWire ALSA %s", - pw_get_prgname()); - if (server) - pw_properties_set(props, PW_KEY_REMOTE_NAME, server); + pw_properties_set(ctl->props, PW_KEY_REMOTE_NAME, server); + + pw_context_conf_update_props(ctl->context, "alsa.properties", ctl->props); + + pw_context_conf_section_match_rules(ctl->context, "alsa.rules", + &pw_context_get_properties(ctl->context)->dict, + execute_match, ctl); + + if (pw_properties_get(ctl->props, PW_KEY_APP_NAME) == NULL) + pw_properties_setf(ctl->props, PW_KEY_APP_NAME, "PipeWire ALSA %s", + pw_get_prgname()); + + str = getenv("PIPEWIRE_ALSA"); + if (str != NULL) + pw_properties_update_string(ctl->props, str, strlen(str)); + + if ((str = pw_properties_get(ctl->props, "alsa.volume-method")) == NULL) + str = DEFAULT_VOLUME_METHOD; + + if (spa_streq(str, "cubic")) + ctl->volume_method = VOLUME_METHOD_CUBIC; + else if (spa_streq(str, "linear")) + ctl->volume_method = VOLUME_METHOD_LINEAR; + else { + ctl->volume_method = VOLUME_METHOD_CUBIC; + SNDERR("unknown alsa.volume-method %s, using cubic", str); + } if ((err = pw_thread_loop_start(ctl->mainloop)) < 0) goto error; pw_thread_loop_lock(ctl->mainloop); - ctl->core = pw_context_connect(ctl->context, props, 0); - props = NULL; + ctl->core = pw_context_connect(ctl->context, pw_properties_copy(ctl->props), 0); if (ctl->core == NULL) { err = -errno; goto error_unlock;
View file
pipewire-0.3.64.tar.gz/pipewire-alsa/alsa-plugins/meson.build -> pipewire-0.3.65.tar.gz/pipewire-alsa/alsa-plugins/meson.build
Changed
@@ -21,7 +21,7 @@ pipewire_alsa_plugin_ctl_sources, c_args : pipewire_alsa_plugin_c_args, include_directories : configinc, - dependencies : pipewire_dep, alsa_dep, + dependencies : pipewire_dep, alsa_dep, mathlib, install : true, install_dir : pipewire_libdir / 'alsa-lib', )
View file
pipewire-0.3.64.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c -> pipewire-0.3.65.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c
Changed
@@ -70,30 +70,12 @@ #define MIN_BUFFER_BYTES (2*MIN_PERIOD_BYTES) #define MAX_BUFFER_BYTES (2*MAX_PERIOD_BYTES) -struct params { - const char *node_name; - const char *server_name; - const char *playback_node; - const char *capture_node; - const char *role; - snd_pcm_format_t format; - int rate; - int channels; - int period_bytes; - int buffer_bytes; - uint32_t flags; -}; - typedef struct { snd_pcm_ioplug_t io; snd_output_t *output; FILE *log_file; - char *node_name; - char *target; - char *role; - int fd; int error; unsigned int activated:1; /* PipeWire is activated? */ @@ -113,12 +95,12 @@ struct spa_system *system; struct pw_thread_loop *main_loop; + struct pw_properties *props; struct pw_context *context; struct pw_core *core; struct spa_hook core_listener; - uint32_t flags; struct pw_stream *stream; struct spa_hook stream_listener; @@ -192,9 +174,7 @@ spa_system_close(pw->system, pw->fd); if (pw->main_loop) pw_thread_loop_destroy(pw->main_loop); - free(pw->node_name); - free(pw->target); - free(pw->role); + pw_properties_free(pw->props); snd_output_close(pw->output); fclose(pw->log_file); free(pw); @@ -541,7 +521,6 @@ const struct spa_pod *params1; uint8_t buffer1024; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - struct pw_properties *props; uint32_t min_period; pw_thread_loop_lock(pw->main_loop); @@ -568,40 +547,18 @@ goto done; pw->hw_params_changed = false; - props = pw_properties_new(NULL, NULL); - if (props == NULL) - goto error; - - pw_properties_set(props, PW_KEY_CLIENT_API, "alsa"); - pw_properties_setf(props, PW_KEY_APP_NAME, "%s", pw_get_prgname()); - - if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL) - pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%lu/%u", pw->min_avail, io->rate); - if (pw_properties_get(props, PW_KEY_NODE_RATE) == NULL) - pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", io->rate); - if (pw->target != NULL && !spa_streq(pw->target, "-1") && - pw_properties_get(props, PW_KEY_TARGET_OBJECT) == NULL) - pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%s", pw->target); - - if (pw_properties_get(props, PW_KEY_MEDIA_TYPE) == NULL) - pw_properties_set(props, PW_KEY_MEDIA_TYPE, "Audio"); - if (pw_properties_get(props, PW_KEY_MEDIA_CATEGORY) == NULL) - pw_properties_set(props, PW_KEY_MEDIA_CATEGORY, - io->stream == SND_PCM_STREAM_PLAYBACK ? - "Playback" : "Capture"); - if (pw->role != NULL && - pw_properties_get(props, PW_KEY_MEDIA_ROLE) == NULL) - pw_properties_setf(props, PW_KEY_MEDIA_ROLE, "%s", pw->role); + pw_properties_setf(pw->props, PW_KEY_NODE_LATENCY, "%lu/%u", pw->min_avail, io->rate); + pw_properties_setf(pw->props, PW_KEY_NODE_RATE, "1/%u", io->rate); params0 = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &pw->format); if (pw->stream != NULL) { - pw_stream_update_properties(pw->stream, &props->dict); + pw_stream_update_properties(pw->stream, &pw->props->dict); pw_stream_update_params(pw->stream, params, 1); goto done; } - pw->stream = pw_stream_new(pw->core, pw->node_name, props); + pw->stream = pw_stream_new(pw->core, NULL, pw_properties_copy(pw->props)); if (pw->stream == NULL) goto error; @@ -614,7 +571,6 @@ PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT, PW_ID_ANY, - pw->flags | PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS, @@ -969,7 +925,7 @@ .query_chmaps = snd_pcm_pipewire_query_chmaps, }; -static int pipewire_set_hw_constraint(snd_pcm_pipewire_t *pw, struct params *p) +static int pipewire_set_hw_constraint(snd_pcm_pipewire_t *pw) { unsigned int access_list = { SND_PCM_ACCESS_MMAP_INTERLEAVED, @@ -995,6 +951,7 @@ #endif SND_PCM_FORMAT_U8, }; + int val; int min_rate; int max_rate; int min_channels; @@ -1003,29 +960,35 @@ int max_period_bytes; int min_buffer_bytes; int max_buffer_bytes; + const char *str; + snd_pcm_format_t format; int err; - if (p->rate > 0) { - min_rate = max_rate = SPA_CLAMP(p->rate, 1, MAX_RATE); + val = pw_properties_get_uint32(pw->props, "alsa.rate", 0); + if (val > 0) { + min_rate = max_rate = SPA_CLAMP(val, 1, MAX_RATE); } else { min_rate = 1; max_rate = MAX_RATE; } - if (p->channels > 0) { - min_channels = max_channels = SPA_CLAMP(p->channels, 1, MAX_CHANNELS); + val = pw_properties_get_uint32(pw->props, "alsa.channels", 0); + if (val > 0) { + min_channels = max_channels = SPA_CLAMP(val, 1, MAX_CHANNELS); } else { min_channels = 1; max_channels = MAX_CHANNELS; } - if (p->period_bytes > 0) { - min_period_bytes = max_period_bytes = SPA_CLAMP(p->period_bytes, + val = pw_properties_get_uint32(pw->props, "alsa.period-bytes", 0); + if (val > 0) { + min_period_bytes = max_period_bytes = SPA_CLAMP(val, MIN_PERIOD_BYTES, MAX_PERIOD_BYTES); } else { min_period_bytes = MIN_PERIOD_BYTES; max_period_bytes = MAX_PERIOD_BYTES; } - if (p->buffer_bytes > 0) { - min_buffer_bytes = max_buffer_bytes = SPA_CLAMP(p->buffer_bytes, + val = pw_properties_get_uint32(pw->props, "alsa.buffer-bytes", 0); + if (val > 0) { + min_buffer_bytes = max_buffer_bytes = SPA_CLAMP(val, MIN_BUFFER_BYTES, MAX_BUFFER_BYTES); } else { min_buffer_bytes = MIN_BUFFER_BYTES; @@ -1052,11 +1015,14 @@ pw_log_warn("Can't set param list: %s", snd_strerror(err)); return err; } + format = SND_PCM_FORMAT_UNKNOWN; + if ((str = pw_properties_get(pw->props, "alsa.format"))) + format = snd_pcm_format_value(str); - if (p->format != SND_PCM_FORMAT_UNKNOWN) { + if (format != SND_PCM_FORMAT_UNKNOWN) { err = snd_pcm_ioplug_set_param_list(&pw->io, SND_PCM_IOPLUG_HW_FORMAT, - 1, (unsigned int *)&p->format); + 1, (unsigned int *)&format); if (err < 0) { pw_log_warn("Can't set param list: %s", snd_strerror(err)); return err; @@ -1113,61 +1079,31 @@ .write = log_write, }; +static int execute_match(void *data, const char *location, const char *action, + const char *val, size_t len) +{ + snd_pcm_pipewire_t *pw = data; + if (spa_streq(action, "update-props")) + pw_properties_update_string(pw->props, val, len); + return 1; +} + static int snd_pcm_pipewire_open(snd_pcm_t **pcmp, - struct params *p, snd_pcm_stream_t stream, int mode) + struct pw_properties *props, snd_pcm_stream_t stream, int mode) { snd_pcm_pipewire_t *pw; int err; - const char *str; - struct pw_properties *props = NULL; + const char *str, *node_name = NULL; struct pw_loop *loop; - uint32_t val; assert(pcmp); pw = calloc(1, sizeof(*pw)); if (!pw) return -ENOMEM; - props = pw_properties_new(NULL, NULL); - if (props == NULL) { - err = -errno; - goto error; - } - - str = getenv("PIPEWIRE_ALSA"); - if (str != NULL) { - pw_properties_update_string(props, str, strlen(str)); - if ((str = pw_properties_get(props, "alsa.format"))) - p->format = snd_pcm_format_value(str); - if ((str = pw_properties_get(props, "alsa.rate")) && - spa_atou32(str, &val, 0)) - p->rate = val; - if ((str = pw_properties_get(props, "alsa.channels")) && - spa_atou32(str, &val, 0)) - p->channels = val; - if ((str = pw_properties_get(props, "alsa.period-bytes")) && - spa_atou32(str, &val, 0)) - p->period_bytes = val; - if ((str = pw_properties_get(props, "alsa.buffer-bytes")) && - spa_atou32(str, &val, 0)) - p->buffer_bytes = val; - } - - str = getenv("PIPEWIRE_REMOTE"); - if (str != NULL && str0 != '\0') - p->server_name = str; - - str = getenv("PIPEWIRE_NODE"); - - pw_log_debug("%p: open name:%s stream:%s mode:%d flags:%08x rate:%d format:%s " - "channels:%d period-bytes:%d buffer-bytes:%d target:'%s'", pw, p->node_name, - snd_pcm_stream_name(stream), mode, p->flags, p->rate, - snd_pcm_format_name(p->format), p->channels, p->period_bytes, - p->buffer_bytes, str); - + pw->props = props; pw->fd = -1; pw->io.poll_fd = -1; - pw->flags = p->flags; pw->log_file = fopencookie(pw, "w", io_funcs); if (pw->log_file == NULL) { pw_log_error("can't create log file: %m"); @@ -1179,29 +1115,6 @@ goto error; } - if (p->node_name == NULL) - pw->node_name = spa_aprintf("ALSA %s", - stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture"); - else - pw->node_name = strdup(p->node_name); - - if (pw->node_name == NULL) { - err = -errno; - goto error; - } - - pw->target = NULL; - if (str != NULL) - pw->target = strdup(str); - else { - if (stream == SND_PCM_STREAM_PLAYBACK) - pw->target = p->playback_node ? strdup(p->playback_node) : NULL; - else - pw->target = p->capture_node ? strdup(p->capture_node) : NULL; - } - - pw->role = (p->role && *p->role) ? strdup(p->role) : NULL; - pw->main_loop = pw_thread_loop_new("alsa-pipewire", NULL); if (pw->main_loop == NULL) { err = -errno; @@ -1212,24 +1125,48 @@ if ((pw->context = pw_context_new(loop, pw_properties_new( PW_KEY_CONFIG_NAME, "client-rt.conf", + PW_KEY_CLIENT_API, "alsa", NULL), 0)) == NULL) { err = -errno; goto error; } - pw_properties_setf(props, PW_KEY_APP_NAME, "PipeWire ALSA %s", - pw_get_prgname()); + pw_context_conf_update_props(pw->context, "alsa.properties", pw->props); - if (p->server_name) - pw_properties_set(props, PW_KEY_REMOTE_NAME, p->server_name); + pw_context_conf_section_match_rules(pw->context, "alsa.rules", + &pw_context_get_properties(pw->context)->dict, execute_match, pw); + + if (pw_properties_get(pw->props, PW_KEY_APP_NAME) == NULL) + pw_properties_setf(pw->props, PW_KEY_APP_NAME, "PipeWire ALSA %s", + pw_get_prgname()); + if (pw_properties_get(pw->props, PW_KEY_NODE_NAME) == NULL) + pw_properties_setf(pw->props, PW_KEY_NODE_NAME, "ALSA %s", + stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture"); + if (pw_properties_get(pw->props, PW_KEY_MEDIA_TYPE) == NULL) + pw_properties_set(pw->props, PW_KEY_MEDIA_TYPE, "Audio"); + if (pw_properties_get(pw->props, PW_KEY_MEDIA_CATEGORY) == NULL) + pw_properties_set(pw->props, PW_KEY_MEDIA_CATEGORY, + stream == SND_PCM_STREAM_PLAYBACK ? + "Playback" : "Capture"); + + str = getenv("PIPEWIRE_ALSA"); + if (str != NULL) + pw_properties_update_string(pw->props, str, strlen(str)); + + str = getenv("PIPEWIRE_NODE"); + if (str != NULL && str0) + pw_properties_set(pw->props, PW_KEY_TARGET_OBJECT, str); + + node_name = pw_properties_get(pw->props, PW_KEY_NODE_NAME); + if (pw_properties_get(pw->props, PW_KEY_MEDIA_NAME) == NULL) + pw_properties_set(pw->props, PW_KEY_MEDIA_NAME, node_name); if ((err = pw_thread_loop_start(pw->main_loop)) < 0) goto error; pw_thread_loop_lock(pw->main_loop); - pw->core = pw_context_connect(pw->context, props, 0); - props = NULL; + pw->core = pw_context_connect(pw->context, pw_properties_copy(pw->props), 0); if (pw->core == NULL) { err = -errno; pw_thread_loop_unlock(pw->main_loop); @@ -1254,13 +1191,13 @@ #endif pw->io.flags |= SND_PCM_IOPLUG_FLAG_MONOTONIC; - if ((err = snd_pcm_ioplug_create(&pw->io, p->node_name, stream, mode)) < 0) + if ((err = snd_pcm_ioplug_create(&pw->io, node_name, stream, mode)) < 0) goto error; - if ((err = pipewire_set_hw_constraint(pw, p)) < 0) + if ((err = pipewire_set_hw_constraint(pw)) < 0) goto error; - pw_log_debug("%p: opened name:%s stream:%s mode:%d", pw, p->node_name, + pw_log_debug("%p: opened name:%s stream:%s mode:%d", pw, node_name, snd_pcm_stream_name(pw->io.stream), mode); *pcmp = pw->io.pcm; @@ -1268,8 +1205,7 @@ return 0; error: - pw_log_debug("%p: failed to open %s :%s", pw, p->node_name, spa_strerror(err)); - pw_properties_free(props); + pw_log_debug("%p: failed to open %s :%s", pw, node_name, spa_strerror(err)); snd_pcm_pipewire_free(pw); return err; } @@ -1279,16 +1215,20 @@ SND_PCM_PLUGIN_DEFINE_FUNC(pipewire) { snd_config_iterator_t i, next; - struct params params; + struct pw_properties *props; + const char *str; + long val; int err; pw_init(NULL, NULL); if (strstr(pw_get_library_version(), "0.2") != NULL) return -ENOTSUP; + props = pw_properties_new(NULL, NULL); + if (props == NULL) + return -errno; + PW_LOG_TOPIC_INIT(alsa_log_topic); - spa_zero(params); - params.format = SND_PCM_FORMAT_UNKNOWN; snd_config_for_each(i, next, conf) { snd_config_t *n = snd_config_iterator_entry(i); @@ -1298,83 +1238,93 @@ if (spa_streq(id, "comment") || spa_streq(id, "type") || spa_streq(id, "hint")) continue; if (spa_streq(id, "name")) { - snd_config_get_string(n, ¶ms.node_name); + if (snd_config_get_string(n, &str) == 0) + pw_properties_set(props, PW_KEY_NODE_NAME, str); continue; } if (spa_streq(id, "server")) { - snd_config_get_string(n, ¶ms.server_name); + if (snd_config_get_string(n, &str) == 0) + pw_properties_set(props, PW_KEY_REMOTE_NAME, str); continue; } if (spa_streq(id, "playback_node")) { - snd_config_get_string(n, ¶ms.playback_node); + if (stream == SND_PCM_STREAM_PLAYBACK && + snd_config_get_string(n, &str) == 0) + if (str != NULL && !spa_streq(str, "-1")) + pw_properties_set(props, PW_KEY_TARGET_OBJECT, str); continue; } if (spa_streq(id, "capture_node")) { - snd_config_get_string(n, ¶ms.capture_node); + if (stream == SND_PCM_STREAM_CAPTURE && + snd_config_get_string(n, &str) == 0) + if (str != NULL && !spa_streq(str, "-1")) + pw_properties_set(props, PW_KEY_TARGET_OBJECT, str); continue; } if (spa_streq(id, "role")) { - snd_config_get_string(n, ¶ms.role); + if (snd_config_get_string(n, &str) == 0) + if (str != NULL && *str) + pw_properties_set(props, PW_KEY_MEDIA_ROLE, str); continue; } if (spa_streq(id, "exclusive")) { if (snd_config_get_bool(n)) - params.flags |= PW_STREAM_FLAG_EXCLUSIVE; + pw_properties_set(props, PW_KEY_NODE_EXCLUSIVE, "true"); continue; } if (spa_streq(id, "rate")) { - long val; - - if (snd_config_get_integer(n, &val) == 0) - params.rate = val; - else + if (snd_config_get_integer(n, &val) == 0) { + if (val != 0) + pw_properties_setf(props, "alsa.rate", "%ld", val); + } else { SNDERR("%s: invalid type", id); + } continue; } if (spa_streq(id, "format")) { - const char *str; - if (snd_config_get_string(n, &str) == 0) { - params.format = snd_pcm_format_value(str); - if (*str && params.format == SND_PCM_FORMAT_UNKNOWN) - SNDERR("%s: invalid value %s", id, str); + if (str != NULL && *str) + pw_properties_set(props, "alsa.format", str); } else { SNDERR("%s: invalid type", id); } continue; } if (spa_streq(id, "channels")) { - long val; - - if (snd_config_get_integer(n, &val) == 0) - params.channels = val; - else + if (snd_config_get_integer(n, &val) == 0) { + if (val != 0) + pw_properties_setf(props, "alsa.channels", "%ld", val); + } else { SNDERR("%s: invalid type", id); + } continue; } if (spa_streq(id, "period_bytes")) { - long val; - - if (snd_config_get_integer(n, &val) == 0) - params.period_bytes = val; - else + if (snd_config_get_integer(n, &val) == 0) { + if (val != 0) + pw_properties_setf(props, "alsa.period-bytes", "%ld", val); + } else { SNDERR("%s: invalid type", id); + } continue; } if (spa_streq(id, "buffer_bytes")) { long val; - if (snd_config_get_integer(n, &val) == 0) - params.buffer_bytes = val; - else + if (snd_config_get_integer(n, &val) == 0) { + if (val != 0) + pw_properties_setf(props, "alsa.buffer-bytes", "%ld", val); + } else { SNDERR("%s: invalid type", id); + } continue; } SNDERR("Unknown field %s", id); + pw_properties_free(props); return -EINVAL; } - err = snd_pcm_pipewire_open(pcmp, ¶ms, stream, mode); + err = snd_pcm_pipewire_open(pcmp, props, stream, mode); return err; }
View file
pipewire-0.3.64.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.65.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
@@ -3480,7 +3480,7 @@ client->info.change_mask = 0; client->show_monitor = pw_properties_get_bool(client->props, "jack.show-monitor", true); - client->merge_monitor = pw_properties_get_bool(client->props, "jack.merge-monitor", false); + client->merge_monitor = pw_properties_get_bool(client->props, "jack.merge-monitor", true); client->short_name = pw_properties_get_bool(client->props, "jack.short-name", false); client->filter_name = pw_properties_get_bool(client->props, "jack.filter-name", false); client->filter_char = ' ';
View file
pipewire-0.3.64.tar.gz/spa/include/spa/buffer/meta.h -> pipewire-0.3.65.tar.gz/spa/include/spa/buffer/meta.h
Changed
@@ -177,7 +177,8 @@ /** a transformation of the buffer */ struct spa_meta_videotransform { - uint32_t transform; /**< orientation transformation that was applied to the buffer */ + uint32_t transform; /**< orientation transformation that was applied to the buffer, + * one of enum spa_meta_videotransform_value */ }; /**
View file
pipewire-0.3.64.tar.gz/spa/include/spa/buffer/type-info.h -> pipewire-0.3.65.tar.gz/spa/include/spa/buffer/type-info.h
Changed
@@ -79,6 +79,7 @@ { SPA_META_Cursor, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Cursor", NULL }, { SPA_META_Control, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Control", NULL }, { SPA_META_Busy, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Busy", NULL }, + { SPA_META_VideoTransform, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "VideoTransform", NULL }, { 0, 0, NULL, NULL }, };
View file
pipewire-0.3.64.tar.gz/spa/include/spa/debug/buffer.h -> pipewire-0.3.65.tar.gz/spa/include/spa/debug/buffer.h
Changed
@@ -38,56 +38,56 @@ * \{ */ -#include <spa/debug/log.h> +#include <spa/debug/context.h> #include <spa/debug/mem.h> #include <spa/debug/types.h> #include <spa/buffer/type-info.h> -static inline int spa_debug_buffer(int indent, const struct spa_buffer *buffer) +static inline int spa_debugc_buffer(struct spa_debug_context *ctx, int indent, const struct spa_buffer *buffer) { uint32_t i; - spa_debug("%*s" "struct spa_buffer %p:", indent, "", buffer); - spa_debug("%*s" " n_metas: %u (at %p)", indent, "", buffer->n_metas, buffer->metas); + spa_debugc(ctx, "%*s" "struct spa_buffer %p:", indent, "", buffer); + spa_debugc(ctx, "%*s" " n_metas: %u (at %p)", indent, "", buffer->n_metas, buffer->metas); for (i = 0; i < buffer->n_metas; i++) { struct spa_meta *m = &buffer->metasi; const char *type_name; type_name = spa_debug_type_find_name(spa_type_meta_type, m->type); - spa_debug("%*s" " meta %d: type %d (%s), data %p, size %d:", indent, "", i, m->type, + spa_debugc(ctx, "%*s" " meta %d: type %d (%s), data %p, size %d:", indent, "", i, m->type, type_name, m->data, m->size); switch (m->type) { case SPA_META_Header: { struct spa_meta_header *h = (struct spa_meta_header*)m->data; - spa_debug("%*s" " struct spa_meta_header:", indent, ""); - spa_debug("%*s" " flags: %08x", indent, "", h->flags); - spa_debug("%*s" " offset: %u", indent, "", h->offset); - spa_debug("%*s" " seq: %" PRIu64, indent, "", h->seq); - spa_debug("%*s" " pts: %" PRIi64, indent, "", h->pts); - spa_debug("%*s" " dts_offset: %" PRIi64, indent, "", h->dts_offset); + spa_debugc(ctx, "%*s" " struct spa_meta_header:", indent, ""); + spa_debugc(ctx, "%*s" " flags: %08x", indent, "", h->flags); + spa_debugc(ctx, "%*s" " offset: %u", indent, "", h->offset); + spa_debugc(ctx, "%*s" " seq: %" PRIu64, indent, "", h->seq); + spa_debugc(ctx, "%*s" " pts: %" PRIi64, indent, "", h->pts); + spa_debugc(ctx, "%*s" " dts_offset: %" PRIi64, indent, "", h->dts_offset); break; } case SPA_META_VideoCrop: { struct spa_meta_region *h = (struct spa_meta_region*)m->data; - spa_debug("%*s" " struct spa_meta_region:", indent, ""); - spa_debug("%*s" " x: %d", indent, "", h->region.position.x); - spa_debug("%*s" " y: %d", indent, "", h->region.position.y); - spa_debug("%*s" " width: %d", indent, "", h->region.size.width); - spa_debug("%*s" " height: %d", indent, "", h->region.size.height); + spa_debugc(ctx, "%*s" " struct spa_meta_region:", indent, ""); + spa_debugc(ctx, "%*s" " x: %d", indent, "", h->region.position.x); + spa_debugc(ctx, "%*s" " y: %d", indent, "", h->region.position.y); + spa_debugc(ctx, "%*s" " width: %d", indent, "", h->region.size.width); + spa_debugc(ctx, "%*s" " height: %d", indent, "", h->region.size.height); break; } case SPA_META_VideoDamage: { struct spa_meta_region *h; spa_meta_for_each(h, m) { - spa_debug("%*s" " struct spa_meta_region:", indent, ""); - spa_debug("%*s" " x: %d", indent, "", h->region.position.x); - spa_debug("%*s" " y: %d", indent, "", h->region.position.y); - spa_debug("%*s" " width: %d", indent, "", h->region.size.width); - spa_debug("%*s" " height: %d", indent, "", h->region.size.height); + spa_debugc(ctx, "%*s" " struct spa_meta_region:", indent, ""); + spa_debugc(ctx, "%*s" " x: %d", indent, "", h->region.position.x); + spa_debugc(ctx, "%*s" " y: %d", indent, "", h->region.position.y); + spa_debugc(ctx, "%*s" " width: %d", indent, "", h->region.size.width); + spa_debugc(ctx, "%*s" " height: %d", indent, "", h->region.size.height); } break; } @@ -96,28 +96,32 @@ case SPA_META_Cursor: break; default: - spa_debug("%*s" " Unknown:", indent, ""); - spa_debug_mem(5, m->data, m->size); + spa_debugc(ctx, "%*s" " Unknown:", indent, ""); + spa_debugc_mem(ctx, 5, m->data, m->size); } } - spa_debug("%*s" " n_datas: \t%u (at %p)", indent, "", buffer->n_datas, buffer->datas); + spa_debugc(ctx, "%*s" " n_datas: \t%u (at %p)", indent, "", buffer->n_datas, buffer->datas); for (i = 0; i < buffer->n_datas; i++) { struct spa_data *d = &buffer->datasi; - spa_debug("%*s" " type: %d (%s)", indent, "", d->type, + spa_debugc(ctx, "%*s" " type: %d (%s)", indent, "", d->type, spa_debug_type_find_name(spa_type_data_type, d->type)); - spa_debug("%*s" " flags: %d", indent, "", d->flags); - spa_debug("%*s" " data: %p", indent, "", d->data); - spa_debug("%*s" " fd: %" PRIi64, indent, "", d->fd); - spa_debug("%*s" " offset: %d", indent, "", d->mapoffset); - spa_debug("%*s" " maxsize: %u", indent, "", d->maxsize); - spa_debug("%*s" " chunk: %p", indent, "", d->chunk); - spa_debug("%*s" " offset: %d", indent, "", d->chunk->offset); - spa_debug("%*s" " size: %u", indent, "", d->chunk->size); - spa_debug("%*s" " stride: %d", indent, "", d->chunk->stride); + spa_debugc(ctx, "%*s" " flags: %d", indent, "", d->flags); + spa_debugc(ctx, "%*s" " data: %p", indent, "", d->data); + spa_debugc(ctx, "%*s" " fd: %" PRIi64, indent, "", d->fd); + spa_debugc(ctx, "%*s" " offset: %d", indent, "", d->mapoffset); + spa_debugc(ctx, "%*s" " maxsize: %u", indent, "", d->maxsize); + spa_debugc(ctx, "%*s" " chunk: %p", indent, "", d->chunk); + spa_debugc(ctx, "%*s" " offset: %d", indent, "", d->chunk->offset); + spa_debugc(ctx, "%*s" " size: %u", indent, "", d->chunk->size); + spa_debugc(ctx, "%*s" " stride: %d", indent, "", d->chunk->stride); } return 0; } +static inline int spa_debug_buffer(int indent, const struct spa_buffer *buffer) +{ + return spa_debugc_buffer(NULL, indent, buffer); +} /** * \} */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/debug/context.h
Added
@@ -0,0 +1,62 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_DEBUG_CONTEXT_H +#define SPA_DEBUG_CONTEXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <stdarg.h> + +#include <spa/utils/defs.h> +/** + * \addtogroup spa_debug + * \{ + */ + +#ifndef spa_debugn +#define spa_debugn(_fmt,...) printf((_fmt), ## __VA_ARGS__) +#endif +#ifndef spa_debug +#define spa_debug(_fmt,...) spa_debugn(_fmt"\n", ## __VA_ARGS__) +#endif + +struct spa_debug_context { + void (*log) (struct spa_debug_context *ctx, const char *fmt, ...) SPA_PRINTF_FUNC(2, 3); +}; + +#define spa_debugc(_c,_fmt,...) (_c)?((_c)->log((_c),_fmt, ## __VA_ARGS__)):(void)spa_debug(_fmt, ## __VA_ARGS__) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_DEBUG_CONTEXT_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/debug/dict.h -> pipewire-0.3.65.tar.gz/spa/include/spa/debug/dict.h
Changed
@@ -34,19 +34,23 @@ * \{ */ -#include <spa/debug/log.h> +#include <spa/debug/context.h> #include <spa/utils/dict.h> -static inline int spa_debug_dict(int indent, const struct spa_dict *dict) +static inline int spa_debugc_dict(struct spa_debug_context *ctx, int indent, const struct spa_dict *dict) { const struct spa_dict_item *item; - spa_debug("%*sflags:%08x n_items:%d", indent, "", dict->flags, dict->n_items); + spa_debugc(ctx, "%*sflags:%08x n_items:%d", indent, "", dict->flags, dict->n_items); spa_dict_for_each(item, dict) { - spa_debug("%*s %s = \"%s\"", indent, "", item->key, item->value); + spa_debugc(ctx, "%*s %s = \"%s\"", indent, "", item->key, item->value); } return 0; } +static inline int spa_debug_dict(int indent, const struct spa_dict *dict) +{ + return spa_debugc_dict(NULL, indent, dict); +} /** * \} */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/debug/format.h -> pipewire-0.3.65.tar.gz/spa/include/spa/debug/format.h
Changed
@@ -35,18 +35,20 @@ */ #include <spa/pod/parser.h> -#include <spa/debug/log.h> +#include <spa/utils/string.h> +#include <spa/debug/context.h> #include <spa/debug/types.h> #include <spa/param/type-info.h> #include <spa/param/format-utils.h> static inline int -spa_debug_format_value(const struct spa_type_info *info, +spa_debug_strbuf_format_value(struct spa_strbuf *buffer, const struct spa_type_info *info, uint32_t type, void *body, uint32_t size) { + switch (type) { case SPA_TYPE_Bool: - spa_debugn("%s", *(int32_t *) body ? "true" : "false"); + spa_strbuf_append(buffer, "%s", *(int32_t *) body ? "true" : "false"); break; case SPA_TYPE_Id: { @@ -56,41 +58,41 @@ snprintf(tmp, sizeof(tmp), "%d", *(int32_t*)body); str = tmp; } - spa_debugn("%s", str); + spa_strbuf_append(buffer, "%s", str); break; } case SPA_TYPE_Int: - spa_debugn("%d", *(int32_t *) body); + spa_strbuf_append(buffer, "%d", *(int32_t *) body); break; case SPA_TYPE_Long: - spa_debugn("%" PRIi64, *(int64_t *) body); + spa_strbuf_append(buffer, "%" PRIi64, *(int64_t *) body); break; case SPA_TYPE_Float: - spa_debugn("%f", *(float *) body); + spa_strbuf_append(buffer, "%f", *(float *) body); break; case SPA_TYPE_Double: - spa_debugn("%f", *(double *) body); + spa_strbuf_append(buffer, "%f", *(double *) body); break; case SPA_TYPE_String: - spa_debugn("%s", (char *) body); + spa_strbuf_append(buffer, "%s", (char *) body); break; case SPA_TYPE_Rectangle: { struct spa_rectangle *r = (struct spa_rectangle *)body; - spa_debugn("%" PRIu32 "x%" PRIu32, r->width, r->height); + spa_strbuf_append(buffer, "%" PRIu32 "x%" PRIu32, r->width, r->height); break; } case SPA_TYPE_Fraction: { struct spa_fraction *f = (struct spa_fraction *)body; - spa_debugn("%" PRIu32 "/%" PRIu32, f->num, f->denom); + spa_strbuf_append(buffer, "%" PRIu32 "/%" PRIu32, f->num, f->denom); break; } case SPA_TYPE_Bitmap: - spa_debugn("Bitmap"); + spa_strbuf_append(buffer, "Bitmap"); break; case SPA_TYPE_Bytes: - spa_debugn("Bytes"); + spa_strbuf_append(buffer, "Bytes"); break; case SPA_TYPE_Array: { @@ -98,23 +100,35 @@ struct spa_pod_array_body *b = (struct spa_pod_array_body *)body; int i = 0; info = info && info->values ? info->values : info; - spa_debugn("< "); + spa_strbuf_append(buffer, "< "); SPA_POD_ARRAY_BODY_FOREACH(b, size, p) { if (i++ > 0) - spa_debugn(", "); - spa_debug_format_value(info, b->child.type, p, b->child.size); + spa_strbuf_append(buffer, ", "); + spa_debug_strbuf_format_value(buffer, info, b->child.type, p, b->child.size); } - spa_debugn(" >"); + spa_strbuf_append(buffer, " >"); break; } default: - spa_debugn("INVALID type %d", type); + spa_strbuf_append(buffer, "INVALID type %d", type); break; } return 0; } -static inline int spa_debug_format(int indent, +static inline int +spa_debug_format_value(const struct spa_type_info *info, + uint32_t type, void *body, uint32_t size) +{ + char buffer1024; + struct spa_strbuf buf; + spa_strbuf_init(&buf, buffer, sizeof(buffer)); + spa_debug_strbuf_format_value(&buf, info, type, body, size); + spa_debugn("%s", buffer); + return 0; +} + +static inline int spa_debugc_format(struct spa_debug_context *ctx, int indent, const struct spa_type_info *info, const struct spa_pod *format) { const char *media_type; @@ -134,7 +148,7 @@ media_type = spa_debug_type_find_name(spa_type_media_type, mtype); media_subtype = spa_debug_type_find_name(spa_type_media_subtype, mstype); - spa_debug("%*s %s/%s", indent, "", + spa_debugc(ctx, "%*s %s/%s", indent, "", media_type ? spa_debug_type_short_name(media_type) : "unknown", media_subtype ? spa_debug_type_short_name(media_subtype) : "unknown"); @@ -144,6 +158,8 @@ uint32_t i, type, size, n_vals, choice; const struct spa_pod *val; void *vals; + char buffer1024; + struct spa_strbuf buf; if (prop->key == SPA_FORMAT_mediaType || prop->key == SPA_FORMAT_mediaSubtype) @@ -161,12 +177,13 @@ ti = spa_debug_type_find(info, prop->key); key = ti ? ti->name : NULL; - spa_debugn("%*s %16s : (%s) ", indent, "", + spa_strbuf_init(&buf, buffer, sizeof(buffer)); + spa_strbuf_append(&buf, "%*s %16s : (%s) ", indent, "", key ? spa_debug_type_short_name(key) : "unknown", spa_debug_type_short_name(spa_typestype.name)); if (choice == SPA_CHOICE_None) { - spa_debug_format_value(ti ? ti->values : NULL, type, vals, size); + spa_debug_strbuf_format_value(&buf, ti ? ti->values : NULL, type, vals, size); } else { const char *ssep, *esep, *sep; @@ -186,21 +203,26 @@ break; } - spa_debugn("%s", ssep); + spa_strbuf_append(&buf, "%s", ssep); for (i = 1; i < n_vals; i++) { vals = SPA_PTROFF(vals, size, void); if (i > 1) - spa_debugn("%s", sep); - spa_debug_format_value(ti ? ti->values : NULL, type, vals, size); + spa_strbuf_append(&buf, "%s", sep); + spa_debug_strbuf_format_value(&buf, ti ? ti->values : NULL, type, vals, size); } - spa_debugn("%s", esep); + spa_strbuf_append(&buf, "%s", esep); } - spa_debugn("\n"); + spa_debugc(ctx, "%s", buffer); } return 0; } +static inline int spa_debug_format(int indent, + const struct spa_type_info *info, const struct spa_pod *format) +{ + return spa_debugc_format(NULL, indent, info, format); +} /** * \} */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/debug/log.h -> pipewire-0.3.65.tar.gz/spa/include/spa/debug/log.h
Changed
@@ -30,17 +30,67 @@ #endif #include <stdio.h> +#include <stdarg.h> + +#include <spa/utils/defs.h> +#include <spa/support/log.h> +#include <spa/debug/context.h> + /** * \addtogroup spa_debug * \{ */ -#ifndef spa_debug -#define spa_debug(fmt,...) ({ printf((fmt"\n"), ## __VA_ARGS__); }) -#endif -#ifndef spa_debugn -#define spa_debugn(fmt,...) ({ printf((fmt), ## __VA_ARGS__); }) -#endif +struct spa_debug_log_ctx { + struct spa_debug_context ctx; + struct spa_log *log; + enum spa_log_level level; + const struct spa_log_topic *topic; + const char *file; + int line; + const char *func; +}; + +SPA_PRINTF_FUNC(2,3) +static inline void spa_debug_log_log(struct spa_debug_context *ctx, const char *fmt, ...) +{ + struct spa_debug_log_ctx *c = (struct spa_debug_log_ctx*)ctx; + va_list args; + va_start(args, fmt); + spa_log_logtv(c->log, c->level, c->topic, c->file, c->line, c->func, fmt, args); + va_end(args); +} + +#define SPA_LOGF_DEBUG_INIT(_l,_lev,_t,_file,_line,_func) \ + (struct spa_debug_log_ctx){ { spa_debug_log_log }, _l, _lev, _t, \ + _file, _line, _func } + +#define SPA_LOGT_DEBUG_INIT(_l,_lev,_t) \ + SPA_LOGF_DEBUG_INIT(_l,_lev,_t,__FILE__,__LINE__,__func__) + +#define SPA_LOG_DEBUG_INIT(l,lev) \ + SPA_LOGT_DEBUG_INIT(l,lev,SPA_LOG_TOPIC_DEFAULT) + +#define spa_debug_log_pod(l,lev,indent,info,pod) \ +({ \ + struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \ + if (SPA_UNLIKELY(spa_log_level_topic_enabled(c.log, c.topic, c.level))) \ + spa_debugc_pod(&c.ctx, indent, info, pod); \ +}) + +#define spa_debug_log_format(l,lev,indent,info,format) \ +({ \ + struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \ + if (SPA_UNLIKELY(spa_log_level_topic_enabled(c.log, c.topic, c.level))) \ + spa_debugc_format(&c.ctx, indent, info, format); \ +}) + +#define spa_debug_log_mem(l,lev,indent,data,len) \ +({ \ + struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \ + if (SPA_UNLIKELY(spa_log_level_topic_enabled(c.log, c.topic, c.level))) \ + spa_debugc_mem(&c.ctx, indent, data, len); \ +}) /** * \} @@ -50,4 +100,4 @@ } /* extern "C" */ #endif -#endif /* SPA_DEBUG_LOGH */ +#endif /* SPA_DEBUG_LOG_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/debug/mem.h -> pipewire-0.3.65.tar.gz/spa/include/spa/debug/mem.h
Changed
@@ -36,9 +36,9 @@ * \{ */ -#include <spa/debug/log.h> +#include <spa/debug/context.h> -static inline int spa_debug_mem(int indent, const void *data, size_t size) +static inline int spa_debugc_mem(struct spa_debug_context *ctx, int indent, const void *data, size_t size) { const uint8_t *t = (const uint8_t*)data; char buffer512; @@ -50,12 +50,16 @@ pos = sprintf(buffer, "%p: ", &ti); pos += sprintf(buffer + pos, "%02x ", ti); if (i % 16 == 15 || i == size - 1) { - spa_debug("%*s" "%s", indent, "", buffer); + spa_debugc(ctx, "%*s" "%s", indent, "", buffer); } } return 0; } +static inline int spa_debug_mem(int indent, const void *data, size_t size) +{ + return spa_debugc_mem(NULL, indent, data, size); +} /** * \} */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/debug/node.h -> pipewire-0.3.65.tar.gz/spa/include/spa/debug/node.h
Changed
@@ -35,22 +35,26 @@ */ #include <spa/node/node.h> -#include <spa/debug/log.h> +#include <spa/debug/context.h> #include <spa/debug/dict.h> -static inline int spa_debug_port_info(int indent, const struct spa_port_info *info) +static inline int spa_debugc_port_info(struct spa_debug_context *ctx, int indent, const struct spa_port_info *info) { - spa_debug("%*s" "struct spa_port_info %p:", indent, "", info); - spa_debug("%*s" " flags: \t%08" PRIx64, indent, "", info->flags); - spa_debug("%*s" " rate: \t%d/%d", indent, "", info->rate.num, info->rate.denom); - spa_debug("%*s" " props:", indent, ""); + spa_debugc(ctx, "%*s" "struct spa_port_info %p:", indent, "", info); + spa_debugc(ctx, "%*s" " flags: \t%08" PRIx64, indent, "", info->flags); + spa_debugc(ctx, "%*s" " rate: \t%d/%d", indent, "", info->rate.num, info->rate.denom); + spa_debugc(ctx, "%*s" " props:", indent, ""); if (info->props) - spa_debug_dict(indent + 2, info->props); + spa_debugc_dict(ctx, indent + 2, info->props); else - spa_debug("%*s" " none", indent, ""); + spa_debugc(ctx, "%*s" " none", indent, ""); return 0; } +static inline int spa_debug_port_info(int indent, const struct spa_port_info *info) +{ + return spa_debugc_port_info(NULL, indent, info); +} /** * \} */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/debug/pod.h -> pipewire-0.3.65.tar.gz/spa/include/spa/debug/pod.h
Changed
@@ -34,63 +34,63 @@ * \{ */ -#include <spa/debug/log.h> +#include <spa/debug/context.h> #include <spa/debug/mem.h> #include <spa/debug/types.h> #include <spa/pod/pod.h> #include <spa/pod/iter.h> static inline int -spa_debug_pod_value(int indent, const struct spa_type_info *info, +spa_debugc_pod_value(struct spa_debug_context *ctx, int indent, const struct spa_type_info *info, uint32_t type, void *body, uint32_t size) { switch (type) { case SPA_TYPE_Bool: - spa_debug("%*s" "Bool %s", indent, "", (*(int32_t *) body) ? "true" : "false"); + spa_debugc(ctx, "%*s" "Bool %s", indent, "", (*(int32_t *) body) ? "true" : "false"); break; case SPA_TYPE_Id: - spa_debug("%*s" "Id %-8d (%s)", indent, "", *(int32_t *) body, + spa_debugc(ctx, "%*s" "Id %-8d (%s)", indent, "", *(int32_t *) body, spa_debug_type_find_name(info, *(int32_t *) body)); break; case SPA_TYPE_Int: - spa_debug("%*s" "Int %d", indent, "", *(int32_t *) body); + spa_debugc(ctx, "%*s" "Int %d", indent, "", *(int32_t *) body); break; case SPA_TYPE_Long: - spa_debug("%*s" "Long %" PRIi64 "", indent, "", *(int64_t *) body); + spa_debugc(ctx, "%*s" "Long %" PRIi64 "", indent, "", *(int64_t *) body); break; case SPA_TYPE_Float: - spa_debug("%*s" "Float %f", indent, "", *(float *) body); + spa_debugc(ctx, "%*s" "Float %f", indent, "", *(float *) body); break; case SPA_TYPE_Double: - spa_debug("%*s" "Double %f", indent, "", *(double *) body); + spa_debugc(ctx, "%*s" "Double %f", indent, "", *(double *) body); break; case SPA_TYPE_String: - spa_debug("%*s" "String \"%s\"", indent, "", (char *) body); + spa_debugc(ctx, "%*s" "String \"%s\"", indent, "", (char *) body); break; case SPA_TYPE_Fd: - spa_debug("%*s" "Fd %d", indent, "", *(int *) body); + spa_debugc(ctx, "%*s" "Fd %d", indent, "", *(int *) body); break; case SPA_TYPE_Pointer: { struct spa_pod_pointer_body *b = (struct spa_pod_pointer_body *)body; - spa_debug("%*s" "Pointer %s %p", indent, "", + spa_debugc(ctx, "%*s" "Pointer %s %p", indent, "", spa_debug_type_find_name(SPA_TYPE_ROOT, b->type), b->value); break; } case SPA_TYPE_Rectangle: { struct spa_rectangle *r = (struct spa_rectangle *)body; - spa_debug("%*s" "Rectangle %dx%d", indent, "", r->width, r->height); + spa_debugc(ctx, "%*s" "Rectangle %dx%d", indent, "", r->width, r->height); break; } case SPA_TYPE_Fraction: { struct spa_fraction *f = (struct spa_fraction *)body; - spa_debug("%*s" "Fraction %d/%d", indent, "", f->num, f->denom); + spa_debugc(ctx, "%*s" "Fraction %d/%d", indent, "", f->num, f->denom); break; } case SPA_TYPE_Bitmap: - spa_debug("%*s" "Bitmap", indent, ""); + spa_debugc(ctx, "%*s" "Bitmap", indent, ""); break; case SPA_TYPE_Array: { @@ -98,12 +98,12 @@ void *p; const struct spa_type_info *ti = spa_debug_type_find(SPA_TYPE_ROOT, b->child.type); - spa_debug("%*s" "Array: child.size %d, child.type %s", indent, "", + spa_debugc(ctx, "%*s" "Array: child.size %d, child.type %s", indent, "", b->child.size, ti ? ti->name : "unknown"); info = info && info->values ? info->values : info; SPA_POD_ARRAY_BODY_FOREACH(b, size, p) - spa_debug_pod_value(indent + 2, info, b->child.type, p, b->child.size); + spa_debugc_pod_value(ctx, indent + 2, info, b->child.type, p, b->child.size); break; } case SPA_TYPE_Choice: @@ -112,19 +112,19 @@ void *p; const struct spa_type_info *ti = spa_debug_type_find(spa_type_choice, b->type); - spa_debug("%*s" "Choice: type %s, flags %08x %d %d", indent, "", + spa_debugc(ctx, "%*s" "Choice: type %s, flags %08x %d %d", indent, "", ti ? ti->name : "unknown", b->flags, size, b->child.size); SPA_POD_CHOICE_BODY_FOREACH(b, size, p) - spa_debug_pod_value(indent + 2, info, b->child.type, p, b->child.size); + spa_debugc_pod_value(ctx, indent + 2, info, b->child.type, p, b->child.size); break; } case SPA_TYPE_Struct: { struct spa_pod *b = (struct spa_pod *)body, *p; - spa_debug("%*s" "Struct: size %d", indent, "", size); + spa_debugc(ctx, "%*s" "Struct: size %d", indent, "", size); SPA_POD_FOREACH(b, size, p) - spa_debug_pod_value(indent + 2, info, p->type, SPA_POD_BODY(p), p->size); + spa_debugc_pod_value(ctx, indent + 2, info, p->type, SPA_POD_BODY(p), p->size); break; } case SPA_TYPE_Object: @@ -137,7 +137,7 @@ ii = ti ? spa_debug_type_find(ti->values, 0) : NULL; ii = ii ? spa_debug_type_find(ii->values, b->id) : NULL; - spa_debug("%*s" "Object: size %d, type %s (%d), id %s (%d)", indent, "", size, + spa_debugc(ctx, "%*s" "Object: size %d, type %s (%d), id %s (%d)", indent, "", size, ti ? ti->name : "unknown", b->type, ii ? ii->name : "unknown", b->id); info = ti ? ti->values : info; @@ -145,10 +145,10 @@ SPA_POD_OBJECT_BODY_FOREACH(b, size, p) { ii = spa_debug_type_find(info, p->key); - spa_debug("%*s" "Prop: key %s (%d), flags %08x", indent+2, "", + spa_debugc(ctx, "%*s" "Prop: key %s (%d), flags %08x", indent+2, "", ii ? ii->name : "unknown", p->key, p->flags); - spa_debug_pod_value(indent + 4, ii ? ii->values : NULL, + spa_debugc_pod_value(ctx, indent + 4, ii ? ii->values : NULL, p->value.type, SPA_POD_CONTENTS(struct spa_pod_prop, p), p->value.size); @@ -163,16 +163,16 @@ ti = spa_debug_type_find(info, b->unit); - spa_debug("%*s" "Sequence: size %d, unit %s", indent, "", size, + spa_debugc(ctx, "%*s" "Sequence: size %d, unit %s", indent, "", size, ti ? ti->name : "unknown"); SPA_POD_SEQUENCE_BODY_FOREACH(b, size, c) { ii = spa_debug_type_find(spa_type_control, c->type); - spa_debug("%*s" "Control: offset %d, type %s", indent+2, "", + spa_debugc(ctx, "%*s" "Control: offset %d, type %s", indent+2, "", c->offset, ii ? ii->name : "unknown"); - spa_debug_pod_value(indent + 4, ii ? ii->values : NULL, + spa_debugc_pod_value(ctx, indent + 4, ii ? ii->values : NULL, c->value.type, SPA_POD_CONTENTS(struct spa_pod_control, c), c->value.size); @@ -180,29 +180,41 @@ break; } case SPA_TYPE_Bytes: - spa_debug("%*s" "Bytes", indent, ""); - spa_debug_mem(indent + 2, body, size); + spa_debugc(ctx, "%*s" "Bytes", indent, ""); + spa_debugc_mem(ctx, indent + 2, body, size); break; case SPA_TYPE_None: - spa_debug("%*s" "None", indent, ""); - spa_debug_mem(indent + 2, body, size); + spa_debugc(ctx, "%*s" "None", indent, ""); + spa_debugc_mem(ctx, indent + 2, body, size); break; default: - spa_debug("%*s" "unhandled POD type %d", indent, "", type); + spa_debugc(ctx, "%*s" "unhandled POD type %d", indent, "", type); break; } return 0; } -static inline int spa_debug_pod(int indent, +static inline int spa_debugc_pod(struct spa_debug_context *ctx, int indent, const struct spa_type_info *info, const struct spa_pod *pod) { - return spa_debug_pod_value(indent, info ? info : SPA_TYPE_ROOT, + return spa_debugc_pod_value(ctx, indent, info ? info : SPA_TYPE_ROOT, SPA_POD_TYPE(pod), SPA_POD_BODY(pod), SPA_POD_BODY_SIZE(pod)); } +static inline int +spa_debug_pod_value(int indent, const struct spa_type_info *info, + uint32_t type, void *body, uint32_t size) +{ + return spa_debugc_pod_value(NULL, indent, info, type, body, size); +} + +static inline int spa_debug_pod(int indent, + const struct spa_type_info *info, const struct spa_pod *pod) +{ + return spa_debugc_pod(NULL, indent, info, pod); +} /** * \} */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/node/type-info.h -> pipewire-0.3.65.tar.gz/spa/include/spa/node/type-info.h
Changed
@@ -34,7 +34,7 @@ * \{ */ -#include <spa/utils/type-info.h> +#include <spa/utils/type.h> #include <spa/node/command.h> #include <spa/node/event.h>
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/aac-types.h
Added
@@ -0,0 +1,58 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_AAC_TYPES_H +#define SPA_AUDIO_AAC_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/utils/type.h> +#include <spa/param/audio/aac.h> + +#define SPA_TYPE_INFO_AudioAACStreamFormat SPA_TYPE_INFO_ENUM_BASE "AudioAACStreamFormat" +#define SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE SPA_TYPE_INFO_AudioAACStreamFormat ":" + +static const struct spa_type_info spa_type_audio_aac_stream_format = { + { SPA_AUDIO_AAC_STREAM_FORMAT_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "UNKNOWN", NULL }, + { SPA_AUDIO_AAC_STREAM_FORMAT_RAW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "RAW", NULL }, + { SPA_AUDIO_AAC_STREAM_FORMAT_MP2ADTS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "MP2ADTS", NULL }, + { SPA_AUDIO_AAC_STREAM_FORMAT_MP4ADTS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "MP4ADTS", NULL }, + { SPA_AUDIO_AAC_STREAM_FORMAT_MP4LOAS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "MP4LOAS", NULL }, + { SPA_AUDIO_AAC_STREAM_FORMAT_MP4LATM, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "MP4LATM", NULL }, + { SPA_AUDIO_AAC_STREAM_FORMAT_ADIF, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "ADIF", NULL }, + { SPA_AUDIO_AAC_STREAM_FORMAT_MP4FF, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AAC_STREAM_FORMAT_BASE "MP4FF", NULL }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_AAC_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/aac-utils.h
Added
@@ -0,0 +1,89 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_AAC_UTILS_H +#define SPA_AUDIO_AAC_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_aac_parse(const struct spa_pod *format, struct spa_audio_info_aac *info) +{ + int res; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels), + SPA_FORMAT_AUDIO_bitrate, SPA_POD_OPT_Int(&info->bitrate), + SPA_FORMAT_AUDIO_AAC_streamFormat, SPA_POD_OPT_Id(&info->stream_format)); + + return res; +} + +static inline struct spa_pod * +spa_format_audio_aac_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_aac *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_aac), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_ENCODED), + 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + if (info->channels != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); + if (info->bitrate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_bitrate, SPA_POD_Int(info->bitrate), 0); + if (info->stream_format != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_AAC_streamFormat, SPA_POD_Id(info->stream_format), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_AAC_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/aac.h
Added
@@ -0,0 +1,71 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_AAC_H +#define SPA_AUDIO_AAC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/param/audio/raw.h> + +enum spa_audio_aac_stream_format { + SPA_AUDIO_AAC_STREAM_FORMAT_UNKNOWN, + /* Raw AAC frames */ + SPA_AUDIO_AAC_STREAM_FORMAT_RAW, + /* ISO/IEC 13818-7 MPEG-2 Audio Data Transport Stream (ADTS) */ + SPA_AUDIO_AAC_STREAM_FORMAT_MP2ADTS, + /* ISO/IEC 14496-3 MPEG-4 Audio Data Transport Stream (ADTS) */ + SPA_AUDIO_AAC_STREAM_FORMAT_MP4ADTS, + /* ISO/IEC 14496-3 Low Overhead Audio Stream (LOAS) */ + SPA_AUDIO_AAC_STREAM_FORMAT_MP4LOAS, + /* ISO/IEC 14496-3 Low Overhead Audio Transport Multiplex (LATM) */ + SPA_AUDIO_AAC_STREAM_FORMAT_MP4LATM, + /* ISO/IEC 14496-3 Audio Data Interchange Format (ADIF) */ + SPA_AUDIO_AAC_STREAM_FORMAT_ADIF, + /* ISO/IEC 14496-12 MPEG-4 file format */ + SPA_AUDIO_AAC_STREAM_FORMAT_MP4FF, + + SPA_AUDIO_AAC_STREAM_FORMAT_CUSTOM = 0x10000, +}; + +struct spa_audio_info_aac { + uint32_t rate; /*< sample rate */ + uint32_t channels; /*< number of channels */ + uint32_t bitrate; /*< stream bitrate */ + enum spa_audio_aac_stream_format stream_format; /*< AAC audio stream format */ +}; + +#define SPA_AUDIO_INFO_AAC_INIT(...) ((struct spa_audio_info_aac) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_AAC_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/alac-utils.h
Added
@@ -0,0 +1,80 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_ALAC_UTILS_H +#define SPA_AUDIO_ALAC_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_alac_parse(const struct spa_pod *format, struct spa_audio_info_alac *info) +{ + int res; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels)); + return res; +} + +static inline struct spa_pod * +spa_format_audio_alac_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_alac *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_alac), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_ENCODED), + 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + if (info->channels != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_ALAC_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/alac.h
Added
@@ -0,0 +1,49 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_ALAC_H +#define SPA_AUDIO_ALAC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/param/audio/raw.h> + +struct spa_audio_info_alac { + uint32_t rate; /*< sample rate */ + uint32_t channels; /*< number of channels */ +}; + +#define SPA_AUDIO_INFO_ALAC_INIT(...) ((struct spa_audio_info_alac) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_ALAC_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/amr-types.h
Added
@@ -0,0 +1,52 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_AMR_TYPES_H +#define SPA_AUDIO_AMR_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/utils/type.h> +#include <spa/param/audio/amr.h> + +#define SPA_TYPE_INFO_AudioAMRBandMode SPA_TYPE_INFO_ENUM_BASE "AudioAMRBandMode" +#define SPA_TYPE_INFO_AUDIO_AMR_BAND_MODE_BASE SPA_TYPE_INFO_AudioAMRBandMode ":" + +static const struct spa_type_info spa_type_audio_amr_band_mode = { + { SPA_AUDIO_AMR_BAND_MODE_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AMR_BAND_MODE_BASE "UNKNOWN", NULL }, + { SPA_AUDIO_AMR_BAND_MODE_NB, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AMR_BAND_MODE_BASE "NB", NULL }, + { SPA_AUDIO_AMR_BAND_MODE_WB, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_AMR_BAND_MODE_BASE "WB", NULL }, + { 0, 0, NULL, NULL }, +}; +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_AMR_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/amr-utils.h
Added
@@ -0,0 +1,84 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_AMR_UTILS_H +#define SPA_AUDIO_AMR_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_amr_parse(const struct spa_pod *format, struct spa_audio_info_amr *info) +{ + int res; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels), + SPA_FORMAT_AUDIO_AMR_bandMode, SPA_POD_OPT_Id(&info->band_mode)); + return res; +} + +static inline struct spa_pod * +spa_format_audio_amr_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_amr *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_amr), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_ENCODED), + 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + if (info->channels != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); + if (info->band_mode != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_AMR_bandMode, SPA_POD_Id(info->band_mode), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_AMR_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/amr.h
Added
@@ -0,0 +1,56 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_AMR_H +#define SPA_AUDIO_AMR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/param/audio/raw.h> + +enum spa_audio_amr_band_mode { + SPA_AUDIO_AMR_BAND_MODE_UNKNOWN, + SPA_AUDIO_AMR_BAND_MODE_NB, + SPA_AUDIO_AMR_BAND_MODE_WB, +}; + +struct spa_audio_info_amr { + uint32_t rate; /*< sample rate */ + uint32_t channels; /*< number of channels */ + enum spa_audio_amr_band_mode band_mode; +}; + +#define SPA_AUDIO_INFO_AMR_INIT(...) ((struct spa_audio_info_amr) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_AMR_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/ape-utils.h
Added
@@ -0,0 +1,80 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_APE_UTILS_H +#define SPA_AUDIO_APE_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_ape_parse(const struct spa_pod *format, struct spa_audio_info_ape *info) +{ + int res; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels)); + return res; +} + +static inline struct spa_pod * +spa_format_audio_ape_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_ape *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_ape), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_ENCODED), + 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + if (info->channels != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_APE_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/ape.h
Added
@@ -0,0 +1,49 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_APE_H +#define SPA_AUDIO_APE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/param/audio/raw.h> + +struct spa_audio_info_ape { + uint32_t rate; /*< sample rate */ + uint32_t channels; /*< number of channels */ +}; + +#define SPA_AUDIO_INFO_APE_INIT(...) ((struct spa_audio_info_ape) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_APE_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/compressed.h
Added
@@ -0,0 +1,39 @@ +/* Simple Plugin API + * + * Copyright © 2021 Wim Taymans + * © 2022 Asymptotic Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_COMPRESSED_H +#define SPA_AUDIO_COMPRESSED_H + +#include <spa/param/audio/aac.h> +#include <spa/param/audio/alac.h> +#include <spa/param/audio/amr.h> +#include <spa/param/audio/ape.h> +#include <spa/param/audio/flac.h> +#include <spa/param/audio/mp3.h> +#include <spa/param/audio/ra.h> +#include <spa/param/audio/vorbis.h> +#include <spa/param/audio/wma.h> + +#endif /* SPA_AUDIO_COMPRESSED_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/dsd-utils.h
Added
@@ -0,0 +1,100 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_DSD_UTILS_H +#define SPA_AUDIO_DSD_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/format-utils.h> +#include <spa/param/audio/format.h> + +static inline int +spa_format_audio_dsd_parse(const struct spa_pod *format, struct spa_audio_info_dsd *info) +{ + struct spa_pod *position = NULL; + int res; + info->flags = 0; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_bitorder, SPA_POD_OPT_Id(&info->bitorder), + SPA_FORMAT_AUDIO_interleave, SPA_POD_OPT_Int(&info->interleave), + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels), + SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position)); + if (position == NULL || + !spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_AUDIO_MAX_CHANNELS)) + SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED); + + return res; +} + +static inline struct spa_pod * +spa_format_audio_dsd_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_dsd *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsd), + 0); + if (info->bitorder != SPA_PARAM_BITORDER_unknown) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_bitorder, SPA_POD_Id(info->bitorder), 0); + if (info->interleave != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_interleave, SPA_POD_Int(info->interleave), 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + if (info->channels != 0) { + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); + if (!SPA_FLAG_IS_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED)) { + spa_pod_builder_add(builder, SPA_FORMAT_AUDIO_position, + SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, + info->channels, info->position), 0); + } + } + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_DSD_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/dsp-utils.h
Added
@@ -0,0 +1,75 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_DSP_UTILS_H +#define SPA_AUDIO_DSP_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_dsp_parse(const struct spa_pod *format, struct spa_audio_info_dsp *info) +{ + int res; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_format, SPA_POD_OPT_Id(&info->format)); + return res; +} + +static inline struct spa_pod * +spa_format_audio_dsp_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_dsp *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp), + 0); + if (info->format != SPA_AUDIO_FORMAT_UNKNOWN) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_format, SPA_POD_Id(info->format), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_DSP_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/dsp.h
Added
@@ -0,0 +1,48 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_DSP_H +#define SPA_AUDIO_DSP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/param/audio/raw.h> + +struct spa_audio_info_dsp { + enum spa_audio_format format; /*< format, one of the DSP formats in enum spa_audio_format */ +}; + +#define SPA_AUDIO_INFO_DSP_INIT(...) ((struct spa_audio_info_dsp) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_DSP_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/flac-utils.h
Added
@@ -0,0 +1,80 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_FLAC_UTILS_H +#define SPA_AUDIO_FLAC_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_flac_parse(const struct spa_pod *format, struct spa_audio_info_flac *info) +{ + int res; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels)); + return res; +} + +static inline struct spa_pod * +spa_format_audio_flac_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_flac *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_flac), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_ENCODED), + 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + if (info->channels != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_FLAC_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/flac.h
Added
@@ -0,0 +1,49 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_FLAC_H +#define SPA_AUDIO_FLAC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/param/audio/raw.h> + +struct spa_audio_info_flac { + uint32_t rate; /*< sample rate */ + uint32_t channels; /*< number of channels */ +}; + +#define SPA_AUDIO_INFO_FLAC_INIT(...) ((struct spa_audio_info_flac) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_FLAC_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/audio/format-utils.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/format-utils.h
Changed
@@ -29,167 +29,107 @@ extern "C" { #endif -/** - * \addtogroup spa_param - * \{ - */ - #include <spa/pod/parser.h> #include <spa/pod/builder.h> #include <spa/param/audio/format.h> #include <spa/param/format-utils.h> -static inline int -spa_format_audio_raw_parse(const struct spa_pod *format, struct spa_audio_info_raw *info) -{ - struct spa_pod *position = NULL; - int res; - info->flags = 0; - res = spa_pod_parse_object(format, - SPA_TYPE_OBJECT_Format, NULL, - SPA_FORMAT_AUDIO_format, SPA_POD_OPT_Id(&info->format), - SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), - SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels), - SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position)); - if (position == NULL || - !spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_AUDIO_MAX_CHANNELS)) - SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED); - - return res; -} +#include <spa/param/audio/raw-utils.h> +#include <spa/param/audio/dsp-utils.h> +#include <spa/param/audio/iec958-utils.h> +#include <spa/param/audio/dsd-utils.h> +#include <spa/param/audio/mp3-utils.h> +#include <spa/param/audio/aac-utils.h> +#include <spa/param/audio/vorbis-utils.h> +#include <spa/param/audio/wma-utils.h> +#include <spa/param/audio/ra-utils.h> +#include <spa/param/audio/amr-utils.h> +#include <spa/param/audio/alac-utils.h> +#include <spa/param/audio/flac-utils.h> +#include <spa/param/audio/ape-utils.h> -static inline int -spa_format_audio_dsp_parse(const struct spa_pod *format, struct spa_audio_info_dsp *info) -{ - int res; - res = spa_pod_parse_object(format, - SPA_TYPE_OBJECT_Format, NULL, - SPA_FORMAT_AUDIO_format, SPA_POD_OPT_Id(&info->format)); - return res; -} -static inline int -spa_format_audio_iec958_parse(const struct spa_pod *format, struct spa_audio_info_iec958 *info) -{ - int res; - res = spa_pod_parse_object(format, - SPA_TYPE_OBJECT_Format, NULL, - SPA_FORMAT_AUDIO_iec958Codec, SPA_POD_OPT_Id(&info->codec), - SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate)); - return res; -} +/** + * \addtogroup spa_param + * \{ + */ static inline int -spa_format_audio_dsd_parse(const struct spa_pod *format, struct spa_audio_info_dsd *info) +spa_format_audio_parse(const struct spa_pod *format, struct spa_audio_info *info) { - struct spa_pod *position = NULL; int res; - info->flags = 0; - res = spa_pod_parse_object(format, - SPA_TYPE_OBJECT_Format, NULL, - SPA_FORMAT_AUDIO_bitorder, SPA_POD_OPT_Id(&info->bitorder), - SPA_FORMAT_AUDIO_interleave, SPA_POD_OPT_Int(&info->interleave), - SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), - SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels), - SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position)); - if (position == NULL || - !spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_AUDIO_MAX_CHANNELS)) - SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED); - return res; -} - -static inline struct spa_pod * -spa_format_audio_raw_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_raw *info) -{ - struct spa_pod_frame f; - spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); - spa_pod_builder_add(builder, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), - 0); - if (info->format != SPA_AUDIO_FORMAT_UNKNOWN) - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_format, SPA_POD_Id(info->format), 0); - if (info->rate != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); - if (info->channels != 0) { - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); - if (!SPA_FLAG_IS_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED)) { - spa_pod_builder_add(builder, SPA_FORMAT_AUDIO_position, - SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, - info->channels, info->position), 0); - } + if ((res = spa_format_parse(format, &info->media_type, &info->media_subtype)) < 0) + return res; + + if (info->media_type != SPA_MEDIA_TYPE_audio) + return -EINVAL; + + switch (info->media_subtype) { + case SPA_MEDIA_SUBTYPE_raw: + return spa_format_audio_raw_parse(format, &info->info.raw); + case SPA_MEDIA_SUBTYPE_dsp: + return spa_format_audio_dsp_parse(format, &info->info.dsp); + case SPA_MEDIA_SUBTYPE_iec958: + return spa_format_audio_iec958_parse(format, &info->info.iec958); + case SPA_MEDIA_SUBTYPE_dsd: + return spa_format_audio_dsd_parse(format, &info->info.dsd); + case SPA_MEDIA_SUBTYPE_mp3: + return spa_format_audio_mp3_parse(format, &info->info.mp3); + case SPA_MEDIA_SUBTYPE_aac: + return spa_format_audio_aac_parse(format, &info->info.aac); + case SPA_MEDIA_SUBTYPE_vorbis: + return spa_format_audio_vorbis_parse(format, &info->info.vorbis); + case SPA_MEDIA_SUBTYPE_wma: + return spa_format_audio_wma_parse(format, &info->info.wma); + case SPA_MEDIA_SUBTYPE_ra: + return spa_format_audio_ra_parse(format, &info->info.ra); + case SPA_MEDIA_SUBTYPE_amr: + return spa_format_audio_amr_parse(format, &info->info.amr); + case SPA_MEDIA_SUBTYPE_alac: + return spa_format_audio_alac_parse(format, &info->info.alac); + case SPA_MEDIA_SUBTYPE_flac: + return spa_format_audio_flac_parse(format, &info->info.flac); + case SPA_MEDIA_SUBTYPE_ape: + return spa_format_audio_ape_parse(format, &info->info.ape); } - return (struct spa_pod*)spa_pod_builder_pop(builder, &f); -} - -static inline struct spa_pod * -spa_format_audio_dsp_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_dsp *info) -{ - struct spa_pod_frame f; - spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); - spa_pod_builder_add(builder, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp), - 0); - if (info->format != SPA_AUDIO_FORMAT_UNKNOWN) - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_format, SPA_POD_Id(info->format), 0); - return (struct spa_pod*)spa_pod_builder_pop(builder, &f); + return -ENOTSUP; } - static inline struct spa_pod * -spa_format_audio_iec958_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_iec958 *info) +spa_format_audio_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info *info) { - struct spa_pod_frame f; - spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); - spa_pod_builder_add(builder, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_iec958), - 0); - if (info->codec != SPA_AUDIO_IEC958_CODEC_UNKNOWN) - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_iec958Codec, SPA_POD_Id(info->codec), 0); - if (info->rate != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); - return (struct spa_pod*)spa_pod_builder_pop(builder, &f); -} - -static inline struct spa_pod * -spa_format_audio_dsd_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_dsd *info) -{ - struct spa_pod_frame f; - spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); - spa_pod_builder_add(builder, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsd), - 0); - if (info->bitorder != SPA_PARAM_BITORDER_unknown) - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_bitorder, SPA_POD_Id(info->bitorder), 0); - if (info->interleave != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_interleave, SPA_POD_Int(info->interleave), 0); - if (info->rate != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); - if (info->channels != 0) { - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); - if (!SPA_FLAG_IS_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED)) { - spa_pod_builder_add(builder, SPA_FORMAT_AUDIO_position, - SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, - info->channels, info->position), 0); - } + switch (info->media_subtype) { + case SPA_MEDIA_SUBTYPE_raw: + return spa_format_audio_raw_build(builder, id, &info->info.raw); + case SPA_MEDIA_SUBTYPE_dsp: + return spa_format_audio_dsp_build(builder, id, &info->info.dsp); + case SPA_MEDIA_SUBTYPE_iec958: + return spa_format_audio_iec958_build(builder, id, &info->info.iec958); + case SPA_MEDIA_SUBTYPE_dsd: + return spa_format_audio_dsd_build(builder, id, &info->info.dsd); + case SPA_MEDIA_SUBTYPE_mp3: + return spa_format_audio_mp3_build(builder, id, &info->info.mp3); + case SPA_MEDIA_SUBTYPE_aac: + return spa_format_audio_aac_build(builder, id, &info->info.aac); + case SPA_MEDIA_SUBTYPE_vorbis: + return spa_format_audio_vorbis_build(builder, id, &info->info.vorbis); + case SPA_MEDIA_SUBTYPE_wma: + return spa_format_audio_wma_build(builder, id, &info->info.wma); + case SPA_MEDIA_SUBTYPE_ra: + return spa_format_audio_ra_build(builder, id, &info->info.ra); + case SPA_MEDIA_SUBTYPE_amr: + return spa_format_audio_amr_build(builder, id, &info->info.amr); + case SPA_MEDIA_SUBTYPE_alac: + return spa_format_audio_alac_build(builder, id, &info->info.alac); + case SPA_MEDIA_SUBTYPE_flac: + return spa_format_audio_flac_build(builder, id, &info->info.flac); + case SPA_MEDIA_SUBTYPE_ape: + return spa_format_audio_ape_build(builder, id, &info->info.ape); } - return (struct spa_pod*)spa_pod_builder_pop(builder, &f); + errno = ENOTSUP; + return NULL; } - /** * \} */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/audio/format.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/format.h
Changed
@@ -36,8 +36,18 @@ #include <spa/param/format.h> #include <spa/param/audio/raw.h> +#include <spa/param/audio/dsp.h> #include <spa/param/audio/iec958.h> #include <spa/param/audio/dsd.h> +#include <spa/param/audio/mp3.h> +#include <spa/param/audio/aac.h> +#include <spa/param/audio/vorbis.h> +#include <spa/param/audio/wma.h> +#include <spa/param/audio/ra.h> +#include <spa/param/audio/amr.h> +#include <spa/param/audio/alac.h> +#include <spa/param/audio/flac.h> +#include <spa/param/audio/ape.h> struct spa_audio_info { uint32_t media_type; @@ -47,6 +57,15 @@ struct spa_audio_info_dsp dsp; struct spa_audio_info_iec958 iec958; struct spa_audio_info_dsd dsd; + struct spa_audio_info_mp3 mp3; + struct spa_audio_info_aac aac; + struct spa_audio_info_vorbis vorbis; + struct spa_audio_info_wma wma; + struct spa_audio_info_ra ra; + struct spa_audio_info_amr amr; + struct spa_audio_info_alac alac; + struct spa_audio_info_flac flac; + struct spa_audio_info_ape ape; } info; };
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/iec958-types.h
Added
@@ -0,0 +1,59 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_IEC958_TYPES_H +#define SPA_AUDIO_IEC958_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/utils/type.h> +#include <spa/param/audio/iec958.h> + +#define SPA_TYPE_INFO_AudioIEC958Codec SPA_TYPE_INFO_ENUM_BASE "AudioIEC958Codec" +#define SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE SPA_TYPE_INFO_AudioIEC958Codec ":" + +static const struct spa_type_info spa_type_audio_iec958_codec = { + { SPA_AUDIO_IEC958_CODEC_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "UNKNOWN", NULL }, + { SPA_AUDIO_IEC958_CODEC_PCM, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "PCM", NULL }, + { SPA_AUDIO_IEC958_CODEC_DTS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "DTS", NULL }, + { SPA_AUDIO_IEC958_CODEC_AC3, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "AC3", NULL }, + { SPA_AUDIO_IEC958_CODEC_MPEG, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "MPEG", NULL }, + { SPA_AUDIO_IEC958_CODEC_MPEG2_AAC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "MPEG2-AAC", NULL }, + { SPA_AUDIO_IEC958_CODEC_EAC3, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "EAC3", NULL }, + { SPA_AUDIO_IEC958_CODEC_TRUEHD, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "TrueHD", NULL }, + { SPA_AUDIO_IEC958_CODEC_DTSHD, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "DTS-HD", NULL }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_RAW_IEC958_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/iec958-utils.h
Added
@@ -0,0 +1,79 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_IEC958_UTILS_H +#define SPA_AUDIO_IEC958_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_iec958_parse(const struct spa_pod *format, struct spa_audio_info_iec958 *info) +{ + int res; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_iec958Codec, SPA_POD_OPT_Id(&info->codec), + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate)); + return res; +} + +static inline struct spa_pod * +spa_format_audio_iec958_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_iec958 *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_iec958), + 0); + if (info->codec != SPA_AUDIO_IEC958_CODEC_UNKNOWN) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_iec958Codec, SPA_POD_Id(info->codec), 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_IEC958_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/mp3-types.h
Added
@@ -0,0 +1,54 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_MP3_TYPES_H +#define SPA_AUDIO_MP3_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/utils/type.h> +#include <spa/param/audio/mp3.h> + +#define SPA_TYPE_INFO_AudioMP3ChannelMode SPA_TYPE_INFO_ENUM_BASE "AudioMP3ChannelMode" +#define SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE SPA_TYPE_INFO_AudioMP3ChannelMode ":" + +static const struct spa_type_info spa_type_audio_mp3_channel_mode = { + { SPA_AUDIO_MP3_CHANNEL_MODE_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE "UNKNOWN", NULL }, + { SPA_AUDIO_MP3_CHANNEL_MODE_MONO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE "Mono", NULL }, + { SPA_AUDIO_MP3_CHANNEL_MODE_STEREO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE "Stereo", NULL }, + { SPA_AUDIO_MP3_CHANNEL_MODE_JOINTSTEREO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE "Joint-stereo", NULL }, + { SPA_AUDIO_MP3_CHANNEL_MODE_DUAL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_MP3_CHANNEL_MODE_BASE "Dual", NULL }, + { 0, 0, NULL, NULL }, +}; +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_MP3_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/mp3-utils.h
Added
@@ -0,0 +1,80 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_MP3_UTILS_H +#define SPA_AUDIO_MP3_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_mp3_parse(const struct spa_pod *format, struct spa_audio_info_mp3 *info) +{ + int res; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels)); + return res; +} + +static inline struct spa_pod * +spa_format_audio_mp3_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_mp3 *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_mp3), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_ENCODED), + 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + if (info->channels != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_MP3_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/mp3.h
Added
@@ -0,0 +1,57 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_MP3_H +#define SPA_AUDIO_MP3_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/param/audio/raw.h> + +enum spa_audio_mp3_channel_mode { + SPA_AUDIO_MP3_CHANNEL_MODE_UNKNOWN, + SPA_AUDIO_MP3_CHANNEL_MODE_MONO, + SPA_AUDIO_MP3_CHANNEL_MODE_STEREO, + SPA_AUDIO_MP3_CHANNEL_MODE_JOINTSTEREO, + SPA_AUDIO_MP3_CHANNEL_MODE_DUAL, +}; + +struct spa_audio_info_mp3 { + uint32_t rate; /*< sample rate */ + uint32_t channels; /*< number of channels */ +}; + +#define SPA_AUDIO_INFO_MP3_INIT(...) ((struct spa_audio_info_mp3) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_MP3_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/ra-utils.h
Added
@@ -0,0 +1,80 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_RA_UTILS_H +#define SPA_AUDIO_RA_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_ra_parse(const struct spa_pod *format, struct spa_audio_info_ra *info) +{ + int res; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels)); + return res; +} + +static inline struct spa_pod * +spa_format_audio_ra_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_ra *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_ra), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_ENCODED), + 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + if (info->channels != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_RA_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/ra.h
Added
@@ -0,0 +1,49 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_RA_H +#define SPA_AUDIO_RA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/param/audio/raw.h> + +struct spa_audio_info_ra { + uint32_t rate; /*< sample rate */ + uint32_t channels; /*< number of channels */ +}; + +#define SPA_AUDIO_INFO_RA_INIT(...) ((struct spa_audio_info_ra) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_RA_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/raw-types.h
Added
@@ -0,0 +1,278 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_RAW_TYPES_H +#define SPA_AUDIO_RAW_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/utils/type.h> +#include <spa/param/audio/raw.h> + +#define SPA_TYPE_INFO_AudioFormat SPA_TYPE_INFO_ENUM_BASE "AudioFormat" +#define SPA_TYPE_INFO_AUDIO_FORMAT_BASE SPA_TYPE_INFO_AudioFormat ":" + +static const struct spa_type_info spa_type_audio_format = { + { SPA_AUDIO_FORMAT_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "UNKNOWN", NULL }, + { SPA_AUDIO_FORMAT_ENCODED, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "ENCODED", NULL }, + { SPA_AUDIO_FORMAT_S8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S8", NULL }, + { SPA_AUDIO_FORMAT_U8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U8", NULL }, + { SPA_AUDIO_FORMAT_S16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16LE", NULL }, + { SPA_AUDIO_FORMAT_S16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16BE", NULL }, + { SPA_AUDIO_FORMAT_U16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16LE", NULL }, + { SPA_AUDIO_FORMAT_U16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16BE", NULL }, + { SPA_AUDIO_FORMAT_S24_32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32LE", NULL }, + { SPA_AUDIO_FORMAT_S24_32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32BE", NULL }, + { SPA_AUDIO_FORMAT_U24_32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32LE", NULL }, + { SPA_AUDIO_FORMAT_U24_32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32BE", NULL }, + { SPA_AUDIO_FORMAT_S32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32LE", NULL }, + { SPA_AUDIO_FORMAT_S32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32BE", NULL }, + { SPA_AUDIO_FORMAT_U32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32LE", NULL }, + { SPA_AUDIO_FORMAT_U32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32BE", NULL }, + { SPA_AUDIO_FORMAT_S24_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24LE", NULL }, + { SPA_AUDIO_FORMAT_S24_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24BE", NULL }, + { SPA_AUDIO_FORMAT_U24_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24LE", NULL }, + { SPA_AUDIO_FORMAT_U24_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24BE", NULL }, + { SPA_AUDIO_FORMAT_S20_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20LE", NULL }, + { SPA_AUDIO_FORMAT_S20_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20BE", NULL }, + { SPA_AUDIO_FORMAT_U20_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20LE", NULL }, + { SPA_AUDIO_FORMAT_U20_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20BE", NULL }, + { SPA_AUDIO_FORMAT_S18_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18LE", NULL }, + { SPA_AUDIO_FORMAT_S18_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18BE", NULL }, + { SPA_AUDIO_FORMAT_U18_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18LE", NULL }, + { SPA_AUDIO_FORMAT_U18_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18BE", NULL }, + { SPA_AUDIO_FORMAT_F32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32LE", NULL }, + { SPA_AUDIO_FORMAT_F32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32BE", NULL }, + { SPA_AUDIO_FORMAT_F64_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64LE", NULL }, + { SPA_AUDIO_FORMAT_F64_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64BE", NULL }, + + { SPA_AUDIO_FORMAT_ULAW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "ULAW", NULL }, + { SPA_AUDIO_FORMAT_ALAW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "ALAW", NULL }, + + { SPA_AUDIO_FORMAT_U8P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U8P", NULL }, + { SPA_AUDIO_FORMAT_S16P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16P", NULL }, + { SPA_AUDIO_FORMAT_S24_32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32P", NULL }, + { SPA_AUDIO_FORMAT_S32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32P", NULL }, + { SPA_AUDIO_FORMAT_S24P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24P", NULL }, + { SPA_AUDIO_FORMAT_F32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32P", NULL }, + { SPA_AUDIO_FORMAT_F64P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64P", NULL }, + { SPA_AUDIO_FORMAT_S8P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S8P", NULL }, + +#if __BYTE_ORDER == __BIG_ENDIAN + { SPA_AUDIO_FORMAT_S16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16OE", NULL }, + { SPA_AUDIO_FORMAT_S16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16", NULL }, + { SPA_AUDIO_FORMAT_U16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16OE", NULL }, + { SPA_AUDIO_FORMAT_U16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16", NULL }, + { SPA_AUDIO_FORMAT_S24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32OE", NULL }, + { SPA_AUDIO_FORMAT_S24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32", NULL }, + { SPA_AUDIO_FORMAT_U24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32OE", NULL }, + { SPA_AUDIO_FORMAT_U24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32", NULL }, + { SPA_AUDIO_FORMAT_S32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32OE", NULL }, + { SPA_AUDIO_FORMAT_S32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32", NULL }, + { SPA_AUDIO_FORMAT_U32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32OE", NULL }, + { SPA_AUDIO_FORMAT_U32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32", NULL }, + { SPA_AUDIO_FORMAT_S24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24OE", NULL }, + { SPA_AUDIO_FORMAT_S24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24", NULL }, + { SPA_AUDIO_FORMAT_U24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24OE", NULL }, + { SPA_AUDIO_FORMAT_U24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24", NULL }, + { SPA_AUDIO_FORMAT_S20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20OE", NULL }, + { SPA_AUDIO_FORMAT_S20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20", NULL }, + { SPA_AUDIO_FORMAT_U20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20OE", NULL }, + { SPA_AUDIO_FORMAT_U20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20", NULL }, + { SPA_AUDIO_FORMAT_S18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18OE", NULL }, + { SPA_AUDIO_FORMAT_S18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18", NULL }, + { SPA_AUDIO_FORMAT_U18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18OE", NULL }, + { SPA_AUDIO_FORMAT_U18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18", NULL }, + { SPA_AUDIO_FORMAT_F32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32OE", NULL }, + { SPA_AUDIO_FORMAT_F32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32", NULL }, + { SPA_AUDIO_FORMAT_F64_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64OE", NULL }, + { SPA_AUDIO_FORMAT_F64, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64", NULL }, +#elif __BYTE_ORDER == __LITTLE_ENDIAN + { SPA_AUDIO_FORMAT_S16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16", NULL }, + { SPA_AUDIO_FORMAT_S16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16OE", NULL }, + { SPA_AUDIO_FORMAT_U16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16", NULL }, + { SPA_AUDIO_FORMAT_U16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16OE", NULL }, + { SPA_AUDIO_FORMAT_S24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32", NULL }, + { SPA_AUDIO_FORMAT_S24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32OE", NULL }, + { SPA_AUDIO_FORMAT_U24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32", NULL }, + { SPA_AUDIO_FORMAT_U24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32OE", NULL }, + { SPA_AUDIO_FORMAT_S32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32", NULL }, + { SPA_AUDIO_FORMAT_S32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32OE", NULL }, + { SPA_AUDIO_FORMAT_U32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32", NULL }, + { SPA_AUDIO_FORMAT_U32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32OE", NULL }, + { SPA_AUDIO_FORMAT_S24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24", NULL }, + { SPA_AUDIO_FORMAT_S24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24OE", NULL }, + { SPA_AUDIO_FORMAT_U24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24", NULL }, + { SPA_AUDIO_FORMAT_U24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24OE", NULL }, + { SPA_AUDIO_FORMAT_S20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20", NULL }, + { SPA_AUDIO_FORMAT_S20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20OE", NULL }, + { SPA_AUDIO_FORMAT_U20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20", NULL }, + { SPA_AUDIO_FORMAT_U20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20OE", NULL }, + { SPA_AUDIO_FORMAT_S18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18", NULL }, + { SPA_AUDIO_FORMAT_S18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18OE", NULL }, + { SPA_AUDIO_FORMAT_U18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18", NULL }, + { SPA_AUDIO_FORMAT_U18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18OE", NULL }, + { SPA_AUDIO_FORMAT_F32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32", NULL }, + { SPA_AUDIO_FORMAT_F32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32OE", NULL }, + { SPA_AUDIO_FORMAT_F64, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64", NULL }, + { SPA_AUDIO_FORMAT_F64_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64OE", NULL }, +#endif + { 0, 0, NULL, NULL }, +}; + +#define SPA_TYPE_INFO_AudioFlags SPA_TYPE_INFO_FLAGS_BASE "AudioFlags" +#define SPA_TYPE_INFO_AUDIO_FLAGS_BASE SPA_TYPE_INFO_AudioFlags ":" + +static const struct spa_type_info spa_type_audio_flags = { + { SPA_AUDIO_FLAG_NONE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FLAGS_BASE "none", NULL }, + { SPA_AUDIO_FLAG_UNPOSITIONED, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FLAGS_BASE "unpositioned", NULL }, + { 0, 0, NULL, NULL }, +}; + +#define SPA_TYPE_INFO_AudioChannel SPA_TYPE_INFO_ENUM_BASE "AudioChannel" +#define SPA_TYPE_INFO_AUDIO_CHANNEL_BASE SPA_TYPE_INFO_AudioChannel ":" + +static const struct spa_type_info spa_type_audio_channel = { + { SPA_AUDIO_CHANNEL_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "UNK", NULL }, + { SPA_AUDIO_CHANNEL_NA, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "NA", NULL }, + { SPA_AUDIO_CHANNEL_MONO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "MONO", NULL }, + { SPA_AUDIO_CHANNEL_FL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FL", NULL }, + { SPA_AUDIO_CHANNEL_FR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FR", NULL }, + { SPA_AUDIO_CHANNEL_FC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FC", NULL }, + { SPA_AUDIO_CHANNEL_LFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LFE", NULL }, + { SPA_AUDIO_CHANNEL_SL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "SL", NULL }, + { SPA_AUDIO_CHANNEL_SR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "SR", NULL }, + { SPA_AUDIO_CHANNEL_FLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLC", NULL }, + { SPA_AUDIO_CHANNEL_FRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRC", NULL }, + { SPA_AUDIO_CHANNEL_RC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RC", NULL }, + { SPA_AUDIO_CHANNEL_RL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RL", NULL }, + { SPA_AUDIO_CHANNEL_RR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RR", NULL }, + { SPA_AUDIO_CHANNEL_TC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TC", NULL }, + { SPA_AUDIO_CHANNEL_TFL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFL", NULL }, + { SPA_AUDIO_CHANNEL_TFC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFC", NULL }, + { SPA_AUDIO_CHANNEL_TFR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFR", NULL }, + { SPA_AUDIO_CHANNEL_TRL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRL", NULL }, + { SPA_AUDIO_CHANNEL_TRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRC", NULL }, + { SPA_AUDIO_CHANNEL_TRR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRR", NULL }, + { SPA_AUDIO_CHANNEL_RLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RLC", NULL }, + { SPA_AUDIO_CHANNEL_RRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RRC", NULL }, + { SPA_AUDIO_CHANNEL_FLW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLW", NULL }, + { SPA_AUDIO_CHANNEL_FRW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRW", NULL }, + { SPA_AUDIO_CHANNEL_LFE2, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LFE2", NULL }, + { SPA_AUDIO_CHANNEL_FLH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLH", NULL }, + { SPA_AUDIO_CHANNEL_FCH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FCH", NULL }, + { SPA_AUDIO_CHANNEL_FRH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRH", NULL }, + { SPA_AUDIO_CHANNEL_TFLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFLC", NULL }, + { SPA_AUDIO_CHANNEL_TFRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFRC", NULL }, + { SPA_AUDIO_CHANNEL_TSL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TSL", NULL }, + { SPA_AUDIO_CHANNEL_TSR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TSR", NULL }, + { SPA_AUDIO_CHANNEL_LLFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LLFR", NULL }, + { SPA_AUDIO_CHANNEL_RLFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RLFE", NULL }, + { SPA_AUDIO_CHANNEL_BC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BC", NULL }, + { SPA_AUDIO_CHANNEL_BLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BLC", NULL }, + { SPA_AUDIO_CHANNEL_BRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BRC", NULL }, + + { SPA_AUDIO_CHANNEL_AUX0, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX0", NULL }, + { SPA_AUDIO_CHANNEL_AUX1, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX1", NULL }, + { SPA_AUDIO_CHANNEL_AUX2, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX2", NULL }, + { SPA_AUDIO_CHANNEL_AUX3, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX3", NULL }, + { SPA_AUDIO_CHANNEL_AUX4, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX4", NULL }, + { SPA_AUDIO_CHANNEL_AUX5, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX5", NULL }, + { SPA_AUDIO_CHANNEL_AUX6, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX6", NULL }, + { SPA_AUDIO_CHANNEL_AUX7, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX7", NULL }, + { SPA_AUDIO_CHANNEL_AUX8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX8", NULL }, + { SPA_AUDIO_CHANNEL_AUX9, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX9", NULL }, + { SPA_AUDIO_CHANNEL_AUX10, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX10", NULL }, + { SPA_AUDIO_CHANNEL_AUX11, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX11", NULL }, + { SPA_AUDIO_CHANNEL_AUX12, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX12", NULL }, + { SPA_AUDIO_CHANNEL_AUX13, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX13", NULL }, + { SPA_AUDIO_CHANNEL_AUX14, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX14", NULL }, + { SPA_AUDIO_CHANNEL_AUX15, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX15", NULL }, + { SPA_AUDIO_CHANNEL_AUX16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX16", NULL }, + { SPA_AUDIO_CHANNEL_AUX17, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX17", NULL }, + { SPA_AUDIO_CHANNEL_AUX18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX18", NULL }, + { SPA_AUDIO_CHANNEL_AUX19, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX19", NULL }, + { SPA_AUDIO_CHANNEL_AUX20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX20", NULL }, + { SPA_AUDIO_CHANNEL_AUX21, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX21", NULL }, + { SPA_AUDIO_CHANNEL_AUX22, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX22", NULL }, + { SPA_AUDIO_CHANNEL_AUX23, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX23", NULL }, + { SPA_AUDIO_CHANNEL_AUX24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX24", NULL }, + { SPA_AUDIO_CHANNEL_AUX25, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX25", NULL }, + { SPA_AUDIO_CHANNEL_AUX26, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX26", NULL }, + { SPA_AUDIO_CHANNEL_AUX27, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX27", NULL }, + { SPA_AUDIO_CHANNEL_AUX28, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX28", NULL }, + { SPA_AUDIO_CHANNEL_AUX29, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX29", NULL }, + { SPA_AUDIO_CHANNEL_AUX30, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX30", NULL }, + { SPA_AUDIO_CHANNEL_AUX31, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX31", NULL }, + { SPA_AUDIO_CHANNEL_AUX32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX32", NULL }, + { SPA_AUDIO_CHANNEL_AUX33, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX33", NULL }, + { SPA_AUDIO_CHANNEL_AUX34, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX34", NULL }, + { SPA_AUDIO_CHANNEL_AUX35, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX35", NULL }, + { SPA_AUDIO_CHANNEL_AUX36, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX36", NULL }, + { SPA_AUDIO_CHANNEL_AUX37, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX37", NULL }, + { SPA_AUDIO_CHANNEL_AUX38, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX38", NULL }, + { SPA_AUDIO_CHANNEL_AUX39, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX39", NULL }, + { SPA_AUDIO_CHANNEL_AUX40, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX40", NULL }, + { SPA_AUDIO_CHANNEL_AUX41, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX41", NULL }, + { SPA_AUDIO_CHANNEL_AUX42, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX42", NULL }, + { SPA_AUDIO_CHANNEL_AUX43, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX43", NULL }, + { SPA_AUDIO_CHANNEL_AUX44, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX44", NULL }, + { SPA_AUDIO_CHANNEL_AUX45, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX45", NULL }, + { SPA_AUDIO_CHANNEL_AUX46, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX46", NULL }, + { SPA_AUDIO_CHANNEL_AUX47, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX47", NULL }, + { SPA_AUDIO_CHANNEL_AUX48, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX48", NULL }, + { SPA_AUDIO_CHANNEL_AUX49, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX49", NULL }, + { SPA_AUDIO_CHANNEL_AUX50, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX50", NULL }, + { SPA_AUDIO_CHANNEL_AUX51, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX51", NULL }, + { SPA_AUDIO_CHANNEL_AUX52, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX52", NULL }, + { SPA_AUDIO_CHANNEL_AUX53, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX53", NULL }, + { SPA_AUDIO_CHANNEL_AUX54, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX54", NULL }, + { SPA_AUDIO_CHANNEL_AUX55, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX55", NULL }, + { SPA_AUDIO_CHANNEL_AUX56, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX56", NULL }, + { SPA_AUDIO_CHANNEL_AUX57, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX57", NULL }, + { SPA_AUDIO_CHANNEL_AUX58, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX58", NULL }, + { SPA_AUDIO_CHANNEL_AUX59, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX59", NULL }, + { SPA_AUDIO_CHANNEL_AUX60, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX60", NULL }, + { SPA_AUDIO_CHANNEL_AUX61, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX61", NULL }, + { SPA_AUDIO_CHANNEL_AUX62, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX62", NULL }, + { SPA_AUDIO_CHANNEL_AUX63, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX63", NULL }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_RAW_RAW_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/raw-utils.h
Added
@@ -0,0 +1,96 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_RAW_UTILS_H +#define SPA_AUDIO_RAW_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_raw_parse(const struct spa_pod *format, struct spa_audio_info_raw *info) +{ + struct spa_pod *position = NULL; + int res; + info->flags = 0; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_format, SPA_POD_OPT_Id(&info->format), + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels), + SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position)); + if (position == NULL || + !spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_AUDIO_MAX_CHANNELS)) + SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED); + + return res; +} + +static inline struct spa_pod * +spa_format_audio_raw_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_raw *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), + 0); + if (info->format != SPA_AUDIO_FORMAT_UNKNOWN) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_format, SPA_POD_Id(info->format), 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + if (info->channels != 0) { + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); + if (!SPA_FLAG_IS_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED)) { + spa_pod_builder_add(builder, SPA_FORMAT_AUDIO_position, + SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, + info->channels, info->position), 0); + } + } + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_RAW_UTILS_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/audio/raw.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/raw.h
Changed
@@ -306,13 +306,6 @@ * of channels ex. "FL,FR" */ #define SPA_KEY_AUDIO_ALLOWED_RATES "audio.allowed-rates" /**< a list of allowed samplerates * ex. " 44100 48000 " */ - -struct spa_audio_info_dsp { - enum spa_audio_format format; /*< format, one of the DSP formats in enum spa_audio_format_dsp */ -}; - -#define SPA_AUDIO_INFO_DSP_INIT(...) ((struct spa_audio_info_dsp) { __VA_ARGS__ }) - /** * \} */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/audio/type-info.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/type-info.h
Changed
@@ -25,272 +25,11 @@ #ifndef SPA_AUDIO_TYPES_H #define SPA_AUDIO_TYPES_H -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \addtogroup spa_param - * \{ - */ - -#include <spa/param/audio/raw.h> - -#define SPA_TYPE_INFO_AudioFormat SPA_TYPE_INFO_ENUM_BASE "AudioFormat" -#define SPA_TYPE_INFO_AUDIO_FORMAT_BASE SPA_TYPE_INFO_AudioFormat ":" - -static const struct spa_type_info spa_type_audio_format = { - { SPA_AUDIO_FORMAT_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "UNKNOWN", NULL }, - { SPA_AUDIO_FORMAT_ENCODED, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "ENCODED", NULL }, - { SPA_AUDIO_FORMAT_S8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S8", NULL }, - { SPA_AUDIO_FORMAT_U8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U8", NULL }, - { SPA_AUDIO_FORMAT_S16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16LE", NULL }, - { SPA_AUDIO_FORMAT_S16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16BE", NULL }, - { SPA_AUDIO_FORMAT_U16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16LE", NULL }, - { SPA_AUDIO_FORMAT_U16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16BE", NULL }, - { SPA_AUDIO_FORMAT_S24_32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32LE", NULL }, - { SPA_AUDIO_FORMAT_S24_32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32BE", NULL }, - { SPA_AUDIO_FORMAT_U24_32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32LE", NULL }, - { SPA_AUDIO_FORMAT_U24_32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32BE", NULL }, - { SPA_AUDIO_FORMAT_S32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32LE", NULL }, - { SPA_AUDIO_FORMAT_S32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32BE", NULL }, - { SPA_AUDIO_FORMAT_U32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32LE", NULL }, - { SPA_AUDIO_FORMAT_U32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32BE", NULL }, - { SPA_AUDIO_FORMAT_S24_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24LE", NULL }, - { SPA_AUDIO_FORMAT_S24_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24BE", NULL }, - { SPA_AUDIO_FORMAT_U24_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24LE", NULL }, - { SPA_AUDIO_FORMAT_U24_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24BE", NULL }, - { SPA_AUDIO_FORMAT_S20_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20LE", NULL }, - { SPA_AUDIO_FORMAT_S20_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20BE", NULL }, - { SPA_AUDIO_FORMAT_U20_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20LE", NULL }, - { SPA_AUDIO_FORMAT_U20_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20BE", NULL }, - { SPA_AUDIO_FORMAT_S18_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18LE", NULL }, - { SPA_AUDIO_FORMAT_S18_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18BE", NULL }, - { SPA_AUDIO_FORMAT_U18_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18LE", NULL }, - { SPA_AUDIO_FORMAT_U18_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18BE", NULL }, - { SPA_AUDIO_FORMAT_F32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32LE", NULL }, - { SPA_AUDIO_FORMAT_F32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32BE", NULL }, - { SPA_AUDIO_FORMAT_F64_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64LE", NULL }, - { SPA_AUDIO_FORMAT_F64_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64BE", NULL }, - - { SPA_AUDIO_FORMAT_ULAW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "ULAW", NULL }, - { SPA_AUDIO_FORMAT_ALAW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "ALAW", NULL }, - - { SPA_AUDIO_FORMAT_U8P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U8P", NULL }, - { SPA_AUDIO_FORMAT_S16P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16P", NULL }, - { SPA_AUDIO_FORMAT_S24_32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32P", NULL }, - { SPA_AUDIO_FORMAT_S32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32P", NULL }, - { SPA_AUDIO_FORMAT_S24P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24P", NULL }, - { SPA_AUDIO_FORMAT_F32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32P", NULL }, - { SPA_AUDIO_FORMAT_F64P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64P", NULL }, - { SPA_AUDIO_FORMAT_S8P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S8P", NULL }, - -#if __BYTE_ORDER == __BIG_ENDIAN - { SPA_AUDIO_FORMAT_S16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16OE", NULL }, - { SPA_AUDIO_FORMAT_S16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16", NULL }, - { SPA_AUDIO_FORMAT_U16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16OE", NULL }, - { SPA_AUDIO_FORMAT_U16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16", NULL }, - { SPA_AUDIO_FORMAT_S24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32OE", NULL }, - { SPA_AUDIO_FORMAT_S24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32", NULL }, - { SPA_AUDIO_FORMAT_U24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32OE", NULL }, - { SPA_AUDIO_FORMAT_U24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32", NULL }, - { SPA_AUDIO_FORMAT_S32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32OE", NULL }, - { SPA_AUDIO_FORMAT_S32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32", NULL }, - { SPA_AUDIO_FORMAT_U32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32OE", NULL }, - { SPA_AUDIO_FORMAT_U32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32", NULL }, - { SPA_AUDIO_FORMAT_S24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24OE", NULL }, - { SPA_AUDIO_FORMAT_S24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24", NULL }, - { SPA_AUDIO_FORMAT_U24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24OE", NULL }, - { SPA_AUDIO_FORMAT_U24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24", NULL }, - { SPA_AUDIO_FORMAT_S20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20OE", NULL }, - { SPA_AUDIO_FORMAT_S20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20", NULL }, - { SPA_AUDIO_FORMAT_U20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20OE", NULL }, - { SPA_AUDIO_FORMAT_U20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20", NULL }, - { SPA_AUDIO_FORMAT_S18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18OE", NULL }, - { SPA_AUDIO_FORMAT_S18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18", NULL }, - { SPA_AUDIO_FORMAT_U18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18OE", NULL }, - { SPA_AUDIO_FORMAT_U18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18", NULL }, - { SPA_AUDIO_FORMAT_F32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32OE", NULL }, - { SPA_AUDIO_FORMAT_F32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32", NULL }, - { SPA_AUDIO_FORMAT_F64_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64OE", NULL }, - { SPA_AUDIO_FORMAT_F64, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64", NULL }, -#elif __BYTE_ORDER == __LITTLE_ENDIAN - { SPA_AUDIO_FORMAT_S16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16", NULL }, - { SPA_AUDIO_FORMAT_S16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16OE", NULL }, - { SPA_AUDIO_FORMAT_U16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16", NULL }, - { SPA_AUDIO_FORMAT_U16_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16OE", NULL }, - { SPA_AUDIO_FORMAT_S24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32", NULL }, - { SPA_AUDIO_FORMAT_S24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32OE", NULL }, - { SPA_AUDIO_FORMAT_U24_32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32", NULL }, - { SPA_AUDIO_FORMAT_U24_32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32OE", NULL }, - { SPA_AUDIO_FORMAT_S32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32", NULL }, - { SPA_AUDIO_FORMAT_S32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32OE", NULL }, - { SPA_AUDIO_FORMAT_U32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32", NULL }, - { SPA_AUDIO_FORMAT_U32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32OE", NULL }, - { SPA_AUDIO_FORMAT_S24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24", NULL }, - { SPA_AUDIO_FORMAT_S24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24OE", NULL }, - { SPA_AUDIO_FORMAT_U24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24", NULL }, - { SPA_AUDIO_FORMAT_U24_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24OE", NULL }, - { SPA_AUDIO_FORMAT_S20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20", NULL }, - { SPA_AUDIO_FORMAT_S20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20OE", NULL }, - { SPA_AUDIO_FORMAT_U20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20", NULL }, - { SPA_AUDIO_FORMAT_U20_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20OE", NULL }, - { SPA_AUDIO_FORMAT_S18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18", NULL }, - { SPA_AUDIO_FORMAT_S18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18OE", NULL }, - { SPA_AUDIO_FORMAT_U18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18", NULL }, - { SPA_AUDIO_FORMAT_U18_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18OE", NULL }, - { SPA_AUDIO_FORMAT_F32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32", NULL }, - { SPA_AUDIO_FORMAT_F32_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32OE", NULL }, - { SPA_AUDIO_FORMAT_F64, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64", NULL }, - { SPA_AUDIO_FORMAT_F64_OE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64OE", NULL }, -#endif - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_AudioFlags SPA_TYPE_INFO_FLAGS_BASE "AudioFlags" -#define SPA_TYPE_INFO_AUDIO_FLAGS_BASE SPA_TYPE_INFO_AudioFlags ":" - -static const struct spa_type_info spa_type_audio_flags = { - { SPA_AUDIO_FLAG_NONE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FLAGS_BASE "none", NULL }, - { SPA_AUDIO_FLAG_UNPOSITIONED, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FLAGS_BASE "unpositioned", NULL }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_AudioChannel SPA_TYPE_INFO_ENUM_BASE "AudioChannel" -#define SPA_TYPE_INFO_AUDIO_CHANNEL_BASE SPA_TYPE_INFO_AudioChannel ":" - -static const struct spa_type_info spa_type_audio_channel = { - { SPA_AUDIO_CHANNEL_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "UNK", NULL }, - { SPA_AUDIO_CHANNEL_NA, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "NA", NULL }, - { SPA_AUDIO_CHANNEL_MONO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "MONO", NULL }, - { SPA_AUDIO_CHANNEL_FL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FL", NULL }, - { SPA_AUDIO_CHANNEL_FR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FR", NULL }, - { SPA_AUDIO_CHANNEL_FC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FC", NULL }, - { SPA_AUDIO_CHANNEL_LFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LFE", NULL }, - { SPA_AUDIO_CHANNEL_SL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "SL", NULL }, - { SPA_AUDIO_CHANNEL_SR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "SR", NULL }, - { SPA_AUDIO_CHANNEL_FLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLC", NULL }, - { SPA_AUDIO_CHANNEL_FRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRC", NULL }, - { SPA_AUDIO_CHANNEL_RC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RC", NULL }, - { SPA_AUDIO_CHANNEL_RL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RL", NULL }, - { SPA_AUDIO_CHANNEL_RR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RR", NULL }, - { SPA_AUDIO_CHANNEL_TC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TC", NULL }, - { SPA_AUDIO_CHANNEL_TFL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFL", NULL }, - { SPA_AUDIO_CHANNEL_TFC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFC", NULL }, - { SPA_AUDIO_CHANNEL_TFR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFR", NULL }, - { SPA_AUDIO_CHANNEL_TRL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRL", NULL }, - { SPA_AUDIO_CHANNEL_TRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRC", NULL }, - { SPA_AUDIO_CHANNEL_TRR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRR", NULL }, - { SPA_AUDIO_CHANNEL_RLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RLC", NULL }, - { SPA_AUDIO_CHANNEL_RRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RRC", NULL }, - { SPA_AUDIO_CHANNEL_FLW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLW", NULL }, - { SPA_AUDIO_CHANNEL_FRW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRW", NULL }, - { SPA_AUDIO_CHANNEL_LFE2, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LFE2", NULL }, - { SPA_AUDIO_CHANNEL_FLH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLH", NULL }, - { SPA_AUDIO_CHANNEL_FCH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FCH", NULL }, - { SPA_AUDIO_CHANNEL_FRH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRH", NULL }, - { SPA_AUDIO_CHANNEL_TFLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFLC", NULL }, - { SPA_AUDIO_CHANNEL_TFRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFRC", NULL }, - { SPA_AUDIO_CHANNEL_TSL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TSL", NULL }, - { SPA_AUDIO_CHANNEL_TSR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TSR", NULL }, - { SPA_AUDIO_CHANNEL_LLFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LLFR", NULL }, - { SPA_AUDIO_CHANNEL_RLFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RLFE", NULL }, - { SPA_AUDIO_CHANNEL_BC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BC", NULL }, - { SPA_AUDIO_CHANNEL_BLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BLC", NULL }, - { SPA_AUDIO_CHANNEL_BRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BRC", NULL }, - - { SPA_AUDIO_CHANNEL_AUX0, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX0", NULL }, - { SPA_AUDIO_CHANNEL_AUX1, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX1", NULL }, - { SPA_AUDIO_CHANNEL_AUX2, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX2", NULL }, - { SPA_AUDIO_CHANNEL_AUX3, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX3", NULL }, - { SPA_AUDIO_CHANNEL_AUX4, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX4", NULL }, - { SPA_AUDIO_CHANNEL_AUX5, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX5", NULL }, - { SPA_AUDIO_CHANNEL_AUX6, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX6", NULL }, - { SPA_AUDIO_CHANNEL_AUX7, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX7", NULL }, - { SPA_AUDIO_CHANNEL_AUX8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX8", NULL }, - { SPA_AUDIO_CHANNEL_AUX9, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX9", NULL }, - { SPA_AUDIO_CHANNEL_AUX10, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX10", NULL }, - { SPA_AUDIO_CHANNEL_AUX11, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX11", NULL }, - { SPA_AUDIO_CHANNEL_AUX12, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX12", NULL }, - { SPA_AUDIO_CHANNEL_AUX13, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX13", NULL }, - { SPA_AUDIO_CHANNEL_AUX14, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX14", NULL }, - { SPA_AUDIO_CHANNEL_AUX15, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX15", NULL }, - { SPA_AUDIO_CHANNEL_AUX16, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX16", NULL }, - { SPA_AUDIO_CHANNEL_AUX17, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX17", NULL }, - { SPA_AUDIO_CHANNEL_AUX18, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX18", NULL }, - { SPA_AUDIO_CHANNEL_AUX19, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX19", NULL }, - { SPA_AUDIO_CHANNEL_AUX20, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX20", NULL }, - { SPA_AUDIO_CHANNEL_AUX21, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX21", NULL }, - { SPA_AUDIO_CHANNEL_AUX22, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX22", NULL }, - { SPA_AUDIO_CHANNEL_AUX23, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX23", NULL }, - { SPA_AUDIO_CHANNEL_AUX24, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX24", NULL }, - { SPA_AUDIO_CHANNEL_AUX25, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX25", NULL }, - { SPA_AUDIO_CHANNEL_AUX26, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX26", NULL }, - { SPA_AUDIO_CHANNEL_AUX27, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX27", NULL }, - { SPA_AUDIO_CHANNEL_AUX28, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX28", NULL }, - { SPA_AUDIO_CHANNEL_AUX29, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX29", NULL }, - { SPA_AUDIO_CHANNEL_AUX30, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX30", NULL }, - { SPA_AUDIO_CHANNEL_AUX31, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX31", NULL }, - { SPA_AUDIO_CHANNEL_AUX32, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX32", NULL }, - { SPA_AUDIO_CHANNEL_AUX33, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX33", NULL }, - { SPA_AUDIO_CHANNEL_AUX34, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX34", NULL }, - { SPA_AUDIO_CHANNEL_AUX35, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX35", NULL }, - { SPA_AUDIO_CHANNEL_AUX36, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX36", NULL }, - { SPA_AUDIO_CHANNEL_AUX37, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX37", NULL }, - { SPA_AUDIO_CHANNEL_AUX38, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX38", NULL }, - { SPA_AUDIO_CHANNEL_AUX39, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX39", NULL }, - { SPA_AUDIO_CHANNEL_AUX40, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX40", NULL }, - { SPA_AUDIO_CHANNEL_AUX41, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX41", NULL }, - { SPA_AUDIO_CHANNEL_AUX42, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX42", NULL }, - { SPA_AUDIO_CHANNEL_AUX43, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX43", NULL }, - { SPA_AUDIO_CHANNEL_AUX44, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX44", NULL }, - { SPA_AUDIO_CHANNEL_AUX45, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX45", NULL }, - { SPA_AUDIO_CHANNEL_AUX46, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX46", NULL }, - { SPA_AUDIO_CHANNEL_AUX47, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX47", NULL }, - { SPA_AUDIO_CHANNEL_AUX48, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX48", NULL }, - { SPA_AUDIO_CHANNEL_AUX49, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX49", NULL }, - { SPA_AUDIO_CHANNEL_AUX50, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX50", NULL }, - { SPA_AUDIO_CHANNEL_AUX51, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX51", NULL }, - { SPA_AUDIO_CHANNEL_AUX52, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX52", NULL }, - { SPA_AUDIO_CHANNEL_AUX53, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX53", NULL }, - { SPA_AUDIO_CHANNEL_AUX54, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX54", NULL }, - { SPA_AUDIO_CHANNEL_AUX55, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX55", NULL }, - { SPA_AUDIO_CHANNEL_AUX56, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX56", NULL }, - { SPA_AUDIO_CHANNEL_AUX57, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX57", NULL }, - { SPA_AUDIO_CHANNEL_AUX58, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX58", NULL }, - { SPA_AUDIO_CHANNEL_AUX59, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX59", NULL }, - { SPA_AUDIO_CHANNEL_AUX60, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX60", NULL }, - { SPA_AUDIO_CHANNEL_AUX61, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX61", NULL }, - { SPA_AUDIO_CHANNEL_AUX62, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX62", NULL }, - { SPA_AUDIO_CHANNEL_AUX63, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "AUX63", NULL }, - { 0, 0, NULL, NULL }, -}; - - -#include <spa/param/audio/iec958.h> - -#define SPA_TYPE_INFO_AudioIEC958Codec SPA_TYPE_INFO_ENUM_BASE "AudioIEC958Codec" -#define SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE SPA_TYPE_INFO_AudioIEC958Codec ":" - -static const struct spa_type_info spa_type_audio_iec958_codec = { - { SPA_AUDIO_IEC958_CODEC_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "UNKNOWN", NULL }, - { SPA_AUDIO_IEC958_CODEC_PCM, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "PCM", NULL }, - { SPA_AUDIO_IEC958_CODEC_DTS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "DTS", NULL }, - { SPA_AUDIO_IEC958_CODEC_AC3, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "AC3", NULL }, - { SPA_AUDIO_IEC958_CODEC_MPEG, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "MPEG", NULL }, - { SPA_AUDIO_IEC958_CODEC_MPEG2_AAC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "MPEG2-AAC", NULL }, - { SPA_AUDIO_IEC958_CODEC_EAC3, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "EAC3", NULL }, - { SPA_AUDIO_IEC958_CODEC_TRUEHD, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "TrueHD", NULL }, - { SPA_AUDIO_IEC958_CODEC_DTSHD, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_IEC958_CODEC_BASE "DTS-HD", NULL }, - { 0, 0, NULL, NULL }, -}; - -/** - * \} - */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* SPA_AUDIO_RAW_TYPES_H */ +#include <spa/param/audio/raw-types.h> +#include <spa/param/audio/iec958-types.h> +#include <spa/param/audio/mp3-types.h> +#include <spa/param/audio/aac-types.h> +#include <spa/param/audio/wma-types.h> +#include <spa/param/audio/amr-types.h> + +#endif /* SPA_AUDIO_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/vorbis-utils.h
Added
@@ -0,0 +1,80 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_VORBIS_UTILS_H +#define SPA_AUDIO_VORBIS_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_vorbis_parse(const struct spa_pod *format, struct spa_audio_info_vorbis *info) +{ + int res; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels)); + return res; +} + +static inline struct spa_pod * +spa_format_audio_vorbis_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_vorbis *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_vorbis), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_ENCODED), + 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + if (info->channels != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_VORBIS_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/vorbis.h
Added
@@ -0,0 +1,49 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_VORBIS_H +#define SPA_AUDIO_VORBIS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/param/audio/raw.h> + +struct spa_audio_info_vorbis { + uint32_t rate; /*< sample rate */ + uint32_t channels; /*< number of channels */ +}; + +#define SPA_AUDIO_INFO_VORBIS_INIT(...) ((struct spa_audio_info_vorbis) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_VORBIS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/wma-types.h
Added
@@ -0,0 +1,57 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_WMA_TYPES_H +#define SPA_AUDIO_WMA_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/utils/type.h> +#include <spa/param/audio/wma.h> + +#define SPA_TYPE_INFO_AudioWMAProfile SPA_TYPE_INFO_ENUM_BASE "AudioWMAProfile" +#define SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE SPA_TYPE_INFO_AudioWMAProfile ":" + +static const struct spa_type_info spa_type_audio_wma_profile = { + { SPA_AUDIO_WMA_PROFILE_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "UNKNOWN", NULL }, + { SPA_AUDIO_WMA_PROFILE_WMA7, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA7", NULL }, + { SPA_AUDIO_WMA_PROFILE_WMA8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA8", NULL }, + { SPA_AUDIO_WMA_PROFILE_WMA9, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA9", NULL }, + { SPA_AUDIO_WMA_PROFILE_WMA10, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA10", NULL }, + { SPA_AUDIO_WMA_PROFILE_WMA9_PRO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA9-Pro", NULL }, + { SPA_AUDIO_WMA_PROFILE_WMA9_LOSSLESS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA9-Lossless", NULL }, + { SPA_AUDIO_WMA_PROFILE_WMA10_LOSSLESS, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_WMA_PROFILE_BASE "WMA10-Lossless", NULL }, + { 0, 0, NULL, NULL }, +}; +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_WMA_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/wma-utils.h
Added
@@ -0,0 +1,93 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_WMA_UTILS_H +#define SPA_AUDIO_WMA_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format.h> +#include <spa/param/format-utils.h> + +static inline int +spa_format_audio_wma_parse(const struct spa_pod *format, struct spa_audio_info_wma *info) +{ + int res; + res = spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels), + SPA_FORMAT_AUDIO_bitrate, SPA_POD_OPT_Int(&info->bitrate), + SPA_FORMAT_AUDIO_blockAlign, SPA_POD_OPT_Int(&info->block_align), + SPA_FORMAT_AUDIO_WMA_profile, SPA_POD_OPT_Id(&info->profile)); + return res; +} + +static inline struct spa_pod * +spa_format_audio_wma_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_wma *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_wma), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_ENCODED), + 0); + if (info->rate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate), 0); + if (info->channels != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0); + if (info->bitrate != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_bitrate, SPA_POD_Int(info->bitrate), 0); + if (info->block_align != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_blockAlign, SPA_POD_Int(info->block_align), 0); + if (info->profile != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_AUDIO_WMA_profile, SPA_POD_Id(info->profile), 0); + + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_WMA_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/audio/wma.h
Added
@@ -0,0 +1,67 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_AUDIO_WMA_H +#define SPA_AUDIO_WMA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/param/audio/raw.h> + +enum spa_audio_wma_profile { + SPA_AUDIO_WMA_PROFILE_UNKNOWN, + + SPA_AUDIO_WMA_PROFILE_WMA7, + SPA_AUDIO_WMA_PROFILE_WMA8, + SPA_AUDIO_WMA_PROFILE_WMA9, + SPA_AUDIO_WMA_PROFILE_WMA10, + SPA_AUDIO_WMA_PROFILE_WMA9_PRO, + SPA_AUDIO_WMA_PROFILE_WMA9_LOSSLESS, + SPA_AUDIO_WMA_PROFILE_WMA10_LOSSLESS, + + SPA_AUDIO_WMA_PROFILE_CUSTOM = 0x10000, +}; + +struct spa_audio_info_wma { + uint32_t rate; /*< sample rate */ + uint32_t channels; /*< number of channels */ + uint32_t bitrate; /*< stream bitrate */ + uint32_t block_align; /*< block alignment */ + enum spa_audio_wma_profile profile; /*< WMA profile */ + +}; + +#define SPA_AUDIO_INFO_WMA_INIT(...) ((struct spa_audio_info_wma) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_WMA_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/buffers-types.h
Added
@@ -0,0 +1,90 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_BUFFERS_TYPES_H +#define SPA_PARAM_BUFFERS_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/param-types.h> +#include <spa/node/type-info.h> + +#include <spa/param/buffers.h> + +#define SPA_TYPE_INFO_PARAM_Meta SPA_TYPE_INFO_PARAM_BASE "Meta" +#define SPA_TYPE_INFO_PARAM_META_BASE SPA_TYPE_INFO_PARAM_Meta ":" + +static const struct spa_type_info spa_type_param_meta = { + { SPA_PARAM_META_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_META_BASE, spa_type_param }, + { SPA_PARAM_META_type, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_META_BASE "type", spa_type_meta_type }, + { SPA_PARAM_META_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_META_BASE "size", NULL }, + { 0, 0, NULL, NULL }, +}; + +/** Base for parameters that describe IO areas to exchange data, + * control and properties with a node. + */ +#define SPA_TYPE_INFO_PARAM_IO SPA_TYPE_INFO_PARAM_BASE "IO" +#define SPA_TYPE_INFO_PARAM_IO_BASE SPA_TYPE_INFO_PARAM_IO ":" + +static const struct spa_type_info spa_type_param_io = { + { SPA_PARAM_IO_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_IO_BASE, spa_type_param, }, + { SPA_PARAM_IO_id, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_IO_BASE "id", spa_type_io }, + { SPA_PARAM_IO_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_IO_BASE "size", NULL }, + { 0, 0, NULL, NULL }, +}; + +#define SPA_TYPE_INFO_PARAM_Buffers SPA_TYPE_INFO_PARAM_BASE "Buffers" +#define SPA_TYPE_INFO_PARAM_BUFFERS_BASE SPA_TYPE_INFO_PARAM_Buffers ":" + +#define SPA_TYPE_INFO_PARAM_BlockInfo SPA_TYPE_INFO_PARAM_BUFFERS_BASE "BlockInfo" +#define SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE SPA_TYPE_INFO_PARAM_BlockInfo ":" + +static const struct spa_type_info spa_type_param_buffers = { + { SPA_PARAM_BUFFERS_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_BUFFERS_BASE, spa_type_param, }, + { SPA_PARAM_BUFFERS_buffers, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BUFFERS_BASE "buffers", NULL }, + { SPA_PARAM_BUFFERS_blocks, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BUFFERS_BASE "blocks", NULL }, + { SPA_PARAM_BUFFERS_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "size", NULL }, + { SPA_PARAM_BUFFERS_stride, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "stride", NULL }, + { SPA_PARAM_BUFFERS_align, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "align", NULL }, + { SPA_PARAM_BUFFERS_dataType, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "dataType", NULL }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_BUFFERS_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/buffers.h
Added
@@ -0,0 +1,72 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_BUFFERS_H +#define SPA_PARAM_BUFFERS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/param.h> + +/** properties for SPA_TYPE_OBJECT_ParamBuffers */ +enum spa_param_buffers { + SPA_PARAM_BUFFERS_START, + SPA_PARAM_BUFFERS_buffers, /**< number of buffers (Int) */ + SPA_PARAM_BUFFERS_blocks, /**< number of data blocks per buffer (Int) */ + SPA_PARAM_BUFFERS_size, /**< size of a data block memory (Int)*/ + SPA_PARAM_BUFFERS_stride, /**< stride of data block memory (Int) */ + SPA_PARAM_BUFFERS_align, /**< alignment of data block memory (Int) */ + SPA_PARAM_BUFFERS_dataType, /**< possible memory types (Int, mask of enum spa_data_type) */ +}; + +/** properties for SPA_TYPE_OBJECT_ParamMeta */ +enum spa_param_meta { + SPA_PARAM_META_START, + SPA_PARAM_META_type, /**< the metadata, one of enum spa_meta_type (Id enum spa_meta_type) */ + SPA_PARAM_META_size, /**< the expected maximum size the meta (Int) */ +}; + +/** properties for SPA_TYPE_OBJECT_ParamIO */ +enum spa_param_io { + SPA_PARAM_IO_START, + SPA_PARAM_IO_id, /**< type ID, uniquely identifies the io area (Id enum spa_io_type) */ + SPA_PARAM_IO_size, /**< size of the io area (Int) */ +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_BUFFERS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/format-types.h
Added
@@ -0,0 +1,191 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_FORMAT_TYPES_H +#define SPA_PARAM_FORMAT_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/format.h> +#include <spa/param/param-types.h> + +#include <spa/param/audio/type-info.h> +#include <spa/param/video/type-info.h> + +#define SPA_TYPE_INFO_Format SPA_TYPE_INFO_PARAM_BASE "Format" +#define SPA_TYPE_INFO_FORMAT_BASE SPA_TYPE_INFO_Format ":" + +#define SPA_TYPE_INFO_MediaType SPA_TYPE_INFO_ENUM_BASE "MediaType" +#define SPA_TYPE_INFO_MEDIA_TYPE_BASE SPA_TYPE_INFO_MediaType ":" + +static const struct spa_type_info spa_type_media_type = { + { SPA_MEDIA_TYPE_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "unknown", NULL }, + { SPA_MEDIA_TYPE_audio, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "audio", NULL }, + { SPA_MEDIA_TYPE_video, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "video", NULL }, + { SPA_MEDIA_TYPE_image, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "image", NULL }, + { SPA_MEDIA_TYPE_binary, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "binary", NULL }, + { SPA_MEDIA_TYPE_stream, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "stream", NULL }, + { SPA_MEDIA_TYPE_application, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "application", NULL }, + { 0, 0, NULL, NULL }, +}; + +#define SPA_TYPE_INFO_MediaSubtype SPA_TYPE_INFO_ENUM_BASE "MediaSubtype" +#define SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE SPA_TYPE_INFO_MediaSubtype ":" + +static const struct spa_type_info spa_type_media_subtype = { + { SPA_MEDIA_SUBTYPE_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "unknown", NULL }, + /* generic subtypes */ + { SPA_MEDIA_SUBTYPE_raw, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "raw", NULL }, + { SPA_MEDIA_SUBTYPE_dsp, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "dsp", NULL }, + { SPA_MEDIA_SUBTYPE_iec958, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "iec958", NULL }, + { SPA_MEDIA_SUBTYPE_dsd, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "dsd", NULL }, + /* audio subtypes */ + { SPA_MEDIA_SUBTYPE_mp3, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mp3", NULL }, + { SPA_MEDIA_SUBTYPE_aac, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "aac", NULL }, + { SPA_MEDIA_SUBTYPE_vorbis, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vorbis", NULL }, + { SPA_MEDIA_SUBTYPE_wma, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "wma", NULL }, + { SPA_MEDIA_SUBTYPE_ra, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "ra", NULL }, + { SPA_MEDIA_SUBTYPE_sbc, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "sbc", NULL }, + { SPA_MEDIA_SUBTYPE_adpcm, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "adpcm", NULL }, + { SPA_MEDIA_SUBTYPE_g723, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g723", NULL }, + { SPA_MEDIA_SUBTYPE_g726, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g726", NULL }, + { SPA_MEDIA_SUBTYPE_g729, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g729", NULL }, + { SPA_MEDIA_SUBTYPE_amr, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "amr", NULL }, + { SPA_MEDIA_SUBTYPE_gsm, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "gsm", NULL }, + { SPA_MEDIA_SUBTYPE_alac, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "alac", NULL }, + { SPA_MEDIA_SUBTYPE_flac, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "flac", NULL }, + { SPA_MEDIA_SUBTYPE_ape, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "ape", NULL }, + /* video subtypes */ + { SPA_MEDIA_SUBTYPE_h264, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "h264", NULL }, + { SPA_MEDIA_SUBTYPE_mjpg, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mjpg", NULL }, + { SPA_MEDIA_SUBTYPE_dv, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "dv", NULL }, + { SPA_MEDIA_SUBTYPE_mpegts, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpegts", NULL }, + { SPA_MEDIA_SUBTYPE_h263, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "h263", NULL }, + { SPA_MEDIA_SUBTYPE_mpeg1, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg1", NULL }, + { SPA_MEDIA_SUBTYPE_mpeg2, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg2", NULL }, + { SPA_MEDIA_SUBTYPE_mpeg4, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg4", NULL }, + { SPA_MEDIA_SUBTYPE_xvid, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "xvid", NULL }, + { SPA_MEDIA_SUBTYPE_vc1, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vc1", NULL }, + { SPA_MEDIA_SUBTYPE_vp8, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vp8", NULL }, + { SPA_MEDIA_SUBTYPE_vp9, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vp9", NULL }, + { SPA_MEDIA_SUBTYPE_bayer, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "bayer", NULL }, + /* image subtypes */ + { SPA_MEDIA_SUBTYPE_jpeg, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "jpeg", NULL }, + /* stream subtypes */ + { SPA_MEDIA_SUBTYPE_midi, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "midi", NULL }, + /* application subtypes */ + { SPA_MEDIA_SUBTYPE_control, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "control", NULL }, + { 0, 0, NULL, NULL }, +}; + +#define SPA_TYPE_INFO_FormatAudio SPA_TYPE_INFO_FORMAT_BASE "Audio" +#define SPA_TYPE_INFO_FORMAT_AUDIO_BASE SPA_TYPE_INFO_FormatAudio ":" + +#define SPA_TYPE_INFO_FORMAT_AUDIO_AAC SPA_TYPE_INFO_FORMAT_AUDIO_BASE "AAC" +#define SPA_TYPE_INFO_FORMAT_AUDIO_AAC_BASE SPA_TYPE_INFO_FORMAT_AUDIO_AAC ":" +#define SPA_TYPE_INFO_FORMAT_AUDIO_WMA SPA_TYPE_INFO_FORMAT_AUDIO_BASE "WMA" +#define SPA_TYPE_INFO_FORMAT_AUDIO_WMA_BASE SPA_TYPE_INFO_FORMAT_AUDIO_WMA ":" +#define SPA_TYPE_INFO_FORMAT_AUDIO_AMR SPA_TYPE_INFO_FORMAT_AUDIO_BASE "AMR" +#define SPA_TYPE_INFO_FORMAT_AUDIO_AMR_BASE SPA_TYPE_INFO_FORMAT_AUDIO_AMR ":" + +#define SPA_TYPE_INFO_FormatVideo SPA_TYPE_INFO_FORMAT_BASE "Video" +#define SPA_TYPE_INFO_FORMAT_VIDEO_BASE SPA_TYPE_INFO_FormatVideo ":" + +#define SPA_TYPE_INFO_FORMAT_VIDEO_H264 SPA_TYPE_INFO_FORMAT_VIDEO_BASE "H264" +#define SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE SPA_TYPE_INFO_FORMAT_VIDEO_H264 ":" + +static const struct spa_type_info spa_type_format = { + { SPA_FORMAT_START, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE, spa_type_param, }, + + { SPA_FORMAT_mediaType, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE "mediaType", + spa_type_media_type, }, + { SPA_FORMAT_mediaSubtype, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE "mediaSubtype", + spa_type_media_subtype, }, + + { SPA_FORMAT_AUDIO_format, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "format", + spa_type_audio_format }, + { SPA_FORMAT_AUDIO_flags, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "flags", + spa_type_audio_flags }, + { SPA_FORMAT_AUDIO_rate, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "rate", NULL }, + { SPA_FORMAT_AUDIO_channels, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "channels", NULL }, + { SPA_FORMAT_AUDIO_position, SPA_TYPE_Array, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "position", + spa_type_prop_channel_map }, + + { SPA_FORMAT_AUDIO_iec958Codec, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "iec958Codec", + spa_type_audio_iec958_codec }, + + { SPA_FORMAT_AUDIO_bitorder, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "bitorder", + spa_type_param_bitorder }, + { SPA_FORMAT_AUDIO_interleave, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "interleave", NULL }, + { SPA_FORMAT_AUDIO_bitrate, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "bitrate", NULL }, + { SPA_FORMAT_AUDIO_blockAlign, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "blockAlign", NULL }, + + { SPA_FORMAT_AUDIO_AAC_streamFormat, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_AAC_BASE "streamFormat", + spa_type_audio_aac_stream_format }, + { SPA_FORMAT_AUDIO_WMA_profile, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_WMA_BASE "profile", + spa_type_audio_wma_profile }, + { SPA_FORMAT_AUDIO_AMR_bandMode, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_AMR_BASE "bandMode", + spa_type_audio_amr_band_mode }, + + { SPA_FORMAT_VIDEO_format, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "format", + spa_type_video_format, }, + { SPA_FORMAT_VIDEO_modifier, SPA_TYPE_Long, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "modifier", NULL }, + { SPA_FORMAT_VIDEO_size, SPA_TYPE_Rectangle, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "size", NULL }, + { SPA_FORMAT_VIDEO_framerate, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "framerate", NULL }, + { SPA_FORMAT_VIDEO_maxFramerate, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "maxFramerate", NULL }, + { SPA_FORMAT_VIDEO_views, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "views", NULL }, + { SPA_FORMAT_VIDEO_interlaceMode, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "interlaceMode", + spa_type_video_interlace_mode, }, + { SPA_FORMAT_VIDEO_pixelAspectRatio, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "pixelAspectRatio", NULL }, + { SPA_FORMAT_VIDEO_multiviewMode, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "multiviewMode", NULL }, + { SPA_FORMAT_VIDEO_multiviewFlags, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "multiviewFlags", NULL }, + { SPA_FORMAT_VIDEO_chromaSite, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "chromaSite", NULL }, + { SPA_FORMAT_VIDEO_colorRange, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorRange", NULL }, + { SPA_FORMAT_VIDEO_colorMatrix, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorMatrix", NULL }, + { SPA_FORMAT_VIDEO_transferFunction, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "transferFunction", NULL }, + { SPA_FORMAT_VIDEO_colorPrimaries, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorPrimaries", NULL }, + { SPA_FORMAT_VIDEO_profile, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "profile", NULL }, + { SPA_FORMAT_VIDEO_level, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "level", NULL }, + + { SPA_FORMAT_VIDEO_H264_streamFormat, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE "streamFormat", NULL }, + { SPA_FORMAT_VIDEO_H264_alignment, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE "alignment", NULL }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_FORMAT_TYPES_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/format.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/format.h
Changed
@@ -68,6 +68,9 @@ SPA_MEDIA_SUBTYPE_g729, SPA_MEDIA_SUBTYPE_amr, SPA_MEDIA_SUBTYPE_gsm, + SPA_MEDIA_SUBTYPE_alac, /** since 0.3.65 */ + SPA_MEDIA_SUBTYPE_flac, /** since 0.3.65 */ + SPA_MEDIA_SUBTYPE_ape, /** since 0.3.65 */ SPA_MEDIA_SUBTYPE_START_Video = 0x20000, SPA_MEDIA_SUBTYPE_h264, @@ -106,16 +109,25 @@ /* Audio format keys */ SPA_FORMAT_START_Audio = 0x10000, - SPA_FORMAT_AUDIO_format, /**< audio format, (Id enum spa_audio_format) */ - SPA_FORMAT_AUDIO_flags, /**< optional flags (Int) */ - SPA_FORMAT_AUDIO_rate, /**< sample rate (Int) */ - SPA_FORMAT_AUDIO_channels, /**< number of audio channels (Int) */ - SPA_FORMAT_AUDIO_position, /**< channel positions (Id enum spa_audio_position) */ + SPA_FORMAT_AUDIO_format, /**< audio format, (Id enum spa_audio_format) */ + SPA_FORMAT_AUDIO_flags, /**< optional flags (Int) */ + SPA_FORMAT_AUDIO_rate, /**< sample rate (Int) */ + SPA_FORMAT_AUDIO_channels, /**< number of audio channels (Int) */ + SPA_FORMAT_AUDIO_position, /**< channel positions (Id enum spa_audio_position) */ - SPA_FORMAT_AUDIO_iec958Codec, /**< codec used (IEC958) (Id enum spa_audio_iec958_codec) */ + SPA_FORMAT_AUDIO_iec958Codec, /**< codec used (IEC958) (Id enum spa_audio_iec958_codec) */ + + SPA_FORMAT_AUDIO_bitorder, /**< bit order (Id enum spa_param_bitorder) */ + SPA_FORMAT_AUDIO_interleave, /**< Interleave bytes (Int) */ + SPA_FORMAT_AUDIO_bitrate, /**< bit rate (Int) */ + SPA_FORMAT_AUDIO_blockAlign, /**< audio data block alignment (Int) */ + + SPA_FORMAT_AUDIO_AAC_streamFormat, /**< AAC stream format, (Id enum spa_audio_aac_stream_format) */ + + SPA_FORMAT_AUDIO_WMA_profile, /**< WMA profile (Id enum spa_audio_wma_profile) */ + + SPA_FORMAT_AUDIO_AMR_bandMode, /**< AMR band mode (Id enum spa_audio_amr_band_mode) */ - SPA_FORMAT_AUDIO_bitorder, /**< bit order (Id enum spa_param_bitorder) */ - SPA_FORMAT_AUDIO_interleave, /**< Interleave bytes (Int) */ /* Video Format keys */ SPA_FORMAT_START_Video = 0x20000,
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/latency-types.h
Added
@@ -0,0 +1,75 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_LATENCY_TYPES_H +#define SPA_PARAM_LATENCY_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/utils/enum-types.h> +#include <spa/param/param-types.h> +#include <spa/param/latency.h> + +#define SPA_TYPE_INFO_PARAM_Latency SPA_TYPE_INFO_PARAM_BASE "Latency" +#define SPA_TYPE_INFO_PARAM_LATENCY_BASE SPA_TYPE_INFO_PARAM_Latency ":" + +static const struct spa_type_info spa_type_param_latency = { + { SPA_PARAM_LATENCY_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_LATENCY_BASE, spa_type_param, }, + { SPA_PARAM_LATENCY_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_LATENCY_BASE "direction", spa_type_direction, }, + { SPA_PARAM_LATENCY_minQuantum, SPA_TYPE_Float, SPA_TYPE_INFO_PARAM_LATENCY_BASE "minQuantum", NULL, }, + { SPA_PARAM_LATENCY_maxQuantum, SPA_TYPE_Float, SPA_TYPE_INFO_PARAM_LATENCY_BASE "maxQuantum", NULL, }, + { SPA_PARAM_LATENCY_minRate, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_LATENCY_BASE "minRate", NULL, }, + { SPA_PARAM_LATENCY_maxRate, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_LATENCY_BASE "maxRate", NULL, }, + { SPA_PARAM_LATENCY_minNs, SPA_TYPE_Long, SPA_TYPE_INFO_PARAM_LATENCY_BASE "minNs", NULL, }, + { SPA_PARAM_LATENCY_maxNs, SPA_TYPE_Long, SPA_TYPE_INFO_PARAM_LATENCY_BASE "maxNs", NULL, }, + { 0, 0, NULL, NULL }, +}; + +#define SPA_TYPE_INFO_PARAM_ProcessLatency SPA_TYPE_INFO_PARAM_BASE "ProcessLatency" +#define SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE SPA_TYPE_INFO_PARAM_ProcessLatency ":" + +static const struct spa_type_info spa_type_param_process_latency = { + { SPA_PARAM_PROCESS_LATENCY_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_LATENCY_BASE, spa_type_param, }, + { SPA_PARAM_PROCESS_LATENCY_quantum, SPA_TYPE_Float, SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE "quantum", NULL, }, + { SPA_PARAM_PROCESS_LATENCY_rate, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE "rate", NULL, }, + { SPA_PARAM_PROCESS_LATENCY_ns, SPA_TYPE_Long, SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE "ns", NULL, }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_LATENCY_TYPES_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/latency-utils.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/latency-utils.h
Changed
@@ -38,19 +38,7 @@ #include <spa/pod/builder.h> #include <spa/pod/parser.h> -#include <spa/param/param.h> - -struct spa_latency_info { - enum spa_direction direction; - float min_quantum; - float max_quantum; - uint32_t min_rate; - uint32_t max_rate; - uint64_t min_ns; - uint64_t max_ns; -}; - -#define SPA_LATENCY_INFO(dir,...) ((struct spa_latency_info) { .direction = (dir), ## __VA_ARGS__ }) +#include <spa/param/latency.h> static inline int spa_latency_info_compare(const struct spa_latency_info *a, struct spa_latency_info *b) @@ -140,14 +128,6 @@ SPA_PARAM_LATENCY_maxNs, SPA_POD_Long(info->max_ns)); } -struct spa_process_latency_info { - float quantum; - uint32_t rate; - uint64_t ns; -}; - -#define SPA_PROCESS_LATENCY_INFO_INIT(...) ((struct spa_process_latency_info) { __VA_ARGS__ }) - static inline int spa_process_latency_parse(const struct spa_pod *latency, struct spa_process_latency_info *info) {
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/latency.h
Added
@@ -0,0 +1,89 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_LATENY_H +#define SPA_PARAM_LATENY_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/param.h> + +/** properties for SPA_TYPE_OBJECT_ParamLatency */ +enum spa_param_latency { + SPA_PARAM_LATENCY_START, + SPA_PARAM_LATENCY_direction, /**< direction, input/output (Id enum spa_direction) */ + SPA_PARAM_LATENCY_minQuantum, /**< min latency relative to quantum (Float) */ + SPA_PARAM_LATENCY_maxQuantum, /**< max latency relative to quantum (Float) */ + SPA_PARAM_LATENCY_minRate, /**< min latency (Int) relative to rate */ + SPA_PARAM_LATENCY_maxRate, /**< max latency (Int) relative to rate */ + SPA_PARAM_LATENCY_minNs, /**< min latency (Long) in nanoseconds */ + SPA_PARAM_LATENCY_maxNs, /**< max latency (Long) in nanoseconds */ +}; + +/** helper structure for managing latency objects */ +struct spa_latency_info { + enum spa_direction direction; + float min_quantum; + float max_quantum; + uint32_t min_rate; + uint32_t max_rate; + uint64_t min_ns; + uint64_t max_ns; +}; + +#define SPA_LATENCY_INFO(dir,...) ((struct spa_latency_info) { .direction = (dir), ## __VA_ARGS__ }) + +/** properties for SPA_TYPE_OBJECT_ParamProcessLatency */ +enum spa_param_process_latency { + SPA_PARAM_PROCESS_LATENCY_START, + SPA_PARAM_PROCESS_LATENCY_quantum, /**< latency relative to quantum (Float) */ + SPA_PARAM_PROCESS_LATENCY_rate, /**< latency (Int) relative to rate */ + SPA_PARAM_PROCESS_LATENCY_ns, /**< latency (Long) in nanoseconds */ +}; + +/** Helper structure for managing process latency objects */ +struct spa_process_latency_info { + float quantum; + uint32_t rate; + uint64_t ns; +}; + +#define SPA_PROCESS_LATENCY_INFO_INIT(...) ((struct spa_process_latency_info) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_LATENY_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/param-types.h
Added
@@ -0,0 +1,115 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_TYPES_H +#define SPA_PARAM_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/props.h> +#include <spa/param/format.h> +#include <spa/buffer/type-info.h> + +/* base for parameter object enumerations */ +#define SPA_TYPE_INFO_ParamId SPA_TYPE_INFO_ENUM_BASE "ParamId" +#define SPA_TYPE_INFO_PARAM_ID_BASE SPA_TYPE_INFO_ParamId ":" + +static const struct spa_type_info spa_type_param = { + { SPA_PARAM_Invalid, SPA_TYPE_None, SPA_TYPE_INFO_PARAM_ID_BASE "Invalid", NULL }, + { SPA_PARAM_PropInfo, SPA_TYPE_OBJECT_PropInfo, SPA_TYPE_INFO_PARAM_ID_BASE "PropInfo", NULL }, + { SPA_PARAM_Props, SPA_TYPE_OBJECT_Props, SPA_TYPE_INFO_PARAM_ID_BASE "Props", NULL }, + { SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_TYPE_INFO_PARAM_ID_BASE "EnumFormat", NULL }, + { SPA_PARAM_Format, SPA_TYPE_OBJECT_Format, SPA_TYPE_INFO_PARAM_ID_BASE "Format", NULL }, + { SPA_PARAM_Buffers, SPA_TYPE_OBJECT_ParamBuffers, SPA_TYPE_INFO_PARAM_ID_BASE "Buffers", NULL }, + { SPA_PARAM_Meta, SPA_TYPE_OBJECT_ParamMeta, SPA_TYPE_INFO_PARAM_ID_BASE "Meta", NULL }, + { SPA_PARAM_IO, SPA_TYPE_OBJECT_ParamIO, SPA_TYPE_INFO_PARAM_ID_BASE "IO", NULL }, + { SPA_PARAM_EnumProfile, SPA_TYPE_OBJECT_ParamProfile, SPA_TYPE_INFO_PARAM_ID_BASE "EnumProfile", NULL }, + { SPA_PARAM_Profile, SPA_TYPE_OBJECT_ParamProfile, SPA_TYPE_INFO_PARAM_ID_BASE "Profile", NULL }, + { SPA_PARAM_EnumPortConfig, SPA_TYPE_OBJECT_ParamPortConfig, SPA_TYPE_INFO_PARAM_ID_BASE "EnumPortConfig", NULL }, + { SPA_PARAM_PortConfig, SPA_TYPE_OBJECT_ParamPortConfig, SPA_TYPE_INFO_PARAM_ID_BASE "PortConfig", NULL }, + { SPA_PARAM_EnumRoute, SPA_TYPE_OBJECT_ParamRoute, SPA_TYPE_INFO_PARAM_ID_BASE "EnumRoute", NULL }, + { SPA_PARAM_Route, SPA_TYPE_OBJECT_ParamRoute, SPA_TYPE_INFO_PARAM_ID_BASE "Route", NULL }, + { SPA_PARAM_Control, SPA_TYPE_Sequence, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL }, + { SPA_PARAM_Latency, SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_INFO_PARAM_ID_BASE "Latency", NULL }, + { SPA_PARAM_ProcessLatency, SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_INFO_PARAM_ID_BASE "ProcessLatency", NULL }, + { 0, 0, NULL, NULL }, +}; + +/* base for parameter objects */ +#define SPA_TYPE_INFO_Param SPA_TYPE_INFO_OBJECT_BASE "Param" +#define SPA_TYPE_INFO_PARAM_BASE SPA_TYPE_INFO_Param ":" + +#include <spa/param/audio/type-info.h> + +static const struct spa_type_info spa_type_prop_float_array = { + { SPA_PROP_START, SPA_TYPE_Float, SPA_TYPE_INFO_BASE "floatArray", NULL, }, + { 0, 0, NULL, NULL }, +}; + +static const struct spa_type_info spa_type_prop_channel_map = { + { SPA_PROP_START, SPA_TYPE_Id, SPA_TYPE_INFO_BASE "channelMap", spa_type_audio_channel, }, + { 0, 0, NULL, NULL }, +}; + +static const struct spa_type_info spa_type_prop_iec958_codec = { + { SPA_PROP_START, SPA_TYPE_Id, SPA_TYPE_INFO_BASE "iec958Codec", spa_type_audio_iec958_codec, }, + { 0, 0, NULL, NULL }, +}; + +#define SPA_TYPE_INFO_ParamBitorder SPA_TYPE_INFO_ENUM_BASE "ParamBitorder" +#define SPA_TYPE_INFO_PARAM_BITORDER_BASE SPA_TYPE_INFO_ParamBitorder ":" + +static const struct spa_type_info spa_type_param_bitorder = { + { SPA_PARAM_BITORDER_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BITORDER_BASE "unknown", NULL }, + { SPA_PARAM_BITORDER_msb, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BITORDER_BASE "msb", NULL }, + { SPA_PARAM_BITORDER_lsb, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BITORDER_BASE "lsb", NULL }, + { 0, 0, NULL, NULL }, +}; + +#define SPA_TYPE_INFO_ParamAvailability SPA_TYPE_INFO_ENUM_BASE "ParamAvailability" +#define SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE SPA_TYPE_INFO_ParamAvailability ":" + +static const struct spa_type_info spa_type_param_availability = { + { SPA_PARAM_AVAILABILITY_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "unknown", NULL }, + { SPA_PARAM_AVAILABILITY_no, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "no", NULL }, + { SPA_PARAM_AVAILABILITY_yes, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "yes", NULL }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_TYPES_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/param.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/param.h
Changed
@@ -79,29 +79,10 @@ #define SPA_PARAM_INFO(id,flags) ((struct spa_param_info){ (id), (flags) }) -/** properties for SPA_TYPE_OBJECT_ParamBuffers */ -enum spa_param_buffers { - SPA_PARAM_BUFFERS_START, - SPA_PARAM_BUFFERS_buffers, /**< number of buffers (Int) */ - SPA_PARAM_BUFFERS_blocks, /**< number of data blocks per buffer (Int) */ - SPA_PARAM_BUFFERS_size, /**< size of a data block memory (Int)*/ - SPA_PARAM_BUFFERS_stride, /**< stride of data block memory (Int) */ - SPA_PARAM_BUFFERS_align, /**< alignment of data block memory (Int) */ - SPA_PARAM_BUFFERS_dataType, /**< possible memory types (Int, mask of enum spa_data_type) */ -}; - -/** properties for SPA_TYPE_OBJECT_ParamMeta */ -enum spa_param_meta { - SPA_PARAM_META_START, - SPA_PARAM_META_type, /**< the metadata, one of enum spa_meta_type (Id enum spa_meta_type) */ - SPA_PARAM_META_size, /**< the expected maximum size the meta (Int) */ -}; - -/** properties for SPA_TYPE_OBJECT_ParamIO */ -enum spa_param_io { - SPA_PARAM_IO_START, - SPA_PARAM_IO_id, /**< type ID, uniquely identifies the io area (Id enum spa_io_type) */ - SPA_PARAM_IO_size, /**< size of the io area (Int) */ +enum spa_param_bitorder { + SPA_PARAM_BITORDER_unknown, /**< unknown bitorder */ + SPA_PARAM_BITORDER_msb, /**< most significant bit */ + SPA_PARAM_BITORDER_lsb, /**< least significant bit */ }; enum spa_param_availability { @@ -110,98 +91,10 @@ SPA_PARAM_AVAILABILITY_yes, /**< available */ }; -/** properties for SPA_TYPE_OBJECT_ParamProfile */ -enum spa_param_profile { - SPA_PARAM_PROFILE_START, - SPA_PARAM_PROFILE_index, /**< profile index (Int) */ - SPA_PARAM_PROFILE_name, /**< profile name (String) */ - SPA_PARAM_PROFILE_description, /**< profile description (String) */ - SPA_PARAM_PROFILE_priority, /**< profile priority (Int) */ - SPA_PARAM_PROFILE_available, /**< availability of the profile - * (Id enum spa_param_availability) */ - SPA_PARAM_PROFILE_info, /**< info (Struct( - * Int : n_items, - * (String : key, - * String : value)*)) */ - SPA_PARAM_PROFILE_classes, /**< node classes provided by this profile - * (Struct( - * Int : number of items following - * Struct( - * String : class name (eg. "Audio/Source"), - * Int : number of nodes - * String : property (eg. "card.profile.devices"), - * Array of Int: device indexes - * )*)) */ - SPA_PARAM_PROFILE_save, /**< If profile should be saved (Bool) */ -}; - -enum spa_param_port_config_mode { - SPA_PARAM_PORT_CONFIG_MODE_none, /**< no configuration */ - SPA_PARAM_PORT_CONFIG_MODE_passthrough, /**< passthrough configuration */ - SPA_PARAM_PORT_CONFIG_MODE_convert, /**< convert configuration */ - SPA_PARAM_PORT_CONFIG_MODE_dsp, /**< dsp configuration, depending on the external - * format. For audio, ports will be configured for - * the given number of channels with F32 format. */ -}; - -/** properties for SPA_TYPE_OBJECT_ParamPortConfig */ -enum spa_param_port_config { - SPA_PARAM_PORT_CONFIG_START, - SPA_PARAM_PORT_CONFIG_direction, /**< direction, input/output (Id enum spa_direction) */ - SPA_PARAM_PORT_CONFIG_mode, /**< (Id enum spa_param_port_config_mode) mode */ - SPA_PARAM_PORT_CONFIG_monitor, /**< (Bool) enable monitor output ports on input ports */ - SPA_PARAM_PORT_CONFIG_control, /**< (Bool) enable control ports */ - SPA_PARAM_PORT_CONFIG_format, /**< (Object) format filter */ -}; - -/** properties for SPA_TYPE_OBJECT_ParamRoute */ -enum spa_param_route { - SPA_PARAM_ROUTE_START, - SPA_PARAM_ROUTE_index, /**< index of the routing destination (Int) */ - SPA_PARAM_ROUTE_direction, /**< direction, input/output (Id enum spa_direction) */ - SPA_PARAM_ROUTE_device, /**< device id (Int) */ - SPA_PARAM_ROUTE_name, /**< name of the routing destination (String) */ - SPA_PARAM_ROUTE_description, /**< description of the destination (String) */ - SPA_PARAM_ROUTE_priority, /**< priority of the destination (Int) */ - SPA_PARAM_ROUTE_available, /**< availability of the destination - * (Id enum spa_param_availability) */ - SPA_PARAM_ROUTE_info, /**< info (Struct( - * Int : n_items, - * (String : key, - * String : value)*)) */ - SPA_PARAM_ROUTE_profiles, /**< associated profile indexes (Array of Int) */ - SPA_PARAM_ROUTE_props, /**< properties SPA_TYPE_OBJECT_Props */ - SPA_PARAM_ROUTE_devices, /**< associated device indexes (Array of Int) */ - SPA_PARAM_ROUTE_profile, /**< profile id (Int) */ - SPA_PARAM_ROUTE_save, /**< If route should be saved (Bool) */ -}; - - -/** properties for SPA_TYPE_OBJECT_ParamLatency */ -enum spa_param_latency { - SPA_PARAM_LATENCY_START, - SPA_PARAM_LATENCY_direction, /**< direction, input/output (Id enum spa_direction) */ - SPA_PARAM_LATENCY_minQuantum, /**< min latency relative to quantum (Float) */ - SPA_PARAM_LATENCY_maxQuantum, /**< max latency relative to quantum (Float) */ - SPA_PARAM_LATENCY_minRate, /**< min latency (Int) relative to rate */ - SPA_PARAM_LATENCY_maxRate, /**< max latency (Int) relative to rate */ - SPA_PARAM_LATENCY_minNs, /**< min latency (Long) in nanoseconds */ - SPA_PARAM_LATENCY_maxNs, /**< max latency (Long) in nanoseconds */ -}; - -/** properties for SPA_TYPE_OBJECT_ParamProcessLatency */ -enum spa_param_process_latency { - SPA_PARAM_PROCESS_LATENCY_START, - SPA_PARAM_PROCESS_LATENCY_quantum, /**< latency relative to quantum (Float) */ - SPA_PARAM_PROCESS_LATENCY_rate, /**< latency (Int) relative to rate */ - SPA_PARAM_PROCESS_LATENCY_ns, /**< latency (Long) in nanoseconds */ -}; - -enum spa_param_bitorder { - SPA_PARAM_BITORDER_unknown, /**< unknown bitorder */ - SPA_PARAM_BITORDER_msb, /**< most significant bit */ - SPA_PARAM_BITORDER_lsb, /**< least significant bit */ -}; +#include <spa/param/buffers.h> +#include <spa/param/profile.h> +#include <spa/param/port-config.h> +#include <spa/param/route.h> /** * \}
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/port-config-types.h
Added
@@ -0,0 +1,73 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_PORT_CONFIG_TYPES_H +#define SPA_PARAM_PORT_CONFIG_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/utils/enum-types.h> +#include <spa/param/param-types.h> +#include <spa/param/port-config.h> + +#define SPA_TYPE_INFO_ParamPortConfigMode SPA_TYPE_INFO_ENUM_BASE "ParamPortConfigMode" +#define SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE SPA_TYPE_INFO_ParamPortConfigMode ":" + +static const struct spa_type_info spa_type_param_port_config_mode = { + { SPA_PARAM_PORT_CONFIG_MODE_none, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "none", NULL }, + { SPA_PARAM_PORT_CONFIG_MODE_passthrough, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "passthrough", NULL }, + { SPA_PARAM_PORT_CONFIG_MODE_convert, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "convert", NULL }, + { SPA_PARAM_PORT_CONFIG_MODE_dsp, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "dsp", NULL }, + { 0, 0, NULL, NULL }, +}; + +#define SPA_TYPE_INFO_PARAM_PortConfig SPA_TYPE_INFO_PARAM_BASE "PortConfig" +#define SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE SPA_TYPE_INFO_PARAM_PortConfig ":" + +static const struct spa_type_info spa_type_param_port_config = { + { SPA_PARAM_PORT_CONFIG_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE, spa_type_param, }, + { SPA_PARAM_PORT_CONFIG_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "direction", spa_type_direction, }, + { SPA_PARAM_PORT_CONFIG_mode, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "mode", spa_type_param_port_config_mode }, + { SPA_PARAM_PORT_CONFIG_monitor, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "monitor", NULL }, + { SPA_PARAM_PORT_CONFIG_control, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "control", NULL }, + { SPA_PARAM_PORT_CONFIG_format, SPA_TYPE_OBJECT_Format, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "format", NULL }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_PORT_CONFIG_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/port-config.h
Added
@@ -0,0 +1,66 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_PORT_CONFIG_H +#define SPA_PARAM_PORT_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/param.h> + +enum spa_param_port_config_mode { + SPA_PARAM_PORT_CONFIG_MODE_none, /**< no configuration */ + SPA_PARAM_PORT_CONFIG_MODE_passthrough, /**< passthrough configuration */ + SPA_PARAM_PORT_CONFIG_MODE_convert, /**< convert configuration */ + SPA_PARAM_PORT_CONFIG_MODE_dsp, /**< dsp configuration, depending on the external + * format. For audio, ports will be configured for + * the given number of channels with F32 format. */ +}; + +/** properties for SPA_TYPE_OBJECT_ParamPortConfig */ +enum spa_param_port_config { + SPA_PARAM_PORT_CONFIG_START, + SPA_PARAM_PORT_CONFIG_direction, /**< direction, input/output (Id enum spa_direction) */ + SPA_PARAM_PORT_CONFIG_mode, /**< (Id enum spa_param_port_config_mode) mode */ + SPA_PARAM_PORT_CONFIG_monitor, /**< (Bool) enable monitor output ports on input ports */ + SPA_PARAM_PORT_CONFIG_control, /**< (Bool) enable control ports */ + SPA_PARAM_PORT_CONFIG_format, /**< (Object) format filter */ +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_PORT_CONFIG_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/profile-types.h
Added
@@ -0,0 +1,65 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_PROFILE_TYPES_H +#define SPA_PARAM_PROFILE_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/param-types.h> + +#include <spa/param/profile.h> + +#define SPA_TYPE_INFO_PARAM_Profile SPA_TYPE_INFO_PARAM_BASE "Profile" +#define SPA_TYPE_INFO_PARAM_PROFILE_BASE SPA_TYPE_INFO_PARAM_Profile ":" + +static const struct spa_type_info spa_type_param_profile = { + { SPA_PARAM_PROFILE_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PROFILE_BASE, spa_type_param, }, + { SPA_PARAM_PROFILE_index, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PROFILE_BASE "index", NULL }, + { SPA_PARAM_PROFILE_name, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_PROFILE_BASE "name", NULL }, + { SPA_PARAM_PROFILE_description, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_PROFILE_BASE "description", NULL }, + { SPA_PARAM_PROFILE_priority, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PROFILE_BASE "priority", NULL }, + { SPA_PARAM_PROFILE_available, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PROFILE_BASE "available", spa_type_param_availability, }, + { SPA_PARAM_PROFILE_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_PROFILE_BASE "info", NULL, }, + { SPA_PARAM_PROFILE_classes, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_PROFILE_BASE "classes", NULL, }, + { SPA_PARAM_PROFILE_save, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PROFILE_BASE "save", NULL, }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_PROFILE_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/profile.h
Added
@@ -0,0 +1,72 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_PROFILE_H +#define SPA_PARAM_PROFILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/param.h> + +/** properties for SPA_TYPE_OBJECT_ParamProfile */ +enum spa_param_profile { + SPA_PARAM_PROFILE_START, + SPA_PARAM_PROFILE_index, /**< profile index (Int) */ + SPA_PARAM_PROFILE_name, /**< profile name (String) */ + SPA_PARAM_PROFILE_description, /**< profile description (String) */ + SPA_PARAM_PROFILE_priority, /**< profile priority (Int) */ + SPA_PARAM_PROFILE_available, /**< availability of the profile + * (Id enum spa_param_availability) */ + SPA_PARAM_PROFILE_info, /**< info (Struct( + * Int : n_items, + * (String : key, + * String : value)*)) */ + SPA_PARAM_PROFILE_classes, /**< node classes provided by this profile + * (Struct( + * Int : number of items following + * Struct( + * String : class name (eg. "Audio/Source"), + * Int : number of nodes + * String : property (eg. "card.profile.devices"), + * Array of Int: device indexes + * )*)) */ + SPA_PARAM_PROFILE_save, /**< If profile should be saved (Bool) */ +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_PROFILE_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/profiler-types.h
Added
@@ -0,0 +1,60 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_PROFILER_TYPES_H +#define SPA_PARAM_PROFILER_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/param-types.h> +#include <spa/param/profiler.h> + +#define SPA_TYPE_INFO_Profiler SPA_TYPE_INFO_OBJECT_BASE "Profiler" +#define SPA_TYPE_INFO_PROFILER_BASE SPA_TYPE_INFO_Profiler ":" + +static const struct spa_type_info spa_type_profiler = { + { SPA_PROFILER_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROFILER_BASE, spa_type_param, }, + { SPA_PROFILER_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "info", NULL, }, + { SPA_PROFILER_clock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "clock", NULL, }, + { SPA_PROFILER_driverBlock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "driverBlock", NULL, }, + { SPA_PROFILER_followerBlock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "followerBlock", NULL, }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_PROFILER_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/props-types.h
Added
@@ -0,0 +1,119 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_PROPS_TYPES_H +#define SPA_PARAM_PROPS_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/param-types.h> + +#include <spa/param/bluetooth/type-info.h> + +/** Props Param */ +#define SPA_TYPE_INFO_Props SPA_TYPE_INFO_PARAM_BASE "Props" +#define SPA_TYPE_INFO_PROPS_BASE SPA_TYPE_INFO_Props ":" + +static const struct spa_type_info spa_type_props = { + { SPA_PROP_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE, spa_type_param, }, + { SPA_PROP_unknown, SPA_TYPE_None, SPA_TYPE_INFO_PROPS_BASE "unknown", NULL }, + { SPA_PROP_device, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "device", NULL }, + { SPA_PROP_deviceName, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "deviceName", NULL }, + { SPA_PROP_deviceFd, SPA_TYPE_Fd, SPA_TYPE_INFO_PROPS_BASE "deviceFd", NULL }, + { SPA_PROP_card, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "card", NULL }, + { SPA_PROP_cardName, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "cardName", NULL }, + { SPA_PROP_minLatency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "minLatency", NULL }, + { SPA_PROP_maxLatency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "maxLatency", NULL }, + { SPA_PROP_periods, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "periods", NULL }, + { SPA_PROP_periodSize, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "periodSize", NULL }, + { SPA_PROP_periodEvent, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "periodEvent", NULL }, + { SPA_PROP_live, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "live", NULL }, + { SPA_PROP_rate, SPA_TYPE_Double, SPA_TYPE_INFO_PROPS_BASE "rate", NULL }, + { SPA_PROP_quality, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "quality", NULL }, + { SPA_PROP_bluetoothAudioCodec, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "bluetoothAudioCodec", spa_type_bluetooth_audio_codec }, + { SPA_PROP_bluetoothOffloadActive, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "bluetoothOffloadActive", NULL }, + + { SPA_PROP_waveType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "waveType", NULL }, + { SPA_PROP_frequency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "frequency", NULL }, + { SPA_PROP_volume, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volume", NULL }, + { SPA_PROP_mute, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "mute", NULL }, + { SPA_PROP_patternType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "patternType", NULL }, + { SPA_PROP_ditherType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "ditherType", NULL }, + { SPA_PROP_truncate, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "truncate", NULL }, + { SPA_PROP_channelVolumes, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "channelVolumes", spa_type_prop_float_array }, + { SPA_PROP_volumeBase, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volumeBase", NULL }, + { SPA_PROP_volumeStep, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volumeStep", NULL }, + { SPA_PROP_channelMap, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "channelMap", spa_type_prop_channel_map }, + { SPA_PROP_monitorMute, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "monitorMute", NULL }, + { SPA_PROP_monitorVolumes, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "monitorVolumes", spa_type_prop_float_array }, + { SPA_PROP_latencyOffsetNsec, SPA_TYPE_Long, SPA_TYPE_INFO_PROPS_BASE "latencyOffsetNsec", NULL }, + { SPA_PROP_softMute, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "softMute", NULL }, + { SPA_PROP_softVolumes, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "softVolumes", spa_type_prop_float_array }, + { SPA_PROP_iec958Codecs, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "iec958Codecs", spa_type_prop_iec958_codec }, + + { SPA_PROP_brightness, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "brightness", NULL }, + { SPA_PROP_contrast, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "contrast", NULL }, + { SPA_PROP_saturation, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "saturation", NULL }, + { SPA_PROP_hue, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "hue", NULL }, + { SPA_PROP_gamma, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "gamma", NULL }, + { SPA_PROP_exposure, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "exposure", NULL }, + { SPA_PROP_gain, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "gain", NULL }, + { SPA_PROP_sharpness, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "sharpness", NULL }, + + { SPA_PROP_params, SPA_TYPE_Struct, SPA_TYPE_INFO_PROPS_BASE "params", NULL }, + { 0, 0, NULL, NULL }, +}; + +/** Enum Property info */ +#define SPA_TYPE_INFO_PropInfo SPA_TYPE_INFO_PARAM_BASE "PropInfo" +#define SPA_TYPE_INFO_PROP_INFO_BASE SPA_TYPE_INFO_PropInfo ":" + +static const struct spa_type_info spa_type_prop_info = { + { SPA_PROP_INFO_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROP_INFO_BASE, spa_type_param, }, + { SPA_PROP_INFO_id, SPA_TYPE_Id, SPA_TYPE_INFO_PROP_INFO_BASE "id", spa_type_props }, + { SPA_PROP_INFO_name, SPA_TYPE_String, SPA_TYPE_INFO_PROP_INFO_BASE "name", NULL }, + { SPA_PROP_INFO_type, SPA_TYPE_Pod, SPA_TYPE_INFO_PROP_INFO_BASE "type", NULL }, + { SPA_PROP_INFO_labels, SPA_TYPE_Struct, SPA_TYPE_INFO_PROP_INFO_BASE "labels", NULL }, + { SPA_PROP_INFO_container, SPA_TYPE_Id, SPA_TYPE_INFO_PROP_INFO_BASE "container", NULL }, + { SPA_PROP_INFO_params, SPA_TYPE_Bool, SPA_TYPE_INFO_PROP_INFO_BASE "params", NULL }, + { SPA_PROP_INFO_description, SPA_TYPE_String, SPA_TYPE_INFO_PROP_INFO_BASE "description", NULL }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_PROPS_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/route-types.h
Added
@@ -0,0 +1,71 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_ROUTE_TYPES_H +#define SPA_PARAM_ROUTE_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/utils/enum-types.h> +#include <spa/param/param-types.h> + +#include <spa/param/route.h> + +#define SPA_TYPE_INFO_PARAM_Route SPA_TYPE_INFO_PARAM_BASE "Route" +#define SPA_TYPE_INFO_PARAM_ROUTE_BASE SPA_TYPE_INFO_PARAM_Route ":" + +static const struct spa_type_info spa_type_param_route = { + { SPA_PARAM_ROUTE_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE, spa_type_param, }, + { SPA_PARAM_ROUTE_index, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "index", NULL, }, + { SPA_PARAM_ROUTE_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE "direction", spa_type_direction, }, + { SPA_PARAM_ROUTE_device, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "device", NULL, }, + { SPA_PARAM_ROUTE_name, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_ROUTE_BASE "name", NULL, }, + { SPA_PARAM_ROUTE_description, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_ROUTE_BASE "description", NULL, }, + { SPA_PARAM_ROUTE_priority, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "priority", NULL, }, + { SPA_PARAM_ROUTE_available, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE "available", spa_type_param_availability, }, + { SPA_PARAM_ROUTE_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_ROUTE_BASE "info", NULL, }, + { SPA_PARAM_ROUTE_profiles, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profiles", NULL, }, + { SPA_PARAM_ROUTE_props, SPA_TYPE_OBJECT_Props, SPA_TYPE_INFO_PARAM_ROUTE_BASE "props", NULL, }, + { SPA_PARAM_ROUTE_devices, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "devices", NULL, }, + { SPA_PARAM_ROUTE_profile, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profile", NULL, }, + { SPA_PARAM_ROUTE_save, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_ROUTE_BASE "save", NULL, }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_ROUTE_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/route.h
Added
@@ -0,0 +1,69 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_PARAM_ROUTE_H +#define SPA_PARAM_ROUTE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/param.h> + +/** properties for SPA_TYPE_OBJECT_ParamRoute */ +enum spa_param_route { + SPA_PARAM_ROUTE_START, + SPA_PARAM_ROUTE_index, /**< index of the routing destination (Int) */ + SPA_PARAM_ROUTE_direction, /**< direction, input/output (Id enum spa_direction) */ + SPA_PARAM_ROUTE_device, /**< device id (Int) */ + SPA_PARAM_ROUTE_name, /**< name of the routing destination (String) */ + SPA_PARAM_ROUTE_description, /**< description of the destination (String) */ + SPA_PARAM_ROUTE_priority, /**< priority of the destination (Int) */ + SPA_PARAM_ROUTE_available, /**< availability of the destination + * (Id enum spa_param_availability) */ + SPA_PARAM_ROUTE_info, /**< info (Struct( + * Int : n_items, + * (String : key, + * String : value)*)) */ + SPA_PARAM_ROUTE_profiles, /**< associated profile indexes (Array of Int) */ + SPA_PARAM_ROUTE_props, /**< properties SPA_TYPE_OBJECT_Props */ + SPA_PARAM_ROUTE_devices, /**< associated device indexes (Array of Int) */ + SPA_PARAM_ROUTE_profile, /**< profile id (Int) */ + SPA_PARAM_ROUTE_save, /**< If route should be saved (Bool) */ +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_ROUTE_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/type-info.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/type-info.h
Changed
@@ -22,428 +22,17 @@ * DEALINGS IN THE SOFTWARE. */ -#ifndef SPA_PARAM_TYPES_H -#define SPA_PARAM_TYPES_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \addtogroup spa_param - * \{ - */ - -#include <spa/utils/defs.h> -#include <spa/param/props.h> -#include <spa/param/format.h> -#include <spa/buffer/type-info.h> - -/* base for parameter object enumerations */ -#define SPA_TYPE_INFO_ParamId SPA_TYPE_INFO_ENUM_BASE "ParamId" -#define SPA_TYPE_INFO_PARAM_ID_BASE SPA_TYPE_INFO_ParamId ":" - -static const struct spa_type_info spa_type_param = { - { SPA_PARAM_Invalid, SPA_TYPE_None, SPA_TYPE_INFO_PARAM_ID_BASE "Invalid", NULL }, - { SPA_PARAM_PropInfo, SPA_TYPE_OBJECT_PropInfo, SPA_TYPE_INFO_PARAM_ID_BASE "PropInfo", NULL }, - { SPA_PARAM_Props, SPA_TYPE_OBJECT_Props, SPA_TYPE_INFO_PARAM_ID_BASE "Props", NULL }, - { SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_TYPE_INFO_PARAM_ID_BASE "EnumFormat", NULL }, - { SPA_PARAM_Format, SPA_TYPE_OBJECT_Format, SPA_TYPE_INFO_PARAM_ID_BASE "Format", NULL }, - { SPA_PARAM_Buffers, SPA_TYPE_OBJECT_ParamBuffers, SPA_TYPE_INFO_PARAM_ID_BASE "Buffers", NULL }, - { SPA_PARAM_Meta, SPA_TYPE_OBJECT_ParamMeta, SPA_TYPE_INFO_PARAM_ID_BASE "Meta", NULL }, - { SPA_PARAM_IO, SPA_TYPE_OBJECT_ParamIO, SPA_TYPE_INFO_PARAM_ID_BASE "IO", NULL }, - { SPA_PARAM_EnumProfile, SPA_TYPE_OBJECT_ParamProfile, SPA_TYPE_INFO_PARAM_ID_BASE "EnumProfile", NULL }, - { SPA_PARAM_Profile, SPA_TYPE_OBJECT_ParamProfile, SPA_TYPE_INFO_PARAM_ID_BASE "Profile", NULL }, - { SPA_PARAM_EnumPortConfig, SPA_TYPE_OBJECT_ParamPortConfig, SPA_TYPE_INFO_PARAM_ID_BASE "EnumPortConfig", NULL }, - { SPA_PARAM_PortConfig, SPA_TYPE_OBJECT_ParamPortConfig, SPA_TYPE_INFO_PARAM_ID_BASE "PortConfig", NULL }, - { SPA_PARAM_EnumRoute, SPA_TYPE_OBJECT_ParamRoute, SPA_TYPE_INFO_PARAM_ID_BASE "EnumRoute", NULL }, - { SPA_PARAM_Route, SPA_TYPE_OBJECT_ParamRoute, SPA_TYPE_INFO_PARAM_ID_BASE "Route", NULL }, - { SPA_PARAM_Control, SPA_TYPE_Sequence, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL }, - { SPA_PARAM_Latency, SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_INFO_PARAM_ID_BASE "Latency", NULL }, - { SPA_PARAM_ProcessLatency, SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_INFO_PARAM_ID_BASE "ProcessLatency", NULL }, - { 0, 0, NULL, NULL }, -}; - -/* base for parameter objects */ -#define SPA_TYPE_INFO_Param SPA_TYPE_INFO_OBJECT_BASE "Param" -#define SPA_TYPE_INFO_PARAM_BASE SPA_TYPE_INFO_Param ":" - -#define SPA_TYPE_INFO_Props SPA_TYPE_INFO_PARAM_BASE "Props" -#define SPA_TYPE_INFO_PROPS_BASE SPA_TYPE_INFO_Props ":" - -#include <spa/param/audio/type-info.h> -#include <spa/param/video/type-info.h> -#include <spa/param/bluetooth/type-info.h> - -static const struct spa_type_info spa_type_prop_float_array = { - { SPA_PROP_START, SPA_TYPE_Float, SPA_TYPE_INFO_BASE "floatArray", NULL, }, - { 0, 0, NULL, NULL }, -}; - -static const struct spa_type_info spa_type_prop_channel_map = { - { SPA_PROP_START, SPA_TYPE_Id, SPA_TYPE_INFO_BASE "channelMap", spa_type_audio_channel, }, - { 0, 0, NULL, NULL }, -}; - -static const struct spa_type_info spa_type_prop_iec958_codec = { - { SPA_PROP_START, SPA_TYPE_Id, SPA_TYPE_INFO_BASE "iec958Codec", spa_type_audio_iec958_codec, }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_ParamBitorder SPA_TYPE_INFO_ENUM_BASE "ParamBitorder" -#define SPA_TYPE_INFO_PARAM_BITORDER_BASE SPA_TYPE_INFO_ParamBitorder ":" - -static const struct spa_type_info spa_type_param_bitorder = { - { SPA_PARAM_BITORDER_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BITORDER_BASE "unknown", NULL }, - { SPA_PARAM_BITORDER_msb, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BITORDER_BASE "msb", NULL }, - { SPA_PARAM_BITORDER_lsb, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BITORDER_BASE "lsb", NULL }, - { 0, 0, NULL, NULL }, -}; - -static const struct spa_type_info spa_type_props = { - { SPA_PROP_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE, spa_type_param, }, - { SPA_PROP_unknown, SPA_TYPE_None, SPA_TYPE_INFO_PROPS_BASE "unknown", NULL }, - { SPA_PROP_device, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "device", NULL }, - { SPA_PROP_deviceName, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "deviceName", NULL }, - { SPA_PROP_deviceFd, SPA_TYPE_Fd, SPA_TYPE_INFO_PROPS_BASE "deviceFd", NULL }, - { SPA_PROP_card, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "card", NULL }, - { SPA_PROP_cardName, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "cardName", NULL }, - { SPA_PROP_minLatency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "minLatency", NULL }, - { SPA_PROP_maxLatency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "maxLatency", NULL }, - { SPA_PROP_periods, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "periods", NULL }, - { SPA_PROP_periodSize, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "periodSize", NULL }, - { SPA_PROP_periodEvent, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "periodEvent", NULL }, - { SPA_PROP_live, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "live", NULL }, - { SPA_PROP_rate, SPA_TYPE_Double, SPA_TYPE_INFO_PROPS_BASE "rate", NULL }, - { SPA_PROP_quality, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "quality", NULL }, - { SPA_PROP_bluetoothAudioCodec, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "bluetoothAudioCodec", spa_type_bluetooth_audio_codec }, - { SPA_PROP_bluetoothOffloadActive, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "bluetoothOffloadActive", NULL }, - - { SPA_PROP_waveType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "waveType", NULL }, - { SPA_PROP_frequency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "frequency", NULL }, - { SPA_PROP_volume, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volume", NULL }, - { SPA_PROP_mute, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "mute", NULL }, - { SPA_PROP_patternType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "patternType", NULL }, - { SPA_PROP_ditherType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "ditherType", NULL }, - { SPA_PROP_truncate, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "truncate", NULL }, - { SPA_PROP_channelVolumes, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "channelVolumes", spa_type_prop_float_array }, - { SPA_PROP_volumeBase, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volumeBase", NULL }, - { SPA_PROP_volumeStep, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volumeStep", NULL }, - { SPA_PROP_channelMap, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "channelMap", spa_type_prop_channel_map }, - { SPA_PROP_monitorMute, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "monitorMute", NULL }, - { SPA_PROP_monitorVolumes, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "monitorVolumes", spa_type_prop_float_array }, - { SPA_PROP_latencyOffsetNsec, SPA_TYPE_Long, SPA_TYPE_INFO_PROPS_BASE "latencyOffsetNsec", NULL }, - { SPA_PROP_softMute, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "softMute", NULL }, - { SPA_PROP_softVolumes, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "softVolumes", spa_type_prop_float_array }, - { SPA_PROP_iec958Codecs, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "iec958Codecs", spa_type_prop_iec958_codec }, - - { SPA_PROP_brightness, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "brightness", NULL }, - { SPA_PROP_contrast, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "contrast", NULL }, - { SPA_PROP_saturation, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "saturation", NULL }, - { SPA_PROP_hue, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "hue", NULL }, - { SPA_PROP_gamma, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "gamma", NULL }, - { SPA_PROP_exposure, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "exposure", NULL }, - { SPA_PROP_gain, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "gain", NULL }, - { SPA_PROP_sharpness, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "sharpness", NULL }, - - { SPA_PROP_params, SPA_TYPE_Struct, SPA_TYPE_INFO_PROPS_BASE "params", NULL }, - { 0, 0, NULL, NULL }, -}; - -/** Enum Property info */ -#define SPA_TYPE_INFO_PropInfo SPA_TYPE_INFO_PARAM_BASE "PropInfo" -#define SPA_TYPE_INFO_PROP_INFO_BASE SPA_TYPE_INFO_PropInfo ":" - -static const struct spa_type_info spa_type_prop_info = { - { SPA_PROP_INFO_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROP_INFO_BASE, spa_type_param, }, - { SPA_PROP_INFO_id, SPA_TYPE_Id, SPA_TYPE_INFO_PROP_INFO_BASE "id", spa_type_props }, - { SPA_PROP_INFO_name, SPA_TYPE_String, SPA_TYPE_INFO_PROP_INFO_BASE "name", NULL }, - { SPA_PROP_INFO_type, SPA_TYPE_Pod, SPA_TYPE_INFO_PROP_INFO_BASE "type", NULL }, - { SPA_PROP_INFO_labels, SPA_TYPE_Struct, SPA_TYPE_INFO_PROP_INFO_BASE "labels", NULL }, - { SPA_PROP_INFO_container, SPA_TYPE_Id, SPA_TYPE_INFO_PROP_INFO_BASE "container", NULL }, - { SPA_PROP_INFO_params, SPA_TYPE_Bool, SPA_TYPE_INFO_PROP_INFO_BASE "params", NULL }, - { SPA_PROP_INFO_description, SPA_TYPE_String, SPA_TYPE_INFO_PROP_INFO_BASE "description", NULL }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_PARAM_Meta SPA_TYPE_INFO_PARAM_BASE "Meta" -#define SPA_TYPE_INFO_PARAM_META_BASE SPA_TYPE_INFO_PARAM_Meta ":" - -static const struct spa_type_info spa_type_param_meta = { - { SPA_PARAM_META_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_META_BASE, spa_type_param }, - { SPA_PARAM_META_type, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_META_BASE "type", spa_type_meta_type }, - { SPA_PARAM_META_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_META_BASE "size", NULL }, - { 0, 0, NULL, NULL }, -}; - -/** Base for parameters that describe IO areas to exchange data, - * control and properties with a node. - */ -#define SPA_TYPE_INFO_PARAM_IO SPA_TYPE_INFO_PARAM_BASE "IO" -#define SPA_TYPE_INFO_PARAM_IO_BASE SPA_TYPE_INFO_PARAM_IO ":" - -static const struct spa_type_info spa_type_param_io = { - { SPA_PARAM_IO_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_IO_BASE, spa_type_param, }, - { SPA_PARAM_IO_id, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_IO_BASE "id", spa_type_io }, - { SPA_PARAM_IO_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_IO_BASE "size", NULL }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_Format SPA_TYPE_INFO_PARAM_BASE "Format" -#define SPA_TYPE_INFO_FORMAT_BASE SPA_TYPE_INFO_Format ":" - -#define SPA_TYPE_INFO_MediaType SPA_TYPE_INFO_ENUM_BASE "MediaType" -#define SPA_TYPE_INFO_MEDIA_TYPE_BASE SPA_TYPE_INFO_MediaType ":" - -static const struct spa_type_info spa_type_media_type = { - { SPA_MEDIA_TYPE_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "unknown", NULL }, - { SPA_MEDIA_TYPE_audio, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "audio", NULL }, - { SPA_MEDIA_TYPE_video, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "video", NULL }, - { SPA_MEDIA_TYPE_image, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "image", NULL }, - { SPA_MEDIA_TYPE_binary, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "binary", NULL }, - { SPA_MEDIA_TYPE_stream, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "stream", NULL }, - { SPA_MEDIA_TYPE_application, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "application", NULL }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_MediaSubtype SPA_TYPE_INFO_ENUM_BASE "MediaSubtype" -#define SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE SPA_TYPE_INFO_MediaSubtype ":" - -static const struct spa_type_info spa_type_media_subtype = { - { SPA_MEDIA_SUBTYPE_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "unknown", NULL }, - /* generic subtypes */ - { SPA_MEDIA_SUBTYPE_raw, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "raw", NULL }, - { SPA_MEDIA_SUBTYPE_dsp, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "dsp", NULL }, - { SPA_MEDIA_SUBTYPE_iec958, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "iec958", NULL }, - { SPA_MEDIA_SUBTYPE_dsd, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "dsd", NULL }, - /* audio subtypes */ - { SPA_MEDIA_SUBTYPE_mp3, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mp3", NULL }, - { SPA_MEDIA_SUBTYPE_aac, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "aac", NULL }, - { SPA_MEDIA_SUBTYPE_vorbis, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vorbis", NULL }, - { SPA_MEDIA_SUBTYPE_wma, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "wma", NULL }, - { SPA_MEDIA_SUBTYPE_ra, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "ra", NULL }, - { SPA_MEDIA_SUBTYPE_sbc, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "sbc", NULL }, - { SPA_MEDIA_SUBTYPE_adpcm, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "adpcm", NULL }, - { SPA_MEDIA_SUBTYPE_g723, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g723", NULL }, - { SPA_MEDIA_SUBTYPE_g726, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g726", NULL }, - { SPA_MEDIA_SUBTYPE_g729, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g729", NULL }, - { SPA_MEDIA_SUBTYPE_amr, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "amr", NULL }, - { SPA_MEDIA_SUBTYPE_gsm, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "gsm", NULL }, - /* video subtypes */ - { SPA_MEDIA_SUBTYPE_h264, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "h264", NULL }, - { SPA_MEDIA_SUBTYPE_mjpg, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mjpg", NULL }, - { SPA_MEDIA_SUBTYPE_dv, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "dv", NULL }, - { SPA_MEDIA_SUBTYPE_mpegts, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpegts", NULL }, - { SPA_MEDIA_SUBTYPE_h263, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "h263", NULL }, - { SPA_MEDIA_SUBTYPE_mpeg1, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg1", NULL }, - { SPA_MEDIA_SUBTYPE_mpeg2, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg2", NULL }, - { SPA_MEDIA_SUBTYPE_mpeg4, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg4", NULL }, - { SPA_MEDIA_SUBTYPE_xvid, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "xvid", NULL }, - { SPA_MEDIA_SUBTYPE_vc1, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vc1", NULL }, - { SPA_MEDIA_SUBTYPE_vp8, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vp8", NULL }, - { SPA_MEDIA_SUBTYPE_vp9, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vp9", NULL }, - { SPA_MEDIA_SUBTYPE_bayer, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "bayer", NULL }, - /* image subtypes */ - { SPA_MEDIA_SUBTYPE_jpeg, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "jpeg", NULL }, - /* stream subtypes */ - { SPA_MEDIA_SUBTYPE_midi, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "midi", NULL }, - /* application subtypes */ - { SPA_MEDIA_SUBTYPE_control, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "control", NULL }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_FormatAudio SPA_TYPE_INFO_FORMAT_BASE "Audio" -#define SPA_TYPE_INFO_FORMAT_AUDIO_BASE SPA_TYPE_INFO_FormatAudio ":" - -#define SPA_TYPE_INFO_FormatVideo SPA_TYPE_INFO_FORMAT_BASE "Video" -#define SPA_TYPE_INFO_FORMAT_VIDEO_BASE SPA_TYPE_INFO_FormatVideo ":" - -#define SPA_TYPE_INFO_FORMAT_VIDEO_H264 SPA_TYPE_INFO_FORMAT_VIDEO_BASE "H264" -#define SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE SPA_TYPE_INFO_FORMAT_VIDEO_H264 ":" - -static const struct spa_type_info spa_type_format = { - { SPA_FORMAT_START, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE, spa_type_param, }, - - { SPA_FORMAT_mediaType, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE "mediaType", - spa_type_media_type, }, - { SPA_FORMAT_mediaSubtype, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE "mediaSubtype", - spa_type_media_subtype, }, - - { SPA_FORMAT_AUDIO_format, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "format", - spa_type_audio_format }, - { SPA_FORMAT_AUDIO_flags, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "flags", - spa_type_audio_flags }, - { SPA_FORMAT_AUDIO_rate, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "rate", NULL }, - { SPA_FORMAT_AUDIO_channels, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "channels", NULL }, - { SPA_FORMAT_AUDIO_position, SPA_TYPE_Array, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "position", - spa_type_prop_channel_map }, - - { SPA_FORMAT_AUDIO_iec958Codec, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "iec958Codec", - spa_type_audio_iec958_codec }, - - { SPA_FORMAT_AUDIO_bitorder, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "bitorder", - spa_type_param_bitorder }, - { SPA_FORMAT_AUDIO_interleave, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "interleave", NULL }, - - { SPA_FORMAT_VIDEO_format, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "format", - spa_type_video_format, }, - { SPA_FORMAT_VIDEO_modifier, SPA_TYPE_Long, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "modifier", NULL }, - { SPA_FORMAT_VIDEO_size, SPA_TYPE_Rectangle, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "size", NULL }, - { SPA_FORMAT_VIDEO_framerate, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "framerate", NULL }, - { SPA_FORMAT_VIDEO_maxFramerate, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "maxFramerate", NULL }, - { SPA_FORMAT_VIDEO_views, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "views", NULL }, - { SPA_FORMAT_VIDEO_interlaceMode, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "interlaceMode", NULL }, - { SPA_FORMAT_VIDEO_pixelAspectRatio, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "pixelAspectRatio", NULL }, - { SPA_FORMAT_VIDEO_multiviewMode, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "multiviewMode", NULL }, - { SPA_FORMAT_VIDEO_multiviewFlags, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "multiviewFlags", NULL }, - { SPA_FORMAT_VIDEO_chromaSite, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "chromaSite", NULL }, - { SPA_FORMAT_VIDEO_colorRange, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorRange", NULL }, - { SPA_FORMAT_VIDEO_colorMatrix, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorMatrix", NULL }, - { SPA_FORMAT_VIDEO_transferFunction, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "transferFunction", NULL }, - { SPA_FORMAT_VIDEO_colorPrimaries, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorPrimaries", NULL }, - { SPA_FORMAT_VIDEO_profile, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "profile", NULL }, - { SPA_FORMAT_VIDEO_level, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "level", NULL }, - - { SPA_FORMAT_VIDEO_H264_streamFormat, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE "streamFormat", NULL }, - { SPA_FORMAT_VIDEO_H264_alignment, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE "alignment", NULL }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_PARAM_Buffers SPA_TYPE_INFO_PARAM_BASE "Buffers" -#define SPA_TYPE_INFO_PARAM_BUFFERS_BASE SPA_TYPE_INFO_PARAM_Buffers ":" - -#define SPA_TYPE_INFO_PARAM_BlockInfo SPA_TYPE_INFO_PARAM_BUFFERS_BASE "BlockInfo" -#define SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE SPA_TYPE_INFO_PARAM_BlockInfo ":" - -static const struct spa_type_info spa_type_param_buffers = { - { SPA_PARAM_BUFFERS_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_BUFFERS_BASE, spa_type_param, }, - { SPA_PARAM_BUFFERS_buffers, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BUFFERS_BASE "buffers", NULL }, - { SPA_PARAM_BUFFERS_blocks, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BUFFERS_BASE "blocks", NULL }, - { SPA_PARAM_BUFFERS_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "size", NULL }, - { SPA_PARAM_BUFFERS_stride, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "stride", NULL }, - { SPA_PARAM_BUFFERS_align, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "align", NULL }, - { SPA_PARAM_BUFFERS_dataType, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "dataType", NULL }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_ParamAvailability SPA_TYPE_INFO_ENUM_BASE "ParamAvailability" -#define SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE SPA_TYPE_INFO_ParamAvailability ":" - -static const struct spa_type_info spa_type_param_availability = { - { SPA_PARAM_AVAILABILITY_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "unknown", NULL }, - { SPA_PARAM_AVAILABILITY_no, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "no", NULL }, - { SPA_PARAM_AVAILABILITY_yes, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "yes", NULL }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_PARAM_Profile SPA_TYPE_INFO_PARAM_BASE "Profile" -#define SPA_TYPE_INFO_PARAM_PROFILE_BASE SPA_TYPE_INFO_PARAM_Profile ":" - -static const struct spa_type_info spa_type_param_profile = { - { SPA_PARAM_PROFILE_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PROFILE_BASE, spa_type_param, }, - { SPA_PARAM_PROFILE_index, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PROFILE_BASE "index", NULL }, - { SPA_PARAM_PROFILE_name, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_PROFILE_BASE "name", NULL }, - { SPA_PARAM_PROFILE_description, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_PROFILE_BASE "description", NULL }, - { SPA_PARAM_PROFILE_priority, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PROFILE_BASE "priority", NULL }, - { SPA_PARAM_PROFILE_available, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PROFILE_BASE "available", spa_type_param_availability, }, - { SPA_PARAM_PROFILE_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_PROFILE_BASE "info", NULL, }, - { SPA_PARAM_PROFILE_classes, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_PROFILE_BASE "classes", NULL, }, - { SPA_PARAM_PROFILE_save, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PROFILE_BASE "save", NULL, }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_ParamPortConfigMode SPA_TYPE_INFO_ENUM_BASE "ParamPortConfigMode" -#define SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE SPA_TYPE_INFO_ParamPortConfigMode ":" - -static const struct spa_type_info spa_type_param_port_config_mode = { - { SPA_PARAM_PORT_CONFIG_MODE_none, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "none", NULL }, - { SPA_PARAM_PORT_CONFIG_MODE_passthrough, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "passthrough", NULL }, - { SPA_PARAM_PORT_CONFIG_MODE_convert, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "convert", NULL }, - { SPA_PARAM_PORT_CONFIG_MODE_dsp, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "dsp", NULL }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_PARAM_PortConfig SPA_TYPE_INFO_PARAM_BASE "PortConfig" -#define SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE SPA_TYPE_INFO_PARAM_PortConfig ":" - -static const struct spa_type_info spa_type_param_port_config = { - { SPA_PARAM_PORT_CONFIG_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE, spa_type_param, }, - { SPA_PARAM_PORT_CONFIG_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "direction", spa_type_direction, }, - { SPA_PARAM_PORT_CONFIG_mode, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "mode", spa_type_param_port_config_mode }, - { SPA_PARAM_PORT_CONFIG_monitor, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "monitor", NULL }, - { SPA_PARAM_PORT_CONFIG_control, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "control", NULL }, - { SPA_PARAM_PORT_CONFIG_format, SPA_TYPE_OBJECT_Format, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "format", NULL }, - { 0, 0, NULL, NULL }, -}; - - -#define SPA_TYPE_INFO_PARAM_Route SPA_TYPE_INFO_PARAM_BASE "Route" -#define SPA_TYPE_INFO_PARAM_ROUTE_BASE SPA_TYPE_INFO_PARAM_Route ":" - -static const struct spa_type_info spa_type_param_route = { - { SPA_PARAM_ROUTE_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE, spa_type_param, }, - { SPA_PARAM_ROUTE_index, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "index", NULL, }, - { SPA_PARAM_ROUTE_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE "direction", spa_type_direction, }, - { SPA_PARAM_ROUTE_device, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "device", NULL, }, - { SPA_PARAM_ROUTE_name, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_ROUTE_BASE "name", NULL, }, - { SPA_PARAM_ROUTE_description, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_ROUTE_BASE "description", NULL, }, - { SPA_PARAM_ROUTE_priority, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "priority", NULL, }, - { SPA_PARAM_ROUTE_available, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE "available", spa_type_param_availability, }, - { SPA_PARAM_ROUTE_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_ROUTE_BASE "info", NULL, }, - { SPA_PARAM_ROUTE_profiles, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profiles", NULL, }, - { SPA_PARAM_ROUTE_props, SPA_TYPE_OBJECT_Props, SPA_TYPE_INFO_PARAM_ROUTE_BASE "props", NULL, }, - { SPA_PARAM_ROUTE_devices, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "devices", NULL, }, - { SPA_PARAM_ROUTE_profile, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profile", NULL, }, - { SPA_PARAM_ROUTE_save, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_ROUTE_BASE "save", NULL, }, - { 0, 0, NULL, NULL }, -}; - -#include <spa/param/profiler.h> - -#define SPA_TYPE_INFO_Profiler SPA_TYPE_INFO_OBJECT_BASE "Profiler" -#define SPA_TYPE_INFO_PROFILER_BASE SPA_TYPE_INFO_Profiler ":" - -static const struct spa_type_info spa_type_profiler = { - { SPA_PROFILER_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROFILER_BASE, spa_type_param, }, - { SPA_PROFILER_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "info", NULL, }, - { SPA_PROFILER_clock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "clock", NULL, }, - { SPA_PROFILER_driverBlock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "driverBlock", NULL, }, - { SPA_PROFILER_followerBlock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "followerBlock", NULL, }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_PARAM_Latency SPA_TYPE_INFO_PARAM_BASE "Latency" -#define SPA_TYPE_INFO_PARAM_LATENCY_BASE SPA_TYPE_INFO_PARAM_Latency ":" - -static const struct spa_type_info spa_type_param_latency = { - { SPA_PARAM_LATENCY_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_LATENCY_BASE, spa_type_param, }, - { SPA_PARAM_LATENCY_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_LATENCY_BASE "direction", spa_type_direction, }, - { SPA_PARAM_LATENCY_minQuantum, SPA_TYPE_Float, SPA_TYPE_INFO_PARAM_LATENCY_BASE "minQuantum", NULL, }, - { SPA_PARAM_LATENCY_maxQuantum, SPA_TYPE_Float, SPA_TYPE_INFO_PARAM_LATENCY_BASE "maxQuantum", NULL, }, - { SPA_PARAM_LATENCY_minRate, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_LATENCY_BASE "minRate", NULL, }, - { SPA_PARAM_LATENCY_maxRate, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_LATENCY_BASE "maxRate", NULL, }, - { SPA_PARAM_LATENCY_minNs, SPA_TYPE_Long, SPA_TYPE_INFO_PARAM_LATENCY_BASE "minNs", NULL, }, - { SPA_PARAM_LATENCY_maxNs, SPA_TYPE_Long, SPA_TYPE_INFO_PARAM_LATENCY_BASE "maxNs", NULL, }, - { 0, 0, NULL, NULL }, -}; - -#define SPA_TYPE_INFO_PARAM_ProcessLatency SPA_TYPE_INFO_PARAM_BASE "ProcessLatency" -#define SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE SPA_TYPE_INFO_PARAM_ProcessLatency ":" - -static const struct spa_type_info spa_type_param_process_latency = { - { SPA_PARAM_PROCESS_LATENCY_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_LATENCY_BASE, spa_type_param, }, - { SPA_PARAM_PROCESS_LATENCY_quantum, SPA_TYPE_Float, SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE "quantum", NULL, }, - { SPA_PARAM_PROCESS_LATENCY_rate, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE "rate", NULL, }, - { SPA_PARAM_PROCESS_LATENCY_ns, SPA_TYPE_Long, SPA_TYPE_INFO_PARAM_PROCESS_LATENCY_BASE "ns", NULL, }, - { 0, 0, NULL, NULL }, -}; - -/** - * \} - */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* SPA_PARAM_TYPES_H */ +#ifndef SPA_PARAM_TYPE_INFO_H +#define SPA_PARAM_TYPE_INFO_H + +#include <spa/param/param-types.h> +#include <spa/param/buffers-types.h> +#include <spa/param/props-types.h> +#include <spa/param/format-types.h> +#include <spa/param/latency-types.h> +#include <spa/param/port-config-types.h> +#include <spa/param/profiler-types.h> +#include <spa/param/profile-types.h> +#include <spa/param/route-types.h> + +#endif /* SPA_PARAM_TYPE_INFO_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/video/dsp-utils.h
Added
@@ -0,0 +1,83 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_VIDEO_DSP_UTILS_H +#define SPA_VIDEO_DSP_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/video/dsp.h> + +static inline int +spa_format_video_dsp_parse(const struct spa_pod *format, + struct spa_video_info_dsp *info) +{ + info->flags = SPA_VIDEO_FLAG_NONE; + if (spa_pod_find_prop (format, NULL, SPA_FORMAT_VIDEO_modifier)) { + info->flags |= SPA_VIDEO_FLAG_MODIFIER; + } + + return spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_VIDEO_format, SPA_POD_OPT_Id(&info->format), + SPA_FORMAT_VIDEO_modifier, SPA_POD_OPT_Long(&info->modifier)); +} + +static inline struct spa_pod * +spa_format_video_dsp_build(struct spa_pod_builder *builder, uint32_t id, + struct spa_video_info_dsp *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp), + 0); + if (info->format != SPA_VIDEO_FORMAT_UNKNOWN) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_format, SPA_POD_Id(info->format), 0); + if (info->modifier != 0 || info->flags & SPA_VIDEO_FLAG_MODIFIER) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_modifier, SPA_POD_Long(info->modifier), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_VIDEO_DSP_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/video/dsp.h
Added
@@ -0,0 +1,55 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_VIDEO_DSP_H +#define SPA_VIDEO_DSP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/video/raw.h> + +struct spa_video_info_dsp { + enum spa_video_format format; + uint32_t flags; + uint64_t modifier; +}; + +#define SPA_VIDEO_INFO_DSP_INIT(...) ((struct spa_video_info_dsp) { __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_VIDEO_DSP_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/video/encoded.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/video/encoded.h
Changed
@@ -25,50 +25,7 @@ #ifndef SPA_VIDEO_ENCODED_H #define SPA_VIDEO_ENCODED_H -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \addtogroup spa_param - * \{ - */ - -#include <spa/param/format.h> - -enum spa_h264_stream_format { - SPA_H264_STREAM_FORMAT_UNKNOWN = 0, - SPA_H264_STREAM_FORMAT_AVC, - SPA_H264_STREAM_FORMAT_AVC3, - SPA_H264_STREAM_FORMAT_BYTESTREAM -}; - -enum spa_h264_alignment { - SPA_H264_ALIGNMENT_UNKNOWN = 0, - SPA_H264_ALIGNMENT_AU, - SPA_H264_ALIGNMENT_NAL -}; - -struct spa_video_info_h264 { - struct spa_rectangle size; - struct spa_fraction framerate; - struct spa_fraction max_framerate; - enum spa_h264_stream_format stream_format; - enum spa_h264_alignment alignment; -}; - -struct spa_video_info_mjpg { - struct spa_rectangle size; - struct spa_fraction framerate; - struct spa_fraction max_framerate; -}; - -/** - * \} - */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif +#include <spa/param/video/h264.h> +#include <spa/param/video/mjpg.h> #endif /* SPA_VIDEO_ENCODED_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/video/format-utils.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/video/format-utils.h
Changed
@@ -29,203 +29,54 @@ extern "C" { #endif -/** - * \addtogroup spa_param - * \{ - */ -#include <spa/pod/parser.h> -#include <spa/pod/builder.h> -#include <spa/param/video/format.h> #include <spa/param/format-utils.h> +#include <spa/param/video/format.h> +#include <spa/param/video/raw-utils.h> +#include <spa/param/video/dsp-utils.h> +#include <spa/param/video/h264-utils.h> +#include <spa/param/video/mjpg-utils.h> static inline int -spa_format_video_raw_parse(const struct spa_pod *format, - struct spa_video_info_raw *info) -{ - return spa_pod_parse_object(format, - SPA_TYPE_OBJECT_Format, NULL, - SPA_FORMAT_VIDEO_format, SPA_POD_OPT_Id(&info->format), - SPA_FORMAT_VIDEO_modifier, SPA_POD_OPT_Long(&info->modifier), - SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&info->size), - SPA_FORMAT_VIDEO_framerate, SPA_POD_OPT_Fraction(&info->framerate), - SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate), - SPA_FORMAT_VIDEO_views, SPA_POD_OPT_Int(&info->views), - SPA_FORMAT_VIDEO_interlaceMode, SPA_POD_OPT_Id(&info->interlace_mode), - SPA_FORMAT_VIDEO_pixelAspectRatio, SPA_POD_OPT_Fraction(&info->pixel_aspect_ratio), - SPA_FORMAT_VIDEO_multiviewMode, SPA_POD_OPT_Id(&info->multiview_mode), - SPA_FORMAT_VIDEO_multiviewFlags, SPA_POD_OPT_Id(&info->multiview_flags), - SPA_FORMAT_VIDEO_chromaSite, SPA_POD_OPT_Id(&info->chroma_site), - SPA_FORMAT_VIDEO_colorRange, SPA_POD_OPT_Id(&info->color_range), - SPA_FORMAT_VIDEO_colorMatrix, SPA_POD_OPT_Id(&info->color_matrix), - SPA_FORMAT_VIDEO_transferFunction, SPA_POD_OPT_Id(&info->transfer_function), - SPA_FORMAT_VIDEO_colorPrimaries, SPA_POD_OPT_Id(&info->color_primaries)); -} - -static inline int -spa_format_video_dsp_parse(const struct spa_pod *format, - struct spa_video_info_dsp *info) -{ - return spa_pod_parse_object(format, - SPA_TYPE_OBJECT_Format, NULL, - SPA_FORMAT_VIDEO_format, SPA_POD_OPT_Id(&info->format), - SPA_FORMAT_VIDEO_modifier, SPA_POD_OPT_Long(&info->modifier)); -} - -static inline struct spa_pod * -spa_format_video_raw_build(struct spa_pod_builder *builder, uint32_t id, - struct spa_video_info_raw *info) -{ - struct spa_pod_frame f; - spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); - spa_pod_builder_add(builder, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), - 0); - if (info->format != SPA_VIDEO_FORMAT_UNKNOWN) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_format, SPA_POD_Id(info->format), 0); - if (info->size.width != 0 && info->size.height != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&info->size), 0); - if (info->framerate.denom != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0); - if (info->modifier != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_modifier, SPA_POD_Long(info->modifier), 0); - if (info->max_framerate.denom != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0); - if (info->views != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_views, SPA_POD_Int(info->views), 0); - if (info->interlace_mode != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_interlaceMode, SPA_POD_Id(info->interlace_mode), 0); - if (info->pixel_aspect_ratio.denom != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_pixelAspectRatio,SPA_POD_Fraction(info->pixel_aspect_ratio), 0); - if (info->multiview_mode != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_multiviewMode, SPA_POD_Id(info->multiview_mode), 0); - if (info->multiview_flags != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_multiviewFlags,SPA_POD_Id(info->multiview_flags), 0); - if (info->chroma_site != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_chromaSite, SPA_POD_Id(info->chroma_site), 0); - if (info->color_range != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_colorRange, SPA_POD_Id(info->color_range), 0); - if (info->color_matrix != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_colorMatrix, SPA_POD_Id(info->color_matrix), 0); - if (info->transfer_function != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_transferFunction,SPA_POD_Id(info->transfer_function), 0); - if (info->color_primaries != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_colorPrimaries,SPA_POD_Id(info->color_primaries), 0); - return (struct spa_pod*)spa_pod_builder_pop(builder, &f); -} - -static inline struct spa_pod * -spa_format_video_dsp_build(struct spa_pod_builder *builder, uint32_t id, - struct spa_video_info_dsp *info) +spa_format_video_parse(const struct spa_pod *format, struct spa_video_info *info) { - struct spa_pod_frame f; - spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); - spa_pod_builder_add(builder, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp), - 0); - if (info->format != SPA_VIDEO_FORMAT_UNKNOWN) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_format, SPA_POD_Id(info->format), 0); - if (info->modifier) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_modifier, SPA_POD_Long(info->modifier), 0); - return (struct spa_pod*)spa_pod_builder_pop(builder, &f); -} + int res; -static inline int -spa_format_video_h264_parse(const struct spa_pod *format, - struct spa_video_info_h264 *info) -{ - return spa_pod_parse_object(format, - SPA_TYPE_OBJECT_Format, NULL, - SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&info->size), - SPA_FORMAT_VIDEO_framerate, SPA_POD_OPT_Fraction(&info->framerate), - SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate), - SPA_FORMAT_VIDEO_H264_streamFormat, SPA_POD_OPT_Id(&info->stream_format), - SPA_FORMAT_VIDEO_H264_alignment, SPA_POD_OPT_Id(&info->alignment)); -} + if ((res = spa_format_parse(format, &info->media_type, &info->media_subtype)) < 0) + return res; -static inline struct spa_pod * -spa_format_video_h264_build(struct spa_pod_builder *builder, uint32_t id, - struct spa_video_info_h264 *info) -{ - struct spa_pod_frame f; - spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); - spa_pod_builder_add(builder, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_h264), - 0); - if (info->size.width != 0 && info->size.height != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&info->size), 0); - if (info->framerate.denom != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0); - if (info->max_framerate.denom != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0); - if (info->stream_format != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_H264_streamFormat, SPA_POD_Id(info->stream_format), 0); - if (info->alignment != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_H264_alignment, SPA_POD_Id(info->alignment), 0); - return (struct spa_pod*)spa_pod_builder_pop(builder, &f); -} + if (info->media_type != SPA_MEDIA_TYPE_video) + return -EINVAL; -static inline int -spa_format_video_mjpg_parse(const struct spa_pod *format, - struct spa_video_info_mjpg *info) -{ - return spa_pod_parse_object(format, - SPA_TYPE_OBJECT_Format, NULL, - SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&info->size), - SPA_FORMAT_VIDEO_framerate, SPA_POD_OPT_Fraction(&info->framerate), - SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate)); + switch (info->media_subtype) { + case SPA_MEDIA_SUBTYPE_raw: + return spa_format_video_raw_parse(format, &info->info.raw); + case SPA_MEDIA_SUBTYPE_dsp: + return spa_format_video_dsp_parse(format, &info->info.dsp); + case SPA_MEDIA_SUBTYPE_h264: + return spa_format_video_h264_parse(format, &info->info.h264); + case SPA_MEDIA_SUBTYPE_mjpg: + return spa_format_video_mjpg_parse(format, &info->info.mjpg); + } + return -ENOTSUP; } static inline struct spa_pod * -spa_format_video_mjpg_build(struct spa_pod_builder *builder, uint32_t id, - struct spa_video_info_mjpg *info) +spa_format_video_build(struct spa_pod_builder *builder, uint32_t id, struct spa_video_info *info) { - struct spa_pod_frame f; - spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); - spa_pod_builder_add(builder, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_mjpg), - 0); - if (info->size.width != 0 && info->size.height != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&info->size), 0); - if (info->framerate.denom != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0); - if (info->max_framerate.denom != 0) - spa_pod_builder_add(builder, - SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0); - return (struct spa_pod*)spa_pod_builder_pop(builder, &f); + switch (info->media_subtype) { + case SPA_MEDIA_SUBTYPE_raw: + return spa_format_video_raw_build(builder, id, &info->info.raw); + case SPA_MEDIA_SUBTYPE_dsp: + return spa_format_video_dsp_build(builder, id, &info->info.dsp); + case SPA_MEDIA_SUBTYPE_h264: + return spa_format_video_h264_build(builder, id, &info->info.h264); + case SPA_MEDIA_SUBTYPE_mjpg: + return spa_format_video_mjpg_build(builder, id, &info->info.mjpg); + } + errno = ENOTSUP; + return NULL; } -/** - * \} - */ - #ifdef __cplusplus } /* extern "C" */ #endif
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/video/format.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/video/format.h
Changed
@@ -34,7 +34,9 @@ * \{ */ +#include <spa/param/format.h> #include <spa/param/video/raw.h> +#include <spa/param/video/dsp.h> #include <spa/param/video/encoded.h> struct spa_video_info {
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/video/h264-utils.h
Added
@@ -0,0 +1,90 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_VIDEO_H264_UTILS_H +#define SPA_VIDEO_H264_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/video/h264.h> + +static inline int +spa_format_video_h264_parse(const struct spa_pod *format, + struct spa_video_info_h264 *info) +{ + return spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&info->size), + SPA_FORMAT_VIDEO_framerate, SPA_POD_OPT_Fraction(&info->framerate), + SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate), + SPA_FORMAT_VIDEO_H264_streamFormat, SPA_POD_OPT_Id(&info->stream_format), + SPA_FORMAT_VIDEO_H264_alignment, SPA_POD_OPT_Id(&info->alignment)); +} + +static inline struct spa_pod * +spa_format_video_h264_build(struct spa_pod_builder *builder, uint32_t id, + struct spa_video_info_h264 *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_h264), + 0); + if (info->size.width != 0 && info->size.height != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&info->size), 0); + if (info->framerate.denom != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0); + if (info->max_framerate.denom != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0); + if (info->stream_format != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_H264_streamFormat, SPA_POD_Id(info->stream_format), 0); + if (info->alignment != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_H264_alignment, SPA_POD_Id(info->alignment), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_VIDEO_H264_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/video/h264.h
Added
@@ -0,0 +1,68 @@ +/* Simple Plugin API + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_VIDEO_H264_H +#define SPA_VIDEO_H264_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/format.h> + +enum spa_h264_stream_format { + SPA_H264_STREAM_FORMAT_UNKNOWN = 0, + SPA_H264_STREAM_FORMAT_AVC, + SPA_H264_STREAM_FORMAT_AVC3, + SPA_H264_STREAM_FORMAT_BYTESTREAM +}; + +enum spa_h264_alignment { + SPA_H264_ALIGNMENT_UNKNOWN = 0, + SPA_H264_ALIGNMENT_AU, + SPA_H264_ALIGNMENT_NAL +}; + +struct spa_video_info_h264 { + struct spa_rectangle size; + struct spa_fraction framerate; + struct spa_fraction max_framerate; + enum spa_h264_stream_format stream_format; + enum spa_h264_alignment alignment; +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_VIDEO_H264_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/video/mjpg-utils.h
Added
@@ -0,0 +1,82 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_VIDEO_MJPG_UTILS_H +#define SPA_VIDEO_MJPG_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/video/mjpg.h> + +static inline int +spa_format_video_mjpg_parse(const struct spa_pod *format, + struct spa_video_info_mjpg *info) +{ + return spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&info->size), + SPA_FORMAT_VIDEO_framerate, SPA_POD_OPT_Fraction(&info->framerate), + SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate)); +} + +static inline struct spa_pod * +spa_format_video_mjpg_build(struct spa_pod_builder *builder, uint32_t id, + struct spa_video_info_mjpg *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_mjpg), + 0); + if (info->size.width != 0 && info->size.height != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&info->size), 0); + if (info->framerate.denom != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0); + if (info->max_framerate.denom != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_VIDEO_MJPG_UTILS_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/video/mjpg.h
Added
@@ -0,0 +1,53 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_VIDEO_MJPG_H +#define SPA_VIDEO_MJPG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/format.h> + +struct spa_video_info_mjpg { + struct spa_rectangle size; + struct spa_fraction framerate; + struct spa_fraction max_framerate; +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_VIDEO_MJPG_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/video/raw-types.h
Added
@@ -0,0 +1,164 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_VIDEO_RAW_TYPES_H +#define SPA_VIDEO_RAW_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ +#include <spa/utils/type.h> +#include <spa/param/video/raw.h> + +#define SPA_TYPE_INFO_VideoFormat SPA_TYPE_INFO_ENUM_BASE "VideoFormat" +#define SPA_TYPE_INFO_VIDEO_FORMAT_BASE SPA_TYPE_INFO_VideoFormat ":" + +static const struct spa_type_info spa_type_video_format = { + { SPA_VIDEO_FORMAT_ENCODED, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "encoded", NULL }, + { SPA_VIDEO_FORMAT_I420, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420", NULL }, + { SPA_VIDEO_FORMAT_YV12, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YV12", NULL }, + { SPA_VIDEO_FORMAT_YUY2, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YUY2", NULL }, + { SPA_VIDEO_FORMAT_UYVY, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "UYVY", NULL }, + { SPA_VIDEO_FORMAT_AYUV, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "AYUV", NULL }, + { SPA_VIDEO_FORMAT_RGBx, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBx", NULL }, + { SPA_VIDEO_FORMAT_BGRx, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRx", NULL }, + { SPA_VIDEO_FORMAT_xRGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xRGB", NULL }, + { SPA_VIDEO_FORMAT_xBGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xBGR", NULL }, + { SPA_VIDEO_FORMAT_RGBA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA", NULL }, + { SPA_VIDEO_FORMAT_BGRA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRA", NULL }, + { SPA_VIDEO_FORMAT_ARGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ARGB", NULL }, + { SPA_VIDEO_FORMAT_ABGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ABGR", NULL }, + { SPA_VIDEO_FORMAT_RGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB", NULL }, + { SPA_VIDEO_FORMAT_BGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR", NULL }, + { SPA_VIDEO_FORMAT_Y41B, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y41B", NULL }, + { SPA_VIDEO_FORMAT_Y42B, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y42B", NULL }, + { SPA_VIDEO_FORMAT_YVYU, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YVYU", NULL }, + { SPA_VIDEO_FORMAT_Y444, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444", NULL }, + { SPA_VIDEO_FORMAT_v210, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v210", NULL }, + { SPA_VIDEO_FORMAT_v216, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v216", NULL }, + { SPA_VIDEO_FORMAT_NV12, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV12", NULL }, + { SPA_VIDEO_FORMAT_NV21, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV21", NULL }, + { SPA_VIDEO_FORMAT_GRAY8, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY8", NULL }, + { SPA_VIDEO_FORMAT_GRAY16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY16_BE", NULL }, + { SPA_VIDEO_FORMAT_GRAY16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY16_LE", NULL }, + { SPA_VIDEO_FORMAT_v308, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v308", NULL }, + { SPA_VIDEO_FORMAT_RGB16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB16", NULL }, + { SPA_VIDEO_FORMAT_BGR16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR16", NULL }, + { SPA_VIDEO_FORMAT_RGB15, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB15", NULL }, + { SPA_VIDEO_FORMAT_BGR15, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR15", NULL }, + { SPA_VIDEO_FORMAT_UYVP, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "UYVP", NULL }, + { SPA_VIDEO_FORMAT_A420, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420", NULL }, + { SPA_VIDEO_FORMAT_RGB8P, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB8P", NULL }, + { SPA_VIDEO_FORMAT_YUV9, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YUV9", NULL }, + { SPA_VIDEO_FORMAT_YVU9, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YVU9", NULL }, + { SPA_VIDEO_FORMAT_IYU1, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "IYU1", NULL }, + { SPA_VIDEO_FORMAT_ARGB64, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ARGB64", NULL }, + { SPA_VIDEO_FORMAT_AYUV64, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "AYUV64", NULL }, + { SPA_VIDEO_FORMAT_r210, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "r210", NULL }, + { SPA_VIDEO_FORMAT_I420_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_10BE", NULL }, + { SPA_VIDEO_FORMAT_I420_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_10LE", NULL }, + { SPA_VIDEO_FORMAT_I422_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_10BE", NULL }, + { SPA_VIDEO_FORMAT_I422_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_10LE", NULL }, + { SPA_VIDEO_FORMAT_Y444_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_10BE", NULL }, + { SPA_VIDEO_FORMAT_Y444_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_10LE", NULL }, + { SPA_VIDEO_FORMAT_GBR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR", NULL }, + { SPA_VIDEO_FORMAT_GBR_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_10BE", NULL }, + { SPA_VIDEO_FORMAT_GBR_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_10LE", NULL }, + { SPA_VIDEO_FORMAT_NV16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV16", NULL }, + { SPA_VIDEO_FORMAT_NV24, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV24", NULL }, + { SPA_VIDEO_FORMAT_NV12_64Z32, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV12_64Z32", NULL }, + { SPA_VIDEO_FORMAT_A420_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420_10BE", NULL }, + { SPA_VIDEO_FORMAT_A420_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420_10LE", NULL }, + { SPA_VIDEO_FORMAT_A422_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A422_10BE", NULL }, + { SPA_VIDEO_FORMAT_A422_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A422_10LE", NULL }, + { SPA_VIDEO_FORMAT_A444_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A444_10BE", NULL }, + { SPA_VIDEO_FORMAT_A444_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A444_10LE", NULL }, + { SPA_VIDEO_FORMAT_NV61, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV61", NULL }, + { SPA_VIDEO_FORMAT_P010_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "P010_10BE", NULL }, + { SPA_VIDEO_FORMAT_P010_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "P010_10LE", NULL }, + { SPA_VIDEO_FORMAT_IYU2, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "IYU2", NULL }, + { SPA_VIDEO_FORMAT_VYUY, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "VYUY", NULL }, + { SPA_VIDEO_FORMAT_GBRA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA", NULL }, + { SPA_VIDEO_FORMAT_GBRA_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_10BE", NULL }, + { SPA_VIDEO_FORMAT_GBRA_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_10LE", NULL }, + { SPA_VIDEO_FORMAT_GBR_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_12BE", NULL }, + { SPA_VIDEO_FORMAT_GBR_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_12LE", NULL }, + { SPA_VIDEO_FORMAT_GBRA_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_12BE", NULL }, + { SPA_VIDEO_FORMAT_GBRA_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_12LE", NULL }, + { SPA_VIDEO_FORMAT_I420_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_12BE", NULL }, + { SPA_VIDEO_FORMAT_I420_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_12LE", NULL }, + { SPA_VIDEO_FORMAT_I422_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_12BE", NULL }, + { SPA_VIDEO_FORMAT_I422_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_12LE", NULL }, + { SPA_VIDEO_FORMAT_Y444_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_12BE", NULL }, + { SPA_VIDEO_FORMAT_Y444_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_12LE", NULL }, + { SPA_VIDEO_FORMAT_RGBA_F16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA_F16", NULL }, + { SPA_VIDEO_FORMAT_RGBA_F32, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA_F32", NULL }, + { SPA_VIDEO_FORMAT_xRGB_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xRGB_210LE", NULL }, + { SPA_VIDEO_FORMAT_xBGR_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xBGR_210LE", NULL }, + { SPA_VIDEO_FORMAT_RGBx_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBx_102LE", NULL }, + { SPA_VIDEO_FORMAT_BGRx_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRx_102LE", NULL }, + { SPA_VIDEO_FORMAT_ARGB_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ARGB_210LE", NULL }, + { SPA_VIDEO_FORMAT_ABGR_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ABGR_210LE", NULL }, + { SPA_VIDEO_FORMAT_RGBA_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA_102LE", NULL }, + { SPA_VIDEO_FORMAT_BGRA_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRA_102LE", NULL }, + { 0, 0, NULL, NULL }, +}; + +#define SPA_TYPE_INFO_VideoFlags SPA_TYPE_INFO_FLAGS_BASE "VideoFlags" +#define SPA_TYPE_INFO_VIDEO_FLAGS_BASE SPA_TYPE_INFO_VideoFlags ":" + +static const struct spa_type_info spa_type_video_flags = { + + { SPA_VIDEO_FLAG_NONE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FLAGS_BASE "none", NULL }, + { SPA_VIDEO_FLAG_VARIABLE_FPS, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FLAGS_BASE "variable-fps", NULL }, + { SPA_VIDEO_FLAG_PREMULTIPLIED_ALPHA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FLAGS_BASE "premultiplied-alpha", NULL }, + { SPA_VIDEO_FLAG_MODIFIER, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FLAGS_BASE "modifier", NULL }, + { 0, 0, NULL, NULL }, +}; + +#define SPA_TYPE_INFO_VideoInterlaceMode SPA_TYPE_INFO_ENUM_BASE "VideoInterlaceMode" +#define SPA_TYPE_INFO_VIDEO_INTERLACE_MODE_BASE SPA_TYPE_INFO_VideoInterlaceMode ":" + +static const struct spa_type_info spa_type_video_interlace_mode = { + { SPA_VIDEO_INTERLACE_MODE_PROGRESSIVE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_INTERLACE_MODE_BASE "progressive", NULL }, + { SPA_VIDEO_INTERLACE_MODE_INTERLEAVED, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_INTERLACE_MODE_BASE "interleaved", NULL }, + { SPA_VIDEO_INTERLACE_MODE_MIXED, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_INTERLACE_MODE_BASE "mixed", NULL }, + { SPA_VIDEO_INTERLACE_MODE_FIELDS, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_INTERLACE_MODE_BASE "fields", NULL }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_VIDEO_RAW_TYPES_H */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/video/raw-utils.h
Added
@@ -0,0 +1,135 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_VIDEO_RAW_UTILS_H +#define SPA_VIDEO_RAW_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/pod/parser.h> +#include <spa/pod/builder.h> +#include <spa/param/video/raw.h> + +static inline int +spa_format_video_raw_parse(const struct spa_pod *format, + struct spa_video_info_raw *info) +{ + info->flags = SPA_VIDEO_FLAG_NONE; + if (spa_pod_find_prop (format, NULL, SPA_FORMAT_VIDEO_modifier)) { + info->flags |= SPA_VIDEO_FLAG_MODIFIER; + } + + return spa_pod_parse_object(format, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_VIDEO_format, SPA_POD_OPT_Id(&info->format), + SPA_FORMAT_VIDEO_modifier, SPA_POD_OPT_Long(&info->modifier), + SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&info->size), + SPA_FORMAT_VIDEO_framerate, SPA_POD_OPT_Fraction(&info->framerate), + SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate), + SPA_FORMAT_VIDEO_views, SPA_POD_OPT_Int(&info->views), + SPA_FORMAT_VIDEO_interlaceMode, SPA_POD_OPT_Id(&info->interlace_mode), + SPA_FORMAT_VIDEO_pixelAspectRatio, SPA_POD_OPT_Fraction(&info->pixel_aspect_ratio), + SPA_FORMAT_VIDEO_multiviewMode, SPA_POD_OPT_Id(&info->multiview_mode), + SPA_FORMAT_VIDEO_multiviewFlags, SPA_POD_OPT_Id(&info->multiview_flags), + SPA_FORMAT_VIDEO_chromaSite, SPA_POD_OPT_Id(&info->chroma_site), + SPA_FORMAT_VIDEO_colorRange, SPA_POD_OPT_Id(&info->color_range), + SPA_FORMAT_VIDEO_colorMatrix, SPA_POD_OPT_Id(&info->color_matrix), + SPA_FORMAT_VIDEO_transferFunction, SPA_POD_OPT_Id(&info->transfer_function), + SPA_FORMAT_VIDEO_colorPrimaries, SPA_POD_OPT_Id(&info->color_primaries)); +} + +static inline struct spa_pod * +spa_format_video_raw_build(struct spa_pod_builder *builder, uint32_t id, + struct spa_video_info_raw *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(builder, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), + 0); + if (info->format != SPA_VIDEO_FORMAT_UNKNOWN) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_format, SPA_POD_Id(info->format), 0); + if (info->size.width != 0 && info->size.height != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&info->size), 0); + if (info->framerate.denom != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate), 0); + if (info->modifier != 0 || info->flags & SPA_VIDEO_FLAG_MODIFIER) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_modifier, SPA_POD_Long(info->modifier), 0); + if (info->max_framerate.denom != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0); + if (info->views != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_views, SPA_POD_Int(info->views), 0); + if (info->interlace_mode != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_interlaceMode, SPA_POD_Id(info->interlace_mode), 0); + if (info->pixel_aspect_ratio.denom != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_pixelAspectRatio,SPA_POD_Fraction(info->pixel_aspect_ratio), 0); + if (info->multiview_mode != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_multiviewMode, SPA_POD_Id(info->multiview_mode), 0); + if (info->multiview_flags != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_multiviewFlags,SPA_POD_Id(info->multiview_flags), 0); + if (info->chroma_site != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_chromaSite, SPA_POD_Id(info->chroma_site), 0); + if (info->color_range != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_colorRange, SPA_POD_Id(info->color_range), 0); + if (info->color_matrix != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_colorMatrix, SPA_POD_Id(info->color_matrix), 0); + if (info->transfer_function != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_transferFunction,SPA_POD_Id(info->transfer_function), 0); + if (info->color_primaries != 0) + spa_pod_builder_add(builder, + SPA_FORMAT_VIDEO_colorPrimaries,SPA_POD_Id(info->color_primaries), 0); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_VIDEO_RAW_UTILS_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/video/raw.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/video/raw.h
Changed
@@ -34,7 +34,7 @@ * \{ */ -#include <spa/utils/defs.h> +#include <spa/param/format.h> #include <spa/param/video/chroma.h> #include <spa/param/video/color.h> #include <spa/param/video/multiview.h> @@ -158,6 +158,7 @@ SPA_VIDEO_FLAG_VARIABLE_FPS = (1 << 0), /**< a variable fps is selected, fps_n and fps_d * denote the maximum fps of the video */ SPA_VIDEO_FLAG_PREMULTIPLIED_ALPHA = (1 << 1), /**< Each color has been scaled by the alpha value. */ + SPA_VIDEO_FLAG_MODIFIER = (1 << 2), /**< use the format modifier */ }; /** @@ -186,7 +187,8 @@ */ struct spa_video_info_raw { enum spa_video_format format; /**< the format */ - int64_t modifier; /**< format modifier + uint32_t flags; /**< extra video flags */ + uint64_t modifier; /**< format modifier * only used with DMA-BUF */ struct spa_rectangle size; /**< the frame size of the video */ struct spa_fraction framerate; /**< the framerate of the video, 0/1 means variable rate */ @@ -208,13 +210,6 @@ #define SPA_VIDEO_INFO_RAW_INIT(...) ((struct spa_video_info_raw) { __VA_ARGS__ }) -struct spa_video_info_dsp { - enum spa_video_format format; - int64_t modifier; -}; - -#define SPA_VIDEO_INFO_DSP_INIT(...) ((struct spa_video_info_dsp) { __VA_ARGS__ }) - /** * \} */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/param/video/type-info.h -> pipewire-0.3.65.tar.gz/spa/include/spa/param/video/type-info.h
Changed
@@ -25,116 +25,6 @@ #ifndef SPA_VIDEO_TYPES_H #define SPA_VIDEO_TYPES_H -#ifdef __cplusplus -extern "C" { -#endif +#include <spa/param/video/raw-types.h> -/** - * \addtogroup spa_param - * \{ - */ -#include <spa/param/video/raw.h> - -#define SPA_TYPE_INFO_VideoFormat SPA_TYPE_INFO_ENUM_BASE "VideoFormat" -#define SPA_TYPE_INFO_VIDEO_FORMAT_BASE SPA_TYPE_INFO_VideoFormat ":" - -static const struct spa_type_info spa_type_video_format = { - { SPA_VIDEO_FORMAT_ENCODED, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "encoded", NULL }, - { SPA_VIDEO_FORMAT_I420, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420", NULL }, - { SPA_VIDEO_FORMAT_YV12, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YV12", NULL }, - { SPA_VIDEO_FORMAT_YUY2, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YUY2", NULL }, - { SPA_VIDEO_FORMAT_UYVY, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "UYVY", NULL }, - { SPA_VIDEO_FORMAT_AYUV, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "AYUV", NULL }, - { SPA_VIDEO_FORMAT_RGBx, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBx", NULL }, - { SPA_VIDEO_FORMAT_BGRx, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRx", NULL }, - { SPA_VIDEO_FORMAT_xRGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xRGB", NULL }, - { SPA_VIDEO_FORMAT_xBGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xBGR", NULL }, - { SPA_VIDEO_FORMAT_RGBA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA", NULL }, - { SPA_VIDEO_FORMAT_BGRA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRA", NULL }, - { SPA_VIDEO_FORMAT_ARGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ARGB", NULL }, - { SPA_VIDEO_FORMAT_ABGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ABGR", NULL }, - { SPA_VIDEO_FORMAT_RGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB", NULL }, - { SPA_VIDEO_FORMAT_BGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR", NULL }, - { SPA_VIDEO_FORMAT_Y41B, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y41B", NULL }, - { SPA_VIDEO_FORMAT_Y42B, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y42B", NULL }, - { SPA_VIDEO_FORMAT_YVYU, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YVYU", NULL }, - { SPA_VIDEO_FORMAT_Y444, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444", NULL }, - { SPA_VIDEO_FORMAT_v210, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v210", NULL }, - { SPA_VIDEO_FORMAT_v216, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v216", NULL }, - { SPA_VIDEO_FORMAT_NV12, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV12", NULL }, - { SPA_VIDEO_FORMAT_NV21, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV21", NULL }, - { SPA_VIDEO_FORMAT_GRAY8, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY8", NULL }, - { SPA_VIDEO_FORMAT_GRAY16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY16_BE", NULL }, - { SPA_VIDEO_FORMAT_GRAY16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY16_LE", NULL }, - { SPA_VIDEO_FORMAT_v308, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v308", NULL }, - { SPA_VIDEO_FORMAT_RGB16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB16", NULL }, - { SPA_VIDEO_FORMAT_BGR16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR16", NULL }, - { SPA_VIDEO_FORMAT_RGB15, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB15", NULL }, - { SPA_VIDEO_FORMAT_BGR15, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR15", NULL }, - { SPA_VIDEO_FORMAT_UYVP, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "UYVP", NULL }, - { SPA_VIDEO_FORMAT_A420, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420", NULL }, - { SPA_VIDEO_FORMAT_RGB8P, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB8P", NULL }, - { SPA_VIDEO_FORMAT_YUV9, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YUV9", NULL }, - { SPA_VIDEO_FORMAT_YVU9, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YVU9", NULL }, - { SPA_VIDEO_FORMAT_IYU1, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "IYU1", NULL }, - { SPA_VIDEO_FORMAT_ARGB64, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ARGB64", NULL }, - { SPA_VIDEO_FORMAT_AYUV64, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "AYUV64", NULL }, - { SPA_VIDEO_FORMAT_r210, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "r210", NULL }, - { SPA_VIDEO_FORMAT_I420_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_10BE", NULL }, - { SPA_VIDEO_FORMAT_I420_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_10LE", NULL }, - { SPA_VIDEO_FORMAT_I422_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_10BE", NULL }, - { SPA_VIDEO_FORMAT_I422_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_10LE", NULL }, - { SPA_VIDEO_FORMAT_Y444_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_10BE", NULL }, - { SPA_VIDEO_FORMAT_Y444_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_10LE", NULL }, - { SPA_VIDEO_FORMAT_GBR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR", NULL }, - { SPA_VIDEO_FORMAT_GBR_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_10BE", NULL }, - { SPA_VIDEO_FORMAT_GBR_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_10LE", NULL }, - { SPA_VIDEO_FORMAT_NV16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV16", NULL }, - { SPA_VIDEO_FORMAT_NV24, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV24", NULL }, - { SPA_VIDEO_FORMAT_NV12_64Z32, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV12_64Z32", NULL }, - { SPA_VIDEO_FORMAT_A420_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420_10BE", NULL }, - { SPA_VIDEO_FORMAT_A420_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420_10LE", NULL }, - { SPA_VIDEO_FORMAT_A422_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A422_10BE", NULL }, - { SPA_VIDEO_FORMAT_A422_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A422_10LE", NULL }, - { SPA_VIDEO_FORMAT_A444_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A444_10BE", NULL }, - { SPA_VIDEO_FORMAT_A444_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A444_10LE", NULL }, - { SPA_VIDEO_FORMAT_NV61, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV61", NULL }, - { SPA_VIDEO_FORMAT_P010_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "P010_10BE", NULL }, - { SPA_VIDEO_FORMAT_P010_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "P010_10LE", NULL }, - { SPA_VIDEO_FORMAT_IYU2, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "IYU2", NULL }, - { SPA_VIDEO_FORMAT_VYUY, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "VYUY", NULL }, - { SPA_VIDEO_FORMAT_GBRA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA", NULL }, - { SPA_VIDEO_FORMAT_GBRA_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_10BE", NULL }, - { SPA_VIDEO_FORMAT_GBRA_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_10LE", NULL }, - { SPA_VIDEO_FORMAT_GBR_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_12BE", NULL }, - { SPA_VIDEO_FORMAT_GBR_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_12LE", NULL }, - { SPA_VIDEO_FORMAT_GBRA_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_12BE", NULL }, - { SPA_VIDEO_FORMAT_GBRA_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_12LE", NULL }, - { SPA_VIDEO_FORMAT_I420_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_12BE", NULL }, - { SPA_VIDEO_FORMAT_I420_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_12LE", NULL }, - { SPA_VIDEO_FORMAT_I422_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_12BE", NULL }, - { SPA_VIDEO_FORMAT_I422_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_12LE", NULL }, - { SPA_VIDEO_FORMAT_Y444_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_12BE", NULL }, - { SPA_VIDEO_FORMAT_Y444_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_12LE", NULL }, - { SPA_VIDEO_FORMAT_RGBA_F16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA_F16", NULL }, - { SPA_VIDEO_FORMAT_RGBA_F32, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA_F32", NULL }, - { SPA_VIDEO_FORMAT_xRGB_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xRGB_210LE", NULL }, - { SPA_VIDEO_FORMAT_xBGR_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xBGR_210LE", NULL }, - { SPA_VIDEO_FORMAT_RGBx_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBx_102LE", NULL }, - { SPA_VIDEO_FORMAT_BGRx_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRx_102LE", NULL }, - { SPA_VIDEO_FORMAT_ARGB_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ARGB_210LE", NULL }, - { SPA_VIDEO_FORMAT_ABGR_210LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ABGR_210LE", NULL }, - { SPA_VIDEO_FORMAT_RGBA_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA_102LE", NULL }, - { SPA_VIDEO_FORMAT_BGRA_102LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRA_102LE", NULL }, - { 0, 0, NULL, NULL }, -}; - -/** - * \} - */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* SPA_VIDEO_RAW_TYPES_H */ +#endif /* SPA_VIDEO_TYPES_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/support/log.h -> pipewire-0.3.65.tar.gz/spa/include/spa/support/log.h
Changed
@@ -299,21 +299,6 @@ #define spa_log_trace_fp(l,...) #endif -#define spa_log_hexdump(l,lev,indent,data,len) \ -({ \ - char str512; \ - uint8_t *buf = (uint8_t *)(data); \ - size_t i, j = (len); \ - int pos = 0; \ - \ - for (i = 0; i < j; i++) { \ - if (i % 16 == 0) \ - pos = 0; \ - pos += sprintf(str + pos, "%02x ", bufi); \ - if (i % 16 == 15 || i == j - 1) \ - spa_log_lev(l,lev, "%*s" "%s",indent,"", str); \ - } \ -}) /** \fn spa_log_error */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/utils/defs.h -> pipewire-0.3.65.tar.gz/spa/include/spa/utils/defs.h
Changed
@@ -274,6 +274,14 @@ #define SPA_ROUND_DOWN_N(num,align) ((num) & ~SPA_ROUND_MASK(num, align)) #define SPA_ROUND_UP_N(num,align) ((((num)-1) | SPA_ROUND_MASK(num, align))+1) +#define SPA_SCALE32_UP(val,num,denom) \ +({ \ + uint64_t _val = (val); \ + uint64_t _denom = (denom); \ + (uint32_t)(((_val) * (num) + (_denom)-1) / (_denom)); \ +}) + + #define SPA_PTR_ALIGNMENT(p,align) ((intptr_t)(p) & ((align)-1)) #define SPA_IS_ALIGNED(p,align) (SPA_PTR_ALIGNMENT(p,align) == 0) #define SPA_PTR_ALIGN(p,align,type) ((type*)SPA_ROUND_UP_N((intptr_t)(p), (intptr_t)(align)))
View file
pipewire-0.3.65.tar.gz/spa/include/spa/utils/enum-types.h
Added
@@ -0,0 +1,65 @@ +/* Simple Plugin API + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_ENUM_TYPES_H +#define SPA_ENUM_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/utils/type.h> + +#define SPA_TYPE_INFO_Direction SPA_TYPE_INFO_ENUM_BASE "Direction" +#define SPA_TYPE_INFO_DIRECTION_BASE SPA_TYPE_INFO_Direction ":" + +static const struct spa_type_info spa_type_direction = { + { SPA_DIRECTION_INPUT, SPA_TYPE_Int, SPA_TYPE_INFO_DIRECTION_BASE "Input", NULL }, + { SPA_DIRECTION_OUTPUT, SPA_TYPE_Int, SPA_TYPE_INFO_DIRECTION_BASE "Output", NULL }, + { 0, 0, NULL, NULL } +}; + +#include <spa/pod/pod.h> + +#define SPA_TYPE_INFO_Choice SPA_TYPE_INFO_ENUM_BASE "Choice" +#define SPA_TYPE_INFO_CHOICE_BASE SPA_TYPE_INFO_Choice ":" + +static const struct spa_type_info spa_type_choice = { + { SPA_CHOICE_None, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "None", NULL }, + { SPA_CHOICE_Range, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Range", NULL }, + { SPA_CHOICE_Step, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Step", NULL }, + { SPA_CHOICE_Enum, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Enum", NULL }, + { SPA_CHOICE_Flags, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Flags", NULL }, + { 0, 0, NULL, NULL } +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_TYPE_INFO_H */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/utils/keys.h -> pipewire-0.3.65.tar.gz/spa/include/spa/utils/keys.h
Changed
@@ -129,12 +129,17 @@ #define SPA_KEY_API_BLUEZ5_CODEC "api.bluez5.codec" /**< a bluetooth codec */ #define SPA_KEY_API_BLUEZ5_CLASS "api.bluez5.class" /**< a bluetooth class */ #define SPA_KEY_API_BLUEZ5_ICON "api.bluez5.icon" /**< a bluetooth icon */ +#define SPA_KEY_API_BLUEZ5_ROLE "api.bluez5.role" /**< "client" or "server" */ /** keys for jack api */ #define SPA_KEY_API_JACK "api.jack" /**< key for the JACK api */ #define SPA_KEY_API_JACK_SERVER "api.jack.server" /**< a jack server name */ #define SPA_KEY_API_JACK_CLIENT "api.jack.client" /**< an internal jack client */ +/** keys for glib api */ +#define SPA_KEY_API_GLIB_MAINLOOP "api.glib.mainloop" /**< whether glib mainloop runs + * in same thread as PW loop */ + /** * \} */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/utils/names.h -> pipewire-0.3.65.tar.gz/spa/include/spa/utils/names.h
Changed
@@ -110,6 +110,8 @@ #define SPA_NAME_API_ALSA_SEQ_BRIDGE "api.alsa.seq.bridge" /**< an alsa Node interface for * bridging midi ports */ #define SPA_NAME_API_ALSA_ACP_DEVICE "api.alsa.acp.device" /**< an alsa ACP Device interface */ +#define SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_SINK "api.alsa.compress.offload.sink" /**< an alsa Node interface for + * compressed audio */ /** keys for bluez5 factory names */ #define SPA_NAME_API_BLUEZ5_ENUM_DBUS "api.bluez5.enum.dbus" /**< a dbus Device interface */ @@ -120,6 +122,8 @@ #define SPA_NAME_API_BLUEZ5_A2DP_SOURCE "api.bluez5.a2dp.source" /**< alias for media.source */ #define SPA_NAME_API_BLUEZ5_SCO_SINK "api.bluez5.sco.sink" /**< a playback Node interface for HSP/HFP profiles */ #define SPA_NAME_API_BLUEZ5_SCO_SOURCE "api.bluez5.sco.source" /**< a capture Node interface for HSP/HFP profiles */ +#define SPA_NAME_API_BLUEZ5_MIDI_ENUM "api.bluez5.midi.enum" /**< a dbus midi Device interface */ +#define SPA_NAME_API_BLUEZ5_MIDI_NODE "api.bluez5.midi.node" /**< a midi Node interface */ /** keys for codec factory names */ #define SPA_NAME_API_CODEC_BLUEZ5_MEDIA "api.codec.bluez5.media" /**< Bluez5 Media codec plugin */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/utils/string.h -> pipewire-0.3.65.tar.gz/spa/include/spa/utils/string.h
Changed
@@ -376,6 +376,33 @@ return str; } +struct spa_strbuf { + char *buffer; + size_t maxsize; + size_t pos; +}; + +static inline void spa_strbuf_init(struct spa_strbuf *buf, char *buffer, size_t maxsize) +{ + buf->buffer = buffer; + buf->maxsize = maxsize; + buf->pos = 0; +} + +SPA_PRINTF_FUNC(2, 3) +static inline int spa_strbuf_append(struct spa_strbuf *buf, const char *fmt, ...) +{ + size_t remain = buf->maxsize - buf->pos; + ssize_t written; + va_list args; + va_start(args, fmt); + written = vsnprintf(&buf->bufferbuf->pos, remain, fmt, args); + va_end(args); + if (written > 0) + buf->pos += SPA_MIN(remain, (size_t)written); + return written; +} + /** * \} */
View file
pipewire-0.3.64.tar.gz/spa/include/spa/utils/type-info.h -> pipewire-0.3.65.tar.gz/spa/include/spa/utils/type-info.h
Changed
@@ -46,35 +46,13 @@ } #include <spa/utils/type.h> - -/* base for parameter object enumerations */ -#define SPA_TYPE_INFO_Direction SPA_TYPE_INFO_ENUM_BASE "Direction" -#define SPA_TYPE_INFO_DIRECTION_BASE SPA_TYPE_INFO_Direction ":" - -static const struct spa_type_info spa_type_direction = { - { SPA_DIRECTION_INPUT, SPA_TYPE_Int, SPA_TYPE_INFO_DIRECTION_BASE "Input", NULL }, - { SPA_DIRECTION_OUTPUT, SPA_TYPE_Int, SPA_TYPE_INFO_DIRECTION_BASE "Output", NULL }, - { 0, 0, NULL, NULL } -}; +#include <spa/utils/enum-types.h> #include <spa/monitor/type-info.h> #include <spa/node/type-info.h> #include <spa/param/type-info.h> #include <spa/control/type-info.h> -/* base for parameter object enumerations */ -#define SPA_TYPE_INFO_Choice SPA_TYPE_INFO_ENUM_BASE "Choice" -#define SPA_TYPE_INFO_CHOICE_BASE SPA_TYPE_INFO_Choice ":" - -static const struct spa_type_info spa_type_choice = { - { SPA_CHOICE_None, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "None", NULL }, - { SPA_CHOICE_Range, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Range", NULL }, - { SPA_CHOICE_Step, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Step", NULL }, - { SPA_CHOICE_Enum, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Enum", NULL }, - { SPA_CHOICE_Flags, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Flags", NULL }, - { 0, 0, NULL, NULL } -}; - static const struct spa_type_info spa_types = { /* Basic types */ { SPA_TYPE_START, SPA_TYPE_START, SPA_TYPE_INFO_BASE, NULL },
View file
pipewire-0.3.64.tar.gz/spa/meson.build -> pipewire-0.3.65.tar.gz/spa/meson.build
Changed
@@ -42,8 +42,11 @@ alsa_dep = dependency('alsa', required: get_option('alsa')) summary({'ALSA': alsa_dep.found()}, bool_yn: true, section: 'Backend') bluez_dep = dependency('bluez', version : '>= 4.101', required: get_option('bluez5')) - summary({'Bluetooth audio': bluez_dep.found()}, bool_yn: true, section: 'Backend') - if bluez_dep.found() + gio_dep = dependency('gio-2.0', required : get_option('bluez5')) + gio_unix_dep = dependency('gio-unix-2.0', required : get_option('bluez5')) + bluez_deps_found = bluez_dep.found() and gio_dep.found() and gio_unix_dep.found() + summary({'Bluetooth audio': bluez_deps_found}, bool_yn: true, section: 'Backend') + if bluez_deps_found sbc_dep = dependency('sbc', required: get_option('bluez5')) summary({'SBC': sbc_dep.found()}, bool_yn: true, section: 'Bluetooth audio codecs') ldac_dep = dependency('ldacBT-enc', required : get_option('bluez5-codec-ldac')) @@ -71,7 +74,6 @@ summary({'ModemManager': mm_dep.found()}, bool_yn: true, section: 'Bluetooth backends') endif endif - avcodec_dep = dependency('libavcodec', required: get_option('ffmpeg')) jack_dep = dependency('jack', version : '>= 1.9.10', required: get_option('jack')) summary({'JACK2': jack_dep.found()}, bool_yn: true, section: 'Backend') vulkan_dep = dependency('vulkan', disabler : true, version : '>= 1.1.69', required: get_option('vulkan')) @@ -81,6 +83,10 @@ libcamera_dep = dependency('libcamera', required: get_option('libcamera')) summary({'libcamera': libcamera_dep.found()}, bool_yn: true, section: 'Backend') + tinycompress_dep = cc.find_library('tinycompress', has_headers: 'tinycompress/tinycompress.h' , required: get_option('compress-offload')) + summary({'Compress-Offload': tinycompress_dep.found()}, bool_yn: true, section: 'Backend') + cdata.set('HAVE_ALSA_COMPRESS_OFFLOAD', tinycompress_dep.found()) + # common dependencies libudev_dep = dependency('libudev', required: alsa_dep.found() or get_option('udev').enabled() or get_option('v4l2').enabled()) summary({'Udev': libudev_dep.found()}, bool_yn: true, section: 'Backend')
View file
pipewire-0.3.64.tar.gz/spa/plugins/alsa/90-pipewire-alsa.rules -> pipewire-0.3.65.tar.gz/spa/plugins/alsa/90-pipewire-alsa.rules
Changed
@@ -163,10 +163,12 @@ # ID 1395:005e is for Sennheiser GSX 1000 # ID 1395:00a0 is for Sennheiser GSX 1000 +# ID 1395:00b1 is for Sennheiser GSX 1000 v2 # ID 1395:005f is for Sennheiser GSX 1200 # ID 1395:00a1 is for Sennheiser GSX 1200 ATTRS{idVendor}=="1395", ATTRS{idProduct}=="005e", ENV{ACP_PROFILE_SET}="sennheiser-gsx.conf" ATTRS{idVendor}=="1395", ATTRS{idProduct}=="00a0", ENV{ACP_PROFILE_SET}="sennheiser-gsx.conf" +ATTRS{idVendor}=="1395", ATTRS{idProduct}=="00b1", ENV{ACP_PROFILE_SET}="sennheiser-gsx.conf" ATTRS{idVendor}=="1395", ATTRS{idProduct}=="005f", ENV{ACP_PROFILE_SET}="sennheiser-gsx.conf" ATTRS{idVendor}=="1395", ATTRS{idProduct}=="00a1", ENV{ACP_PROFILE_SET}="sennheiser-gsx.conf"
View file
pipewire-0.3.64.tar.gz/spa/plugins/alsa/alsa-acp-device.c -> pipewire-0.3.65.tar.gz/spa/plugins/alsa/alsa-acp-device.c
Changed
@@ -31,11 +31,12 @@ #include <alsa/asoundlib.h> -#include <spa/utils/type.h> #include <spa/node/node.h> +#include <spa/utils/type.h> #include <spa/utils/keys.h> #include <spa/utils/names.h> #include <spa/utils/string.h> +#include <spa/support/log.h> #include <spa/support/loop.h> #include <spa/support/plugin.h> #include <spa/support/i18n.h> @@ -46,6 +47,7 @@ #include <spa/pod/filter.h> #include <spa/pod/parser.h> #include <spa/debug/pod.h> +#include <spa/debug/log.h> #include "alsa.h" @@ -735,7 +737,7 @@ SPA_PARAM_PROFILE_index, SPA_POD_Int(&idx), SPA_PARAM_PROFILE_save, SPA_POD_OPT_Bool(&save))) < 0) { spa_log_warn(this->log, "can't parse profile"); - spa_debug_pod(0, NULL, param); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param); return res; } @@ -760,7 +762,7 @@ SPA_PARAM_ROUTE_props, SPA_POD_OPT_Pod(&props), SPA_PARAM_ROUTE_save, SPA_POD_OPT_Bool(&save))) < 0) { spa_log_warn(this->log, "can't parse route"); - spa_debug_pod(0, NULL, param); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param); return res; } if (device >= this->card->n_devices)
View file
pipewire-0.3.65.tar.gz/spa/plugins/alsa/alsa-compress-offload-sink.c
Added
@@ -0,0 +1,1143 @@ +/* Spa ALSA Compress-Offload sink + * + * Copyright © 2022 Wim Taymans + * © 2022 Asymptotic Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <errno.h> +#include <stddef.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <fcntl.h> + +#include <spa/monitor/device.h> +#include <spa/support/plugin.h> +#include <spa/support/log.h> +#include <spa/support/system.h> +#include <spa/support/loop.h> +#include <spa/utils/list.h> +#include <spa/utils/keys.h> +#include <spa/utils/json.h> +#include <spa/utils/names.h> +#include <spa/utils/string.h> +#include <spa/utils/result.h> +#include <spa/node/node.h> +#include <spa/node/utils.h> +#include <spa/node/io.h> +#include <spa/node/keys.h> +#include <spa/param/audio/format-utils.h> +#include <spa/debug/types.h> +#include <spa/debug/mem.h> +#include <spa/param/audio/type-info.h> +#include <spa/param/param.h> +#include <spa/pod/filter.h> +#include <spa/control/control.h> + +#include <sound/compress_params.h> +#include <tinycompress/tinycompress.h> + +/* + * This creates a PipeWire sink node which uses the tinycompress user space + * library to use the ALSA Compress-Offload API for writing compressed data + * like MP3, FLAC etc. to an DSP that can handle such data directly. + * + * These show up under /dev/snd like comprCxDx, as opposed to regular + * ALSA PCM devices. + * + * root@dragonboard-845c:~# ls /dev/snd + * by-path comprC0D3 controlC0 pcmC0D0c pcmC0D0p pcmC0D1c pcmC0D1p pcmC0D2c pcmC0D2p timer + * + * ## Example configuration + *\code{.unparsed} + * context.objects = + * { factory = spa-node-factory + * args = { + * factory.name = api.alsa.compress.offload.sink + * node.name = Compress-Offload-Sink + * media.class = "Audio/Sink" + * api.alsa.path = "hw:0,3" + * } + * } + * + *\endcode + * + * TODO: + * - Clocking + * - Implement pause and resume + * - Having a better wait mechanism + * - Automatic loading using alsa-udev + * + */ + +#define NAME "compress-offload-audio-sink" +#define DEFAULT_CHANNELS 2 +#define DEFAULT_RATE 44100 +#define MAX_BUFFERS 4 +#define MAX_PORTS 1 +#define MAX_CODECS 32 /* See include/sound/compress_params.h */ + +#define MIN_FRAGMENT_SIZE (4 * 1024) +#define MAX_FRAGMENT_SIZE (64 * 1024) +#define MIN_NUM_FRAGMENTS (4) +#define MAX_NUM_FRAGMENTS (8 * 4) + +struct props { + uint32_t channels; + uint32_t rate; + uint32_t posSPA_AUDIO_MAX_CHANNELS; + char device64; +}; + +static void reset_props(struct props *props) +{ + props->channels = 0; + props->rate = 0; +} + +struct buffer { + uint32_t id; + uint32_t flags; + struct spa_buffer *outbuf; +}; + +struct impl; + +struct port { + uint64_t info_all; + struct spa_port_info info; + struct spa_param_info params5; + + struct spa_io_buffers *io; + + bool have_format; + struct spa_audio_info current_format; + + struct buffer buffersMAX_BUFFERS; + uint32_t n_buffers; + uint32_t written; +}; + +struct impl { + struct spa_handle handle; + struct spa_node node; + struct spa_log *log; + struct props props; + + struct spa_node_info info; + struct spa_param_info params1; + + struct spa_hook_list hooks; + struct spa_callbacks callbacks; + struct port port; + + unsigned int started_node:1; + unsigned int started_compress:1; + uint64_t info_all; + uint32_t quantum_limit; + + struct compr_config compr_conf; + struct snd_codec codec; + struct compress *compress; + + int32_t codecs_supportedMAX_CODECS; + uint32_t num_codecs; +}; + +#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS) + +static const struct spa_dict_item node_info_items = { + { SPA_KEY_DEVICE_API, "alsa" }, + { SPA_KEY_MEDIA_CLASS, "Audio/Sink" }, + { SPA_KEY_NODE_DRIVER, "false" }, + { SPA_KEY_NODE_PAUSE_ON_IDLE, "false" }, +}; + +static const struct codec_id { + uint32_t codec_id; +} codec_info = { + { SND_AUDIOCODEC_MP3, }, + { SND_AUDIOCODEC_AAC, }, + { SND_AUDIOCODEC_WMA, }, + { SND_AUDIOCODEC_VORBIS, }, + { SND_AUDIOCODEC_FLAC, }, + { SND_AUDIOCODEC_ALAC, }, + { SND_AUDIOCODEC_APE, }, + { SND_AUDIOCODEC_REAL, }, + { SND_AUDIOCODEC_AMR, }, + { SND_AUDIOCODEC_AMRWB, }, +}; + +static int +open_compress(struct impl *this) +{ + struct compress *compress; + + compress = compress_open_by_name(this->props.device, COMPRESS_IN, &this->compr_conf); + if (!compress || !is_compress_ready(compress)) { + spa_log_error(this->log, NAME " %p: Unable to open compress device", this); + return -EINVAL; + } + + this->compress = compress; + + compress_nonblock(this->compress, 1); + + return 0; +} + +static int +write_compress(struct impl *this, void *buf, int32_t size) +{ + int32_t wrote; + int32_t to_write = size; + struct port *port = &this->port; + +retry: + wrote = compress_write(this->compress, buf, to_write); + if (wrote < 0) { + spa_log_error(this->log, NAME " %p: Error playing sample: %s", + this, compress_get_error(this->compress)); + return wrote; + } + port->written += wrote; + + spa_log_debug(this->log, NAME " %p: We wrote %d, DSP accepted %d\n", this, size, wrote); + + if (wrote < to_write) { + /* + * The choice of 20ms as the time to wait is + * completely arbitrary. + */ + compress_wait(this->compress, 20); + buf = (uint8_t *)buf + wrote; + to_write = to_write - wrote; + goto retry; + } + + /* + * One write has to happen before starting the compressed node. Calling + * compress_start before writing MIN_NUM_FRAGMENTS * MIN_FRAGMENT_SIZE + * will result in a distorted audio playback. + */ + if (!this->started_compress && + (port->written >= (MIN_FRAGMENT_SIZE * MIN_NUM_FRAGMENTS))) { + compress_start(this->compress); + this->started_compress = true; + } + + return size; +} + +static void emit_node_info(struct impl *this, bool full) +{ + uint64_t old = full ? this->info.change_mask : 0; + if (full) + this->info.change_mask = this->info_all; + if (this->info.change_mask) { + this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items); + spa_node_emit_info(&this->hooks, &this->info); + this->info.change_mask = old; + } +} + +static void emit_port_info(struct impl *this, struct port *port, bool full) +{ + uint64_t old = full ? port->info.change_mask : 0; + if (full) + port->info.change_mask = port->info_all; + if (port->info.change_mask) { + spa_node_emit_port_info(&this->hooks, + SPA_DIRECTION_INPUT, 0, &port->info); + port->info.change_mask = old; + } +} + +static int impl_node_enum_params(void *object, int seq, + uint32_t id, uint32_t start, uint32_t num, + const struct spa_pod *filter) +{ + struct impl *this = object; + struct spa_pod *param; + struct spa_pod_builder b = { 0 }; + uint8_t buffer4096; + struct spa_result_node_params result; + uint32_t count = 0; + + spa_return_val_if_fail(this != NULL, -EINVAL); + spa_return_val_if_fail(num != 0, -EINVAL); + + result.id = id; + result.next = start; + next: + result.index = result.next++; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + + switch (id) { + case SPA_PARAM_EnumPortConfig: + case SPA_PARAM_PortConfig: + switch (result.index) { + case 0: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamPortConfig, id, + SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(SPA_DIRECTION_INPUT), + SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_passthrough)); + break; + default: + return 0; + } + break; + default: + return -ENOENT; + } + + if (spa_pod_filter(&b, &result.param, param, filter) < 0) + goto next; + + spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result); + + if (++count != num) + goto next; + + return 0; +} + +static int +impl_node_add_port(void *object, enum spa_direction direction, uint32_t port_id, + const struct spa_dict *props) +{ + return -ENOTSUP; +} + +static int +impl_node_remove_port(void *object, enum spa_direction direction, uint32_t port_id) +{ + return -ENOTSUP; +} + +static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size) +{ + return -ENOTSUP; +} + +static int do_start(struct impl *this) +{ + if (this->started_node) + return 0; + + spa_log_debug(this->log, "Open compressed device: %s", this->props.device); + if (open_compress(this) < 0) + return -EINVAL; + + this->started_node = true; + this->started_compress = false; + + return 0; +} + +static int do_drain(struct impl *this) +{ + if (!this->started_node) + return 0; + + if (this->started_compress) { + spa_log_debug(this->log, NAME " %p: Issuing drain command", this); + compress_drain(this->compress); + spa_log_debug(this->log, NAME " %p: Finished drain", this); + } + + return 0; +} + +static int do_stop(struct impl *this) +{ + if (!this->started_node) + return 0; + + compress_stop(this->compress); + compress_close(this->compress); + spa_log_info(this->log, NAME " %p: Closed compress device", this); + + this->compress = NULL; + this->started_node = false; + this->started_compress = false; + + return 0; +} + +static int impl_node_send_command(void *object, const struct spa_command *command) +{ + struct impl *this = object; + struct port *port; + + spa_return_val_if_fail(this != NULL, -EINVAL); + spa_return_val_if_fail(command != NULL, -EINVAL); + + port = &this->port; + + switch (SPA_NODE_COMMAND_ID(command)) { + case SPA_NODE_COMMAND_Start: + { + if (!port->have_format) + return -EIO; + if (port->n_buffers == 0) + return -EIO; + + do_start(this); + break; + } + case SPA_NODE_COMMAND_Pause: + case SPA_NODE_COMMAND_Suspend: + do_drain(this); + do_stop(this); + break; + + default: + return -ENOTSUP; + } + return 0; +} + +static int +impl_node_add_listener(void *object, + struct spa_hook *listener, + const struct spa_node_events *events, + void *data) +{ + struct impl *this = object; + struct spa_hook_list save; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + spa_hook_list_isolate(&this->hooks, &save, listener, events, data); + + emit_node_info(this, true); + emit_port_info(this, &this->port, true); + + spa_hook_list_join(&this->hooks, &save); + + return 0; +} + +static int +impl_node_set_callbacks(void *object, + const struct spa_node_callbacks *callbacks, + void *data) +{ + struct impl *this = object; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + this->callbacks = SPA_CALLBACKS_INIT(callbacks, data); + + return 0; +} + +static int +port_enum_formats(struct impl *this, + enum spa_direction direction, uint32_t port_id, + uint32_t index, + struct spa_pod **param, + struct spa_pod_builder *builder) +{ + struct spa_audio_info info; + uint32_t codec; + + if (index >= this->num_codecs) + return 0; + + codec = this->codecs_supportedindex; + + spa_zero(info); + info.media_type = SPA_MEDIA_TYPE_audio; + + switch (codec) { + case SND_AUDIOCODEC_MP3: + info.media_subtype = SPA_MEDIA_SUBTYPE_mp3; + info.info.mp3.rate = this->props.rate; + info.info.mp3.channels = this->props.channels; + break; + case SND_AUDIOCODEC_AAC: + info.media_subtype = SPA_MEDIA_SUBTYPE_aac; + info.info.aac.rate = this->props.rate; + info.info.aac.channels = this->props.channels; + break; + case SND_AUDIOCODEC_WMA: + info.media_subtype = SPA_MEDIA_SUBTYPE_wma; + info.info.wma.rate = this->props.rate; + info.info.wma.channels = this->props.channels; + break; + case SND_AUDIOCODEC_VORBIS: + info.media_subtype = SPA_MEDIA_SUBTYPE_vorbis; + info.info.vorbis.rate = this->props.rate; + info.info.vorbis.channels = this->props.channels; + break; + case SND_AUDIOCODEC_FLAC: + info.media_subtype = SPA_MEDIA_SUBTYPE_flac; + info.info.flac.rate = this->props.rate; + info.info.flac.channels = this->props.channels; + break; + case SND_AUDIOCODEC_ALAC: + info.media_subtype = SPA_MEDIA_SUBTYPE_alac; + info.info.alac.rate = this->props.rate; + info.info.alac.channels = this->props.channels; + break; + case SND_AUDIOCODEC_APE: + info.media_subtype = SPA_MEDIA_SUBTYPE_ape; + info.info.ape.rate = this->props.rate; + info.info.ape.channels = this->props.channels; + break; + case SND_AUDIOCODEC_REAL: + info.media_subtype = SPA_MEDIA_SUBTYPE_ra; + info.info.ra.rate = this->props.rate; + info.info.ra.channels = this->props.channels; + break; + case SND_AUDIOCODEC_AMR: + info.media_subtype = SPA_MEDIA_SUBTYPE_amr; + info.info.amr.rate = this->props.rate; + info.info.amr.channels = this->props.channels; + info.info.amr.band_mode = SPA_AUDIO_AMR_BAND_MODE_NB; + break; + case SND_AUDIOCODEC_AMRWB: + info.media_subtype = SPA_MEDIA_SUBTYPE_amr; + info.info.amr.rate = this->props.rate; + info.info.amr.channels = this->props.channels; + info.info.amr.band_mode = SPA_AUDIO_AMR_BAND_MODE_WB; + break; + default: + return -ENOTSUP; + } + if ((*param = spa_format_audio_build(builder, SPA_PARAM_EnumFormat, &info)) == NULL) + return -errno; + return 1; +} + +static int +impl_node_port_enum_params(void *object, int seq, + enum spa_direction direction, uint32_t port_id, + uint32_t id, uint32_t start, uint32_t num, + const struct spa_pod *filter) +{ + struct impl *this = object; + struct port *port; + struct spa_pod_builder b = { 0 }; + uint8_t buffer1024; + struct spa_pod *param; + struct spa_result_node_params result; + uint32_t count = 0; + int res; + + spa_return_val_if_fail(this != NULL, -EINVAL); + spa_return_val_if_fail(num != 0, -EINVAL); + + spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); + + port = &this->port; + + result.id = id; + result.next = start; + next: + result.index = result.next++; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + + switch (id) { + case SPA_PARAM_EnumFormat: + if ((res = port_enum_formats(this, direction, port_id, + result.index, ¶m, &b)) <= 0) + return res; + break; + + case SPA_PARAM_Format: + if (!port->have_format) + return -EIO; + if (result.index > 0) + return 0; + + param = spa_format_audio_build(&b, id, &port->current_format); + break; + + case SPA_PARAM_Buffers: + if (!port->have_format) + return -EIO; + if (result.index > 0) + return 0; + + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamBuffers, id, + SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS), + SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(0), + SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( + MIN_FRAGMENT_SIZE * MIN_NUM_FRAGMENTS, + MIN_FRAGMENT_SIZE * MIN_NUM_FRAGMENTS, + MAX_FRAGMENT_SIZE), + SPA_PARAM_BUFFERS_stride, SPA_POD_Int(0)); + break; + case SPA_PARAM_IO: + switch (result.index) { + case 0: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamIO, id, + SPA_PARAM_IO_id, SPA_POD_Id(SPA_IO_Buffers), + SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_buffers))); + break; + default: + return 0; + } + break; + default: + return -ENOENT; + } + + if (spa_pod_filter(&b, &result.param, param, filter) < 0) + goto next; + + spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result); + + if (++count != num) + goto next; + + return 0; +} + +static int clear_buffers(struct impl *this, struct port *port) +{ + if (port->n_buffers > 0) { + spa_log_info(this->log, NAME " %p: clear buffers", this); + port->n_buffers = 0; + this->started_node = false; + } + return 0; +} + +static int +compress_setup(struct impl *this, struct spa_audio_info *info, uint32_t *out_rate) +{ + struct compr_config *config; + struct snd_codec *codec; + uint32_t channels, rate; + + memset(&this->codec, 0, sizeof(this->codec)); + memset(&this->compr_conf, 0, sizeof(this->compr_conf)); + + config = &this->compr_conf; + codec = &this->codec; + + switch (info->media_subtype) { + case SPA_MEDIA_SUBTYPE_vorbis: + codec->id = SND_AUDIOCODEC_VORBIS; + rate = info->info.vorbis.rate; + channels = info->info.vorbis.channels; + break; + case SPA_MEDIA_SUBTYPE_mp3: + codec->id = SND_AUDIOCODEC_MP3; + rate = info->info.mp3.rate; + channels = info->info.mp3.channels; + break; + case SPA_MEDIA_SUBTYPE_aac: + codec->id = SND_AUDIOCODEC_AAC; + rate = info->info.aac.rate; + channels = info->info.aac.channels; + break; + case SPA_MEDIA_SUBTYPE_flac: + codec->id = SND_AUDIOCODEC_FLAC; + /* + * Taken from the fcplay utility in tinycompress. Required for + * FLAC to work. + */ + codec->options.flac_d.sample_size = 16; + codec->options.flac_d.min_blk_size = 16; + codec->options.flac_d.max_blk_size = 65535; + codec->options.flac_d.min_frame_size = 11; + codec->options.flac_d.max_frame_size = 8192 * 4; + rate = info->info.flac.rate; + channels = info->info.flac.channels; + break; + case SPA_MEDIA_SUBTYPE_wma: + codec->id = SND_AUDIOCODEC_WMA; + /* + * WMA does not work with Compress-Offload if codec profile + * is not set. + */ + switch (info->info.wma.profile) { + case SPA_AUDIO_WMA_PROFILE_WMA9: + codec->profile = SND_AUDIOPROFILE_WMA9; + break; + case SPA_AUDIO_WMA_PROFILE_WMA9_PRO: + codec->profile = SND_AUDIOPROFILE_WMA9_PRO; + break; + case SPA_AUDIO_WMA_PROFILE_WMA9_LOSSLESS: + codec->profile = SND_AUDIOPROFILE_WMA9_LOSSLESS; + break; + case SPA_AUDIO_WMA_PROFILE_WMA10: + codec->profile = SND_AUDIOPROFILE_WMA10; + break; + case SPA_AUDIO_WMA_PROFILE_WMA10_LOSSLESS: + codec->profile = SND_AUDIOPROFILE_WMA10_LOSSLESS; + break; + default: + spa_log_error(this->log, NAME " %p: Invalid WMA codec profile", this); + return -EINVAL; + } + codec->bit_rate = info->info.wma.bitrate; + codec->align = info->info.wma.block_align; + rate = info->info.wma.rate; + channels = info->info.wma.channels; + break; + case SPA_MEDIA_SUBTYPE_alac: + codec->id = SND_AUDIOCODEC_ALAC; + rate = info->info.alac.rate; + channels = info->info.alac.channels; + break; + case SPA_MEDIA_SUBTYPE_ape: + codec->id = SND_AUDIOCODEC_APE; + rate = info->info.ape.rate; + channels = info->info.ape.channels; + break; + case SPA_MEDIA_SUBTYPE_ra: + codec->id = SND_AUDIOCODEC_REAL; + rate = info->info.ra.rate; + channels = info->info.ra.channels; + break; + case SPA_MEDIA_SUBTYPE_amr: + if (info->info.amr.band_mode == SPA_AUDIO_AMR_BAND_MODE_WB) + codec->id = SND_AUDIOCODEC_AMRWB; + else + codec->id = SND_AUDIOCODEC_AMR; + rate = info->info.amr.rate; + channels = info->info.amr.channels; + break; + break; + default: + return -ENOTSUP; + } + + codec->ch_in = channels; + codec->ch_out = channels; + codec->sample_rate = rate; + *out_rate = rate; + + codec->rate_control = 0; + codec->level = 0; + codec->ch_mode = 0; + codec->format = 0; + + spa_log_info(this->log, NAME " %p: Codec info, profile: %d align: %d rate: %d bitrate: %d", + this, codec->profile, codec->align, codec->sample_rate, codec->bit_rate); + + if (!is_codec_supported_by_name(this->props.device, 0, codec)) { + spa_log_error(this->log, NAME " %p: Requested codec is not supported by DSP", this); + return -EINVAL; + } + + config->codec = codec; + config->fragment_size = MIN_FRAGMENT_SIZE; + config->fragments = MIN_NUM_FRAGMENTS; + + return 0; +} + +static int +port_set_format(struct impl *this, + enum spa_direction direction, + uint32_t port_id, + uint32_t flags, + const struct spa_pod *format) +{ + int res; + struct port *port = &this->port; + + if (format == NULL) { + port->have_format = false; + clear_buffers(this, port); + } else { + struct spa_audio_info info = { 0 }; + uint32_t rate; + + if ((res = spa_format_audio_parse(format, &info)) < 0) { + spa_log_error(this->log, NAME " %p: format parse error: %s", this, + spa_strerror(res)); + return res; + } + + if ((res = compress_setup(this, &info, &rate)) < 0) { + spa_log_error(this->log, NAME " %p: can't setup compress: %s", + this, spa_strerror(res)); + return res; + } + + port->current_format = info; + port->have_format = true; + port->info.rate = SPA_FRACTION(1, rate); + } + + this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS; + this->info.flags &= ~SPA_NODE_FLAG_NEED_CONFIGURE; + emit_node_info(this, false); + + port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE; + port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + + if (port->have_format) { + port->params1 = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); + port->params3 = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ); + } else { + port->params1 = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); + port->params3 = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); + } + + emit_port_info(this, port, false); + + return 0; +} + +static int +impl_node_port_set_param(void *object, + enum spa_direction direction, uint32_t port_id, + uint32_t id, uint32_t flags, + const struct spa_pod *param) +{ + struct impl *this = object; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); + + switch (id) { + case SPA_PARAM_Format: + return port_set_format(this, direction, port_id, flags, param); + default: + return -ENOENT; + } + return 0; +} + +static int +impl_node_port_use_buffers(void *object, + enum spa_direction direction, + uint32_t port_id, + uint32_t flags, + struct spa_buffer **buffers, + uint32_t n_buffers) +{ + struct impl *this = object; + struct port *port; + uint32_t i; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); + + port = &this->port; + + if (!port->have_format) + return -EIO; + + clear_buffers(this, port); + + for (i = 0; i < n_buffers; i++) { + struct buffer *b; + struct spa_data *d = buffersi->datas; + + b = &port->buffersi; + b->id = i; + b->flags = 0; + b->outbuf = buffersi; + + if (d0.data == NULL) { + spa_log_error(this->log, NAME " %p: invalid memory on buffer %p", this, + buffersi); + return -EINVAL; + } + } + port->n_buffers = n_buffers; + + return 0; +} + +static int +impl_node_port_set_io(void *object, + enum spa_direction direction, + uint32_t port_id, + uint32_t id, + void *data, size_t size) +{ + struct impl *this = object; + struct port *port; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); + + port = &this->port; + + switch (id) { + case SPA_IO_Buffers: + port->io = data; + break; + default: + return -ENOENT; + } + return 0; +} + +static int impl_node_process(void *object) +{ + struct impl *this = object; + struct port *port; + struct spa_io_buffers *io; + struct buffer *b; + uint32_t i; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + port = &this->port; + + io = port->io; + spa_return_val_if_fail(io != NULL, -EIO); + + if (io->status != SPA_STATUS_HAVE_DATA) + return io->status; + + if (io->buffer_id >= port->n_buffers) { + io->status = -EINVAL; + return io->status; + } + + b = &port->buffersio->buffer_id; + + for (i = 0; i < b->outbuf->n_datas; i++) { + int32_t offs, size; + int32_t wrote; + void *buf; + + struct spa_data *d = b->outbuf->datas; + d = b->outbuf->datas; + + offs = SPA_MIN(d->chunk->offset, d->maxsize); + size = SPA_MIN(d->maxsize - offs, d->chunk->size); + buf = SPA_PTROFF(d0.data, offs, void); + + wrote = write_compress(this, buf, size); + if (wrote < 0) { + spa_log_error(this->log, NAME " %p: Error playing sample: %s", + this, compress_get_error(this->compress)); + io->status = wrote; + return SPA_STATUS_STOPPED; + } + } + + io->status = SPA_STATUS_OK; + + return SPA_STATUS_HAVE_DATA; +} + +static const struct spa_node_methods impl_node = { + SPA_VERSION_NODE_METHODS, + .add_listener = impl_node_add_listener, + .set_callbacks = impl_node_set_callbacks, + .enum_params = impl_node_enum_params, + .set_io = impl_node_set_io, + .send_command = impl_node_send_command, + .add_port = impl_node_add_port, + .remove_port = impl_node_remove_port, + .port_enum_params = impl_node_port_enum_params, + .port_set_param = impl_node_port_set_param, + .port_use_buffers = impl_node_port_use_buffers, + .port_set_io = impl_node_port_set_io, + .process = impl_node_process, +}; + +static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) +{ + struct impl *this; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + spa_return_val_if_fail(interface != NULL, -EINVAL); + + this = (struct impl *) handle; + + if (spa_streq(type, SPA_TYPE_INTERFACE_Node)) + *interface = &this->node; + else + return -ENOENT; + + return 0; +} + +static int impl_clear(struct spa_handle *handle) +{ + return 0; +} + +static size_t +impl_get_size(const struct spa_handle_factory *factory, + const struct spa_dict *params) +{ + return sizeof(struct impl); +} + +static int +impl_init(const struct spa_handle_factory *factory, + struct spa_handle *handle, + const struct spa_dict *info, + const struct spa_support *support, + uint32_t n_support) +{ + struct impl *this; + struct port *port; + const char *str; + uint32_t i; + + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(handle != NULL, -EINVAL); + + handle->get_interface = impl_get_interface; + handle->clear = impl_clear; + + this = (struct impl *) handle; + + this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + + spa_hook_list_init(&this->hooks); + + this->node.iface = SPA_INTERFACE_INIT( + SPA_TYPE_INTERFACE_Node, + SPA_VERSION_NODE, + &impl_node, this); + + this->info_all |= SPA_NODE_CHANGE_MASK_FLAGS | + SPA_NODE_CHANGE_MASK_PARAMS; + this->info = SPA_NODE_INFO_INIT(); + this->info.max_input_ports = MAX_PORTS; + this->info.max_output_ports = 0; + this->info.flags = SPA_NODE_FLAG_RT | + SPA_NODE_FLAG_IN_PORT_CONFIG | + SPA_NODE_FLAG_NEED_CONFIGURE; + this->params0 = SPA_PARAM_INFO(SPA_PARAM_EnumPortConfig, SPA_PARAM_INFO_READ); + this->info.params = this->params; + this->info.n_params = 1; + reset_props(&this->props); + + port = &this->port; + port->info_all = SPA_PORT_CHANGE_MASK_FLAGS | + SPA_PORT_CHANGE_MASK_PARAMS; + port->info = SPA_PORT_INFO_INIT(); + port->info.flags = SPA_PORT_FLAG_NO_REF | + SPA_PORT_FLAG_LIVE | + SPA_PORT_FLAG_PHYSICAL | + SPA_PORT_FLAG_TERMINAL; + port->params0 = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); + port->params1 = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); + port->params2 = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ); + port->params3 = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); + port->info.params = port->params; + port->info.n_params = 4; + port->written = 0; + + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->itemsi.key; + const char *s = info->itemsi.value; + if (spa_streq(k, "clock.quantum-limit")) { + spa_atou32(s, &this->quantum_limit, 0); + } else if (spa_streq(k, SPA_KEY_AUDIO_CHANNELS)) { + this->props.channels = atoi(s); + } else if (spa_streq(k, SPA_KEY_AUDIO_RATE)) { + this->props.rate = atoi(s); + } + } + + if (info && (str = spa_dict_lookup(info, SPA_KEY_API_ALSA_PATH))) { + if ((str0 == 'h') || (str1 == 'w') || (str2 == ':')) { + snprintf(this->props.device, sizeof(this->props.device), "%s", str); + } else { + spa_log_error(this->log, NAME " %p: Invalid Compress-Offload hw %s", this, str); + return -EINVAL; + } + } else { + spa_log_error(this->log, NAME " %p: Invalid compress hw", this); + return -EINVAL; + } + + /* + * TODO: + * + * Move this to use new compress_get_supported_codecs_by_name API once + * merged upstream. + * + * Right now, we pretend all codecs are supported and then error out + * at runtime in port_set_format during compress_setup if not + * supported. + */ + this->num_codecs = SPA_N_ELEMENTS (codec_info); + for (i = 0; i < this->num_codecs; i++) { + this->codecs_supportedi = codec_infoi.codec_id; + } + + spa_log_info(this->log, NAME " %p: Initialized Compress-Offload sink %s", + this, this->props.device); + + return 0; +} + +static const struct spa_interface_info impl_interfaces = { + {SPA_TYPE_INTERFACE_Node,}, +}; + +static int +impl_enum_interface_info(const struct spa_handle_factory *factory, + const struct spa_interface_info **info, + uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(info != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *info = &impl_interfaces*index; + break; + default: + return 0; + } + (*index)++; + + return 1; +} + +static const struct spa_dict_item info_items = { + { SPA_KEY_FACTORY_AUTHOR, "Sanchayan Maity <sanchayan@asymptotic.io>" }, + { SPA_KEY_FACTORY_DESCRIPTION, "Play compressed audio (like MP3 or AAC) with the ALSA Compress-Offload API" }, + { SPA_KEY_FACTORY_USAGE, ""SPA_KEY_API_ALSA_PATH"=<path>" }, +}; + +static const struct spa_dict info = SPA_DICT_INIT_ARRAY(info_items); + +const struct spa_handle_factory spa_alsa_compress_offload_sink_factory = { + SPA_VERSION_HANDLE_FACTORY, + SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_SINK, + &info, + impl_get_size, + impl_init, + impl_enum_interface_info, +};
View file
pipewire-0.3.64.tar.gz/spa/plugins/alsa/alsa-pcm-device.c -> pipewire-0.3.65.tar.gz/spa/plugins/alsa/alsa-pcm-device.c
Changed
@@ -31,11 +31,12 @@ #include <alsa/asoundlib.h> -#include <spa/utils/type.h> #include <spa/node/node.h> +#include <spa/utils/type.h> #include <spa/utils/keys.h> #include <spa/utils/names.h> #include <spa/utils/string.h> +#include <spa/support/log.h> #include <spa/support/loop.h> #include <spa/support/plugin.h> #include <spa/monitor/device.h> @@ -44,6 +45,7 @@ #include <spa/pod/filter.h> #include <spa/pod/parser.h> #include <spa/debug/pod.h> +#include <spa/debug/log.h> #include "alsa.h" @@ -462,7 +464,7 @@ SPA_TYPE_OBJECT_ParamProfile, NULL, SPA_PARAM_PROFILE_index, SPA_POD_Int(&idx))) < 0) { spa_log_warn(this->log, "can't parse profile"); - spa_debug_pod(0, NULL, param); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param); return res; }
View file
pipewire-0.3.64.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.65.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
@@ -35,7 +35,6 @@ #include <spa/utils/string.h> #include <spa/param/audio/format.h> #include <spa/pod/filter.h> -#include <spa/debug/pod.h> #include "alsa-pcm.h"
View file
pipewire-0.3.64.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.65.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -1519,6 +1519,11 @@ fmt->info.raw.rate = rrate; match = false; } + if (rchannels == 0 || rrate == 0) { + spa_log_error(state->log, "%s: invalid channels:%d or rate:%d", + state->props.device, rchannels, rrate); + return -EIO; + } state->format = rformat; state->channels = rchannels; @@ -1563,6 +1568,11 @@ CHECK(snd_pcm_hw_params_set_period_size_near(hndl, params, &period_size, &dir), "set_period_size_near"); + if (period_size == 0) { + spa_log_error(state->log, "%s: invalid period_size 0 (driver error?)", state->props.device); + return -EIO; + } + state->period_frames = period_size; if (state->default_period_num != 0) { @@ -1578,6 +1588,10 @@ CHECK(snd_pcm_hw_params_set_buffer_size_near(hndl, params, &state->buffer_frames), "set_buffer_size_near"); periods = state->buffer_frames / period_size; } + if (state->buffer_frames == 0) { + spa_log_error(state->log, "%s: invalid buffer_frames 0 (driver error?)", state->props.device); + return -EIO; + } state->headroom = state->default_headroom; if (is_batch) @@ -1985,7 +1999,7 @@ (state->rate_denom != state->position->clock.rate.denom))) { state->duration = state->position->clock.duration; state->rate_denom = state->position->clock.rate.denom; - state->threshold = (state->duration * state->rate + state->rate_denom-1) / state->rate_denom; + state->threshold = SPA_SCALE32_UP(state->duration, state->rate, state->rate_denom); state->max_error = SPA_MAX(256.0f, state->threshold / 2.0f); state->resample = ((uint32_t)state->rate != state->rate_denom) || state->matching; state->alsa_sync = true; @@ -2542,12 +2556,20 @@ state->duration = 1024; state->rate_denom = state->rate; } + if (state->rate_denom == 0) { + spa_log_error(state->log, "%s: unset rate_denom", state->props.device); + return -EIO; + } + if (state->duration == 0) { + spa_log_error(state->log, "%s: unset duration", state->props.device); + return -EIO; + } state->following = is_following(state); setup_matching(state); spa_dll_init(&state->dll); - state->threshold = (state->duration * state->rate + state->rate_denom-1) / state->rate_denom; + state->threshold = SPA_SCALE32_UP(state->duration, state->rate, state->rate_denom); state->last_threshold = state->threshold; state->max_error = SPA_MAX(256.0f, state->threshold / 2.0f);
View file
pipewire-0.3.64.tar.gz/spa/plugins/alsa/alsa.c -> pipewire-0.3.65.tar.gz/spa/plugins/alsa/alsa.c
Changed
@@ -22,6 +22,8 @@ * DEALINGS IN THE SOFTWARE. */ +#include "config.h" + #include <errno.h> #include <spa/support/plugin.h> @@ -33,6 +35,9 @@ extern const struct spa_handle_factory spa_alsa_device_factory; extern const struct spa_handle_factory spa_alsa_seq_bridge_factory; extern const struct spa_handle_factory spa_alsa_acp_device_factory; +#ifdef HAVE_ALSA_COMPRESS_OFFLOAD +extern const struct spa_handle_factory spa_alsa_compress_offload_sink_factory; +#endif struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.alsa"); struct spa_log_topic *alsa_log_topic = &log_topic; @@ -62,6 +67,11 @@ case 5: *factory = &spa_alsa_acp_device_factory; break; +#ifdef HAVE_ALSA_COMPRESS_OFFLOAD + case 6: + *factory = &spa_alsa_compress_offload_sink_factory; + break; +#endif default: return 0; }
View file
pipewire-0.3.64.tar.gz/spa/plugins/alsa/meson.build -> pipewire-0.3.65.tar.gz/spa/plugins/alsa/meson.build
Changed
@@ -1,6 +1,8 @@ subdir('acp') subdir('mixer') +spa_alsa_dependencies = spa_dep, alsa_dep, libudev_dep, mathlib, epoll_shim_dep, libinotify_dep + spa_alsa_sources = 'alsa.c', 'alsa.h', 'alsa-udev.c', @@ -12,12 +14,17 @@ 'alsa-seq-bridge.c', 'alsa-seq.c' +if tinycompress_dep.found() + spa_alsa_sources += 'alsa-compress-offload-sink.c' + spa_alsa_dependencies += tinycompress_dep +endif + spa_alsa = shared_library( 'spa-alsa', spa_alsa_sources , c_args : acp_c_args, include_directories : configinc, - dependencies : spa_dep, alsa_dep, libudev_dep, mathlib, epoll_shim_dep, libinotify_dep , + dependencies : spa_alsa_dependencies, link_with : acp_lib , install : true, install_dir : spa_plugindir / 'alsa'
View file
pipewire-0.3.64.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.65.tar.gz/spa/plugins/audioconvert/audioadapter.c
Changed
@@ -42,6 +42,7 @@ #include <spa/param/latency-utils.h> #include <spa/debug/format.h> #include <spa/debug/pod.h> +#include <spa/debug/log.h> #undef SPA_LOG_TOPIC_DEFAULT #define SPA_LOG_TOPIC_DEFAULT log_topic @@ -333,7 +334,7 @@ if (filter) { spa_log_error(this->log, "with this filter:"); - spa_debug_pod(2, NULL, filter); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 2, NULL, filter); } else { spa_log_error(this->log, "there was no filter"); } @@ -351,7 +352,7 @@ break; } spa_log_error(this->log, "unmatched %s %d:", debug, count); - spa_debug_pod(2, NULL, param); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 2, NULL, param); count++; } if (count == 0) @@ -480,8 +481,8 @@ return 0; spa_log_debug(this->log, "%p: configure format:", this); - if (format && spa_log_level_enabled(this->log, SPA_LOG_LEVEL_DEBUG)) - spa_debug_format(0, NULL, format); + if (format) + spa_debug_log_format(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, format); if ((res = spa_node_port_set_param(this->follower, this->direction, 0,
View file
pipewire-0.3.64.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.65.tar.gz/spa/plugins/audioconvert/audioconvert.c
Changed
@@ -44,7 +44,6 @@ #include <spa/param/latency-utils.h> #include <spa/pod/filter.h> #include <spa/debug/types.h> -#include <spa/debug/pod.h> #include "volume-ops.h" #include "fmt-ops.h" @@ -1755,7 +1754,7 @@ size = this->quantum_limit * 2; /* scale the buffer size when we can. */ if (irate != 0 && orate != 0) - size = size * (irate + orate - 1) / orate; + size = SPA_SCALE32_UP(size, irate, orate); } param = spa_pod_builder_add_object(&b,
View file
pipewire-0.3.64.tar.gz/spa/plugins/audioconvert/fmt-ops.h -> pipewire-0.3.65.tar.gz/spa/plugins/audioconvert/fmt-ops.h
Changed
@@ -97,34 +97,42 @@ #define F32_TO_S24(v) F32_TO_S24_D(v, 0.0f) #define F32_TO_S24S(v) bswap_s24(F32_TO_S24(v)) -#define U24_32_TO_F32(v) U32_TO_F32((v)<<8) +#define U24_32_TO_U32(v) (((uint32_t)(v)) << 8) + +#define U24_32_TO_F32(v) U32_TO_F32(U24_32_TO_U32(v)) #define U24_32S_TO_F32(v) U24_32_TO_F32(bswap_32(v)) #define F32_TO_U24_32_D(v,d) FTOI(uint32_t, v, U24_SCALE, U24_OFFS, d, U24_MIN, U24_MAX) #define F32_TO_U24_32(v) F32_TO_U24_32_D(v, 0.0f) #define F32_TO_U24_32S(v) bswap_32(F32_TO_U24_32(v)) #define F32_TO_U24_32S_D(v,d) bswap_32(F32_TO_U24_32_D(v,d)) +#define U32_TO_U24_32(v) (((uint32_t)(v)) >> 8) + #define U32_MIN 0u #define U32_MAX 4294967295u #define U32_SCALE 2147483648.f #define U32_OFFS 2147483648.f -#define U32_TO_F32(v) ITOF(uint32_t, (v) >> 8, U24_SCALE, 1.0f) -#define F32_TO_U32(v) (F32_TO_U24_32(v) << 8) -#define F32_TO_U32_D(v,d) (F32_TO_U24_32_D(v,d) << 8) +#define U32_TO_F32(v) ITOF(uint32_t, U32_TO_U24_32(v), U24_SCALE, 1.0f) +#define F32_TO_U32(v) U24_32_TO_U32(F32_TO_U24_32(v)) +#define F32_TO_U32_D(v,d) U24_32_TO_U32(F32_TO_U24_32_D(v,d)) -#define S24_32_TO_F32(v) S32_TO_F32((v)<<8) +#define S24_32_TO_S32(v) ((int32_t)(((uint32_t)(v)) << 8)) + +#define S24_32_TO_F32(v) S32_TO_F32(S24_32_TO_S32(v)) #define S24_32S_TO_F32(v) S24_32_TO_F32(bswap_32(v)) #define F32_TO_S24_32_D(v,d) FTOI(int32_t, v, S24_SCALE, 0.0f, d, S24_MIN, S24_MAX) #define F32_TO_S24_32(v) F32_TO_S24_32_D(v, 0.0f) #define F32_TO_S24_32S(v) bswap_32(F32_TO_S24_32(v)) #define F32_TO_S24_32S_D(v,d) bswap_32(F32_TO_S24_32_D(v,d)) +#define S32_TO_S24_32(v) (((int32_t)(v)) >> 8) + #define S32_MIN (S24_MIN * 256) #define S32_MAX (S24_MAX * 256) -#define S32_TO_F32(v) ITOF(int32_t, (v) >> 8, S24_SCALE, 0.0f) +#define S32_TO_F32(v) ITOF(int32_t, S32_TO_S24_32(v), S24_SCALE, 0.0f) #define S32S_TO_F32(v) S32_TO_F32(bswap_32(v)) -#define F32_TO_S32(v) (F32_TO_S24_32(v) << 8) -#define F32_TO_S32_D(v,d) (F32_TO_S24_32_D(v,d) << 8) +#define F32_TO_S32(v) S24_32_TO_S32(F32_TO_S24_32(v)) +#define F32_TO_S32_D(v,d) S24_32_TO_S32(F32_TO_S24_32_D(v,d)) #define F32_TO_S32S(v) bswap_32(F32_TO_S32(v)) #define F32_TO_S32S_D(v,d) bswap_32(F32_TO_S32_D(v,d))
View file
pipewire-0.3.64.tar.gz/spa/plugins/avb/avb-pcm-sink.c -> pipewire-0.3.65.tar.gz/spa/plugins/avb/avb-pcm-sink.c
Changed
@@ -33,7 +33,6 @@ #include <spa/utils/string.h> #include <spa/param/audio/format.h> #include <spa/pod/filter.h> -#include <spa/debug/pod.h> #include "avb-pcm.h"
View file
pipewire-0.3.64.tar.gz/spa/plugins/avb/avb-pcm-source.c -> pipewire-0.3.65.tar.gz/spa/plugins/avb/avb-pcm-source.c
Changed
@@ -33,7 +33,6 @@ #include <spa/utils/string.h> #include <spa/param/audio/format.h> #include <spa/pod/filter.h> -#include <spa/debug/pod.h> #include "avb-pcm.h"
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/README-MIDI.md
Added
@@ -0,0 +1,24 @@ +## BLE MIDI & SELinux + +The SELinux configuration on Fedora 37 (as of 2022-11-10) does not +permit access to the bluetoothd APIs needed for BLE MIDI. + +As a workaround, hopefully to be not necessary in future, you can +permit such access by creating a file `blemidi.te` with contents: + + policy_module(blemidi, 1.0); + + require { + type system_dbusd_t; + type unconfined_t; + type bluetooth_t; + } + + allow bluetooth_t unconfined_t:unix_stream_socket { read write }; + allow system_dbusd_t bluetooth_t:unix_stream_socket { read write }; + +Then having package `selinux-policy-devel` installed, running +`make -f /usr/share/selinux/devel/Makefile blemidi.pp`, and finally +to insert the rules via `sudo semodule -i blemidi.pp`. + +The policy change can be removed by `sudo semodule -r blemidi`.
View file
pipewire-0.3.64.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.65.tar.gz/spa/plugins/bluez5/backend-native.c
Changed
@@ -36,6 +36,8 @@ #include <dbus/dbus.h> +#include <spa/debug/mem.h> +#include <spa/debug/log.h> #include <spa/support/log.h> #include <spa/support/loop.h> #include <spa/support/dbus.h> @@ -779,6 +781,12 @@ int xapl_product; int xapl_features; + spa_debug_log_mem(backend->log, SPA_LOG_LEVEL_DEBUG, 2, buf, strlen(buf)); + + /* Some devices send initial \n: be permissive */ + while (*buf == '\n') + ++buf; + if (sscanf(buf, "AT+BRSF=%u", &features) == 1) { unsigned int ag_features = SPA_BT_HFP_AG_FEATURE_NONE; @@ -880,6 +888,9 @@ rfcomm_emit_volume_changed(rfcomm, -1, SPA_BT_VOLUME_INVALID); } } + } else if (spa_streq(buf, "\r")) { + /* No commands, reply OK (ITU-T Rec. V.250 Sec. 5.2.1 & 5.6) */ + rfcomm_send_reply(rfcomm, "OK"); } else if (!rfcomm->slc_configured) { spa_log_warn(backend->log, "RFCOMM receive command before SLC completed: %s", buf); rfcomm_send_error(rfcomm, CMEE_AG_FAILURE);
View file
pipewire-0.3.64.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c -> pipewire-0.3.65.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c
Changed
@@ -39,6 +39,8 @@ #include "media-codecs.h" #include "bap-codec-caps.h" +#define MAX_PACS 64 + struct impl { lc3_encoder_t encLC3_MAX_CHANNELS; lc3_decoder_t decLC3_MAX_CHANNELS; @@ -52,11 +54,16 @@ unsigned int codesize; }; -struct ltv { +struct __attribute__((packed)) ltv { uint8_t len; uint8_t type; - uint8_t value0; -} __packed; + uint8_t value; +}; + +struct pac_data { + const uint8_t *data; + size_t size; +}; static int write_ltv(uint8_t *dest, uint8_t type, void* value, size_t len) { @@ -100,6 +107,38 @@ return data - caps; } +static int parse_bluez_pacs(const uint8_t *data, size_t data_size, struct pac_data pacsMAX_PACS) +{ + /* + * BlueZ capabilites for the same codec may contain multiple + * PACs separated by zero-length LTV (see BlueZ b907befc2d80) + */ + int pac = 0; + + pacspac = (struct pac_data){ data, 0 }; + + while (data_size > 0) { + struct ltv *ltv = (struct ltv *)data; + + if (ltv->len == 0) { + /* delimiter */ + if (pac + 1 >= MAX_PACS) + break; + + ++pac; + pacspac = (struct pac_data){ data + 1, 0 }; + } else if (ltv->len >= data_size) { + return -EINVAL; + } else { + pacspac.size += ltv->len + 1; + } + data_size -= ltv->len + 1; + data += ltv->len + 1; + } + + return pac + 1; +} + static bool parse_capabilities(bap_lc3_t *conf, const uint8_t *data, size_t data_size) { uint16_t framelen_min = 0, framelen_max = 0; @@ -113,7 +152,7 @@ while (data_size > 0) { struct ltv *ltv = (struct ltv *)data; - if (ltv->len > data_size) + if (ltv->len < sizeof(struct ltv) || ltv->len >= data_size) return false; switch (ltv->type) { @@ -227,7 +266,7 @@ while (data_size > 0) { struct ltv *ltv = (struct ltv *)data; - if (ltv->len > data_size) + if (ltv->len < sizeof(struct ltv) || ltv->len >= data_size) return false; switch (ltv->type) { @@ -266,18 +305,75 @@ return true; } +static int conf_cmp(const bap_lc3_t *conf1, int res1, const bap_lc3_t *conf2, int res2) +{ + const bap_lc3_t *conf; + int a, b; + +#define PREFER_EXPR(expr) \ + do { \ + conf = conf1; \ + a = (expr); \ + conf = conf2; \ + b = (expr); \ + if (a != b) \ + return b - a; \ + } while (0) + +#define PREFER_BOOL(expr) PREFER_EXPR((expr) ? 1 : 0) + + /* Prefer valid */ + a = (res1 > 0 && (size_t)res1 == sizeof(bap_lc3_t)) ? 1 : 0; + b = (res2 > 0 && (size_t)res2 == sizeof(bap_lc3_t)) ? 1 : 0; + if (!a || !b) + return b - a; + + PREFER_BOOL(conf->channels & LC3_CHAN_2); + PREFER_BOOL(conf->rate & (LC3_CONFIG_FREQ_48KHZ | LC3_CONFIG_FREQ_24KHZ | LC3_CONFIG_FREQ_16KHZ | LC3_CONFIG_FREQ_8KHZ)); + PREFER_BOOL(conf->rate & LC3_CONFIG_FREQ_48KHZ); + + return 0; + +#undef PREFER_EXPR +#undef PREFER_BOOL +} + +static int pac_cmp(const void *p1, const void *p2) +{ + const struct pac_data *pac1 = p1; + const struct pac_data *pac2 = p2; + bap_lc3_t conf1, conf2; + int res1, res2; + + res1 = parse_capabilities(&conf1, pac1->data, pac1->size) ? (int)sizeof(bap_lc3_t) : -EINVAL; + res2 = parse_capabilities(&conf2, pac2->data, pac2->size) ? (int)sizeof(bap_lc3_t) : -EINVAL; + + return conf_cmp(&conf1, res1, &conf2, res2); +} + static int codec_select_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE) { + struct pac_data pacsMAX_PACS; + int npacs; bap_lc3_t conf; uint8_t *data = config; if (caps == NULL) return -EINVAL; - if (!parse_capabilities(&conf, caps, caps_size)) + /* Select best conf from those possible */ + npacs = parse_bluez_pacs(caps, caps_size, pacs); + if (npacs < 0) + return npacs; + else if (npacs == 0) + return -EINVAL; + + qsort(pacs, npacs, sizeof(struct pac_data), pac_cmp); + + if (!parse_capabilities(&conf, pacs0.data, pacs0.size)) return -ENOTSUP; data += write_ltv_uint8(data, LC3_TYPE_FREQ, conf.rate); @@ -293,40 +389,13 @@ const void *caps2, size_t caps2_size, const struct media_codec_audio_info *info, const struct spa_dict *global_settings) { bap_lc3_t conf1, conf2; - bap_lc3_t *conf; int res1, res2; - int a, b; /* Order selected configurations by preference */ res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1); res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2); -#define PREFER_EXPR(expr) \ - do { \ - conf = &conf1; \ - a = (expr); \ - conf = &conf2; \ - b = (expr); \ - if (a != b) \ - return b - a; \ - } while (0) - -#define PREFER_BOOL(expr) PREFER_EXPR((expr) ? 1 : 0) - - /* Prefer valid */ - a = (res1 > 0 && (size_t)res1 == sizeof(bap_lc3_t)) ? 1 : 0; - b = (res2 > 0 && (size_t)res2 == sizeof(bap_lc3_t)) ? 1 : 0; - if (!a || !b) - return b - a; - - PREFER_BOOL(conf->channels & LC3_CHAN_2); - PREFER_BOOL(conf->rate & (LC3_CONFIG_FREQ_48KHZ | LC3_CONFIG_FREQ_24KHZ | LC3_CONFIG_FREQ_16KHZ | LC3_CONFIG_FREQ_8KHZ)); - PREFER_BOOL(conf->rate & LC3_CONFIG_FREQ_48KHZ); - - return 0; - -#undef PREFER_EXPR -#undef PREFER_BOOL + return conf_cmp(&conf1, res1, &conf2, res2); } static uint8_t channels_to_positions(uint32_t channels, uint8_t n_channels, uint32_t *position)
View file
pipewire-0.3.64.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.65.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
@@ -35,6 +35,8 @@ #include <dbus/dbus.h> +#include <spa/debug/mem.h> +#include <spa/debug/log.h> #include <spa/support/log.h> #include <spa/support/loop.h> #include <spa/support/dbus.h> @@ -563,7 +565,7 @@ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } spa_log_info(monitor->log, "%p: %s select conf %d", monitor, path, size); - spa_log_hexdump(monitor->log, SPA_LOG_LEVEL_DEBUG, 2, cap, (size_t)size); + spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, 2, cap, (size_t)size); /* For codecs sharing the same endpoint, BlueZ-initiated connections * always pick the default one. The session manager will @@ -592,7 +594,7 @@ return DBUS_HANDLER_RESULT_NEED_MEMORY; goto exit_send; } - spa_log_hexdump(monitor->log, SPA_LOG_LEVEL_DEBUG, 2, pconf, (size_t)size); + spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, 2, pconf, (size_t)size); if ((r = dbus_message_new_method_return(m)) == NULL) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -628,6 +630,7 @@ uint8_t capsA2DP_MAX_CAPS_SIZE; uint8_t configA2DP_MAX_CAPS_SIZE; int caps_size = 0; + int conf_size; DBusMessageIter dict; struct bap_endpoint_qos endpoint_qos; @@ -688,10 +691,14 @@ } dbus_message_iter_get_fixed_array(&array, &buf, &caps_size); + if (caps_size > (int)sizeof(caps)) { + spa_log_error(monitor->log, "%s size:%d too large", key, (int)caps_size); + goto error_invalid; + } memcpy(caps, buf, caps_size); spa_log_info(monitor->log, "%p: %s %s size:%d", monitor, path, key, caps_size); - spa_log_hexdump(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', caps, (size_t)caps_size); + spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', caps, (size_t)caps_size); } else if (spa_streq(key, "Endpoint")) { if (type != DBUS_TYPE_OBJECT_PATH) { spa_log_error(monitor->log, "Property %s of wrong type %c", key, (char)type); @@ -764,15 +771,14 @@ /* TODO: determine which device the SelectConfiguration() call is associated * with; it's known here based on the remote endpoint. */ - res = codec->select_config(codec, 0, caps, caps_size, &monitor->default_audio_info, NULL, config); - - if (res < 0 || res != caps_size) { + conf_size = codec->select_config(codec, 0, caps, caps_size, &monitor->default_audio_info, NULL, config); + if (conf_size < 0) { spa_log_error(monitor->log, "can't select config: %d (%s)", - res, spa_strerror(res)); + conf_size, spa_strerror(conf_size)); goto error_invalid; } - spa_log_info(monitor->log, "%p: selected conf %d", monitor, caps_size); - spa_log_hexdump(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', (uint8_t *)config, (size_t)caps_size); + spa_log_info(monitor->log, "%p: selected conf %d", monitor, conf_size); + spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', (uint8_t *)config, (size_t)conf_size); if ((r = dbus_message_new_method_return(m)) == NULL) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -784,7 +790,7 @@ DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); - append_basic_array_variant_dict_entry(&dict, "Capabilities", "ay", "y", DBUS_TYPE_BYTE, &config, caps_size); + append_basic_array_variant_dict_entry(&dict, "Capabilities", "ay", "y", DBUS_TYPE_BYTE, &config, conf_size); if (codec->get_qos) { struct bap_codec_qos qos; @@ -793,7 +799,7 @@ spa_zero(qos); - res = codec->get_qos(codec, config, caps_size, &endpoint_qos, &qos); + res = codec->get_qos(codec, config, conf_size, &endpoint_qos, &qos); if (res < 0) { spa_log_error(monitor->log, "can't select QOS config: %d (%s)", res, spa_strerror(res)); @@ -2060,7 +2066,7 @@ dbus_message_iter_get_fixed_array(&iter, &value, &len); spa_log_debug(monitor->log, "remote_endpoint %p: %s=%d", remote_endpoint, key, len); - spa_log_hexdump(monitor->log, SPA_LOG_LEVEL_DEBUG, 2, value, (size_t)len); + spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, 2, value, (size_t)len); free(remote_endpoint->capabilities); remote_endpoint->capabilities_len = 0; @@ -2612,7 +2618,7 @@ dbus_message_iter_get_fixed_array(&iter, &value, &len); spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, len); - spa_log_hexdump(monitor->log, SPA_LOG_LEVEL_DEBUG, 2, value, (size_t)len); + spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, 2, value, (size_t)len); free(transport->configuration); transport->configuration_len = 0; @@ -3807,7 +3813,9 @@ * */ spa_log_warn(monitor->log, "Using legacy bluez5 API for A2DP - only SBC will be supported. " - "Please upgrade bluez5."); + "No LE Audio. Please upgrade bluez5."); + + monitor->le_audio_supported = false; for (i = 0; media_codecsi; i++) { const struct media_codec *codec = media_codecsi;
View file
pipewire-0.3.64.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.65.tar.gz/spa/plugins/bluez5/bluez5-device.c
Changed
@@ -49,6 +49,7 @@ #include <spa/param/bluetooth/audio.h> #include <spa/param/bluetooth/type-info.h> #include <spa/debug/pod.h> +#include <spa/debug/log.h> #include "defs.h" #include "media-codecs.h" @@ -1150,13 +1151,20 @@ if (profile == DEVICE_PROFILE_OFF || profile == DEVICE_PROFILE_AG) return profile; - if (profile == DEVICE_PROFILE_A2DP || profile == DEVICE_PROFILE_BAP) { + if (profile == DEVICE_PROFILE_A2DP) { if (codec == 0 || (this->bt_dev->connected_profiles & SPA_BT_PROFILE_MEDIA_SOURCE)) return profile; return codec + DEVICE_PROFILE_LAST; } + if (profile == DEVICE_PROFILE_BAP) { + if (codec == 0) + return profile; + + return codec + DEVICE_PROFILE_LAST; + } + if (profile == DEVICE_PROFILE_HSP_HFP) { if (codec == 0 || (this->bt_dev->connected_profiles & SPA_BT_PROFILE_HFP_AG)) return profile; @@ -2107,7 +2115,7 @@ SPA_PARAM_PROFILE_index, SPA_POD_Int(&idx), SPA_PARAM_PROFILE_save, SPA_POD_OPT_Bool(&save))) < 0) { spa_log_warn(this->log, "can't parse profile"); - spa_debug_pod(0, NULL, param); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param); return res; } @@ -2135,7 +2143,7 @@ SPA_PARAM_ROUTE_props, SPA_POD_OPT_Pod(&props), SPA_PARAM_ROUTE_save, SPA_POD_OPT_Bool(&save))) < 0) { spa_log_warn(this->log, "can't parse route"); - spa_debug_pod(0, NULL, param); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param); return res; } if (device > 1 || !this->nodesdevice.active) @@ -2166,7 +2174,7 @@ SPA_PROP_bluetoothAudioCodec, SPA_POD_OPT_Id(&codec_id), SPA_PROP_bluetoothOffloadActive, SPA_POD_OPT_Bool(&offload_active))) < 0) { spa_log_warn(this->log, "can't parse props"); - spa_debug_pod(0, NULL, param); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param); return res; }
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/dbus-monitor.c
Added
@@ -0,0 +1,265 @@ +/* Spa midi dbus + * + * Copyright © 2022 Pauli Virtanen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <gio/gio.h> + +#include <spa/utils/defs.h> +#include <spa/utils/string.h> +#include <spa/support/log.h> + +#include "dbus-monitor.h" + + +static void on_g_properties_changed(GDBusProxy *proxy, + GVariant *changed_properties, char **invalidated_properties, + gpointer user_data) +{ + struct dbus_monitor *monitor = user_data; + GDBusInterfaceInfo *info = g_dbus_interface_get_info(G_DBUS_INTERFACE(proxy)); + const char *name = info ? info->name : NULL; + const struct dbus_monitor_proxy_type *p; + + spa_log_trace(monitor->log, "%p: dbus object updated path=%s, name=%s", + monitor, g_dbus_proxy_get_object_path(proxy), name ? name : "<null>"); + + for (p = monitor->proxy_types; p && p->proxy_type != G_TYPE_INVALID ; ++p) { + if (G_TYPE_CHECK_INSTANCE_TYPE(proxy, p->proxy_type)) { + if (p->on_update) + p->on_update(monitor, G_DBUS_INTERFACE(proxy)); + } + } +} + +static void on_remove(struct dbus_monitor *monitor, GDBusProxy *proxy) +{ + const struct dbus_monitor_proxy_type *p; + + for (p = monitor->proxy_types; p && p->proxy_type != G_TYPE_INVALID ; ++p) { + if (G_TYPE_CHECK_INSTANCE_TYPE(proxy, p->proxy_type)) { + if (p->on_remove) + p->on_remove(monitor, G_DBUS_INTERFACE(proxy)); + } + } +} + +static void on_interface_added(GDBusObjectManager *self, GDBusObject *object, + GDBusInterface *iface, gpointer user_data) +{ + struct dbus_monitor *monitor = user_data; + GDBusInterfaceInfo *info = g_dbus_interface_get_info(iface); + const char *name = info ? info->name : NULL; + + spa_log_trace(monitor->log, "%p: dbus interface added path=%s, name=%s", + monitor, g_dbus_object_get_object_path(object), name ? name : "<null>"); + + if (!g_object_get_data(G_OBJECT(iface), "dbus-monitor-signals-connected")) { + g_object_set_data(G_OBJECT(iface), "dbus-monitor-signals-connected", GUINT_TO_POINTER(1)); + g_signal_connect(iface, "g-properties-changed", + G_CALLBACK(on_g_properties_changed), + monitor); + } + + on_g_properties_changed(G_DBUS_PROXY(iface), + NULL, NULL, monitor); +} + +static void on_interface_removed(GDBusObjectManager *manager, GDBusObject *object, + GDBusInterface *iface, gpointer user_data) +{ + struct dbus_monitor *monitor = user_data; + GDBusInterfaceInfo *info = g_dbus_interface_get_info(iface); + const char *name = info ? info->name : NULL; + + spa_log_trace(monitor->log, "%p: dbus interface removed path=%s, name=%s", + monitor, g_dbus_object_get_object_path(object), name ? name : "<null>"); + + if (g_object_get_data(G_OBJECT(iface), "dbus-monitor-signals-connected")) { + g_object_disconnect(G_OBJECT(iface), "g-properties-changed", + G_CALLBACK(on_g_properties_changed), + monitor, NULL); + g_object_set_data(G_OBJECT(iface), "dbus-monitor-signals-connected", NULL); + } + + on_remove(monitor, G_DBUS_PROXY(iface)); +} + +static void on_object_added(GDBusObjectManager *self, GDBusObject *object, + gpointer user_data) +{ + struct dbus_monitor *monitor = user_data; + GList *interfaces = g_dbus_object_get_interfaces(object); + + /* + * on_interface_added won't necessarily be called on objects on + * name owner changes, so we have to call it here for all interfaces. + */ + for (GList *lli = g_list_first(interfaces); lli; lli = lli->next) { + on_interface_added(dbus_monitor_manager(monitor), + object, G_DBUS_INTERFACE(lli->data), monitor); + } + + g_list_free_full(interfaces, g_object_unref); +} + +static void on_object_removed(GDBusObjectManager *manager, GDBusObject *object, + gpointer user_data) +{ + struct dbus_monitor *monitor = user_data; + GList *interfaces = g_dbus_object_get_interfaces(object); + + for (GList *lli = g_list_first(interfaces); lli; lli = lli->next) { + on_interface_removed(dbus_monitor_manager(monitor), + object, G_DBUS_INTERFACE(lli->data), monitor); + } + + g_list_free_full(interfaces, g_object_unref); +} + +static void on_notify(GObject *gobject, GParamSpec *pspec, gpointer user_data) +{ + struct dbus_monitor *monitor = user_data; + + if (spa_streq(pspec->name, "name-owner") && monitor->on_name_owner_change) + monitor->on_name_owner_change(monitor); +} + +static GType get_proxy_type(GDBusObjectManagerClient *manager, const gchar *object_path, + const gchar *interface_name, gpointer user_data) +{ + struct dbus_monitor *monitor = user_data; + const struct dbus_monitor_proxy_type *p; + + for (p = monitor->proxy_types; p && p->proxy_type != G_TYPE_INVALID; ++p) { + if (spa_streq(p->interface_name, interface_name)) + return p->proxy_type; + } + + return G_TYPE_DBUS_PROXY; +} + +static void init_done(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + struct dbus_monitor *monitor = user_data; + GError *error = NULL; + GList *objects; + GObject *ret; + + g_clear_object(&monitor->call); + + ret = g_async_initable_new_finish(G_ASYNC_INITABLE(source_object), res, &error); + if (!ret) { + spa_log_error(monitor->log, "%p: creating DBus object monitor failed: %s", + monitor, error->message); + g_error_free(error); + return; + } + monitor->manager = G_DBUS_OBJECT_MANAGER_CLIENT(ret); + + spa_log_debug(monitor->log, "%p: DBus monitor started", monitor); + + g_signal_connect(monitor->manager, "interface-added", + G_CALLBACK(on_interface_added), monitor); + g_signal_connect(monitor->manager, "interface-removed", + G_CALLBACK(on_interface_removed), monitor); + g_signal_connect(monitor->manager, "object-added", + G_CALLBACK(on_object_added), monitor); + g_signal_connect(monitor->manager, "object-removed", + G_CALLBACK(on_object_removed), monitor); + g_signal_connect(monitor->manager, "notify", + G_CALLBACK(on_notify), monitor); + + /* List all objects now */ + objects = g_dbus_object_manager_get_objects(dbus_monitor_manager(monitor)); + for (GList *llo = g_list_first(objects); llo; llo = llo->next) { + GList *interfaces = g_dbus_object_get_interfaces(G_DBUS_OBJECT(llo->data)); + + for (GList *lli = g_list_first(interfaces); lli; lli = lli->next) { + on_interface_added(dbus_monitor_manager(monitor), + G_DBUS_OBJECT(llo->data), G_DBUS_INTERFACE(lli->data), + monitor); + } + g_list_free_full(interfaces, g_object_unref); + } + g_list_free_full(objects, g_object_unref); +} + +void dbus_monitor_init(struct dbus_monitor *monitor, + GType client_type, + struct spa_log *log, GDBusConnection *conn, + const char *name, const char *object_path, + const struct dbus_monitor_proxy_type *proxy_types, + void (*on_name_owner_change)(struct dbus_monitor *monitor)) +{ + GDBusObjectManagerClientFlags flags = G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START; + size_t i; + + spa_zero(*monitor); + + monitor->log = log; + monitor->call = g_cancellable_new(); + monitor->on_name_owner_change = on_name_owner_change; + + spa_zero(monitor->proxy_types); + + for (i = 0; proxy_types && proxy_typesi.proxy_type != G_TYPE_INVALID; ++i) { + spa_assert(i < DBUS_MONITOR_MAX_TYPES); + monitor->proxy_typesi = proxy_typesi; + } + + g_async_initable_new_async(client_type, G_PRIORITY_DEFAULT, + monitor->call, init_done, monitor, + "flags", flags, "name", name, "connection", conn, + "object-path", object_path, + "get-proxy-type-func", get_proxy_type, + "get-proxy-type-user-data", monitor, + NULL); +} + +void dbus_monitor_clear(struct dbus_monitor *monitor) +{ + g_cancellable_cancel(monitor->call); + g_clear_object(&monitor->call); + + if (monitor->manager) { + /* + * Indicate all objects should stop now. + * + * This has to be a separate hook, because the proxy finalizers + * may be called later asynchronously via e.g. DBus callbacks. + */ + GList *objects = g_dbus_object_manager_get_objects(dbus_monitor_manager(monitor)); + for (GList *llo = g_list_first(objects); llo; llo = llo->next) { + GList *interfaces = g_dbus_object_get_interfaces(G_DBUS_OBJECT(llo->data)); + for (GList *lli = g_list_first(interfaces); lli; lli = lli->next) { + on_interface_removed(dbus_monitor_manager(monitor), + G_DBUS_OBJECT(llo->data), G_DBUS_INTERFACE(lli->data), + monitor); + } + g_list_free_full(interfaces, g_object_unref); + } + g_list_free_full(objects, g_object_unref); + } + + g_clear_object(&monitor->manager); + spa_zero(*monitor); +}
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/dbus-monitor.h
Added
@@ -0,0 +1,83 @@ +/* Spa midi dbus + * + * Copyright © 2022 Pauli Virtanen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#ifndef DBUS_MONITOR_H_ +#define DBUS_MONITOR_H_ + +#include <gio/gio.h> + +#include <spa/utils/defs.h> +#include <spa/utils/string.h> +#include <spa/support/log.h> + +#define DBUS_MONITOR_MAX_TYPES 16 + +struct dbus_monitor; + +struct dbus_monitor_proxy_type +{ + /** Interface name to monitor, or NULL for object type */ + const char *interface_name; + + /** GObject type for the proxy */ + GType proxy_type; + + /** Hook called when object added or properties changed */ + void (*on_update)(struct dbus_monitor *monitor, GDBusInterface *iface); + + /** Hook called when object is removed (or on monitor shutdown) */ + void (*on_remove)(struct dbus_monitor *monitor, GDBusInterface *iface); +}; + +struct dbus_monitor +{ + GDBusObjectManagerClient *manager; + struct spa_log *log; + GCancellable *call; + struct dbus_monitor_proxy_type proxy_typesDBUS_MONITOR_MAX_TYPES+1; + void (*on_name_owner_change)(struct dbus_monitor *monitor); + void *user_data; +}; + +static inline GDBusObjectManager *dbus_monitor_manager(struct dbus_monitor *monitor) +{ + return G_DBUS_OBJECT_MANAGER(monitor->manager); +} + +/** + * Create a DBus object monitor, with a given interface to proxy type map. + * + * \param proxy_types Mapping between interface names and watched proxy + * types, terminated by G_TYPE_INVALID. + * \param on_object_update Called for all objects and interfaces on + * startup, and when object properties are modified. + */ +void dbus_monitor_init(struct dbus_monitor *monitor, + GType client_type, struct spa_log *log, GDBusConnection *conn, + const char *name, const char *object_path, + const struct dbus_monitor_proxy_type *proxy_types, + void (*on_name_owner_change)(struct dbus_monitor *monitor)); + +void dbus_monitor_clear(struct dbus_monitor *monitor); + +#endif DBUS_MONITOR_H_
View file
pipewire-0.3.64.tar.gz/spa/plugins/bluez5/media-codecs.c -> pipewire-0.3.65.tar.gz/spa/plugins/bluez5/media-codecs.c
Changed
@@ -78,7 +78,10 @@ if (res < 0) return false; - return ((size_t)res == caps_size); + if (codec->bap) + return true; + else + return ((size_t)res == caps_size); } #ifdef CODEC_PLUGIN
View file
pipewire-0.3.64.tar.gz/spa/plugins/bluez5/media-sink.c -> pipewire-0.3.65.tar.gz/spa/plugins/bluez5/media-sink.c
Changed
@@ -48,6 +48,8 @@ #include <spa/param/audio/format.h> #include <spa/param/audio/format-utils.h> #include <spa/pod/filter.h> +#include <spa/debug/mem.h> +#include <spa/debug/log.h> #include <sbc/sbc.h> @@ -949,7 +951,7 @@ size = this->transport->configuration_len; spa_log_debug(this->log, "Transport configuration:"); - spa_log_hexdump(this->log, SPA_LOG_LEVEL_DEBUG, 2, conf, (size_t)size); + spa_debug_log_mem(this->log, SPA_LOG_LEVEL_DEBUG, 2, conf, (size_t)size); flags = this->is_duplex ? MEDIA_CODEC_FLAG_SINK : 0;
View file
pipewire-0.3.64.tar.gz/spa/plugins/bluez5/meson.build -> pipewire-0.3.65.tar.gz/spa/plugins/bluez5/meson.build
Changed
@@ -1,4 +1,6 @@ -bluez5_deps = mathlib, dbus_dep, sbc_dep, bluez_dep +gnome = import('gnome') + +bluez5_deps = mathlib, dbus_dep, glib2_dep, sbc_dep, bluez_dep, gio_dep, gio_unix_dep foreach dep: bluez5_deps if not dep.found() subdir_done() @@ -28,9 +30,26 @@ 'player.c', 'bluez5-device.c', 'bluez5-dbus.c', - 'hci.c' + 'hci.c', + 'dbus-monitor.c', + 'midi-enum.c', + 'midi-parser.c', + 'midi-node.c', + 'midi-server.c', +bluez5_interface_src = gnome.gdbus_codegen('bluez5-interface-gen', + sources: 'org.bluez.xml', + interface_prefix : 'org.bluez.', + object_manager: true, + namespace : 'Bluez5', + annotations : + 'org.bluez.GattCharacteristic1.AcquireNotify()', 'org.gtk.GDBus.C.UnixFD', 'true', + 'org.bluez.GattCharacteristic1.AcquireWrite()', 'org.gtk.GDBus.C.UnixFD', 'true', + +) +bluez5_sources += bluez5_interface_src + bluez5_data = 'bluez-hardware.conf' install_data(bluez5_data, install_dir : spa_datadir / 'bluez5') @@ -54,10 +73,14 @@ bluez5_sources += 'backend-hsphfpd.c' endif +# The library uses GObject, and cannot be unloaded +bluez5_link_args = '-Wl,-z', '-Wl,nodelete' + bluez5lib = shared_library('spa-bluez5', bluez5_sources, include_directories : configinc , dependencies : spa_dep, bluez5_deps , + link_args : bluez5_link_args, install : true, install_dir : spa_plugindir / 'bluez5') @@ -146,3 +169,38 @@ install : true, install_dir : spa_plugindir / 'bluez5') endif + +test_apps = + 'test-midi', + +bluez5_test_lib = static_library('bluez5_test_lib', + 'midi-parser.c' , + include_directories : configinc , + dependencies : spa_dep, bluez5_deps , + install : false +) + +foreach a : test_apps + test(a, + executable(a, a + '.c', + dependencies : spa_dep, dl_lib, pthread_lib, mathlib, bluez5_deps , + include_directories : configinc , + link_with : bluez5_test_lib , + install_rpath : spa_plugindir / 'bluez5', + install : installed_tests_enabled, + install_dir : installed_tests_execdir / 'bluez5'), + env : + 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')), + ) + + if installed_tests_enabled + test_conf = configuration_data() + test_conf.set('exec', installed_tests_execdir / 'bluez5' / a) + configure_file( + input: installed_tests_template, + output: a + '.test', + install_dir: installed_tests_metadir / 'bluez5', + configuration: test_conf + ) + endif +endforeach
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/midi-enum.c
Added
@@ -0,0 +1,887 @@ +/* Spa midi dbus + * + * Copyright © 2022 Pauli Virtanen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <errno.h> +#include <stddef.h> + +#include <spa/support/log.h> +#include <spa/support/loop.h> +#include <spa/support/plugin.h> +#include <spa/monitor/device.h> +#include <spa/monitor/utils.h> +#include <spa/utils/hook.h> +#include <spa/utils/type.h> +#include <spa/utils/keys.h> +#include <spa/utils/names.h> +#include <spa/utils/result.h> +#include <spa/utils/string.h> +#include <spa/utils/json.h> +#include <spa/node/node.h> +#include <spa/node/keys.h> + +#include "midi.h" +#include "config.h" + +#include "bluez5-interface-gen.h" +#include "dbus-monitor.h" + +#define MIDI_OBJECT_PATH "/midi" +#define MIDI_PROFILE_PATH MIDI_OBJECT_PATH "/profile" + +static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5.midi"); +#undef SPA_LOG_TOPIC_DEFAULT +#define SPA_LOG_TOPIC_DEFAULT &log_topic + +struct impl +{ + struct spa_handle handle; + struct spa_device device; + + struct spa_log *log; + + GDBusConnection *conn; + struct dbus_monitor monitor; + GDBusObjectManagerServer *manager; + + struct spa_hook_list hooks; + + uint32_t id; +}; + +struct _MidiEnumCharacteristicProxy +{ + Bluez5GattCharacteristic1Proxy parent_instance; + + struct impl *impl; + + gchar *description; + uint32_t id; + GCancellable *read_call; + GCancellable *dsc_call; + unsigned int node_emitted:1; + unsigned int read_probed:1; + unsigned int read_done:1; + unsigned int dsc_probed:1; + unsigned int dsc_done:1; +}; + +G_DECLARE_FINAL_TYPE(MidiEnumCharacteristicProxy, midi_enum_characteristic_proxy, MIDI_ENUM, + CHARACTERISTIC_PROXY, Bluez5GattCharacteristic1Proxy) +G_DEFINE_TYPE(MidiEnumCharacteristicProxy, midi_enum_characteristic_proxy, BLUEZ5_TYPE_GATT_CHARACTERISTIC1_PROXY) +#define MIDI_ENUM_TYPE_CHARACTERISTIC_PROXY (midi_enum_characteristic_proxy_get_type()) + +struct _MidiEnumManagerProxy +{ + Bluez5GattManager1Proxy parent_instance; + + GCancellable *register_call; + unsigned int registered:1; +}; + +G_DECLARE_FINAL_TYPE(MidiEnumManagerProxy, midi_enum_manager_proxy, MIDI_ENUM, + MANAGER_PROXY, Bluez5GattManager1Proxy) +G_DEFINE_TYPE(MidiEnumManagerProxy, midi_enum_manager_proxy, BLUEZ5_TYPE_GATT_MANAGER1_PROXY) +#define MIDI_ENUM_TYPE_MANAGER_PROXY (midi_enum_manager_proxy_get_type()) + + +static void emit_chr_node(struct impl *impl, MidiEnumCharacteristicProxy *chr, Bluez5Device1 *device) +{ + struct spa_device_object_info info; + char nick512, class16; + struct spa_dict_item items23; + uint32_t n_items = 0; + const char *path = g_dbus_proxy_get_object_path(G_DBUS_PROXY(chr)); + const char *alias = bluez5_device1_get_alias(device); + + spa_log_debug(impl->log, "emit node for path=%s", path); + + info = SPA_DEVICE_OBJECT_INFO_INIT(); + info.type = SPA_TYPE_INTERFACE_Node; + info.factory_name = SPA_NAME_API_BLUEZ5_MIDI_NODE; + info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_FLAGS | + SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS; + info.flags = 0; + + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "bluez5"); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_BUS, "bluetooth"); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Midi/Bridge"); + itemsn_items++ = SPA_DICT_ITEM_INIT("node.description", + alias ? alias : bluez5_device1_get_name(device)); + if (chr->description && chr->description0 != '\0') { + spa_scnprintf(nick, sizeof(nick), "%s (%s)", alias, chr->description); + itemsn_items++ = SPA_DICT_ITEM_INIT("node.nick", nick); + } + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_ICON, bluez5_device1_get_icon(device)); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_PATH, path); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_ADDRESS, bluez5_device1_get_address(device)); + snprintf(class, sizeof(class), "0x%06x", bluez5_device1_get_class(device)); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_CLASS, class); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_ROLE, "client"); + + info.props = &SPA_DICT_INIT(items, n_items); + spa_device_emit_object_info(&impl->hooks, chr->id, &info); +} + +static void remove_chr_node(struct impl *impl, MidiEnumCharacteristicProxy *chr) +{ + spa_log_debug(impl->log, "remove node for path=%s", g_dbus_proxy_get_object_path(G_DBUS_PROXY(chr))); + + spa_device_emit_object_info(&impl->hooks, chr->id, NULL); +} + +static void check_chr_node(struct impl *impl, MidiEnumCharacteristicProxy *chr); + +static void read_probe_reply(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + MidiEnumCharacteristicProxy *chr = MIDI_ENUM_CHARACTERISTIC_PROXY(source_object); + struct impl *impl = user_data; + gchar *value = NULL; + GError *err = NULL; + + bluez5_gatt_characteristic1_call_read_value_finish( + BLUEZ5_GATT_CHARACTERISTIC1(source_object), &value, res, &err); + + if (g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + /* Operation canceled: user_data may be invalid by now */ + g_error_free(err); + goto done; + } + if (err) { + spa_log_error(impl->log, "%s.ReadValue() failed: %s", + BLUEZ_GATT_CHR_INTERFACE, + err->message); + g_error_free(err); + goto done; + } + + g_free(value); + + spa_log_debug(impl->log, "MIDI GATT read probe done for path=%s", + g_dbus_proxy_get_object_path(G_DBUS_PROXY(chr))); + + chr->read_done = true; + + check_chr_node(impl, chr); + +done: + g_clear_object(&chr->read_call); +} + +static int read_probe(struct impl *impl, MidiEnumCharacteristicProxy *chr) +{ + GVariantBuilder builder; + GVariant *options; + + /* + * BLE MIDI-1.0 §5: The Central shall read the MIDI I/O characteristic + * of the Peripheral after establishing a connection with the accessory. + */ + + if (chr->read_probed) + return 0; + if (chr->read_call) + return -EBUSY; + + chr->read_probed = true; + + spa_log_debug(impl->log, "MIDI GATT read probe for path=%s", + g_dbus_proxy_get_object_path(G_DBUS_PROXY(chr))); + + chr->read_call = g_cancellable_new(); + + g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); + options = g_variant_builder_end(&builder); + + bluez5_gatt_characteristic1_call_read_value(BLUEZ5_GATT_CHARACTERISTIC1(chr), + options, + chr->read_call, + read_probe_reply, + impl); + + return 0; +} + +Bluez5GattDescriptor1 *find_dsc(struct impl *impl, MidiEnumCharacteristicProxy *chr) +{ + const char *path = g_dbus_proxy_get_object_path(G_DBUS_PROXY(chr)); + Bluez5GattDescriptor1 *found = NULL;; + GList *objects; + + objects = g_dbus_object_manager_get_objects(dbus_monitor_manager(&impl->monitor)); + + for (GList *llo = g_list_first(objects); llo; llo = llo->next) { + GList *interfaces = g_dbus_object_get_interfaces(G_DBUS_OBJECT(llo->data)); + + for (GList *lli = g_list_first(interfaces); lli; lli = lli->next) { + Bluez5GattDescriptor1 *dsc; + + if (!BLUEZ5_IS_GATT_DESCRIPTOR1(lli->data)) + continue; + + dsc = BLUEZ5_GATT_DESCRIPTOR1(lli->data); + + if (!spa_streq(bluez5_gatt_descriptor1_get_uuid(dsc), + BT_GATT_CHARACTERISTIC_USER_DESCRIPTION_UUID)) + continue; + + if (spa_streq(bluez5_gatt_descriptor1_get_characteristic(dsc), path)) { + found = dsc; + break; + } + } + g_list_free_full(interfaces, g_object_unref); + + if (found) + break; + } + g_list_free_full(objects, g_object_unref); + + return found; +} + +static void read_dsc_reply(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + MidiEnumCharacteristicProxy *chr = MIDI_ENUM_CHARACTERISTIC_PROXY(user_data); + struct impl *impl = chr->impl; + gchar *value = NULL; + GError *err = NULL; + + chr->dsc_done = true; + + bluez5_gatt_descriptor1_call_read_value_finish( + BLUEZ5_GATT_DESCRIPTOR1(source_object), &value, res, &err); + + if (g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + /* Operation canceled: user_data may be invalid by now */ + g_error_free(err); + goto done; + } + if (err) { + spa_log_error(impl->log, "%s.ReadValue() failed: %s", + BLUEZ_GATT_DSC_INTERFACE, + err->message); + g_error_free(err); + goto done; + } + + spa_log_debug(impl->log, "MIDI GATT read probe done for path=%s", + g_dbus_proxy_get_object_path(G_DBUS_PROXY(chr))); + + g_free(chr->description); + chr->description = value; + + spa_log_debug(impl->log, "MIDI GATT user descriptor value: '%s'", + chr->description); + + check_chr_node(impl, chr); + +done: + g_clear_object(&chr->dsc_call); +} + +static int read_dsc(struct impl *impl, MidiEnumCharacteristicProxy *chr) +{ + Bluez5GattDescriptor1 *dsc; + GVariant *options; + GVariantBuilder builder; + + if (chr->dsc_probed) + return 0; + if (chr->dsc_call) + return -EBUSY; + + chr->dsc_probed = true; + + dsc = find_dsc(impl, chr); + if (dsc == NULL) { + chr->dsc_done = true; + return -ENOENT; + } + + spa_log_debug(impl->log, "MIDI GATT user descriptor read, path=%s", + g_dbus_proxy_get_object_path(G_DBUS_PROXY(dsc))); + + chr->dsc_call = g_cancellable_new(); + + g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); + options = g_variant_builder_end(&builder); + + bluez5_gatt_descriptor1_call_read_value(BLUEZ5_GATT_DESCRIPTOR1(dsc), + options, + chr->dsc_call, + read_dsc_reply, + chr); + + return 0; +} + +static int read_probe_reset(struct impl *impl, MidiEnumCharacteristicProxy *chr) +{ + g_cancellable_cancel(chr->read_call); + g_clear_object(&chr->read_call); + + g_cancellable_cancel(chr->dsc_call); + g_clear_object(&chr->dsc_call); + + chr->read_probed = false; + chr->read_done = false; + chr->dsc_probed = false; + chr->dsc_done = false; + return 0; +} + +static void lookup_chr_node(struct impl *impl, MidiEnumCharacteristicProxy *chr, + Bluez5GattService1 **service, Bluez5Device1 **device) +{ + GDBusObject *object; + const char *service_path; + const char *device_path; + + *service = NULL; + *device = NULL; + + service_path = bluez5_gatt_characteristic1_get_service(BLUEZ5_GATT_CHARACTERISTIC1(chr)); + if (!service_path) + return; + + object = g_dbus_object_manager_get_object(dbus_monitor_manager(&impl->monitor), service_path); + if (object) { + GDBusInterface *iface = g_dbus_object_get_interface(object, BLUEZ_GATT_SERVICE_INTERFACE); + *service = BLUEZ5_GATT_SERVICE1(iface); + } + + if (!*service) + return; + + device_path = bluez5_gatt_service1_get_device(*service); + if (!device_path) + return; + + object = g_dbus_object_manager_get_object(dbus_monitor_manager(&impl->monitor), device_path); + if (object) { + GDBusInterface *iface = g_dbus_object_get_interface(object, BLUEZ_DEVICE_INTERFACE); + *device = BLUEZ5_DEVICE1(iface); + } +} + +static void check_chr_node(struct impl *impl, MidiEnumCharacteristicProxy *chr) +{ + Bluez5GattService1 *service; + Bluez5Device1 *device; + bool available; + + lookup_chr_node(impl, chr, &service, &device); + + if (!device || !bluez5_device1_get_connected(device)) { + /* Retry read probe on each connection */ + read_probe_reset(impl, chr); + } + + spa_log_debug(impl->log, + "At %s, connected:%d resolved:%d", + g_dbus_proxy_get_object_path(G_DBUS_PROXY(chr)), + bluez5_device1_get_connected(device), + bluez5_device1_get_services_resolved(device)); + + available = service && device && + bluez5_device1_get_connected(device) && + bluez5_device1_get_services_resolved(device) && + spa_streq(bluez5_gatt_service1_get_uuid(service), BT_MIDI_SERVICE_UUID) && + spa_streq(bluez5_gatt_characteristic1_get_uuid(BLUEZ5_GATT_CHARACTERISTIC1(chr)), + BT_MIDI_CHR_UUID); + + if (available && !chr->read_done) { + read_probe(impl, chr); + available = false; + } + + if (available && !chr->dsc_done) { + read_dsc(impl, chr); + available = chr->dsc_done; + } + + if (chr->node_emitted && !available) { + remove_chr_node(impl, chr); + chr->node_emitted = false; + } else if (!chr->node_emitted && available) { + emit_chr_node(impl, chr, device); + chr->node_emitted = true; + } +} + +static GList *get_all_valid_chr(struct impl *impl) +{ + GList *lst = NULL; + GList *objects; + + if (!dbus_monitor_manager(&impl->monitor)) { + /* Still initializing (or it failed) */ + return NULL; + } + + objects = g_dbus_object_manager_get_objects(dbus_monitor_manager(&impl->monitor)); + for (GList *p = g_list_first(objects); p; p = p->next) { + GList *interfaces = g_dbus_object_get_interfaces(G_DBUS_OBJECT(p->data)); + + for (GList *p2 = g_list_first(interfaces); p2; p2 = p2->next) { + MidiEnumCharacteristicProxy *chr; + + if (!MIDI_ENUM_IS_CHARACTERISTIC_PROXY(p2->data)) + continue; + + chr = MIDI_ENUM_CHARACTERISTIC_PROXY(p2->data); + if (chr->impl == NULL) + continue; + + lst = g_list_append(lst, g_object_ref(chr)); + } + g_list_free_full(interfaces, g_object_unref); + } + g_list_free_full(objects, g_object_unref); + + return lst; +} + +static void check_all_nodes(struct impl *impl) +{ + /* + * Check if the nodes we have emitted are in sync with connected devices. + */ + + GList *chrs = get_all_valid_chr(impl); + + for (GList *p = chrs; p; p = p->next) + check_chr_node(impl, MIDI_ENUM_CHARACTERISTIC_PROXY(p->data)); + + g_list_free_full(chrs, g_object_unref); +} + +static void manager_register_application_reply(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + MidiEnumManagerProxy *manager = MIDI_ENUM_MANAGER_PROXY(source_object); + struct impl *impl = user_data; + GError *err = NULL; + + bluez5_gatt_manager1_call_register_application_finish( + BLUEZ5_GATT_MANAGER1(source_object), res, &err); + + if (g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + /* Operation canceled: user_data may be invalid by now */ + g_error_free(err); + goto done; + } + if (err) { + spa_log_error(impl->log, "%s.RegisterApplication() failed: %s", + BLUEZ_GATT_MANAGER_INTERFACE, + err->message); + g_error_free(err); + goto done; + } + + manager->registered = true; + +done: + g_clear_object(&manager->register_call); +} + +static int manager_register_application(struct impl *impl, MidiEnumManagerProxy *manager) +{ + GVariantBuilder builder; + GVariant *options; + + if (manager->registered) + return 0; + if (manager->register_call) + return -EBUSY; + + spa_log_debug(impl->log, "%s.RegisterApplication(%s) on %s", + BLUEZ_GATT_MANAGER_INTERFACE, + g_dbus_object_manager_get_object_path(G_DBUS_OBJECT_MANAGER(impl->manager)), + g_dbus_proxy_get_object_path(G_DBUS_PROXY(manager))); + + manager->register_call = g_cancellable_new(); + + g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); + options = g_variant_builder_end(&builder); + + bluez5_gatt_manager1_call_register_application(BLUEZ5_GATT_MANAGER1(manager), + g_dbus_object_manager_get_object_path(G_DBUS_OBJECT_MANAGER(impl->manager)), + options, + manager->register_call, + manager_register_application_reply, + impl); + + return 0; +} + +/* + * DBus monitoring (Glib) + */ + +static void midi_enum_characteristic_proxy_init(MidiEnumCharacteristicProxy *chr) +{ +} + +static void midi_enum_characteristic_proxy_finalize(GObject *object) +{ + MidiEnumCharacteristicProxy *chr = MIDI_ENUM_CHARACTERISTIC_PROXY(object); + + g_cancellable_cancel(chr->read_call); + g_clear_object(&chr->read_call); + + g_cancellable_cancel(chr->dsc_call); + g_clear_object(&chr->dsc_call); + + if (chr->impl && chr->node_emitted) + remove_chr_node(chr->impl, chr); + + chr->impl = NULL; + + g_free(chr->description); + chr->description = NULL; +} + +static void midi_enum_characteristic_proxy_class_init(MidiEnumCharacteristicProxyClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + + object_class->finalize = midi_enum_characteristic_proxy_finalize; +} + +static void midi_enum_manager_proxy_init(MidiEnumManagerProxy *manager) +{ +} + +static void midi_enum_manager_proxy_finalize(GObject *object) +{ + MidiEnumManagerProxy *manager = MIDI_ENUM_MANAGER_PROXY(object); + + g_cancellable_cancel(manager->register_call); + g_clear_object(&manager->register_call); +} + +static void midi_enum_manager_proxy_class_init(MidiEnumManagerProxyClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + + object_class->finalize = midi_enum_manager_proxy_finalize; +} + +static void manager_update(struct dbus_monitor *monitor, GDBusInterface *iface) +{ + struct impl *impl = SPA_CONTAINER_OF(monitor, struct impl, monitor); + + manager_register_application(impl, MIDI_ENUM_MANAGER_PROXY(iface)); +} + +static void manager_clear(struct dbus_monitor *monitor, GDBusInterface *iface) +{ + midi_enum_manager_proxy_finalize(G_OBJECT(iface)); +} + +static void device_update(struct dbus_monitor *monitor, GDBusInterface *iface) +{ + struct impl *impl = SPA_CONTAINER_OF(monitor, struct impl, monitor); + + check_all_nodes(impl); +} + +static void service_update(struct dbus_monitor *monitor, GDBusInterface *iface) +{ + struct impl *impl = SPA_CONTAINER_OF(monitor, struct impl, monitor); + Bluez5GattService1 *service = BLUEZ5_GATT_SERVICE1(iface); + + if (!spa_streq(bluez5_gatt_service1_get_uuid(service), BT_MIDI_SERVICE_UUID)) + return; + + check_all_nodes(impl); +} + +static void chr_update(struct dbus_monitor *monitor, GDBusInterface *iface) +{ + struct impl *impl = SPA_CONTAINER_OF(monitor, struct impl, monitor); + MidiEnumCharacteristicProxy *chr = MIDI_ENUM_CHARACTERISTIC_PROXY(iface); + + if (!spa_streq(bluez5_gatt_characteristic1_get_uuid(BLUEZ5_GATT_CHARACTERISTIC1(chr)), + BT_MIDI_CHR_UUID)) + return; + + if (chr->impl == NULL) { + chr->impl = impl; + chr->id = ++impl->id; + } + + check_chr_node(impl, chr); +} + +static void chr_clear(struct dbus_monitor *monitor, GDBusInterface *iface) +{ + midi_enum_characteristic_proxy_finalize(G_OBJECT(iface)); +} + +static void monitor_start(struct impl *impl) +{ + struct dbus_monitor_proxy_type proxy_types = { + { BLUEZ_DEVICE_INTERFACE, BLUEZ5_TYPE_DEVICE1_PROXY, device_update, NULL }, + { BLUEZ_GATT_MANAGER_INTERFACE, MIDI_ENUM_TYPE_MANAGER_PROXY, manager_update, manager_clear }, + { BLUEZ_GATT_SERVICE_INTERFACE, BLUEZ5_TYPE_GATT_SERVICE1_PROXY, service_update, NULL }, + { BLUEZ_GATT_CHR_INTERFACE, MIDI_ENUM_TYPE_CHARACTERISTIC_PROXY, chr_update, chr_clear }, + { BLUEZ_GATT_DSC_INTERFACE, BLUEZ5_TYPE_GATT_DESCRIPTOR1_PROXY, NULL, NULL }, + { NULL, BLUEZ5_TYPE_OBJECT_PROXY, NULL, NULL }, + { NULL, G_TYPE_INVALID, NULL, NULL } + }; + + SPA_STATIC_ASSERT(SPA_N_ELEMENTS(proxy_types) <= DBUS_MONITOR_MAX_TYPES); + + dbus_monitor_init(&impl->monitor, BLUEZ5_TYPE_OBJECT_MANAGER_CLIENT, + impl->log, impl->conn, BLUEZ_SERVICE, "/", proxy_types, NULL); +} + +/* + * DBus GATT profile, to enable BlueZ autoconnect + */ + +static gboolean profile_handle_release(Bluez5GattProfile1 *iface, GDBusMethodInvocation *invocation) +{ + bluez5_gatt_profile1_complete_release(iface, invocation); + return TRUE; +} + +static int export_profile(struct impl *impl) +{ + static const char *uuids = { BT_MIDI_SERVICE_UUID, NULL }; + GDBusObjectSkeleton *skeleton = NULL; + Bluez5GattProfile1 *iface = NULL; + int res = -ENOMEM; + + iface = bluez5_gatt_profile1_skeleton_new(); + if (!iface) + goto done; + + skeleton = g_dbus_object_skeleton_new(MIDI_PROFILE_PATH); + if (!skeleton) + goto done; + g_dbus_object_skeleton_add_interface(skeleton, G_DBUS_INTERFACE_SKELETON(iface)); + + bluez5_gatt_profile1_set_uuids(iface, uuids); + g_signal_connect(iface, "handle-release", G_CALLBACK(profile_handle_release), NULL); + + g_dbus_object_manager_server_export(impl->manager, skeleton); + + spa_log_debug(impl->log, "MIDI GATT Profile exported, path=%s", + g_dbus_object_get_object_path(G_DBUS_OBJECT(skeleton))); + + res = 0; + +done: + g_clear_object(&iface); + g_clear_object(&skeleton); + return res; +} + +/* + * Monitor impl + */ + +static int impl_device_add_listener(void *object, struct spa_hook *listener, + const struct spa_device_events *events, void *data) +{ + struct impl *this = object; + struct spa_hook_list save; + GList *chrs; + + spa_return_val_if_fail(this != NULL, -EINVAL); + spa_return_val_if_fail(events != NULL, -EINVAL); + + chrs = get_all_valid_chr(this); + + spa_hook_list_isolate(&this->hooks, &save, listener, events, data); + + for (GList *p = g_list_first(chrs); p; p = p->next) { + MidiEnumCharacteristicProxy *chr = MIDI_ENUM_CHARACTERISTIC_PROXY(p->data); + Bluez5Device1 *device; + Bluez5GattService1 *service; + + if (!chr->node_emitted) + continue; + + lookup_chr_node(this, chr, &service, &device); + if (device) + emit_chr_node(this, chr, device); + } + g_list_free_full(chrs, g_object_unref); + + spa_hook_list_join(&this->hooks, &save); + + return 0; +} + +static const struct spa_device_methods impl_device = { + SPA_VERSION_DEVICE_METHODS, + .add_listener = impl_device_add_listener, +}; + +static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) +{ + struct impl *this; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + spa_return_val_if_fail(interface != NULL, -EINVAL); + + this = (struct impl *) handle; + + if (spa_streq(type, SPA_TYPE_INTERFACE_Device)) + *interface = &this->device; + else + return -ENOENT; + + return 0; +} + +static int impl_clear(struct spa_handle *handle) +{ + struct impl *this; + + this = (struct impl *) handle; + + dbus_monitor_clear(&this->monitor); + g_clear_object(&this->manager); + g_clear_object(&this->conn); + + spa_zero(*this); + + return 0; +} + +static size_t +impl_get_size(const struct spa_handle_factory *factory, + const struct spa_dict *params) +{ + return sizeof(struct impl); +} + +static int +impl_init(const struct spa_handle_factory *factory, + struct spa_handle *handle, + const struct spa_dict *info, + const struct spa_support *support, + uint32_t n_support) +{ + struct impl *this; + GError *error = NULL; + int res = 0; + + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(handle != NULL, -EINVAL); + + handle->get_interface = impl_get_interface; + handle->clear = impl_clear; + + this = (struct impl *) handle; + + this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + + if (this->log == NULL) + return -EINVAL; + + spa_log_topic_init(this->log, &log_topic); + + if (!(info && spa_atob(spa_dict_lookup(info, SPA_KEY_API_GLIB_MAINLOOP)))) { + spa_log_error(this->log, "Glib mainloop is not usable: %s not set", + SPA_KEY_API_GLIB_MAINLOOP); + return -EINVAL; + } + + spa_hook_list_init(&this->hooks); + + this->device.iface = SPA_INTERFACE_INIT( + SPA_TYPE_INTERFACE_Device, + SPA_VERSION_DEVICE, + &impl_device, this); + + this->conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (!this->conn) { + spa_log_error(this->log, "Creating GDBus connection failed: %s", + error->message); + g_error_free(error); + goto fail; + } + + this->manager = g_dbus_object_manager_server_new(MIDI_OBJECT_PATH); + if (!this->manager){ + spa_log_error(this->log, "Creating GDBus object manager failed"); + goto fail; + } + + if ((res = export_profile(this)) < 0) + goto fail; + + g_dbus_object_manager_server_set_connection(this->manager, this->conn); + + monitor_start(this); + + return 0; + +fail: + res = (res < 0) ? res : ((errno > 0) ? -errno : -EIO); + impl_clear(handle); + return res; +} + +static const struct spa_interface_info impl_interfaces = { + {SPA_TYPE_INTERFACE_Device,}, +}; + +static int +impl_enum_interface_info(const struct spa_handle_factory *factory, + const struct spa_interface_info **info, + uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(info != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + if (*index >= SPA_N_ELEMENTS(impl_interfaces)) + return 0; + + *info = &impl_interfaces(*index)++; + + return 1; +} + +static const struct spa_dict_item info_items = { + { SPA_KEY_FACTORY_AUTHOR, "Pauli Virtanen <pav@iki.fi>" }, + { SPA_KEY_FACTORY_DESCRIPTION, "Bluez5 MIDI connection" }, +}; + +static const struct spa_dict info = SPA_DICT_INIT_ARRAY(info_items); + +const struct spa_handle_factory spa_bluez5_midi_enum_factory = { + SPA_VERSION_HANDLE_FACTORY, + SPA_NAME_API_BLUEZ5_MIDI_ENUM, + &info, + impl_get_size, + impl_init, + impl_enum_interface_info, +};
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/midi-node.c
Added
@@ -0,0 +1,2151 @@ +/* Spa MIDI node + * + * Copyright © 2022 Pauli Virtanen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <unistd.h> +#include <stddef.h> +#include <stdio.h> +#include <time.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <spa/support/plugin.h> +#include <spa/support/loop.h> +#include <spa/support/log.h> +#include <spa/support/system.h> +#include <spa/utils/list.h> +#include <spa/utils/keys.h> +#include <spa/utils/names.h> +#include <spa/utils/string.h> +#include <spa/utils/result.h> +#include <spa/utils/dll.h> +#include <spa/utils/ringbuffer.h> +#include <spa/monitor/device.h> +#include <spa/control/control.h> + +#include <spa/node/node.h> +#include <spa/node/utils.h> +#include <spa/node/io.h> +#include <spa/node/keys.h> +#include <spa/param/param.h> +#include <spa/param/latency-utils.h> +#include <spa/param/audio/format.h> +#include <spa/param/audio/format-utils.h> +#include <spa/pod/filter.h> + +#include <spa/debug/mem.h> +#include <spa/debug/log.h> + +#include "midi.h" + +#include "bluez5-interface-gen.h" + +static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5.midi.node"); +#undef SPA_LOG_TOPIC_DEFAULT +#define SPA_LOG_TOPIC_DEFAULT &log_topic + +#define DEFAULT_CLOCK_NAME "clock.system.monotonic" + +#define DLL_BW 0.05 + +#define DEFAULT_LATENCY_OFFSET (0 * SPA_NSEC_PER_MSEC) + +#define MAX_BUFFERS 32 + +#define MIDI_RINGBUF_SIZE (8192*4) + +enum node_role { + NODE_SERVER, + NODE_CLIENT, +}; + +struct props { + char clock_name64; + char device_name512; + int64_t latency_offset; +}; + +struct midi_event_ringbuffer_entry { + uint64_t time; + unsigned int size; +}; + +struct midi_event_ringbuffer { + struct spa_ringbuffer rbuf; + uint8_t bufMIDI_RINGBUF_SIZE; +}; + +struct buffer { + uint32_t id; + unsigned int outgoing:1; + struct spa_buffer *buf; + struct spa_meta_header *h; + struct spa_list link; +}; + +struct time_sync { + uint64_t prev_recv_time; + uint64_t recv_time; + + uint16_t prev_device_timestamp; + uint16_t device_timestamp; + + uint64_t device_time; + + struct spa_dll dll; +}; + +struct port { + uint32_t id; + enum spa_direction direction; + + struct spa_audio_info current_format; + unsigned int have_format:1; + + uint64_t info_all; + struct spa_port_info info; + struct spa_io_buffers *io; + struct spa_latency_info latency; +#define IDX_EnumFormat 0 +#define IDX_Meta 1 +#define IDX_IO 2 +#define IDX_Format 3 +#define IDX_Buffers 4 +#define IDX_Latency 5 +#define N_PORT_PARAMS 6 + struct spa_param_info paramsN_PORT_PARAMS; + + struct buffer buffersMAX_BUFFERS; + uint32_t n_buffers; + + struct spa_list free; + struct spa_list ready; + + int fd; + uint16_t mtu; + + struct buffer *buffer; + struct spa_pod_builder builder; + struct spa_pod_frame frame; + + struct time_sync sync; + + unsigned int acquired:1; + GCancellable *acquire_call; + + struct spa_source source; + + struct impl *impl; +}; + +struct impl { + struct spa_handle handle; + struct spa_node node; + + struct spa_log *log; + struct spa_loop *main_loop; + struct spa_loop *data_loop; + struct spa_system *data_system; + + GDBusConnection *conn; + Bluez5GattCharacteristic1 *proxy; + + struct spa_hook_list hooks; + struct spa_callbacks callbacks; + + uint64_t info_all; + struct spa_node_info info; +#define IDX_PropInfo 0 +#define IDX_Props 1 +#define IDX_NODE_IO 2 +#define N_NODE_PARAMS 3 + struct spa_param_info paramsN_NODE_PARAMS; + struct props props; + +#define PORT_IN 0 +#define PORT_OUT 1 +#define N_PORTS 2 + struct port portsN_PORTS; + + char *chr_path; + + unsigned int started:1; + unsigned int following:1; + + struct spa_source timer_source; + + int timerfd; + + struct spa_io_clock *clock; + struct spa_io_position *position; + + uint32_t duration; + uint32_t rate; + + uint64_t current_time; + uint64_t next_time; + + struct midi_event_ringbuffer event_rbuf; + + struct spa_bt_midi_parser parser; + struct spa_bt_midi_parser tmp_parser; + uint8_t read_bufferMIDI_MAX_MTU; + + struct spa_bt_midi_writer writer; + + enum node_role role; + + struct spa_bt_midi_server *server; +}; + +#define CHECK_PORT(this,d,p) ((p) == 0 && ((d) == SPA_DIRECTION_INPUT || (d) == SPA_DIRECTION_OUTPUT)) +#define GET_PORT(this,d,p) (&(this)->ports(d) == SPA_DIRECTION_OUTPUT ? PORT_OUT : PORT_IN) + +static void midi_event_ringbuffer_init(struct midi_event_ringbuffer *mbuf) +{ + spa_ringbuffer_init(&mbuf->rbuf); +} + +static int midi_event_ringbuffer_push(struct midi_event_ringbuffer *mbuf, + uint64_t time, uint8_t *event, unsigned int size) +{ + const unsigned int bufsize = sizeof(mbuf->buf); + int32_t avail; + uint32_t index; + struct midi_event_ringbuffer_entry evt = { + .time = time, + .size = size + }; + + avail = spa_ringbuffer_get_write_index(&mbuf->rbuf, &index); + if (avail < 0 || avail + sizeof(evt) + size > bufsize) + return -ENOSPC; + + spa_ringbuffer_write_data(&mbuf->rbuf, mbuf->buf, bufsize, index % bufsize, + &evt, sizeof(evt)); + index += sizeof(evt); + spa_ringbuffer_write_update(&mbuf->rbuf, index); + spa_ringbuffer_write_data(&mbuf->rbuf, mbuf->buf, bufsize, index % bufsize, + event, size); + index += size; + spa_ringbuffer_write_update(&mbuf->rbuf, index); + + return 0; +} + +static int midi_event_ringbuffer_peek(struct midi_event_ringbuffer *mbuf, uint64_t *time, unsigned int *size) +{ + const unsigned bufsize = sizeof(mbuf->buf); + int32_t avail; + uint32_t index; + struct midi_event_ringbuffer_entry evt; + + avail = spa_ringbuffer_get_read_index(&mbuf->rbuf, &index); + if (avail < (int)sizeof(evt)) + return -ENOENT; + + spa_ringbuffer_read_data(&mbuf->rbuf, mbuf->buf, bufsize, index % bufsize, + &evt, sizeof(evt)); + + *time = evt.time; + *size = evt.size; + return 0; +} + +static int midi_event_ringbuffer_pop(struct midi_event_ringbuffer *mbuf, uint8_t *data, size_t max_size) +{ + const unsigned bufsize = sizeof(mbuf->buf); + int32_t avail; + uint32_t index; + struct midi_event_ringbuffer_entry evt; + + avail = spa_ringbuffer_get_read_index(&mbuf->rbuf, &index); + if (avail < (int)sizeof(evt)) + return -ENOENT; + + spa_ringbuffer_read_data(&mbuf->rbuf, mbuf->buf, bufsize, index % bufsize, + &evt, sizeof(evt)); + index += sizeof(evt); + avail -= sizeof(evt); + spa_ringbuffer_read_update(&mbuf->rbuf, index); + + if ((uint32_t)avail < evt.size) { + /* corrupted ringbuffer: should never happen */ + spa_assert_not_reached(); + return -EINVAL; + } + + if (evt.size <= max_size) + spa_ringbuffer_read_data(&mbuf->rbuf, mbuf->buf, bufsize, index % bufsize, + data, SPA_MIN(max_size, evt.size)); + index += evt.size; + spa_ringbuffer_read_update(&mbuf->rbuf, index); + + if (evt.size > max_size) + return -ENOSPC; + + return 0; +} + +static void reset_props(struct props *props) +{ + props->latency_offset = DEFAULT_LATENCY_OFFSET; + strncpy(props->clock_name, DEFAULT_CLOCK_NAME, sizeof(props->clock_name)); + props->device_name0 = '\0'; +} + +static bool is_following(struct impl *this) +{ + return this->position && this->clock && this->position->clock.id != this->clock->id; +} + +static int set_timeout(struct impl *this, uint64_t time) +{ + struct itimerspec ts; + ts.it_value.tv_sec = time / SPA_NSEC_PER_SEC; + ts.it_value.tv_nsec = time % SPA_NSEC_PER_SEC; + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + return spa_system_timerfd_settime(this->data_system, + this->timerfd, SPA_FD_TIMER_ABSTIME, &ts, NULL); +} + +static int set_timers(struct impl *this) +{ + struct timespec now; + + spa_system_clock_gettime(this->data_system, CLOCK_MONOTONIC, &now); + this->next_time = SPA_TIMESPEC_TO_NSEC(&now); + + return set_timeout(this, this->following ? 0 : this->next_time); +} + +static void recycle_buffer(struct impl *this, struct port *port, uint32_t buffer_id) +{ + struct buffer *b = &port->buffersbuffer_id; + + if (b->outgoing) { + spa_log_trace(this->log, "%p: recycle buffer %u", this, buffer_id); + spa_list_append(&port->free, &b->link); + b->outgoing = false; + } +} + +static int clear_buffers(struct impl *this, struct port *port) +{ + if (port->n_buffers > 0) { + spa_list_init(&port->free); + spa_list_init(&port->ready); + port->n_buffers = 0; + } + return 0; +} + +static void reset_buffers(struct port *port) +{ + uint32_t i; + + spa_list_init(&port->free); + spa_list_init(&port->ready); + + for (i = 0; i < port->n_buffers; i++) { + struct buffer *b = &port->buffersi; + + if (port->direction == SPA_DIRECTION_OUTPUT) { + spa_list_append(&port->free, &b->link); + b->outgoing = false; + } else { + b->outgoing = true; + } + } +} + +static struct buffer *peek_buffer(struct impl *this, struct port *port) +{ + if (spa_list_is_empty(&port->free)) + return NULL; + return spa_list_first(&port->free, struct buffer, link); +} + +static int prepare_buffer(struct impl *this, struct port *port) +{ + if (port->buffer != NULL) + return 0; + if ((port->buffer = peek_buffer(this, port)) == NULL) + return -EPIPE; + + spa_pod_builder_init(&port->builder, + port->buffer->buf->datas0.data, + port->buffer->buf->datas0.maxsize); + spa_pod_builder_push_sequence(&port->builder, &port->frame, 0); + + return 0; +} + +static int finish_buffer(struct impl *this, struct port *port) +{ + if (port->buffer == NULL) + return 0; + + spa_pod_builder_pop(&port->builder, &port->frame); + + port->buffer->buf->datas0.chunk->offset = 0; + port->buffer->buf->datas0.chunk->size = port->builder.state.offset; + + /* move buffer to ready queue */ + spa_list_remove(&port->buffer->link); + spa_list_append(&port->ready, &port->buffer->link); + port->buffer = NULL; + + return 0; +} + +/* Replace value -> value + n*period, to minimize |value - target| */ +static int64_t unwrap_to_closest(int64_t value, int64_t target, int64_t period) +{ + if (value > target) + value -= SPA_ROUND_DOWN(value - target + period/2, period); + if (value < target) + value += SPA_ROUND_DOWN(target - value + period/2, period); + return value; +} + +static int64_t time_diff(uint64_t a, uint64_t b) +{ + if (a >= b) + return a - b; + else + return -(int64_t)(b - a); +} + +static void midi_event_get_last_timestamp(void *user_data, uint16_t timestamp, uint8_t *data, size_t size) +{ + int *last_timestamp = user_data; + *last_timestamp = timestamp; +} + +static uint64_t midi_convert_time(struct time_sync *sync, uint16_t timestamp) +{ + int offset; + + /* + * sync->device_timestamp is a device timestamp that corresponds to system + * clock time sync->device_time. + * + * It is the timestamp of the last MIDI event in the current packet, so we can + * assume here no event here has timestamp after it. + */ + if (timestamp > sync->device_timestamp) + offset = sync->device_timestamp + MIDI_CLOCK_PERIOD_MSEC - timestamp; + else + offset = sync->device_timestamp - timestamp; + + return sync->device_time - offset * SPA_NSEC_PER_MSEC; +} + +static void midi_event_recv(void *user_data, uint16_t timestamp, uint8_t *data, size_t size) +{ + struct impl *this = user_data; + struct port *port = &this->portsPORT_OUT; + struct time_sync *sync = &port->sync; + uint64_t time; + int res; + + spa_assert(size > 0); + + time = midi_convert_time(sync, timestamp); + + spa_log_trace(this->log, "%p: event:0x%x size:%d timestamp:%d time:%"PRIu64"", + this, (int)data0, (int)size, (int)timestamp, (uint64_t)time); + + res = midi_event_ringbuffer_push(&this->event_rbuf, time, data, size); + if (res < 0) { + midi_event_ringbuffer_init(&this->event_rbuf); + spa_log_warn(this->log, "%p: MIDI receive buffer overflow: %s", + this, spa_strerror(res)); + } +} + +static int unacquire_port(struct port *port) +{ + struct impl *this = port->impl; + + if (!port->acquired) + return 0; + + spa_log_debug(this->log, "%p: unacquire port:%d", this, port->direction); + + shutdown(port->fd, SHUT_RDWR); + close(port->fd); + port->fd = -1; + port->acquired = false; + + if (this->server) + spa_bt_midi_server_released(this->server, + (port->direction == SPA_DIRECTION_OUTPUT)); + + return 0; +} + +static int do_unacquire_port(struct spa_loop *loop, bool async, uint32_t seq, + const void *data, size_t size, void *user_data) +{ + struct port *port = user_data; + + /* in main thread */ + unacquire_port(port); + return 0; +} + +static void on_ready_read(struct spa_source *source) +{ + struct port *port = source->data; + struct impl *this = port->impl; + struct timespec now; + int res, size, last_timestamp; + + if (SPA_FLAG_IS_SET(source->rmask, SPA_IO_ERR) || + SPA_FLAG_IS_SET(source->rmask, SPA_IO_HUP)) { + spa_log_debug(this->log, "%p: port:%d ERR/HUP", this, port->direction); + goto stop; + } + + spa_system_clock_gettime(this->data_system, CLOCK_MONOTONIC, &now); + + /* read data from socket */ +again: + size = recv(port->fd, this->read_buffer, sizeof(this->read_buffer), MSG_DONTWAIT | MSG_NOSIGNAL); + if (size == 0) { + return; + } else if (size < 0) { + if (errno == EINTR) + goto again; + if (errno == EAGAIN || errno == EWOULDBLOCK) + return; + goto stop; + } + + spa_log_trace(this->log, "%p: port:%d recv data size:%d", this, port->direction, size); + spa_debug_log_mem(this->log, SPA_LOG_LEVEL_TRACE, 4, this->read_buffer, size); + + if (port->direction != SPA_DIRECTION_OUTPUT) { + /* Just monitor errors for the input port */ + spa_log_debug(this->log, "%p: port:%d is not RX port; ignoring data", + this, port->direction); + return; + } + + /* prepare for producing events */ + if (port->io == NULL || port->n_buffers == 0 || !this->started) + return; + + /* + * Remote clock synchronization: + * + * Assume: Last timestamp in packet on average corresponds to packet send time. + * There is some unknown latency in between, but on average it is constant. + * + * The `device_time` computed below is the estimated wall-clock time + * corresponding to the timestamp `device_timestamp` of the last event + * in the packet. This timestamp is late by the average transmission latency, + * which is unknown. + * + * Packet reception jitter and any clock drift is smoothed over with DLL. + * The estimated timestamps are stable and preserve event intervals. + * + * To allow latency_offset to work better, we don't write the events + * to the output buffer here, but instead put them to a ringbuffer. + * This is because if the offset shifts events to later buffers, + * this is simpler to handle with the rbuf. + */ + last_timestamp = -1; + spa_bt_midi_parser_dup(&this->parser, &this->tmp_parser, true); + res = spa_bt_midi_parser_parse(&this->tmp_parser, this->read_buffer, size, true, + midi_event_get_last_timestamp, &last_timestamp); + if (res >= 0 && last_timestamp >= 0) { + struct time_sync *sync = &port->sync; + int64_t clock_elapsed; + int64_t device_elapsed; + int64_t err_nsec; + double corr, tcorr; + + sync->prev_recv_time = sync->recv_time; + sync->recv_time = SPA_TIMESPEC_TO_NSEC(&now); + + sync->prev_device_timestamp = sync->device_timestamp; + sync->device_timestamp = last_timestamp; + + if (port->sync.prev_recv_time == 0) { + sync->prev_recv_time = sync->recv_time; + sync->prev_device_timestamp = sync->device_timestamp; + spa_dll_init(&sync->dll); + } + if (SPA_UNLIKELY(sync->dll.bw == 0)) + spa_dll_set_bw(&sync->dll, DLL_BW, 1024, 48000); + + /* move device clock forward */ + clock_elapsed = sync->recv_time - sync->prev_recv_time; + + device_elapsed = (int)sync->device_timestamp - (int)sync->prev_device_timestamp; + device_elapsed *= SPA_NSEC_PER_MSEC; + device_elapsed = unwrap_to_closest(device_elapsed, clock_elapsed, MIDI_CLOCK_PERIOD_NSEC); + sync->device_time += device_elapsed; + + /* smooth clock sync */ + err_nsec = time_diff(sync->recv_time, sync->device_time); + corr = spa_dll_update(&sync->dll, + -SPA_CLAMP(err_nsec, -20*SPA_NSEC_PER_MSEC, 20*SPA_NSEC_PER_MSEC) + * this->rate / SPA_NSEC_PER_SEC); + tcorr = SPA_MIN(device_elapsed, SPA_NSEC_PER_SEC) * (corr - 1); + sync->device_time += tcorr; + + /* reset if too much off */ + if (err_nsec < -50 * SPA_NSEC_PER_MSEC || + err_nsec > 200 * SPA_NSEC_PER_MSEC || + SPA_ABS(tcorr) > 20*SPA_NSEC_PER_MSEC || + device_elapsed < 0) { + spa_log_debug(this->log, "%p: device clock sync off too much: resync", this); + spa_dll_init(&sync->dll); + sync->device_time = sync->recv_time; + } + + spa_log_debug(this->log, + "timestamp:%d dt:%d dt2:%d err:%.1f tcorr:%.2f (ms) corr:%f", + (int)sync->device_timestamp, + (int)(clock_elapsed/SPA_NSEC_PER_MSEC), + (int)(device_elapsed/SPA_NSEC_PER_MSEC), + (double)err_nsec / SPA_NSEC_PER_MSEC, + tcorr/SPA_NSEC_PER_MSEC, + corr); + } + + /* put midi event data to the buffer */ + res = spa_bt_midi_parser_parse(&this->parser, this->read_buffer, size, false, + midi_event_recv, this); + if (res < 0) { + /* bad data */ + spa_bt_midi_parser_init(&this->parser); + + spa_log_info(this->log, "BLE MIDI data packet parsing failed: %d", res); + spa_debug_log_mem(this->log, SPA_LOG_LEVEL_DEBUG, 4, this->read_buffer, size); + } + + return; + +stop: + spa_log_debug(this->log, "%p: port:%d stopping port", this, port->direction); + + if (port->source.loop) + spa_loop_remove_source(this->data_loop, &port->source); + + /* port->acquired is updated only from the main thread */ + spa_loop_invoke(this->main_loop, do_unacquire_port, 0, NULL, 0, false, port); +} + +static int process_output(struct impl *this) +{ + struct port *port = &this->portsPORT_OUT; + struct buffer *buffer; + struct spa_io_buffers *io = port->io; + + /* Check if we are able to process */ + if (io == NULL || !port->acquired) + return SPA_STATUS_OK; + + /* Return if we already have a buffer */ + if (io->status == SPA_STATUS_HAVE_DATA) + return SPA_STATUS_HAVE_DATA; + + /* Recycle */ + if (io->buffer_id < port->n_buffers) { + recycle_buffer(this, port, io->buffer_id); + io->buffer_id = SPA_ID_INVALID; + } + + /* Produce buffer */ + if (prepare_buffer(this, port) >= 0) { + /* + * this->current_time is at the end time of the buffer, and offsets + * are recorded vs. the start of the buffer. + */ + const uint64_t start_time = this->current_time + - this->duration * SPA_NSEC_PER_SEC / this->rate; + const uint64_t end_time = this->current_time; + uint64_t time; + uint32_t offset; + void *buf; + unsigned int size; + int res; + + while (true) { + res = midi_event_ringbuffer_peek(&this->event_rbuf, &time, &size); + if (res < 0) + break; + + time -= this->props.latency_offset; + + if (time > end_time) { + break; + } else if (time + SPA_NSEC_PER_MSEC < start_time) { + /* Log events in the past by more than 1 ms, but don't + * do anything about them. The user can change the latency + * offset to choose whether to tradeoff latency for more + * accurate timestamps. + * + * TODO: maybe this information should be available in + * a more visible place, some latency property? + */ + spa_log_debug(this->log, "%p: event in the past by %d ms", + this, (int)((start_time - time) / SPA_NSEC_PER_MSEC)); + } + + time = SPA_MAX(time, start_time) - start_time; + offset = time * this->rate / SPA_NSEC_PER_SEC; + offset = SPA_CLAMP(offset, 0u, this->duration - 1); + + spa_pod_builder_control(&port->builder, offset, SPA_CONTROL_Midi); + buf = spa_pod_builder_reserve_bytes(&port->builder, size); + if (buf) { + midi_event_ringbuffer_pop(&this->event_rbuf, buf, size); + + spa_log_trace(this->log, "%p: produce event:0x%x offset:%d time:%"PRIu64"", + this, (int)*(uint8_t*)buf, (int)offset, + (uint64_t)(start_time + offset * SPA_NSEC_PER_SEC / this->rate)); + } + } + + finish_buffer(this, port); + } + + /* Return if there are no buffers ready to be processed */ + if (spa_list_is_empty(&port->ready)) + return SPA_STATUS_OK; + + /* Get the new buffer from the ready list */ + buffer = spa_list_first(&port->ready, struct buffer, link); + spa_list_remove(&buffer->link); + buffer->outgoing = true; + + /* Set the new buffer in IO */ + io->buffer_id = buffer->id; + io->status = SPA_STATUS_HAVE_DATA; + + /* Notify we have a buffer ready to be processed */ + return SPA_STATUS_HAVE_DATA; +} + +static int flush_packet(struct impl *this) +{ + struct port *port = &this->portsPORT_IN; + int res; + + if (this->writer.size == 0) + return 0; + + res = send(port->fd, this->writer.buf, this->writer.size, + MSG_DONTWAIT | MSG_NOSIGNAL); + if (res < 0) + return -errno; + + spa_log_trace(this->log, "%p: send packet size:%d", this, this->writer.size); + spa_debug_log_mem(this->log, SPA_LOG_LEVEL_TRACE, 4, this->writer.buf, this->writer.size); + + return 0; +} + +static int write_data(struct impl *this, struct spa_data *d) +{ + struct port *port = &this->portsPORT_IN; + struct spa_pod_sequence *pod; + struct spa_pod_control *c; + uint64_t time; + int res; + + pod = spa_pod_from_data(d->data, d->maxsize, d->chunk->offset, d->chunk->size); + if (pod == NULL) { + spa_log_warn(this->log, "%p: invalid sequence in buffer max:%u offset:%u size:%u", + this, d->maxsize, d->chunk->offset, d->chunk->size); + return -EINVAL; + } + + spa_bt_midi_writer_init(&this->writer, port->mtu); + time = 0; + + SPA_POD_SEQUENCE_FOREACH(pod, c) { + uint8_t *event; + size_t size; + + if (c->type != SPA_CONTROL_Midi) + continue; + + time = SPA_MAX(time, this->current_time + c->offset * SPA_NSEC_PER_SEC / this->rate); + event = SPA_POD_BODY(&c->value); + size = SPA_POD_BODY_SIZE(&c->value); + + spa_log_trace(this->log, "%p: output event:0x%x time:%"PRIu64, this, + (size > 0) ? event0 : 0, time); + + do { + res = spa_bt_midi_writer_write(&this->writer, + time, event, size); + if (res < 0) { + return res; + } else if (res) { + int res2; + if ((res2 = flush_packet(this)) < 0) + return res2; + } + } while (res); + } + + if ((res = flush_packet(this)) < 0) + return res; + + return 0; +} + +static int process_input(struct impl *this) +{ + struct port *port = &this->portsPORT_IN; + struct buffer *b; + struct spa_io_buffers *io = port->io; + int res; + + /* Check if we are able to process */ + if (io == NULL || !port->acquired) + return SPA_STATUS_OK; + + if (io->status != SPA_STATUS_HAVE_DATA || io->buffer_id >= port->n_buffers) + return SPA_STATUS_OK; + + b = &port->buffersio->buffer_id; + if (!b->outgoing) { + spa_log_warn(this->log, "%p: buffer %u not outgoing", this, io->buffer_id); + io->status = -EINVAL; + return -EINVAL; + } + + if ((res = write_data(this, &b->buf->datas0)) < 0) { + spa_log_info(this->log, "%p: writing data failed: %s", + this, spa_strerror(res)); + } + + port->io->buffer_id = b->id; + io->status = SPA_STATUS_NEED_DATA; + spa_node_call_reuse_buffer(&this->callbacks, 0, io->buffer_id); + + return SPA_STATUS_HAVE_DATA; +} + +static void update_position(struct impl *this) +{ + if (SPA_LIKELY(this->position)) { + this->duration = this->position->clock.duration; + this->rate = this->position->clock.rate.denom; + } else { + this->duration = 1024; + this->rate = 48000; + } +} + +static void on_timeout(struct spa_source *source) +{ + struct impl *this = source->data; + uint64_t exp; + uint64_t prev_time, now_time; + int status; + + if (!this->started) + return; + + if (spa_system_timerfd_read(this->data_system, this->timerfd, &exp) < 0) + spa_log_warn(this->log, "%p: error reading timerfd: %s", this, strerror(errno)); + + prev_time = this->current_time; + now_time = this->current_time = this->next_time; + + spa_log_trace(this->log, "%p: timer %"PRIu64" %"PRIu64"", this, + now_time, now_time - prev_time); + + update_position(this); + + this->next_time = now_time + this->duration * SPA_NSEC_PER_SEC / this->rate; + + if (SPA_LIKELY(this->clock)) { + this->clock->nsec = now_time; + this->clock->position += this->duration; + this->clock->duration = this->duration; + this->clock->rate_diff = 1.0f; + this->clock->next_nsec = this->next_time; + } + + status = process_output(this); + spa_log_trace(this->log, "%p: status:%d", this, status); + + spa_node_call_ready(&this->callbacks, status | SPA_STATUS_NEED_DATA); + + set_timeout(this, this->next_time); +} + +static int do_start(struct impl *this); + +static int do_release(struct impl *this); + +static int do_stop(struct impl *this); + +static void acquire_reply(GObject *source_object, GAsyncResult *res, gpointer user_data, bool notify) +{ + struct port *port; + struct impl *this; + const char *method; + GError *err = NULL; + GUnixFDList *fd_list = NULL; + GVariant *fd_handle = NULL; + int fd; + guint16 mtu; + + if (notify) { + bluez5_gatt_characteristic1_call_acquire_notify_finish( + BLUEZ5_GATT_CHARACTERISTIC1(source_object), &fd_handle, &mtu, &fd_list, res, &err); + } else { + bluez5_gatt_characteristic1_call_acquire_write_finish( + BLUEZ5_GATT_CHARACTERISTIC1(source_object), &fd_handle, &mtu, &fd_list, res, &err); + } + + if (g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + /* Operation canceled: user_data may be invalid by now. */ + g_error_free(err); + return; + } + + port = user_data; + this = port->impl; + method = notify ? "AcquireNotify" : "AcquireWrite"; + if (err) { + spa_log_error(this->log, "%s.%s() for %s failed: %s", + BLUEZ_GATT_CHR_INTERFACE, method, + this->chr_path, err->message); + goto fail; + } + + fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(fd_handle), &err); + if (fd < 0) { + spa_log_error(this->log, "%s.%s() for %s failed to get fd: %s", + BLUEZ_GATT_CHR_INTERFACE, method, + this->chr_path, err->message); + goto fail; + } + + spa_log_info(this->log, "%p: BLE MIDI %s %s success mtu:%d", + this, this->chr_path, method, mtu); + port->fd = fd; + port->mtu = mtu; + port->acquired = true; + + if (port->direction == SPA_DIRECTION_OUTPUT) { + spa_bt_midi_parser_init(&this->parser); + + /* Start source */ + port->source.data = port; + port->source.fd = port->fd; + port->source.func = on_ready_read; + port->source.mask = SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR; + port->source.rmask = 0; + spa_loop_add_source(this->data_loop, &port->source); + } + return; + +fail: + g_error_free(err); + g_clear_object(&fd_list); + g_clear_object(&fd_handle); + do_stop(this); + do_release(this); +} + +static void acquire_notify_reply(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + acquire_reply(source_object, res, user_data, true); +} + +static void acquire_write_reply(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + acquire_reply(source_object, res, user_data, false); +} + +static int do_acquire(struct port *port) +{ + struct impl *this = port->impl; + const char *method = (port->direction == SPA_DIRECTION_OUTPUT) ? + "AcquireNotify" : "AcquireWrite"; + GVariant *options; + GVariantBuilder builder; + + if (port->acquired) + return 0; + if (port->acquire_call) + return 0; + + spa_log_info(this->log, + "%p: port %d: client %s for BLE MIDI device characteristic %s", + this, port->direction, method, this->chr_path); + + port->acquire_call = g_cancellable_new(); + + g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); + options = g_variant_builder_end(&builder); + + if (port->direction == SPA_DIRECTION_OUTPUT) { + bluez5_gatt_characteristic1_call_acquire_notify( + BLUEZ5_GATT_CHARACTERISTIC1(this->proxy), + options, + NULL, + port->acquire_call, + acquire_notify_reply, + port); + } else { + bluez5_gatt_characteristic1_call_acquire_write( + BLUEZ5_GATT_CHARACTERISTIC1(this->proxy), + options, + NULL, + port->acquire_call, + acquire_write_reply, + port); + } + + return 0; +} + +static int server_do_acquire(struct port *port, int fd, uint16_t mtu) +{ + struct impl *this = port->impl; + const char *method = (port->direction == SPA_DIRECTION_OUTPUT) ? + "AcquireWrite" : "AcquireNotify"; + + spa_log_info(this->log, + "%p: port %d: server %s for BLE MIDI device characteristic %s", + this, port->direction, method, this->server->chr_path); + + if (port->acquired) { + spa_log_info(this->log, + "%p: port %d: %s failed: already acquired", + this, port->direction, method); + return -EBUSY; + } + + port->fd = fd; + port->mtu = mtu; + + if (port->direction == SPA_DIRECTION_OUTPUT) + spa_bt_midi_parser_init(&this->parser); + + /* Start source */ + port->source.data = port; + port->source.fd = port->fd; + port->source.func = on_ready_read; + port->source.mask = SPA_IO_HUP | SPA_IO_ERR; + if (port->direction == SPA_DIRECTION_OUTPUT) + port->source.mask |= SPA_IO_IN; + port->source.rmask = 0; + spa_loop_add_source(this->data_loop, &port->source); + + port->acquired = true; + return 0; +} + +static int server_acquire_write(void *user_data, int fd, uint16_t mtu) +{ + struct impl *this = user_data; + return server_do_acquire(&this->portsPORT_OUT, fd, mtu); +} + +static int server_acquire_notify(void *user_data, int fd, uint16_t mtu) +{ + struct impl *this = user_data; + return server_do_acquire(&this->portsPORT_IN, fd, mtu); +} + +static int server_release(void *user_data) +{ + struct impl *this = user_data; + do_release(this); + return 0; +} + +static const char *server_description(void *user_data) +{ + struct impl *this = user_data; + return this->props.device_name; +} + +static int do_remove_port_source(struct spa_loop *loop, + bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct impl *this = user_data; + int i; + + for (i = 0; i < N_PORTS; ++i) { + struct port *port = &this->portsi; + + if (port->source.loop) + spa_loop_remove_source(this->data_loop, &port->source); + } + + return 0; +} + +static int do_remove_source(struct spa_loop *loop, + bool async, + uint32_t seq, + const void *data, + size_t size, + void *user_data) +{ + struct impl *this = user_data; + struct itimerspec ts; + + if (this->timer_source.loop) + spa_loop_remove_source(this->data_loop, &this->timer_source); + + ts.it_value.tv_sec = 0; + ts.it_value.tv_nsec = 0; + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + spa_system_timerfd_settime(this->data_system, this->timerfd, 0, &ts, NULL); + + return 0; +} + +static int do_stop(struct impl *this) +{ + int res = 0; + + spa_log_debug(this->log, "%p: stop", this); + + spa_loop_invoke(this->data_loop, do_remove_source, 0, NULL, 0, true, this); + + this->started = false; + + return res; +} + +static int do_release(struct impl *this) +{ + int res = 0; + size_t i; + + spa_log_debug(this->log, "%p: release", this); + + spa_loop_invoke(this->data_loop, do_remove_port_source, 0, NULL, 0, true, this); + + for (i = 0; i < N_PORTS; ++i) { + struct port *port = &this->portsi; + + g_cancellable_cancel(port->acquire_call); + g_clear_object(&port->acquire_call); + + unacquire_port(port); + } + + return res; +} + +static int do_start(struct impl *this) +{ + int res; + size_t i; + + if (this->started) + return 0; + + this->following = is_following(this); + + update_position(this); + + spa_log_debug(this->log, "%p: start following:%d", + this, this->following); + + for (i = 0; i < N_PORTS; ++i) { + struct port *port = &this->portsi; + + switch (this->role) { + case NODE_CLIENT: + /* Acquire Bluetooth I/O */ + if ((res = do_acquire(port)) < 0) { + do_stop(this); + do_release(this); + return res; + } + break; + case NODE_SERVER: + /* + * In MIDI server role, the device/BlueZ invokes + * the acquire asynchronously as available/needed. + */ + break; + default: + spa_assert_not_reached(); + } + + reset_buffers(port); + } + + midi_event_ringbuffer_init(&this->event_rbuf); + + this->started = true; + + /* Start timer */ + this->timer_source.data = this; + this->timer_source.fd = this->timerfd; + this->timer_source.func = on_timeout; + this->timer_source.mask = SPA_IO_IN; + this->timer_source.rmask = 0; + spa_loop_add_source(this->data_loop, &this->timer_source); + + set_timers(this); + + return 0; +} + + +static int do_reassign_follower(struct spa_loop *loop, + bool async, + uint32_t seq, + const void *data, + size_t size, + void *user_data) +{ + struct impl *this = user_data; + + set_timers(this); + return 0; +} + +static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size) +{ + struct impl *this = object; + bool following; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + switch (id) { + case SPA_IO_Clock: + this->clock = data; + if (this->clock != NULL) { + spa_scnprintf(this->clock->name, + sizeof(this->clock->name), + "%s", this->props.clock_name); + } + break; + case SPA_IO_Position: + this->position = data; + break; + default: + return -ENOENT; + } + + following = is_following(this); + if (this->started && following != this->following) { + spa_log_debug(this->log, "%p: reassign follower %d->%d", this, this->following, following); + this->following = following; + spa_loop_invoke(this->data_loop, do_reassign_follower, 0, NULL, 0, true, this); + } + + return 0; +} + +static void emit_node_info(struct impl *this, bool full); + +static int impl_node_enum_params(void *object, int seq, + uint32_t id, uint32_t start, uint32_t num, + const struct spa_pod *filter) +{ + struct impl *this = object; + struct spa_pod *param; + struct spa_pod_builder b = { 0 }; + uint8_t buffer1024; + struct spa_result_node_params result; + uint32_t count = 0; + + spa_return_val_if_fail(this != NULL, -EINVAL); + spa_return_val_if_fail(num != 0, -EINVAL); + + result.id = id; + result.next = start; +next: + result.index = result.next++; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + + switch (id) { + case SPA_PARAM_PropInfo: + { + struct props *p = &this->props; + + switch (result.index) { + case 0: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_latencyOffsetNsec), + SPA_PROP_INFO_description, SPA_POD_String("Latency offset (ns)"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, INT64_MIN, INT64_MAX)); + break; + case 1: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_deviceName), + SPA_PROP_INFO_description, SPA_POD_String("Device name"), + SPA_PROP_INFO_type, SPA_POD_String(p->device_name)); + break; + default: + return 0; + } + break; + } + case SPA_PARAM_Props: + { + struct props *p = &this->props; + + switch (result.index) { + case 0: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_Props, id, + SPA_PROP_latencyOffsetNsec, SPA_POD_Long(p->latency_offset), + SPA_PROP_deviceName, SPA_POD_String(p->device_name)); + break; + default: + return 0; + } + break; + } + default: + return -ENOENT; + } + + if (spa_pod_filter(&b, &result.param, param, filter) < 0) + goto next; + + spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result); + + if (++count != num) + goto next; + + return 0; +} + +static void emit_port_info(struct impl *this, struct port *port, bool full); + +static void set_latency(struct impl *this, bool emit_latency) +{ + struct port *port = &this->portsPORT_OUT; + + port->latency.min_ns = port->latency.max_ns = this->props.latency_offset; + + if (emit_latency) { + port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + port->paramsIDX_Latency.flags ^= SPA_PARAM_INFO_SERIAL; + emit_port_info(this, port, false); + } +} + +static int apply_props(struct impl *this, const struct spa_pod *param) +{ + struct props new_props = this->props; + int changed = 0; + + if (param == NULL) { + reset_props(&new_props); + } else { + spa_pod_parse_object(param, + SPA_TYPE_OBJECT_Props, NULL, + SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&new_props.latency_offset), + SPA_PROP_deviceName, SPA_POD_OPT_Stringn(new_props.device_name, + sizeof(new_props.device_name))); + } + + changed = (memcmp(&new_props, &this->props, sizeof(struct props)) != 0); + this->props = new_props; + + if (changed) + set_latency(this, true); + + return changed; +} + +static int impl_node_set_param(void *object, uint32_t id, uint32_t flags, + const struct spa_pod *param) +{ + struct impl *this = object; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + switch (id) { + case SPA_PARAM_Props: + { + if (apply_props(this, param) > 0) { + this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + this->paramsIDX_Props.flags ^= SPA_PARAM_INFO_SERIAL; + emit_node_info(this, false); + } + break; + } + default: + return -ENOENT; + } + + return 0; +} + +static int impl_node_send_command(void *object, const struct spa_command *command) +{ + struct impl *this = object; + int res, res2; + + spa_return_val_if_fail(this != NULL, -EINVAL); + spa_return_val_if_fail(command != NULL, -EINVAL); + + switch (SPA_NODE_COMMAND_ID(command)) { + case SPA_NODE_COMMAND_Start: + if ((res = do_start(this)) < 0) + return res; + break; + case SPA_NODE_COMMAND_Pause: + if ((res = do_stop(this)) < 0) + return res; + break; + case SPA_NODE_COMMAND_Suspend: + res = do_stop(this); + if (this->role == NODE_CLIENT) + res2 = do_release(this); + else + res2 = 0; + if (res < 0) + return res; + if (res2 < 0) + return res2; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static void emit_node_info(struct impl *this, bool full) +{ + const struct spa_dict_item node_info_items = { + { SPA_KEY_DEVICE_API, "bluez5" }, + { SPA_KEY_MEDIA_CLASS, "Midi/Bridge" }, + }; + uint64_t old = full ? this->info.change_mask : 0; + + if (full) + this->info.change_mask = this->info_all; + if (this->info.change_mask) { + this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items); + spa_node_emit_info(&this->hooks, &this->info); + this->info.change_mask = old; + } +} + +static void emit_port_info(struct impl *this, struct port *port, bool full) +{ + uint64_t old = full ? port->info.change_mask : 0; + if (full) + port->info.change_mask = port->info_all; + if (port->info.change_mask) { + spa_node_emit_port_info(&this->hooks, port->direction, port->id, &port->info); + port->info.change_mask = old; + } +} + +static int +impl_node_add_listener(void *object, + struct spa_hook *listener, + const struct spa_node_events *events, + void *data) +{ + struct impl *this = object; + struct spa_hook_list save; + size_t i; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + spa_hook_list_isolate(&this->hooks, &save, listener, events, data); + + emit_node_info(this, true); + + for (i = 0; i < N_PORTS; ++i) + emit_port_info(this, &this->portsi, true); + + spa_hook_list_join(&this->hooks, &save); + + return 0; +} + +static int +impl_node_set_callbacks(void *object, + const struct spa_node_callbacks *callbacks, + void *data) +{ + struct impl *this = object; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + this->callbacks = SPA_CALLBACKS_INIT(callbacks, data); + + return 0; +} + +static int impl_node_sync(void *object, int seq) +{ + struct impl *this = object; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + spa_node_emit_result(&this->hooks, seq, 0, 0, NULL); + + return 0; +} + +static int impl_node_add_port(void *object, enum spa_direction direction, uint32_t port_id, + const struct spa_dict *props) +{ + return -ENOTSUP; +} + +static int impl_node_remove_port(void *object, enum spa_direction direction, uint32_t port_id) +{ + return -ENOTSUP; +} + +static int +impl_node_port_enum_params(void *object, int seq, + enum spa_direction direction, uint32_t port_id, + uint32_t id, uint32_t start, uint32_t num, + const struct spa_pod *filter) +{ + + struct impl *this = object; + struct port *port; + struct spa_pod *param; + struct spa_pod_builder b = { 0 }; + uint8_t buffer1024; + struct spa_result_node_params result; + uint32_t count = 0; + + spa_return_val_if_fail(this != NULL, -EINVAL); + spa_return_val_if_fail(num != 0, -EINVAL); + + spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); + + port = GET_PORT(this, direction, port_id); + + result.id = id; + result.next = start; +next: + result.index = result.next++; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + + switch (id) { + case SPA_PARAM_EnumFormat: + if (result.index > 0) + return 0; + + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control)); + break; + + case SPA_PARAM_Format: + if (!port->have_format) + return -EIO; + if (result.index > 0) + return 0; + + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_Format, SPA_PARAM_Format, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control)); + break; + + case SPA_PARAM_Buffers: + if (!port->have_format) + return -EIO; + if (result.index > 0) + return 0; + + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamBuffers, id, + SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS), + SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1), + SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( + 4096, 4096, INT32_MAX), + SPA_PARAM_BUFFERS_stride, SPA_POD_Int(1)); + break; + + case SPA_PARAM_Meta: + switch (result.index) { + case 0: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamMeta, id, + SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header), + SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header))); + break; + default: + return 0; + } + break; + + case SPA_PARAM_IO: + switch (result.index) { + case 0: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamIO, id, + SPA_PARAM_IO_id, SPA_POD_Id(SPA_IO_Buffers), + SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_buffers))); + break; + default: + return 0; + } + break; + + case SPA_PARAM_Latency: + switch (result.index) { + case 0: + param = spa_latency_build(&b, id, &port->latency); + break; + default: + return 0; + } + break; + + default: + return -ENOENT; + } + + if (spa_pod_filter(&b, &result.param, param, filter) < 0) + goto next; + + spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result); + + if (++count != num) + goto next; + + return 0; +} + +static int port_set_format(struct impl *this, struct port *port, + uint32_t flags, + const struct spa_pod *format) +{ + int err; + + if (format == NULL) { + if (!port->have_format) + return 0; + + clear_buffers(this, port); + port->have_format = false; + } else { + struct spa_audio_info info = { 0 }; + + if ((err = spa_format_parse(format, &info.media_type, &info.media_subtype)) < 0) + return err; + + if (info.media_type != SPA_MEDIA_TYPE_application || + info.media_subtype != SPA_MEDIA_SUBTYPE_control) + return -EINVAL; + + port->current_format = info; + port->have_format = true; + } + + port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE; + port->info.rate = SPA_FRACTION(1, 1); + port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + if (port->have_format) { + port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); + port->paramsIDX_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ); + } else { + port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); + port->paramsIDX_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); + } + emit_port_info(this, port, false); + + return 0; +} + +static int +impl_node_port_set_param(void *object, + enum spa_direction direction, uint32_t port_id, + uint32_t id, uint32_t flags, + const struct spa_pod *param) +{ + struct impl *this = object; + struct port *port; + int res; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); + + port = GET_PORT(this, direction, port_id); + + switch (id) { + case SPA_PARAM_Format: + res = port_set_format(this, port, flags, param); + break; + case SPA_PARAM_Latency: + res = 0; + break; + default: + res = -ENOENT; + break; + } + return res; +} + +static int +impl_node_port_use_buffers(void *object, + enum spa_direction direction, uint32_t port_id, + uint32_t flags, + struct spa_buffer **buffers, uint32_t n_buffers) +{ + struct impl *this = object; + struct port *port; + uint32_t i; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); + + port = GET_PORT(this, direction, port_id); + + spa_log_debug(this->log, "%p: use buffers %d", this, n_buffers); + + if (!port->have_format) + return -EIO; + + clear_buffers(this, port); + + for (i = 0; i < n_buffers; i++) { + struct buffer *b = &port->buffersi; + struct spa_data *d = buffersi->datas; + + b->buf = buffersi; + b->id = i; + + b->h = spa_buffer_find_meta_data(buffersi, SPA_META_Header, sizeof(*b->h)); + + if (d0.data == NULL) { + spa_log_error(this->log, "%p: need mapped memory", this); + return -EINVAL; + } + } + port->n_buffers = n_buffers; + + reset_buffers(port); + + return 0; +} + +static int +impl_node_port_set_io(void *object, + enum spa_direction direction, + uint32_t port_id, + uint32_t id, + void *data, size_t size) +{ + struct impl *this = object; + struct port *port; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); + + port = GET_PORT(this, direction, port_id); + + switch (id) { + case SPA_IO_Buffers: + port->io = data; + break; + default: + return -ENOENT; + } + return 0; +} + +static int impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id) +{ + struct impl *this = object; + struct port *port; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + spa_return_val_if_fail(CHECK_PORT(this, SPA_DIRECTION_OUTPUT, port_id), -EINVAL); + + port = GET_PORT(this, SPA_DIRECTION_OUTPUT, port_id); + + if (port->n_buffers == 0) + return -EIO; + + if (buffer_id >= port->n_buffers) + return -EINVAL; + + recycle_buffer(this, port, buffer_id); + + return 0; +} + +static int impl_node_process(void *object) +{ + struct impl *this = object; + int status = SPA_STATUS_OK; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + if (!this->started) + return SPA_STATUS_OK; + + if (this->following) { + if (this->position) { + this->current_time = this->position->clock.nsec; + } else { + struct timespec now = { 0 }; + spa_system_clock_gettime(this->data_system, CLOCK_MONOTONIC, &now); + this->current_time = SPA_TIMESPEC_TO_NSEC(&now); + } + } + + update_position(this); + + if (this->following) + status |= process_output(this); + + status |= process_input(this); + + return status; +} + +static const struct spa_node_methods impl_node = { + SPA_VERSION_NODE_METHODS, + .add_listener = impl_node_add_listener, + .set_callbacks = impl_node_set_callbacks, + .sync = impl_node_sync, + .enum_params = impl_node_enum_params, + .set_param = impl_node_set_param, + .set_io = impl_node_set_io, + .send_command = impl_node_send_command, + .add_port = impl_node_add_port, + .remove_port = impl_node_remove_port, + .port_enum_params = impl_node_port_enum_params, + .port_set_param = impl_node_port_set_param, + .port_use_buffers = impl_node_port_use_buffers, + .port_set_io = impl_node_port_set_io, + .port_reuse_buffer = impl_node_port_reuse_buffer, + .process = impl_node_process, +}; + +static const struct spa_bt_midi_server_cb impl_server = { + .acquire_write = server_acquire_write, + .acquire_notify = server_acquire_notify, + .release = server_release, + .get_description = server_description, +}; + +static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) +{ + struct impl *this; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + spa_return_val_if_fail(interface != NULL, -EINVAL); + + this = (struct impl *) handle; + + if (spa_streq(type, SPA_TYPE_INTERFACE_Node)) + *interface = &this->node; + else + return -ENOENT; + + return 0; +} + +static int impl_clear(struct spa_handle *handle) +{ + struct impl *this = (struct impl *) handle; + + do_stop(this); + do_release(this); + + free(this->chr_path); + if (this->timerfd > 0) + spa_system_close(this->data_system, this->timerfd); + if (this->server) + spa_bt_midi_server_destroy(this->server); + g_clear_object(&this->proxy); + g_clear_object(&this->conn); + + spa_zero(*this); + + return 0; +} + +static size_t +impl_get_size(const struct spa_handle_factory *factory, + const struct spa_dict *params) +{ + return sizeof(struct impl); +} + +static int +impl_init(const struct spa_handle_factory *factory, + struct spa_handle *handle, + const struct spa_dict *info, + const struct spa_support *support, + uint32_t n_support) +{ + struct impl *this; + const char *device_name = ""; + int res = 0; + GError *err = NULL; + size_t i; + + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(handle != NULL, -EINVAL); + + handle->get_interface = impl_get_interface; + handle->clear = impl_clear; + + this = (struct impl *) handle; + + this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + this->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop); + this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop); + this->data_system = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataSystem); + + if (this->log == NULL) + return -EINVAL; + + spa_log_topic_init(this->log, &log_topic); + + if (!(info && spa_atob(spa_dict_lookup(info, SPA_KEY_API_GLIB_MAINLOOP)))) { + spa_log_error(this->log, "Glib mainloop is not usable: %s not set", + SPA_KEY_API_GLIB_MAINLOOP); + return -EINVAL; + } + + if (this->data_loop == NULL) { + spa_log_error(this->log, "a data loop is needed"); + return -EINVAL; + } + if (this->data_system == NULL) { + spa_log_error(this->log, "a data system is needed"); + return -EINVAL; + } + + this->role = NODE_CLIENT; + + if (info) { + const char *str; + + if ((str = spa_dict_lookup(info, SPA_KEY_API_BLUEZ5_PATH)) != NULL) + this->chr_path = strdup(str); + + if ((str = spa_dict_lookup(info, SPA_KEY_API_BLUEZ5_ROLE)) != NULL) { + if (spa_streq(str, "server")) + this->role = NODE_SERVER; + } + + if ((str = spa_dict_lookup(info, "node.nick")) != NULL) + device_name = str; + else if ((str = spa_dict_lookup(info, "node.description")) != NULL) + device_name = str; + } + + if (this->role == NODE_CLIENT && this->chr_path == NULL) { + spa_log_error(this->log, "missing MIDI service characteristic path"); + res = -EINVAL; + goto fail; + } + + this->conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (this->conn == NULL) { + spa_log_error(this->log, "failed to get dbus connection: %s", + err->message); + g_error_free(err); + res = -EIO; + goto fail; + } + + this->node.iface = SPA_INTERFACE_INIT( + SPA_TYPE_INTERFACE_Node, + SPA_VERSION_NODE, + &impl_node, this); + spa_hook_list_init(&this->hooks); + + reset_props(&this->props); + + spa_scnprintf(this->props.device_name, sizeof(this->props.device_name), + "%s", device_name); + + /* set the node info */ + this->info_all = SPA_NODE_CHANGE_MASK_FLAGS | + SPA_NODE_CHANGE_MASK_PROPS | + SPA_NODE_CHANGE_MASK_PARAMS; + this->info = SPA_NODE_INFO_INIT(); + this->info.max_input_ports = 1; + this->info.max_output_ports = 1; + this->info.flags = SPA_NODE_FLAG_RT; + this->paramsIDX_PropInfo = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ); + this->paramsIDX_Props = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE); + this->paramsIDX_NODE_IO = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ); + this->info.params = this->params; + this->info.n_params = N_NODE_PARAMS; + + /* set the port info */ + for (i = 0; i < N_PORTS; ++i) { + struct port *port = &this->portsi; + static const struct spa_dict_item in_port_items = { + SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi"), + SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, "in"), + SPA_DICT_ITEM_INIT(SPA_KEY_PORT_ALIAS, "in"), + }; + static const struct spa_dict_item out_port_items = { + SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi"), + SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, "out"), + SPA_DICT_ITEM_INIT(SPA_KEY_PORT_ALIAS, "out"), + }; + static const struct spa_dict in_port_props = SPA_DICT_INIT_ARRAY(in_port_items); + static const struct spa_dict out_port_props = SPA_DICT_INIT_ARRAY(out_port_items); + + spa_zero(*port); + + port->impl = this; + + port->id = 0; + port->direction = (i == PORT_OUT) ? SPA_DIRECTION_OUTPUT : + SPA_DIRECTION_INPUT; + + port->info_all = SPA_PORT_CHANGE_MASK_FLAGS | + SPA_PORT_CHANGE_MASK_PROPS | + SPA_PORT_CHANGE_MASK_PARAMS; + port->info = SPA_PORT_INFO_INIT(); + port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS; + port->info.flags = SPA_PORT_FLAG_LIVE; + port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); + port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ); + port->paramsIDX_IO = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ); + port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); + port->paramsIDX_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); + port->paramsIDX_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE); + port->info.params = port->params; + port->info.n_params = N_PORT_PARAMS; + port->info.props = (i == PORT_OUT) ? &out_port_props : &in_port_props; + + port->latency = SPA_LATENCY_INFO(port->direction); + port->latency.min_quantum = 1.0f; + port->latency.max_quantum = 1.0f; + + /* Init the buffer lists */ + spa_list_init(&port->ready); + spa_list_init(&port->free); + } + + this->duration = 1024; + this->rate = 48000; + + set_latency(this, false); + + if (this->role == NODE_SERVER) { + this->server = spa_bt_midi_server_new(&impl_server, this->conn, this->log, this); + if (this->server == NULL) + goto fail; + } else { + this->proxy = bluez5_gatt_characteristic1_proxy_new_sync(this->conn, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + BLUEZ_SERVICE, + this->chr_path, + NULL, + &err); + if (this->proxy == NULL) { + spa_log_error(this->log, + "Failed to create BLE MIDI GATT proxy %s: %s", + this->chr_path, err->message); + g_error_free(err); + res = -EIO; + goto fail; + } + } + + this->timerfd = spa_system_timerfd_create(this->data_system, + CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK); + + return 0; + +fail: + res = (res < 0) ? res : ((errno > 0) ? -errno : -EIO); + impl_clear(handle); + return res; +} + +static const struct spa_interface_info impl_interfaces = { + {SPA_TYPE_INTERFACE_Node,}, +}; + +static int +impl_enum_interface_info(const struct spa_handle_factory *factory, + const struct spa_interface_info **info, uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(info != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *info = &impl_interfaces*index; + break; + default: + return 0; + } + (*index)++; + return 1; +} + +static const struct spa_dict_item info_items = { + { SPA_KEY_FACTORY_AUTHOR, "Pauli Virtanen <pav@iki.fi>" }, + { SPA_KEY_FACTORY_DESCRIPTION, "Bluez5 MIDI connection" }, +}; + +static const struct spa_dict info = SPA_DICT_INIT_ARRAY(info_items); + +const struct spa_handle_factory spa_bluez5_midi_node_factory = { + SPA_VERSION_HANDLE_FACTORY, + SPA_NAME_API_BLUEZ5_MIDI_NODE, + &info, + impl_get_size, + impl_init, + impl_enum_interface_info, +};
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/midi-parser.c
Added
@@ -0,0 +1,295 @@ +/* BLE MIDI parser + * + * Copyright © 2022 Pauli Virtanen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <errno.h> + +#include <spa/utils/defs.h> + +#include "midi.h" + +enum midi_event_class { + MIDI_BASIC, + MIDI_SYSEX, + MIDI_SYSCOMMON, + MIDI_REALTIME, + MIDI_ERROR +}; + +static enum midi_event_class midi_event_info(uint8_t status, unsigned int *size) +{ + switch (status) { + case 0x80 ... 0x8f: + case 0x90 ... 0x9f: + case 0xa0 ... 0xaf: + case 0xb0 ... 0xbf: + case 0xe0 ... 0xef: + *size = 3; + return MIDI_BASIC; + case 0xc0 ... 0xcf: + case 0xd0 ... 0xdf: + *size = 2; + return MIDI_BASIC; + case 0xf0: + /* variable; count only status byte here */ + *size = 1; + return MIDI_SYSEX; + case 0xf1: + case 0xf3: + *size = 2; + return MIDI_SYSCOMMON; + case 0xf2: + *size = 3; + return MIDI_SYSCOMMON; + case 0xf6: + case 0xf7: + *size = 1; + return MIDI_SYSCOMMON; + case 0xf8 ... 0xff: + *size = 1; + return MIDI_REALTIME; + case 0xf4: + case 0xf5: + default: + /* undefined MIDI status */ + *size = 0; + return MIDI_ERROR; + } +} + +static void timestamp_set_high(uint16_t *time, uint8_t byte) +{ + *time = (byte & 0x3f) << 7; +} + +static void timestamp_set_low(uint16_t *time, uint8_t byte) +{ + if ((*time & 0x7f) > (byte & 0x7f)) + *time += 0x80; + + *time &= ~0x7f; + *time |= byte & 0x7f; +} + +int spa_bt_midi_parser_parse(struct spa_bt_midi_parser *parser, + const uint8_t *src, size_t src_size, bool only_time, + void (*event)(void *user_data, uint16_t time, uint8_t *event, size_t event_size), + void *user_data) +{ + const uint8_t *src_end = src + src_size; + uint8_t running_status = 0; + uint16_t time; + uint8_t byte; + +#define NEXT() do { if (src == src_end) return -EINVAL; byte = *src++; } while (0) +#define PUT(byte) do { if (only_time) { parser->size++; break; } \ + if (parser->size == sizeof(parser->buf)) return -ENOSPC; \ + parser->bufparser->size++ = (byte); } while (0) + + /* Header */ + NEXT(); + if (!(byte & 0x80)) + return -EINVAL; + timestamp_set_high(&time, byte); + + while (src < src_end) { + NEXT(); + + if (!parser->sysex) { + uint8_t status = 0; + unsigned int event_size; + + if (byte & 0x80) { + /* Timestamp */ + timestamp_set_low(&time, byte); + NEXT(); + + /* Status? */ + if (byte & 0x80) { + parser->size = 0; + PUT(byte); + status = byte; + } + } + + if (status == 0) { + /* Running status */ + parser->size = 0; + PUT(running_status); + PUT(byte); + status = running_status; + } + + switch (midi_event_info(status, &event_size)) { + case MIDI_BASIC: + running_status = (event_size > 1) ? status : 0; + break; + case MIDI_REALTIME: + case MIDI_SYSCOMMON: + /* keep previous running status */ + break; + case MIDI_SYSEX: + parser->sysex = true; + /* XXX: not fully clear if SYSEX can be running status, assume no */ + running_status = 0; + continue; + default: + goto malformed; + } + + /* Event data */ + while (parser->size < event_size) { + NEXT(); + if (byte & 0x80) { + /* BLE MIDI allows no interleaved events */ + goto malformed; + } + PUT(byte); + } + + event(user_data, time, parser->buf, parser->size); + } else { + if (byte & 0x80) { + /* Timestamp */ + timestamp_set_low(&time, byte); + NEXT(); + + if (byte == 0xf7) { + /* Sysex end */ + PUT(byte); + event(user_data, time, parser->buf, parser->size); + parser->sysex = false; + } else { + /* Interleaved realtime event */ + unsigned int event_size; + + if (midi_event_info(byte, &event_size) != MIDI_REALTIME) + goto malformed; + spa_assert(event_size == 1); + event(user_data, time, &byte, 1); + } + } else { + PUT(byte); + } + } + } + +#undef NEXT +#undef PUT + + return 0; + +malformed: + /* Error (potentially recoverable) */ + return -EINVAL; +} + + +int spa_bt_midi_writer_write(struct spa_bt_midi_writer *writer, + uint64_t time, const uint8_t *event, size_t event_size) +{ + /* BLE MIDI-1.0: maximum payload size is MTU - 3 */ + const unsigned int max_size = writer->mtu - 3; + const uint64_t time_msec = (time / SPA_NSEC_PER_MSEC); + const uint16_t timestamp = time_msec & 0x1fff; + +#define PUT(byte) do { if (writer->size >= max_size) return -ENOSPC; \ + writer->bufwriter->size++ = (byte); } while (0) + + if (writer->mtu < 5+3) + return -ENOSPC; /* all events must fit */ + + spa_assert(max_size <= sizeof(writer->buf)); + spa_assert(writer->size <= max_size); + + if (event_size == 0) + return 0; + + if (writer->flush) { + writer->flush = false; + writer->size = 0; + } + + if (writer->size == max_size) + goto flush; + + /* Packet header */ + if (writer->size == 0) { + PUT(0x80 | (timestamp >> 7)); + writer->running_status = 0; + writer->running_time_msec = time_msec; + } + + /* Timestamp low bits can wrap around, but not multiple times */ + if (time_msec > writer->running_time_msec + 0x7f) + goto flush; + + spa_assert(writer->pos < event_size); + + for (; writer->pos < event_size; ++writer->pos) { + const unsigned int unused = max_size - writer->size; + const uint8_t byte = eventwriter->pos; + + if (byte & 0x80) { + enum midi_event_class class; + unsigned int expected_size; + + class = midi_event_info(event0, &expected_size); + + if (class == MIDI_BASIC && expected_size > 1 && + writer->running_status == byte && + writer->running_time_msec == time_msec) { + /* Running status: continue with data */ + continue; + } + + if (unused < expected_size + 1) + goto flush; + + /* Timestamp before status */ + PUT(0x80 | (timestamp & 0x7f)); + writer->running_time_msec = time_msec; + + if (class == MIDI_BASIC && expected_size > 1) + writer->running_status = byte; + else + writer->running_status = 0; + } else if (unused == 0) { + break; + } + + PUT(byte); + } + + if (writer->pos < event_size) + goto flush; + + writer->pos = 0; + return 0; + +flush: + writer->flush = true; + return 1; + +#undef PUT +}
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/midi-server.c
Added
@@ -0,0 +1,581 @@ +/* Spa Bluez5 midi + * + * Copyright © 2022 Pauli Virtanen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <errno.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <spa/utils/defs.h> +#include <spa/utils/string.h> +#include <spa/utils/result.h> + +#include "midi.h" + +#include "bluez5-interface-gen.h" +#include "dbus-monitor.h" + +#undef SPA_LOG_TOPIC_DEFAULT +#define SPA_LOG_TOPIC_DEFAULT (&impl->log_topic) + +#define MIDI_SERVER_PATH "/midiserver%u" +#define MIDI_SERVICE_PATH "/midiserver%u/service" +#define MIDI_CHR_PATH "/midiserver%u/service/chr" +#define MIDI_DSC_PATH "/midiserver%u/service/chr/dsc" + +#define BLE_DEFAULT_MTU 23 + +struct impl +{ + struct spa_bt_midi_server this; + + struct spa_log_topic log_topic; + struct spa_log *log; + + const struct spa_bt_midi_server_cb *cb; + + GDBusConnection *conn; + struct dbus_monitor monitor; + GDBusObjectManagerServer *manager; + + Bluez5GattCharacteristic1 *chr; + + void *user_data; + + uint32_t server_id; + + unsigned int write_acquired:1; + unsigned int notify_acquired:1; +}; + +struct _MidiServerManagerProxy +{ + Bluez5GattManager1Proxy parent_instance; + + GCancellable *register_call; + unsigned int registered:1; +}; + +G_DECLARE_FINAL_TYPE(MidiServerManagerProxy, midi_server_manager_proxy, MIDI_SERVER, + MANAGER_PROXY, Bluez5GattManager1Proxy) +G_DEFINE_TYPE(MidiServerManagerProxy, midi_server_manager_proxy, BLUEZ5_TYPE_GATT_MANAGER1_PROXY) +#define MIDI_SERVER_TYPE_MANAGER_PROXY (midi_server_manager_proxy_get_type()) + + +/* + * Characteristic user descriptor: not in BLE MIDI standard, but we + * put a device name here in case we have multiple MIDI endpoints. + */ + +static gboolean dsc_handle_read_value(Bluez5GattDescriptor1 *iface, GDBusMethodInvocation *invocation, + GVariant *arg_options, gpointer user_data) +{ + struct impl *impl = user_data; + const char *description = NULL; + uint16_t offset = 0; + int len; + + g_variant_lookup(arg_options, "offset", "q", &offset); + + if (impl->cb->get_description) + description = impl->cb->get_description(impl->user_data); + if (!description) + description = ""; + + len = strlen(description); + if (offset > len) { + g_dbus_method_invocation_return_dbus_error(invocation, + "org.freedesktop.DBus.Error.InvalidArgs", + "Invalid arguments"); + return TRUE; + } + + bluez5_gatt_descriptor1_complete_read_value(iface, + invocation, description + offset); + return TRUE; +} + +static int export_dsc(struct impl *impl) +{ + static const char * const flags = { "encrypt-read", NULL }; + GDBusObjectSkeleton *skeleton = NULL; + Bluez5GattDescriptor1 *iface = NULL; + int res = -ENOMEM; + char path128; + + iface = bluez5_gatt_descriptor1_skeleton_new(); + if (!iface) + goto done; + + spa_scnprintf(path, sizeof(path), MIDI_DSC_PATH, impl->server_id); + skeleton = g_dbus_object_skeleton_new(path); + if (!skeleton) + goto done; + g_dbus_object_skeleton_add_interface(skeleton, G_DBUS_INTERFACE_SKELETON(iface)); + + bluez5_gatt_descriptor1_set_uuid(iface, BT_GATT_CHARACTERISTIC_USER_DESCRIPTION_UUID); + spa_scnprintf(path, sizeof(path), MIDI_CHR_PATH, impl->server_id); + bluez5_gatt_descriptor1_set_characteristic(iface, path); + bluez5_gatt_descriptor1_set_flags(iface, flags); + + g_signal_connect(iface, "handle-read-value", G_CALLBACK(dsc_handle_read_value), impl); + + g_dbus_object_manager_server_export(impl->manager, skeleton); + + spa_log_debug(impl->log, "MIDI GATT Descriptor exported, path=%s", + g_dbus_object_get_object_path(G_DBUS_OBJECT(skeleton))); + + res = 0; + +done: + g_clear_object(&iface); + g_clear_object(&skeleton); + return res; +} + + +/* + * MIDI characteristic + */ + +static gboolean chr_handle_read_value(Bluez5GattCharacteristic1 *iface, + GDBusMethodInvocation *invocation, GVariant *arg_options, + gpointer user_data) +{ + /* BLE MIDI-1.0: returns empty value */ + bluez5_gatt_characteristic1_complete_read_value(iface, invocation, ""); + return TRUE; +} + +static void chr_change_acquired(struct impl *impl, bool write, bool enabled) +{ + if (write) { + impl->write_acquired = enabled; + bluez5_gatt_characteristic1_set_write_acquired(impl->chr, enabled); + } else { + impl->notify_acquired = enabled; + bluez5_gatt_characteristic1_set_notify_acquired(impl->chr, enabled); + } +} + +static int create_socketpair(int fds2) +{ + if (socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0) + return -errno; + return 0; +} + +static gboolean chr_handle_acquire(Bluez5GattCharacteristic1 *object, + GDBusMethodInvocation *invocation, + GUnixFDList *dummy, GVariant *arg_options, + bool write, gpointer user_data) +{ + struct impl *impl = user_data; + const char *err_msg = "Failed"; + uint16_t mtu = BLE_DEFAULT_MTU; + gint fds2 = {-1, -1}; + int res; + GUnixFDList *fd_list = NULL; + GVariant *fd_handle = NULL; + GError *err = NULL; + + if ((write && (impl->cb->acquire_write == NULL)) || + (!write && (impl->cb->acquire_notify == NULL))) { + err_msg = "Not supported"; + goto fail; + } + if ((write && impl->write_acquired) || + (!write && impl->notify_acquired)) { + err_msg = "Already acquired"; + goto fail; + } + + g_variant_lookup(arg_options, "mtu", "q", &mtu); + + if (create_socketpair(fds) < 0) { + err_msg = "Socketpair creation failed"; + goto fail; + } + + if (write) + res = impl->cb->acquire_write(impl->user_data, fds0, mtu); + else + res = impl->cb->acquire_notify(impl->user_data, fds0, mtu); + if (res < 0) { + err_msg = "Acquiring failed"; + goto fail; + } + fds0 = -1; + + fd_handle = g_variant_new_handle(0); + fd_list = g_unix_fd_list_new_from_array(&fds1, 1); + fds1 = -1; + + chr_change_acquired(impl, write, true); + + if (write) { + bluez5_gatt_characteristic1_complete_acquire_write( + object, invocation, fd_list, fd_handle, mtu); + } else { + bluez5_gatt_characteristic1_complete_acquire_notify( + object, invocation, fd_list, fd_handle, mtu); + } + + g_clear_object(&fd_list); + return TRUE; + +fail: + if (fds0 >= 0) + close(fds0); + if (fds1 >= 0) + close(fds1); + + if (err) + g_error_free(err); + g_clear_pointer(&fd_handle, g_variant_unref); + g_clear_object(&fd_list); + g_dbus_method_invocation_return_dbus_error(invocation, + "org.freedesktop.DBus.Error.Failed", err_msg); + return TRUE; + +} + +static gboolean chr_handle_acquire_write(Bluez5GattCharacteristic1 *object, + GDBusMethodInvocation *invocation, + GUnixFDList *fd_list, GVariant *arg_options, + gpointer user_data) +{ + return chr_handle_acquire(object, invocation, fd_list, arg_options, true, user_data); +} + +static gboolean chr_handle_acquire_notify(Bluez5GattCharacteristic1 *object, + GDBusMethodInvocation *invocation, + GUnixFDList *fd_list, GVariant *arg_options, + gpointer user_data) +{ + return chr_handle_acquire(object, invocation, fd_list, arg_options, false, user_data); +} + +static int export_chr(struct impl *impl) +{ + static const char * const flags = { "encrypt-read", "write-without-response", + "encrypt-write", "encrypt-notify", NULL }; + GDBusObjectSkeleton *skeleton = NULL; + Bluez5GattCharacteristic1 *iface = NULL; + int res = -ENOMEM; + char path128; + + iface = bluez5_gatt_characteristic1_skeleton_new(); + if (!iface) + goto done; + + spa_scnprintf(path, sizeof(path), MIDI_CHR_PATH, impl->server_id); + skeleton = g_dbus_object_skeleton_new(path); + if (!skeleton) + goto done; + g_dbus_object_skeleton_add_interface(skeleton, G_DBUS_INTERFACE_SKELETON(iface)); + + bluez5_gatt_characteristic1_set_uuid(iface, BT_MIDI_CHR_UUID); + spa_scnprintf(path, sizeof(path), MIDI_SERVICE_PATH, impl->server_id); + bluez5_gatt_characteristic1_set_service(iface, path); + bluez5_gatt_characteristic1_set_write_acquired(iface, FALSE); + bluez5_gatt_characteristic1_set_notify_acquired(iface, FALSE); + bluez5_gatt_characteristic1_set_flags(iface, flags); + + g_signal_connect(iface, "handle-read-value", G_CALLBACK(chr_handle_read_value), impl); + g_signal_connect(iface, "handle-acquire-write", G_CALLBACK(chr_handle_acquire_write), impl); + g_signal_connect(iface, "handle-acquire-notify", G_CALLBACK(chr_handle_acquire_notify), impl); + + g_dbus_object_manager_server_export(impl->manager, skeleton); + + impl->chr = g_object_ref(iface); + + spa_log_debug(impl->log, "MIDI GATT Characteristic exported, path=%s", + g_dbus_object_get_object_path(G_DBUS_OBJECT(skeleton))); + + res = 0; + +done: + g_clear_object(&iface); + g_clear_object(&skeleton); + return res; +} + + +/* + * MIDI service + */ + +static int export_service(struct impl *impl) +{ + GDBusObjectSkeleton *skeleton = NULL; + Bluez5GattService1 *iface = NULL; + int res = -ENOMEM; + char path128; + + iface = bluez5_gatt_service1_skeleton_new(); + if (!iface) + goto done; + + spa_scnprintf(path, sizeof(path), MIDI_SERVICE_PATH, impl->server_id); + skeleton = g_dbus_object_skeleton_new(path); + if (!skeleton) + goto done; + g_dbus_object_skeleton_add_interface(skeleton, G_DBUS_INTERFACE_SKELETON(iface)); + + bluez5_gatt_service1_set_uuid(iface, BT_MIDI_SERVICE_UUID); + bluez5_gatt_service1_set_primary(iface, TRUE); + + g_dbus_object_manager_server_export(impl->manager, skeleton); + + spa_log_debug(impl->log, "MIDI GATT Service exported, path=%s", + g_dbus_object_get_object_path(G_DBUS_OBJECT(skeleton))); + + res = 0; + +done: + g_clear_object(&iface); + g_clear_object(&skeleton); + return res; +} + + +/* + * Registration on all GattManagers + */ + +static void manager_register_application_reply(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + MidiServerManagerProxy *manager = MIDI_SERVER_MANAGER_PROXY(source_object); + struct impl *impl = user_data; + GError *err = NULL; + + bluez5_gatt_manager1_call_register_application_finish( + BLUEZ5_GATT_MANAGER1(source_object), res, &err); + + if (g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + /* Operation canceled: user_data may be invalid by now */ + g_error_free(err); + goto done; + } + if (err) { + spa_log_error(impl->log, "%s.RegisterApplication() failed: %s", + BLUEZ_GATT_MANAGER_INTERFACE, + err->message); + g_error_free(err); + goto done; + } + + manager->registered = true; + +done: + g_clear_object(&manager->register_call); +} + +static int manager_register_application(struct impl *impl, MidiServerManagerProxy *manager) +{ + GVariantBuilder builder; + GVariant *options; + + if (manager->registered) + return 0; + if (manager->register_call) + return -EBUSY; + + spa_log_debug(impl->log, "%s.RegisterApplication(%s) on %s", + BLUEZ_GATT_MANAGER_INTERFACE, + g_dbus_object_manager_get_object_path(G_DBUS_OBJECT_MANAGER(impl->manager)), + g_dbus_proxy_get_object_path(G_DBUS_PROXY(manager))); + + manager->register_call = g_cancellable_new(); + g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); + options = g_variant_builder_end(&builder); + bluez5_gatt_manager1_call_register_application(BLUEZ5_GATT_MANAGER1(manager), + g_dbus_object_manager_get_object_path(G_DBUS_OBJECT_MANAGER(impl->manager)), + options, + manager->register_call, + manager_register_application_reply, + impl); + + return 0; +} + +static void midi_server_manager_proxy_init(MidiServerManagerProxy *manager) +{ +} + +static void midi_server_manager_proxy_finalize(GObject *object) +{ + MidiServerManagerProxy *manager = MIDI_SERVER_MANAGER_PROXY(object); + + g_cancellable_cancel(manager->register_call); + g_clear_object(&manager->register_call); +} + +static void midi_server_manager_proxy_class_init(MidiServerManagerProxyClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + + object_class->finalize = midi_server_manager_proxy_finalize; +} + +static void manager_update(struct dbus_monitor *monitor, GDBusInterface *iface) +{ + struct impl *impl = SPA_CONTAINER_OF(monitor, struct impl, monitor); + + manager_register_application(impl, MIDI_SERVER_MANAGER_PROXY(iface)); +} + +static void manager_clear(struct dbus_monitor *monitor, GDBusInterface *iface) +{ + midi_server_manager_proxy_finalize(G_OBJECT(iface)); +} + +static void on_name_owner_change(struct dbus_monitor *monitor) +{ + struct impl *impl = SPA_CONTAINER_OF(monitor, struct impl, monitor); + + /* + * BlueZ disappeared/appeared. It does not appear to close the sockets + * it quits, so we should force the chr release now. + */ + if (impl->cb->release) + impl->cb->release(impl->user_data); + chr_change_acquired(impl, true, false); + chr_change_acquired(impl, false, false); +} + +static void monitor_start(struct impl *impl) +{ + struct dbus_monitor_proxy_type proxy_types = { + { BLUEZ_GATT_MANAGER_INTERFACE, MIDI_SERVER_TYPE_MANAGER_PROXY, manager_update, manager_clear }, + { NULL, BLUEZ5_TYPE_OBJECT_PROXY, NULL, NULL }, + { NULL, G_TYPE_INVALID, NULL, NULL }, + }; + + SPA_STATIC_ASSERT(SPA_N_ELEMENTS(proxy_types) <= DBUS_MONITOR_MAX_TYPES); + + dbus_monitor_init(&impl->monitor, BLUEZ5_TYPE_OBJECT_MANAGER_CLIENT, + impl->log, impl->conn, BLUEZ_SERVICE, "/", proxy_types, + on_name_owner_change); +} + + +/* + * Object registration + */ + +static int export_objects(struct impl *impl) +{ + int res = 0; + char path128; + + spa_scnprintf(path, sizeof(path), MIDI_SERVER_PATH, impl->server_id); + impl->manager = g_dbus_object_manager_server_new(path); + if (!impl->manager){ + spa_log_error(impl->log, "Creating GDBus object manager failed"); + goto fail; + } + + if ((res = export_service(impl)) < 0) + goto fail; + + if ((res = export_chr(impl)) < 0) + goto fail; + + if ((res = export_dsc(impl)) < 0) + goto fail; + + g_dbus_object_manager_server_set_connection(impl->manager, impl->conn); + + return 0; + +fail: + res = (res < 0) ? res : ((errno > 0) ? -errno : -EIO); + + spa_log_error(impl->log, "Failed to register BLE MIDI services in DBus: %s", + spa_strerror(res)); + + g_clear_object(&impl->manager); + + return res; +} + +struct spa_bt_midi_server *spa_bt_midi_server_new(const struct spa_bt_midi_server_cb *cb, + GDBusConnection *conn, struct spa_log *log, void *user_data) +{ + static unsigned int server_id = 0; + struct impl *impl; + char path128; + int res = 0; + + impl = calloc(1, sizeof(struct impl)); + if (impl == NULL) + goto fail; + + impl->server_id = server_id++; + impl->user_data = user_data; + impl->cb = cb; + impl->log = log; + impl->log_topic = SPA_LOG_TOPIC(0, "spa.bluez5.midi.server"); + impl->conn = conn; + spa_log_topic_init(impl->log, &impl->log_topic); + + if ((res = export_objects(impl)) < 0) + goto fail; + + monitor_start(impl); + + g_object_ref(impl->conn); + + spa_scnprintf(path, sizeof(path), MIDI_CHR_PATH, impl->server_id); + impl->this.chr_path = strdup(path); + + return &impl->this; + +fail: + res = (res < 0) ? res : ((errno > 0) ? -errno : -EIO); + free(impl); + errno = res; + return NULL; +} + +void spa_bt_midi_server_destroy(struct spa_bt_midi_server *server) +{ + struct impl *impl = SPA_CONTAINER_OF(server, struct impl, this); + + free((void *)impl->this.chr_path); + g_clear_object(&impl->chr); + dbus_monitor_clear(&impl->monitor); + g_clear_object(&impl->manager); + g_clear_object(&impl->conn); + + free(impl); +} + +void spa_bt_midi_server_released(struct spa_bt_midi_server *server, bool write) +{ + struct impl *impl = SPA_CONTAINER_OF(server, struct impl, this); + + chr_change_acquired(impl, write, false); +}
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/midi.h
Added
@@ -0,0 +1,142 @@ +/* Spa V4l2 dbus + * + * Copyright © 2022 Pauli Virtanen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#ifndef SPA_BT_MIDI_H_ +#define SPA_BT_MIDI_H_ + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +#include <gio/gio.h> + +#include <spa/utils/defs.h> +#include <spa/support/log.h> + +#define BLUEZ_SERVICE "org.bluez" +#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter1" +#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device1" +#define BLUEZ_GATT_MANAGER_INTERFACE BLUEZ_SERVICE ".GattManager1" +#define BLUEZ_GATT_PROFILE_INTERFACE BLUEZ_SERVICE ".GattProfile1" +#define BLUEZ_GATT_SERVICE_INTERFACE BLUEZ_SERVICE ".GattService1" +#define BLUEZ_GATT_CHR_INTERFACE BLUEZ_SERVICE ".GattCharacteristic1" +#define BLUEZ_GATT_DSC_INTERFACE BLUEZ_SERVICE ".GattDescriptor1" + +#define BT_MIDI_SERVICE_UUID "03b80e5a-ede8-4b33-a751-6ce34ec4c700" +#define BT_MIDI_CHR_UUID "7772e5db-3868-4112-a1a9-f2669d106bf3" +#define BT_GATT_CHARACTERISTIC_USER_DESCRIPTION_UUID "00002901-0000-1000-8000-00805f9b34fb" + +#define MIDI_BUF_SIZE 8192 +#define MIDI_MAX_MTU 8192 + +#define MIDI_CLOCK_PERIOD_MSEC 0x2000 +#define MIDI_CLOCK_PERIOD_NSEC (MIDI_CLOCK_PERIOD_MSEC * SPA_NSEC_PER_MSEC) + +struct spa_bt_midi_server +{ + const char *chr_path; +}; + +struct spa_bt_midi_parser { + unsigned int size; + unsigned int sysex:1; + uint8_t bufMIDI_BUF_SIZE; +}; + +struct spa_bt_midi_writer { + unsigned int size; + unsigned int mtu; + unsigned int pos; + uint8_t running_status; + uint64_t running_time_msec; + unsigned int flush:1; + uint8_t bufMIDI_MAX_MTU; +}; + +struct spa_bt_midi_server_cb +{ + int (*acquire_notify)(void *user_data, int fd, uint16_t mtu); + int (*acquire_write)(void *user_data, int fd, uint16_t mtu); + int (*release)(void *user_data); + const char *(*get_description)(void *user_data); +}; + +static inline void spa_bt_midi_parser_init(struct spa_bt_midi_parser *parser) +{ + parser->size = 0; + parser->sysex = 0; +} + +static inline void spa_bt_midi_parser_dup(struct spa_bt_midi_parser *src, struct spa_bt_midi_parser *dst, bool only_time) +{ + dst->size = src->size; + dst->sysex = src->sysex; + if (!only_time) + memcpy(dst->buf, src->buf, src->size); +} + +/** + * Parse a single BLE MIDI data packet to normalized MIDI events. + */ +int spa_bt_midi_parser_parse(struct spa_bt_midi_parser *parser, + const uint8_t *src, size_t src_size, + bool only_time, + void (*event)(void *user_data, uint16_t time, uint8_t *event, size_t event_size), + void *user_data); + +static inline void spa_bt_midi_writer_init(struct spa_bt_midi_writer *writer, unsigned int mtu) +{ + writer->size = 0; + writer->mtu = SPA_MIN(mtu, (unsigned int)MIDI_MAX_MTU); + writer->pos = 0; + writer->running_status = 0; + writer->running_time_msec = 0; + writer->flush = 0; +} + +/** + * Add a new event to midi writer buffer. + * + * spa_bt_midi_writer_init(&writer, mtu); + * for (time, event, size) in midi events { + * do { + * res = spa_bt_midi_writer_write(&writer, time, event, size); + * if (res < 0) { + * fail with error + * } else if (res) { + * send_packet(writer->buf, writer->size); + * } + * } while (res); + * } + * if (writer.size > 0) + * send_packet(writer->buf, writer->size); + */ +int spa_bt_midi_writer_write(struct spa_bt_midi_writer *writer, + uint64_t time, const uint8_t *event, size_t event_size); + +struct spa_bt_midi_server *spa_bt_midi_server_new(const struct spa_bt_midi_server_cb *cb, + GDBusConnection *conn, struct spa_log *log, void *user_data); +void spa_bt_midi_server_released(struct spa_bt_midi_server *server, bool write); +void spa_bt_midi_server_destroy(struct spa_bt_midi_server *server); + +#endif
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/org.bluez.xml
Added
@@ -0,0 +1,71 @@ +<node> + <interface name="org.bluez.Adapter1"> + <method name="RegisterApplication"> + <arg direction="in" type="o" name="path"/> + <arg direction="in" type="a{sv}" name="options"/> + </method> + </interface> + + <interface name="org.bluez.Device1"> + <property name="Adapter" type="o" access="read"/> + <property name="Connected" type="b" access="read"/> + <property name="ServicesResolved" type="b" access="read"/> + <property name="Name" type="s" access="read"/> + <property name="Alias" type="s" access="read"/> + <property name="Address" type="s" access="read"/> + <property name="Icon" type="s" access="read"/> + <property name="Class" type="u" access="read"/> + <property name="Appearance" type="q" access="read"/> + </interface> + + <interface name="org.bluez.GattManager1"> + <method name="RegisterApplication"> + <arg direction="in" type="o" name="path"/> + <arg direction="in" type="a{sv}" name="options"/> + </method> + </interface> + + <interface name="org.bluez.GattProfile1"> + <method name="Release"> + </method> + <property name="UUIDs" type="as" access="read"/> + </interface> + + <interface name="org.bluez.GattService1"> + <property name="UUID" type="s" access="read"/> + <property name="Primary" type="b" access="read"/> + <property name="Device" type="o" access="read"/> + </interface> + + <interface name="org.bluez.GattCharacteristic1"> + <method name="ReadValue"> + <arg direction="in" type="a{sv}" name="options"/> + <arg direction="out" type="ay" name="value"/> + </method> + <method name="AcquireNotify"> + <arg direction="in" type="a{sv}" name="options"/> + <arg direction="out" type="h" name="fd"/> + <arg direction="out" type="q" name="mtu"/> + </method> + <method name="AcquireWrite"> + <arg direction="in" type="a{sv}" name="options"/> + <arg direction="out" type="h" name="fd"/> + <arg direction="out" type="q" name="mtu"/> + </method> + <property name="UUID" type="s" access="read"/> + <property name="Service" type="o" access="read"/> + <property name="WriteAcquired" type="b" access="read"/> + <property name="NotifyAcquired" type="b" access="read"/> + <property name="Flags" type="as" access="read"/> + </interface> + + <interface name="org.bluez.GattDescriptor1"> + <method name="ReadValue"> + <arg direction="in" type="a{sv}" name="options"/> + <arg direction="out" type="ay" name="value"/> + </method> + <property name="UUID" type="s" access="read"/> + <property name="Characteristic" type="o" access="read"/> + <property name="Flags" type="as" access="read"/> + </interface> +</node>
View file
pipewire-0.3.64.tar.gz/spa/plugins/bluez5/plugin.c -> pipewire-0.3.65.tar.gz/spa/plugins/bluez5/plugin.c
Changed
@@ -35,6 +35,8 @@ extern const struct spa_handle_factory spa_sco_source_factory; extern const struct spa_handle_factory spa_a2dp_sink_factory; extern const struct spa_handle_factory spa_a2dp_source_factory; +extern const struct spa_handle_factory spa_bluez5_midi_enum_factory; +extern const struct spa_handle_factory spa_bluez5_midi_node_factory; SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) @@ -67,6 +69,12 @@ case 7: *factory = &spa_a2dp_source_factory; break; + case 8: + *factory = &spa_bluez5_midi_enum_factory; + break; + case 9: + *factory = &spa_bluez5_midi_node_factory; + break; default: return 0; }
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/test-midi.c
Added
@@ -0,0 +1,299 @@ +#include <spa/utils/defs.h> + +#include "midi.h" + +#define TIME_HI(v) (0x80 | ((v >> 7) & 0x3f)) +#define TIME_LO(v) (0x80 | (v & 0x7f)) + +struct event { + uint16_t time_msec; + size_t size; + const uint8_t *data; +}; + +struct packet { + size_t size; + const uint8_t *data; +}; + +struct test_info { + const struct packet *packets; + const struct event *events; + unsigned int i; +}; + +static const struct packet midi_1_packets = { + { + .size = 27, + .data = (uint8_t) { + TIME_HI(0x1234), + /* event 1 */ + TIME_LO(0x1234), 0xa0, 0x01, 0x02, + /* event 2: running status */ + 0x03, 0x04, + /* event 3: running status with timestamp */ + TIME_LO(0x1235), 0x05, 0x06, + /* event 4 */ + TIME_LO(0x1236), 0xf8, + /* event 5: sysex */ + TIME_LO(0x1237), 0xf0, 0x0a, 0x0b, 0x0c, + /* event 6: realtime event inside sysex */ + TIME_LO(0x1238), 0xff, + /* event 5 continues */ + 0x0d, 0x0e, TIME_LO(0x1239), 0xf7, + /* event 6: sysex */ + TIME_LO(0x1240), 0xf0, 0x10, 0x11, + /* packet end in middle of sysex */ + }, + }, + { + .size = 7, + .data = (uint8_t) { + TIME_HI(0x1241), + /* event 6: continued from previous packet */ + 0x12, TIME_LO(0x1241), 0xf7, + /* event 7 */ + TIME_LO(0x1242), 0xf1, 0x13, + } + }, + {0} +}; + +static const struct event midi_1_events = { + { 0x1234, 3, (uint8_t) { 0xa0, 0x01, 0x02 } }, + { 0x1234, 3, (uint8_t) { 0xa0, 0x03, 0x04 } }, + { 0x1235, 3, (uint8_t) { 0xa0, 0x05, 0x06 } }, + { 0x1236, 1, (uint8_t) { 0xf8 } }, + /* realtime event inside sysex come before it */ + { 0x1238, 1, (uint8_t) { 0xff } }, + /* sysex timestamp indicates the end time; sysex contains the end marker */ + { 0x1239, 7, (uint8_t) { 0xf0, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0xf7 } }, + { 0x1241, 5, (uint8_t) { 0xf0, 0x10, 0x11, 0x12, 0xf7 } }, + { 0x1242, 2, (uint8_t) { 0xf1, 0x13 } }, + {0} +}; + +static const struct packet midi_1_packets_mtu14 = { + { + .size = 11, + .data = (uint8_t) { + TIME_HI(0x1234), + TIME_LO(0x1234), 0xa0, 0x01, 0x02, + 0x03, 0x04, + /* output Apple-style BLE; running status only for coincident time */ + TIME_LO(0x1235), 0xa0, 0x05, 0x06, + }, + }, + { + .size = 11, + .data = (uint8_t) { + TIME_HI(0x1236), + TIME_LO(0x1236), 0xf8, + TIME_LO(0x1238), 0xff, + TIME_LO(0x1239), 0xf0, 0x0a, 0x0b, 0x0c, 0x0d, + }, + }, + { + .size = 11, + .data = (uint8_t) { + TIME_HI(0x1239), + 0x0e, TIME_LO(0x1239), 0xf7, + TIME_LO(0x1241), 0xf0, 0x10, 0x11, 0x12, TIME_LO(0x1241), 0xf7 + }, + }, + { + .size = 4, + .data = (uint8_t) { + TIME_HI(0x1242), + TIME_LO(0x1242), 0xf1, 0x13 + }, + }, + {0} +}; + +static const struct packet midi_2_packets = { + { + .size = 9, + .data = (uint8_t) { + TIME_HI(0x1234), + /* event 1 */ + TIME_LO(0x1234), 0xa0, 0x01, 0x02, + /* event 2: timestamp low bits rollover */ + TIME_LO(0x12b3), 0xa0, 0x03, 0x04, + }, + }, + { + .size = 5, + .data = (uint8_t) { + TIME_HI(0x18b3), + /* event 3: timestamp high bits jump */ + TIME_LO(0x18b3), 0xa0, 0x05, 0x06, + }, + }, + {0} +}; + +static const struct event midi_2_events = { + { 0x1234, 3, (uint8_t) { 0xa0, 0x01, 0x02 } }, + { 0x12b3, 3, (uint8_t) { 0xa0, 0x03, 0x04 } }, + { 0x18b3, 3, (uint8_t) { 0xa0, 0x05, 0x06 } }, + {0} +}; + +static const struct packet midi_2_packets_mtu11 = { + /* Small MTU: only room for one event per packet */ + { + .size = 5, + .data = (uint8_t) { + TIME_HI(0x1234), TIME_LO(0x1234), 0xa0, 0x01, 0x02, + }, + }, + { + .size = 5, + .data = (uint8_t) { + TIME_HI(0x12b3), TIME_LO(0x12b3), 0xa0, 0x03, 0x04, + }, + }, + { + .size = 5, + .data = (uint8_t) { + TIME_HI(0x18b3), TIME_LO(0x18b3), 0xa0, 0x05, 0x06, + }, + }, + {0} +}; + + +static void check_event(void *user_data, uint16_t time, uint8_t *event, size_t event_size) +{ + struct test_info *info = user_data; + const struct event *ev = &info->eventsinfo->i; + + spa_assert_se(ev->size > 0); + spa_assert_se(ev->time_msec == time); + spa_assert_se(ev->size == event_size); + spa_assert_se(memcmp(event, ev->data, ev->size) == 0); + + ++info->i; +} + +static void check_parser(struct test_info *info) +{ + struct spa_bt_midi_parser parser; + int res; + int i; + + info->i = 0; + + spa_bt_midi_parser_init(&parser); + for (i = 0; info->packetsi.size > 0; ++i) { + res = spa_bt_midi_parser_parse(&parser, + info->packetsi.data, info->packetsi.size, + false, check_event, info); + spa_assert_se(res == 0); + } + spa_assert_se(info->eventsinfo->i.size == 0); +} + +static void check_writer(struct test_info *info, unsigned int mtu) +{ + struct spa_bt_midi_writer writer; + struct spa_bt_midi_parser parser; + unsigned int i, packet; + void SPA_UNUSED *buf = writer.buf; + + spa_bt_midi_parser_init(&parser); + spa_bt_midi_writer_init(&writer, mtu); + + packet = 0; + info->i = 0; + + for (i = 0; info->eventsi.size > 0; ++i) { + const struct event *ev = &info->eventsi; + bool last = (info->eventsi+1.size == 0); + int res; + + do { + res = spa_bt_midi_writer_write(&writer, + ev->time_msec * SPA_NSEC_PER_MSEC, ev->data, ev->size); + spa_assert_se(res >= 0); + if (res || last) { + int r; + + spa_assert_se(info->packetspacket.size > 0); + spa_assert_se(writer.size == info->packetspacket.size); + spa_assert_se(memcmp(writer.buf, info->packetspacket.data, writer.size) == 0); + ++packet; + + /* Test roundtrip */ + r = spa_bt_midi_parser_parse(&parser, writer.buf, writer.size, + false, check_event, info); + spa_assert_se(r == 0); + } + } while (res); + } + + spa_assert_se(info->packetspacket.size == 0); + spa_assert_se(info->eventsinfo->i.size == 0); +} + +static void test_midi_parser_1(void) +{ + struct test_info info = { + .packets = midi_1_packets, + .events = midi_1_events, + }; + + check_parser(&info); +} + +static void test_midi_parser_2(void) +{ + struct test_info info = { + .packets = midi_2_packets, + .events = midi_2_events, + }; + + check_parser(&info); +} + +static void test_midi_writer_1(void) +{ + struct test_info info = { + .packets = midi_1_packets_mtu14, + .events = midi_1_events, + }; + + check_writer(&info, 14); +} + +static void test_midi_writer_2(void) +{ + struct test_info info = { + .packets = midi_2_packets, + .events = midi_2_events, + }; + + check_writer(&info, 23); + check_writer(&info, 12); +} + +static void test_midi_writer_3(void) +{ + struct test_info info = { + .packets = midi_2_packets_mtu11, + .events = midi_2_events, + }; + + check_writer(&info, 11); +} + +int main(void) +{ + test_midi_parser_1(); + test_midi_parser_2(); + test_midi_writer_1(); + test_midi_writer_2(); + test_midi_writer_3(); + return 0; +}
View file
pipewire-0.3.64.tar.gz/spa/plugins/jack/jack-device.c -> pipewire-0.3.65.tar.gz/spa/plugins/jack/jack-device.c
Changed
@@ -44,6 +44,7 @@ #include <spa/pod/filter.h> #include <spa/pod/parser.h> #include <spa/debug/pod.h> +#include <spa/debug/log.h> #include "jack-client.h" @@ -337,7 +338,7 @@ SPA_TYPE_OBJECT_ParamProfile, NULL, SPA_PARAM_PROFILE_index, SPA_POD_Int(&idx))) < 0) { spa_log_warn(this->log, "can't parse profile"); - spa_debug_pod(0, NULL, param); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param); return res; } activate_profile(this, idx);
View file
pipewire-0.3.64.tar.gz/spa/plugins/libcamera/libcamera-device.cpp -> pipewire-0.3.65.tar.gz/spa/plugins/libcamera/libcamera-device.cpp
Changed
@@ -44,7 +44,7 @@ #include <spa/pod/builder.h> #include <spa/monitor/device.h> #include <spa/monitor/utils.h> -#include <spa/debug/pod.h> +#include <spa/param/param.h> #include "libcamera.h" #include "libcamera-manager.hpp"
View file
pipewire-0.3.64.tar.gz/spa/plugins/libcamera/libcamera-source.cpp -> pipewire-0.3.65.tar.gz/spa/plugins/libcamera/libcamera-source.cpp
Changed
@@ -49,8 +49,8 @@ #include <spa/node/keys.h> #include <spa/param/video/format-utils.h> #include <spa/param/param.h> +#include <spa/control/control.h> #include <spa/pod/filter.h> -#include <spa/debug/pod.h> #include <libcamera/camera.h> #include <libcamera/stream.h> @@ -676,7 +676,10 @@ info.media_subtype == port->current_format->media_subtype && info.info.raw.format == port->current_format->info.raw.format && info.info.raw.size.width == port->current_format->info.raw.size.width && - info.info.raw.size.height == port->current_format->info.raw.size.height) + info.info.raw.size.height == port->current_format->info.raw.size.height && + info.info.raw.flags == port->current_format->info.raw.flags && + (!(info.info.raw.flags & SPA_VIDEO_FLAG_MODIFIER) || + (info.info.raw.modifier == port->current_format->info.raw.modifier))) return 0; break; case SPA_MEDIA_SUBTYPE_mjpg:
View file
pipewire-0.3.64.tar.gz/spa/plugins/meson.build -> pipewire-0.3.65.tar.gz/spa/plugins/meson.build
Changed
@@ -16,7 +16,7 @@ if get_option('audiotestsrc').allowed() subdir('audiotestsrc') endif -if bluez_dep.found() +if bluez_deps_found subdir('bluez5') endif if avcodec_dep.found()
View file
pipewire-0.3.64.tar.gz/spa/plugins/support/cpu-arm.c -> pipewire-0.3.65.tar.gz/spa/plugins/support/cpu-arm.c
Changed
@@ -49,37 +49,14 @@ return strndup(colon, end - colon); } -static char *get_cpuinfo(void) -{ - char *cpuinfo; - int n, fd; - - cpuinfo = malloc(MAX_BUFFER); - - if ((fd = open("/proc/cpuinfo", O_RDONLY | O_CLOEXEC, 0)) < 0) { - free(cpuinfo); - return NULL; - } - - if ((n = read(fd, cpuinfo, MAX_BUFFER-1)) < 0) { - free(cpuinfo); - close(fd); - return NULL; - } - cpuinfon = 0; - close(fd); - - return cpuinfo; -} - static int arm_init(struct impl *impl) { uint32_t flags = 0; - char *cpuinfo, *line; + char *cpuinfo, *line, bufferMAX_BUFFER; int arch; - if (!(cpuinfo = get_cpuinfo())) { + if (!(cpuinfo = spa_cpu_read_file("/proc/cpuinfo", buffer, sizeof(buffer)))) { spa_log_warn(impl->log, "%p: Can't read cpuinfo", impl); return 1; } @@ -117,8 +94,6 @@ free(line); } - free(cpuinfo); - impl->flags = flags; return 0;
View file
pipewire-0.3.64.tar.gz/spa/plugins/support/cpu.c -> pipewire-0.3.65.tar.gz/spa/plugins/support/cpu.c
Changed
@@ -59,7 +59,7 @@ uint32_t vm_type; }; -static char *read_file(const char *name, char *buffer, size_t len) +char *spa_cpu_read_file(const char *name, char *buffer, size_t len) { int n, fd; @@ -175,7 +175,7 @@ SPA_FOR_EACH_ELEMENT_VAR(dmi_vendors, dv) { char buffer256, *s; - if ((s = read_file(*dv, buffer, sizeof(buffer))) == NULL) + if ((s = spa_cpu_read_file(*dv, buffer, sizeof(buffer))) == NULL) continue; SPA_FOR_EACH_ELEMENT_VAR(dmi_vendor_table, t) {
View file
pipewire-0.3.64.tar.gz/spa/plugins/v4l2/v4l2-device.c -> pipewire-0.3.65.tar.gz/spa/plugins/v4l2/v4l2-device.c
Changed
@@ -39,7 +39,7 @@ #include <spa/pod/builder.h> #include <spa/monitor/device.h> #include <spa/monitor/utils.h> -#include <spa/debug/pod.h> +#include <spa/param/param.h> #include "v4l2.h"
View file
pipewire-0.3.64.tar.gz/spa/plugins/v4l2/v4l2-source.c -> pipewire-0.3.65.tar.gz/spa/plugins/v4l2/v4l2-source.c
Changed
@@ -45,7 +45,7 @@ #include <spa/param/param.h> #include <spa/param/latency-utils.h> #include <spa/pod/filter.h> -#include <spa/debug/pod.h> +#include <spa/control/control.h> #include "v4l2.h"
View file
pipewire-0.3.64.tar.gz/spa/plugins/videoconvert/videoadapter.c -> pipewire-0.3.65.tar.gz/spa/plugins/videoconvert/videoadapter.c
Changed
@@ -42,6 +42,7 @@ #include <spa/param/latency-utils.h> #include <spa/debug/format.h> #include <spa/debug/pod.h> +#include <spa/debug/log.h> #undef SPA_LOG_TOPIC_DEFAULT #define SPA_LOG_TOPIC_DEFAULT log_topic @@ -299,7 +300,7 @@ if (filter) { spa_log_error(this->log, "with this filter:"); - spa_debug_pod(2, NULL, filter); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 2, NULL, filter); } else { spa_log_error(this->log, "there was no filter"); } @@ -317,7 +318,7 @@ break; } spa_log_error(this->log, "unmatched %s %d:", debug, count); - spa_debug_pod(2, NULL, param); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 2, NULL, param); count++; } if (count == 0) @@ -442,8 +443,8 @@ int res; spa_log_debug(this->log, "%p: configure format:", this); - if (format && spa_log_level_enabled(this->log, SPA_LOG_LEVEL_DEBUG)) - spa_debug_format(0, NULL, format); + if (format) + spa_debug_log_format(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, format); if ((res = spa_node_port_set_param(this->follower, this->direction, 0,
View file
pipewire-0.3.64.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.65.tar.gz/src/daemon/client-rt.conf.in
Changed
@@ -92,3 +92,23 @@ #channelmix.hilbert-taps = 0 #dither.noise = 0 } + +alsa.properties = { + #alsa.format = 0 + #alsa.rate = 0 + #alsa.channels = 0 + #alsa.period-bytes = 0 + #alsa.buffer-bytes = 0 + #alsa.volume-method = cubic # linear, cubic +} + +# client specific properties +alsa.rules = + { matches = { application.process.binary = "resolve" } + actions = { + update-props = { + alsa.buffer-bytes = 131072 + } + } + } +
View file
pipewire-0.3.64.tar.gz/src/daemon/jack.conf.in -> pipewire-0.3.65.tar.gz/src/daemon/jack.conf.in
Changed
@@ -70,7 +70,7 @@ #node.lock-quantum = true #node.force-quantum = 0 #jack.show-monitor = true - #jack.merge-monitor = false + #jack.merge-monitor = true #jack.short-name = false #jack.filter-name = false #jack.filter-char = " " @@ -89,8 +89,7 @@ # client specific properties jack.rules = - { - matches = + { matches = { # all keys must match the value. ~ starts regex. #client.name = "Carla" @@ -104,18 +103,14 @@ } } } - { matches = - { application.process.binary = "jack_bufsize" } - + { matches = { application.process.binary = "jack_bufsize" } actions = { update-props = { jack.global-buffer-size = true # quantum set globally using metadata } } } - { matches = - { application.process.binary = "qsynth" } - + { matches = { application.process.binary = "qsynth" } actions = { update-props = { node.pause-on-idle = false # makes audio fade out when idle @@ -123,4 +118,11 @@ } } } + { matches = { client.name = "Mixxx" } + actions = { + update-props = { + jack.merge-monitor = false + } + } + }
View file
pipewire-0.3.64.tar.gz/src/gst/gstpipewireformat.c -> pipewire-0.3.65.tar.gz/src/gst/gstpipewireformat.c
Changed
@@ -59,6 +59,8 @@ { "video/x-h264", SPA_MEDIA_TYPE_video, SPA_MEDIA_SUBTYPE_h264 }, { "audio/x-mulaw", SPA_MEDIA_TYPE_audio, SPA_MEDIA_SUBTYPE_raw }, { "audio/x-alaw", SPA_MEDIA_TYPE_audio, SPA_MEDIA_SUBTYPE_raw }, + { "audio/mpeg", SPA_MEDIA_TYPE_audio, SPA_MEDIA_SUBTYPE_mp3 }, + { "audio/x-flac", SPA_MEDIA_TYPE_audio, SPA_MEDIA_SUBTYPE_flac }, { NULL, } }; @@ -532,6 +534,12 @@ } else if (strcmp(d->type->name, "audio/x-alaw") == 0) { spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0); spa_pod_builder_id (&d->b, SPA_AUDIO_FORMAT_ALAW); + } else if (strcmp(d->type->name, "audio/mpeg") == 0) { + spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0); + spa_pod_builder_id (&d->b, SPA_AUDIO_FORMAT_ENCODED); + } else if (strcmp(d->type->name, "audio/x-flac") == 0) { + spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0); + spa_pod_builder_id (&d->b, SPA_AUDIO_FORMAT_ENCODED); } #if 0
View file
pipewire-0.3.64.tar.gz/src/gst/gstpipewirepool.c -> pipewire-0.3.65.tar.gz/src/gst/gstpipewirepool.c
Changed
@@ -89,16 +89,19 @@ GST_LOG_OBJECT (pool, "wrap buffer %d %d", d->mapoffset, d->maxsize); if (d->type == SPA_DATA_MemFd) { + GST_LOG_OBJECT (pool, "memory type MemFd"); gmem = gst_fd_allocator_alloc (pool->fd_allocator, dup(d->fd), d->mapoffset + d->maxsize, GST_FD_MEMORY_FLAG_NONE); gst_memory_resize (gmem, d->mapoffset, d->maxsize); } else if(d->type == SPA_DATA_DmaBuf) { + GST_LOG_OBJECT (pool, "memory type DmaBuf"); gmem = gst_fd_allocator_alloc (pool->dmabuf_allocator, dup(d->fd), d->mapoffset + d->maxsize, GST_FD_MEMORY_FLAG_NONE); gst_memory_resize (gmem, d->mapoffset, d->maxsize); } else if (d->type == SPA_DATA_MemPtr) { + GST_LOG_OBJECT (pool, "memory type MemPtr"); gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, 0, d->maxsize, NULL, NULL); }
View file
pipewire-0.3.64.tar.gz/src/gst/gstpipewiresink.c -> pipewire-0.3.65.tar.gz/src/gst/gstpipewiresink.c
Changed
@@ -346,6 +346,14 @@ gst_structure_fixate_field_string (structure, "format", "S16LE"); gst_structure_fixate_field_nearest_int (structure, "channels", 2); gst_structure_fixate_field_nearest_int (structure, "rate", 44100); + } else if (gst_structure_has_name (structure, "audio/mpeg")) { + gst_structure_fixate_field_string (structure, "format", "Encoded"); + gst_structure_fixate_field_nearest_int (structure, "channels", 2); + gst_structure_fixate_field_nearest_int (structure, "rate", 44100); + } else if (gst_structure_has_name (structure, "audio/x-flac")) { + gst_structure_fixate_field_string (structure, "format", "Encoded"); + gst_structure_fixate_field_nearest_int (structure, "channels", 2); + gst_structure_fixate_field_nearest_int (structure, "rate", 44100); } caps = GST_BASE_SINK_CLASS (parent_class)->fixate (bsink, caps);
View file
pipewire-0.3.64.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-0.3.65.tar.gz/src/gst/gstpipewiresrc.c
Changed
@@ -428,6 +428,9 @@ /* we operate in time */ gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME); + /* we're a live source, unless explicitly requested not to be */ + gst_base_src_set_live (GST_BASE_SRC (src), TRUE); + GST_OBJECT_FLAG_SET (src, GST_ELEMENT_FLAG_PROVIDE_CLOCK); src->always_copy = DEFAULT_ALWAYS_COPY; @@ -670,7 +673,7 @@ GST_OBJECT_LOCK (pwsrc); var = pw_properties_get (props, PW_KEY_STREAM_IS_LIVE); - is_live = pwsrc->is_live = var ? pw_properties_parse_bool(var) : FALSE; + is_live = pwsrc->is_live = var ? pw_properties_parse_bool(var) : TRUE; var = pw_properties_get (props, PW_KEY_STREAM_LATENCY_MIN); pwsrc->min_latency = var ? (GstClockTime) atoi (var) : 0; @@ -964,14 +967,14 @@ uint32_t buffers = CLAMP (16, pwsrc->min_buffers, pwsrc->max_buffers); int buffertypes; + buffertypes = (1<<SPA_DATA_DmaBuf); if (spa_pod_find_prop (param, NULL, SPA_FORMAT_VIDEO_modifier)) { - buffertypes = (1<<SPA_DATA_DmaBuf); gst_caps_features_remove (gst_caps_get_features (pwsrc->caps, 0), GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY); gst_caps_features_add (gst_caps_get_features (pwsrc->caps, 0), GST_CAPS_FEATURE_MEMORY_DMABUF); } else { - buffertypes = ((1<<SPA_DATA_MemFd) | (1<<SPA_DATA_MemPtr)); + buffertypes |= ((1<<SPA_DATA_MemFd) | (1<<SPA_DATA_MemPtr)); } GST_DEBUG_OBJECT (pwsrc, "we got format %" GST_PTR_FORMAT, pwsrc->caps);
View file
pipewire-0.3.64.tar.gz/src/modules/meson.build -> pipewire-0.3.65.tar.gz/src/modules/meson.build
Changed
@@ -8,6 +8,7 @@ 'module-avb.c', 'module-client-device.c', 'module-client-node.c', + 'module-combine-stream.c', 'module-echo-cancel.c', 'module-example-sink.c', 'module-example-source.c', @@ -135,6 +136,15 @@ 'module-echo-cancel.c', +pipewire_module_combine_stream = shared_library('pipewire-module-combine-stream', + 'module-combine-stream.c' , + include_directories : configinc, + install : false, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : spa_dep, dl_lib, pipewire_dep, +) + pipewire_module_echo_cancel = shared_library('pipewire-module-echo-cancel', pipewire_module_echo_cancel_sources, include_directories : configinc,
View file
pipewire-0.3.64.tar.gz/src/modules/module-access.c -> pipewire-0.3.65.tar.gz/src/modules/module-access.c
Changed
@@ -44,7 +44,6 @@ #include <spa/utils/json.h> #include <pipewire/impl.h> -#include <pipewire/private.h> #include "flatpak-utils.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-adapter/adapter.c -> pipewire-0.3.65.tar.gz/src/modules/module-adapter/adapter.c
Changed
@@ -42,11 +42,9 @@ #include <spa/param/audio/format-utils.h> #include <spa/param/format-utils.h> #include <spa/debug/types.h> -#include <spa/debug/pod.h> #include <spa/utils/json-pod.h> #include "pipewire/pipewire.h" -#include "pipewire/private.h" #include "modules/spa/spa-node.h" @@ -93,9 +91,9 @@ const struct pw_properties *old; enum pw_direction direction; struct pw_properties *new; - const char *str, *path, *desc, *nick, *name, *node_name, *media_class, *prop_port_names; + const char *str, *path, *desc, *nick, *name, *node_name, *media_class, *prop_port_names, *override_device_prefix; char position8, *prefix; - bool is_monitor, is_device, is_duplex, is_virtual, is_control = false; + bool is_monitor, is_device, is_duplex, is_virtual, is_control = false, no_device_port_prefix; direction = pw_impl_port_get_direction(port); @@ -123,6 +121,8 @@ new = pw_properties_new(NULL, NULL); + override_device_prefix = pw_properties_get(n->props, PW_KEY_NODE_DEVICE_PORT_NAME_PREFIX); + if (is_control) prefix = direction == PW_DIRECTION_INPUT ? "control" : "notify"; @@ -134,7 +134,10 @@ "input" : "capture"; else if (is_device) prefix = direction == PW_DIRECTION_INPUT ? - "playback" : is_monitor ? "monitor" : "capture"; + override_device_prefix != NULL ? + strdup(override_device_prefix) : "playback" + : is_monitor ? "monitor" : override_device_prefix != NULL ? + strdup(override_device_prefix) : "capture"; else prefix = direction == PW_DIRECTION_INPUT ? "input" : is_monitor ? "monitor" : "output"; @@ -161,9 +164,14 @@ pw_properties_setf(new, PW_KEY_OBJECT_PATH, "%s:%s_%d", path ? path : node_name, prefix, pw_impl_port_get_id(port)); + + no_device_port_prefix = is_device && !is_monitor + && override_device_prefix != NULL && strlen(override_device_prefix) == 0; if (is_control) pw_properties_setf(new, PW_KEY_PORT_NAME, "%s", prefix); + else if (no_device_port_prefix) + pw_properties_setf(new, PW_KEY_PORT_NAME, "%s", str); else pw_properties_setf(new, PW_KEY_PORT_NAME, "%s_%s", prefix, str); @@ -192,8 +200,13 @@ if (spa_json_get_string(&it1, v, sizeof(v)) <= 0) break; - if (i == pw_impl_port_get_id(port) + 1) - pw_properties_setf(new, PW_KEY_PORT_NAME, "%s_%s", prefix, v); + if (i == pw_impl_port_get_id(port) + 1 && strlen(v) > 0) { + if (no_device_port_prefix) { + pw_properties_setf(new, PW_KEY_PORT_NAME, "%s", v); + } else { + pw_properties_setf(new, PW_KEY_PORT_NAME, "%s_%s", prefix, v); + } + } } pw_impl_port_update_properties(port, &new->dict);
View file
pipewire-0.3.64.tar.gz/src/modules/module-avb.c -> pipewire-0.3.65.tar.gz/src/modules/module-avb.c
Changed
@@ -37,7 +37,6 @@ #include <spa/utils/json.h> #include <pipewire/impl.h> -#include <pipewire/private.h> #include <pipewire/i18n.h> #include "module-avb/avb.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-avb/avb.c -> pipewire-0.3.65.tar.gz/src/modules/module-avb/avb.c
Changed
@@ -75,8 +75,6 @@ goto error_free; } - impl->work_queue = pw_context_get_work_queue(context); - spa_list_init(&impl->servers); avdecc_server_new(impl, &props->dict);
View file
pipewire-0.3.64.tar.gz/src/modules/module-avb/internal.h -> pipewire-0.3.65.tar.gz/src/modules/module-avb/internal.h
Changed
@@ -45,7 +45,6 @@ unsigned do_disconnect:1; struct pw_properties *props; - struct pw_work_queue *work_queue; struct spa_list servers; };
View file
pipewire-0.3.64.tar.gz/src/modules/module-avb/maap.c -> pipewire-0.3.65.tar.gz/src/modules/module-avb/maap.c
Changed
@@ -27,7 +27,6 @@ #include <spa/utils/json.h> #include <pipewire/pipewire.h> -#include <pipewire/conf.h> #include "utils.h" #include "maap.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-client-node/client-node.c -> pipewire-0.3.65.tar.gz/src/modules/module-client-node/client-node.c
Changed
@@ -806,7 +806,7 @@ endptr = SPA_PTROFF(endptr, SPA_ROUND_UP_N(buffersi->metasj.size, 8), void); } for (j = 0; j < buffersi->n_datas; j++) { - struct spa_data *d = buffersi->datas; + struct spa_data *d = &buffersi->datasj; if (d->type == SPA_DATA_MemPtr) { if ((m = pw_mempool_find_ptr(impl->context->pool, d->data)) == NULL || m != mem)
View file
pipewire-0.3.65.tar.gz/src/modules/module-combine-stream.c
Added
@@ -0,0 +1,1063 @@ +/* PipeWire + * + * Copyright © 2023 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <limits.h> +#include <math.h> + +#include "config.h" + +#include <spa/utils/result.h> +#include <spa/utils/string.h> +#include <spa/utils/json.h> +#include <spa/utils/ringbuffer.h> +#include <spa/debug/types.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format-utils.h> +#include <spa/param/audio/raw.h> + +#include <pipewire/impl.h> +#include <pipewire/i18n.h> + +/** \page page_module_combine_stream PipeWire Module: Combine Stream + * + * The combine stream can make: + * + * - a new virtual sink that forwards audio to other sinks + * - a new virtual source that combines audio from other sources + * + * ## Module Options + * + * - `node.name`: a unique name for the stream + * - `node.description`: a human readable name for the stream + * - `combine.mode` = capture | playback | sink | source, default sink + * - `combine.props = {}`: properties to be passed to the sink/source + * - `stream.props = {}`: properties to be passed to the streams + * + * ## General options + * + * Options with well-known behavior. + * + * - \ref PW_KEY_REMOTE_NAME + * - \ref PW_KEY_AUDIO_CHANNELS + * - \ref SPA_KEY_AUDIO_POSITION + * - \ref PW_KEY_MEDIA_NAME + * - \ref PW_KEY_NODE_LATENCY + * - \ref PW_KEY_NODE_NAME + * - \ref PW_KEY_NODE_DESCRIPTION + * - \ref PW_KEY_NODE_GROUP + * - \ref PW_KEY_NODE_VIRTUAL + * - \ref PW_KEY_MEDIA_CLASS + * + * ## Stream options + * + * - `audio.position`: Set the stream channel map. By default this is the same channel + * map as the combine stream. + * - `combine.audio.position`: map the combine audio positions to the stream positions. + * combine input channels are mapped one-by-one to stream output channels. + * + * ## Example configuration + * + *\code{.unparsed} + * context.modules = + * { name = libpipewire-module-combine-stream + * args = { + * combine.mode = sink + * node.name = "combine_sink" + * node.description = "My Combine Sink" + * combine.props = { + * audio.position = FL FR + * } + * stream.props = { + * } + * stream.rules = + * { + * matches = + * # any of the items in matches needs to match, if one does, + * # actions are emited. + * { + * # all keys must match the value. ~ in value starts regex. + * #node.name = "~alsa_input.*" + * media.class = "Audio/Sink" + * } + * + * actions = { + * create-stream = { + * #combine.audio.position = FL FR + * #audio.position = FL FR + * } + * } + * } + * + * } + * } + * + *\endcode + * + * Below is an example configuration that makes a 5.1 virtual audio sink + * from 3 separate stereo sinks. + * + *\code{.unparsed} + * context.modules = + * { name = libpipewire-module-combine-stream + * args = { + * combine.mode = sink + * node.name = "combine_sink_5_1" + * node.description = "My 5.1 Combine Sink" + * combine.props = { + * audio.position = FL FR FC LFE SL SR + * } + * stream.props = { + * stream.dont-remix = true # link matching channels without remixing + * } + * stream.rules = + * { matches = + * { media.class = "Audio/Sink" + * node.name = "alsa_output.usb-Topping_E30-00.analog-stereo" + * } + * actions = { create-stream = { + * combine.audio.position = FL FR + * audio.position = FL FR + * } } } + * { matches = + * { media.class = "Audio/Sink" + * node.name = "alsa_output.usb-BEHRINGER_UMC404HD_192k-00.pro-output-0" + * } + * actions = { create-stream = { + * combine.audio.position = FC LFE + * audio.position = AUX0 AUX1 + * } } } + * { matches = + * { media.class = "Audio/Sink" + * node.name = "alsa_output.pci-0000_00_1b.0.analog-stereo" + * } + * actions = { create-stream = { + * combine.audio.position = SL SR + * audio.position = FL FR + * } } } + * + * } + * } + * + *\endcode + * + * Below is an example configuration that makes a 4.0 virtual audio source + * from 2 separate stereo sources. + * + *\code{.unparsed} + * context.modules = + * { name = libpipewire-module-combine-stream + * args = { + * combine.mode = source + * node.name = "combine_source_4_0" + * node.description = "My 4.0 Combine Source" + * combine.props = { + * audio.position = FL FR SL SR + * } + * stream.props = { + * stream.dont-remix = true + * } + * stream.rules = + * { matches = + * { media.class = "Audio/Source" + * node.name = "alsa_input.usb-046d_HD_Pro_Webcam_C920_09D53E1F-02.analog-stereo" + * } + * actions = { create-stream = { + * audio.position = FL FR + * combine.audio.position = FL FR + * } } } + * { matches = + * { media.class = "Audio/Source" + * node.name = "alsa_input.usb-046d_0821_9534DE90-00.analog-stereo" + * } + * actions = { create-stream = { + * audio.position = FL FR + * combine.audio.position = SL SR + * } } } + * + * } + * } + * + *\endcode + */ + +#define NAME "combine-stream" + +PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +#define PW_LOG_TOPIC_DEFAULT mod_topic + +#define DEFAULT_CHANNELS 2 +#define DEFAULT_POSITION " FL FR " + +#define MODULE_USAGE " node.latency=<latency as fraction> " \ + " combine.mode=<mode of stream, playback|capture|sink|source>, default:sink " \ + " node.name=<name of the stream> " \ + " node.description=<description of the stream> " \ + " audio.channels=<number of channels, default:"SPA_STRINGIFY(DEFAULT_CHANNELS) "> " \ + " audio.position=<channel map, default:"DEFAULT_POSITION"> " \ + " combine.props=<properties> " \ + " stream.props=<properties> " \ + " stream.rules=<properties> " + + +static const struct spa_dict_item module_props = { + { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, + { PW_KEY_MODULE_DESCRIPTION, "Combine multiple streams into a single stream" }, + { PW_KEY_MODULE_USAGE, MODULE_USAGE }, + { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, +}; + +struct impl { + struct pw_context *context; + struct pw_data_loop *data_loop; + + struct pw_properties *props; + +#define MODE_SINK 0 +#define MODE_SOURCE 1 +#define MODE_CAPTURE 2 +#define MODE_PLAYBACK 3 + uint32_t mode; + struct pw_impl_module *module; + + struct spa_hook module_listener; + + struct pw_core *core; + struct spa_hook core_proxy_listener; + struct spa_hook core_listener; + + struct pw_registry *registry; + struct spa_hook registry_listener; + + struct pw_properties *combine_props; + struct pw_stream *combine; + struct spa_hook combine_listener; + struct pw_stream_events combine_events; + uint32_t combine_id; + + struct pw_properties *stream_props; + + struct spa_audio_info_raw info; + + unsigned int do_disconnect:1; + + struct spa_list streams; + uint32_t n_streams; +}; + +struct stream { + uint32_t id; + + struct impl *impl; + + struct spa_list link; + struct pw_stream *stream; + struct spa_hook stream_listener; + struct pw_stream_events stream_events; + + struct spa_audio_info_raw info; + uint32_t remapSPA_AUDIO_MAX_CHANNELS; + + unsigned int ready:1; + unsigned int added:1; +}; + +static uint32_t channel_from_name(const char *name) +{ + int i; + for (i = 0; spa_type_audio_channeli.name; i++) { + if (spa_streq(name, spa_debug_type_short_name(spa_type_audio_channeli.name))) + return spa_type_audio_channeli.type; + } + return SPA_AUDIO_CHANNEL_UNKNOWN; +} + +static void parse_position(struct spa_audio_info_raw *info, const char *val, size_t len) +{ + struct spa_json it2; + char v256; + + spa_json_init(&it0, val, len); + if (spa_json_enter_array(&it0, &it1) <= 0) + spa_json_init(&it1, val, len); + + info->channels = 0; + while (spa_json_get_string(&it1, v, sizeof(v)) > 0 && + info->channels < SPA_AUDIO_MAX_CHANNELS) { + info->positioninfo->channels++ = channel_from_name(v); + } +} + +static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info) +{ + const char *str; + + spa_zero(*info); + info->format = SPA_AUDIO_FORMAT_F32P; + info->channels = pw_properties_get_uint32(props, PW_KEY_AUDIO_CHANNELS, 0); + info->channels = SPA_MIN(info->channels, SPA_AUDIO_MAX_CHANNELS); + if ((str = pw_properties_get(props, SPA_KEY_AUDIO_POSITION)) != NULL) + parse_position(info, str, strlen(str)); + if (info->channels == 0) + parse_position(info, DEFAULT_POSITION, strlen(DEFAULT_POSITION)); +} + +static struct stream *find_stream(struct impl *impl, uint32_t id) +{ + struct stream *s; + spa_list_for_each(s, &impl->streams, link) + if (s->id == id) + return s; + return NULL; +} + +static int do_add_stream(struct spa_loop *loop, bool async, uint32_t seq, + const void *data, size_t size, void *user_data) +{ + struct stream *s = user_data; + struct impl *impl = s->impl; + if (!s->added) { + spa_list_append(&impl->streams, &s->link); + impl->n_streams++; + s->added = true; + } + return 0; +} + +static int do_remove_stream(struct spa_loop *loop, bool async, uint32_t seq, + const void *data, size_t size, void *user_data) +{ + struct stream *s = user_data; + if (s->added) { + spa_list_remove(&s->link); + s->impl->n_streams--; + s->added = false; + } + return 0; +} + +static void destroy_stream(struct stream *s) +{ + pw_log_debug("destroy stream %d", s->id); + + pw_data_loop_invoke(s->impl->data_loop, do_remove_stream, 0, NULL, 0, true, s); + + if (s->stream) { + spa_hook_remove(&s->stream_listener); + pw_stream_destroy(s->stream); + } + free(s); +} + +static void stream_destroy(void *d) +{ + struct stream *s = d; + spa_hook_remove(&s->stream_listener); + s->stream = NULL; + destroy_stream(s); +} + +static void stream_input_process(void *d) +{ + struct stream *s = d, *t; + struct impl *impl = s->impl; + bool ready = true; + + s->ready = true; + pw_log_debug("stream ready %p", s); + spa_list_for_each(t, &impl->streams, link) { + if (!t->ready) { + ready = false; + break; + } + } + if (ready) { + pw_log_debug("do trigger"); + pw_stream_trigger_process(impl->combine); + } +} + +static void stream_state_changed(void *d, enum pw_stream_state old, + enum pw_stream_state state, const char *error) +{ + struct stream *s = d; + switch (state) { + case PW_STREAM_STATE_ERROR: + case PW_STREAM_STATE_UNCONNECTED: + stream_destroy(s); + break; + default: + break; + } +} + +static const struct pw_stream_events stream_events = { + PW_VERSION_STREAM_EVENTS, + .destroy = stream_destroy, + .state_changed = stream_state_changed, +}; + +struct stream_info { + struct impl *impl; + uint32_t id; + const struct spa_dict *props; + struct pw_properties *stream_props; +}; + +static int create_stream(struct stream_info *info) +{ + struct impl *impl = info->impl; + int res; + uint32_t n_params, i, j; + const struct spa_pod *params1; + const char *str, *node_name; + uint8_t buffer1024; + struct spa_pod_builder b; + struct spa_audio_info_raw remap_info, tmp_info; + struct stream *s; + enum pw_stream_flags flags; + enum pw_direction direction; + + node_name = spa_dict_lookup(info->props, "node.name"); + if (node_name == NULL) + node_name = spa_dict_lookup(info->props, "object.serial"); + if (node_name == NULL) + return -EIO; + + pw_log_info("create stream for %d %s", info->id, node_name); + + s = calloc(1, sizeof(*s)); + if (s == NULL) + goto error_errno; + + s->id = info->id; + s->impl = impl; + + s->info = impl->info; + if ((str = pw_properties_get(info->stream_props, SPA_KEY_AUDIO_POSITION)) != NULL) + parse_position(&s->info, str, strlen(str)); + if (s->info.channels == 0) + s->info = impl->info; + + spa_zero(remap_info); + if ((str = pw_properties_get(info->stream_props, "combine.audio.position")) != NULL) + parse_position(&remap_info, str, strlen(str)); + if (remap_info.channels == 0) + remap_info = s->info; + + tmp_info = impl->info; + for (i = 0; i < remap_info.channels; i++) { + s->remapi = i; + for (j = 0; j < tmp_info.channels; j++) { + if (tmp_info.positionj == remap_info.positioni) { + s->remapi = j; + break; + } + } + pw_log_info("remap %d -> %d", i, s->remapi); + } + + str = pw_properties_get(impl->props, PW_KEY_NODE_DESCRIPTION); + if (str == NULL) + str = pw_properties_get(impl->props, PW_KEY_NODE_NAME); + if (str == NULL) + str = node_name; + + if (pw_properties_get(info->stream_props, PW_KEY_MEDIA_NAME) == NULL) + pw_properties_setf(info->stream_props, PW_KEY_MEDIA_NAME, + "%s output", str); + if (pw_properties_get(info->stream_props, PW_KEY_NODE_DESCRIPTION) == NULL) + pw_properties_setf(info->stream_props, PW_KEY_NODE_DESCRIPTION, + "%s output", str); + + str = pw_properties_get(impl->props, PW_KEY_NODE_NAME); + if (str == NULL) + str = "combine_stream"; + + if (pw_properties_get(info->stream_props, PW_KEY_NODE_NAME) == NULL) + pw_properties_setf(info->stream_props, PW_KEY_NODE_NAME, + "output.%s_%s", str, node_name); + if (pw_properties_get(info->stream_props, PW_KEY_TARGET_OBJECT) == NULL) + pw_properties_set(info->stream_props, PW_KEY_TARGET_OBJECT, node_name); + + s->stream = pw_stream_new(impl->core, "Combine stream", info->stream_props); + info->stream_props = NULL; + if (s->stream == NULL) + goto error_errno; + + s->stream_events = stream_events; + + flags = PW_STREAM_FLAG_AUTOCONNECT | + PW_STREAM_FLAG_MAP_BUFFERS | + PW_STREAM_FLAG_RT_PROCESS; + + if (impl->mode == MODE_SINK || impl->mode == MODE_CAPTURE) { + direction = PW_DIRECTION_OUTPUT; + flags |= PW_STREAM_FLAG_TRIGGER; + } else { + direction = PW_DIRECTION_INPUT; + s->stream_events.process = stream_input_process; + } + + pw_stream_add_listener(s->stream, + &s->stream_listener, + &s->stream_events, s); + + n_params = 0; + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + paramsn_params++ = spa_format_audio_raw_build(&b, + SPA_PARAM_EnumFormat, &s->info); + + if ((res = pw_stream_connect(s->stream, + direction, PW_ID_ANY, flags, params, n_params)) < 0) + goto error; + + pw_data_loop_invoke(impl->data_loop, do_add_stream, 0, NULL, 0, true, s); + return 0; + +error_errno: + res = -errno; +error: + if (s) + destroy_stream(s); + return res; +} + +static int rule_matched(void *data, const char *location, const char *action, + const char *str, size_t len) +{ + struct stream_info *i = data; + struct impl *impl = i->impl; + int res = 0; + + if (spa_streq(action, "create-stream")) { + i->stream_props = pw_properties_copy(impl->stream_props); + + pw_properties_update_string(i->stream_props, str, len); + + res = create_stream(i); + + pw_properties_free(i->stream_props); + } + + return res; +} + +static void registry_event_global(void *data, uint32_t id, + uint32_t permissions, const char *type, uint32_t version, + const struct spa_dict *props) +{ + struct impl *impl = data; + const char *str; + struct stream_info info; + + if (!spa_streq(type, PW_TYPE_INTERFACE_Node) || props == NULL) + return; + + if (id == impl->combine_id) + return; + + spa_zero(info); + info.impl = impl; + info.id = id; + info.props = props; + + str = pw_properties_get(impl->props, "stream.rules"); + if (str == NULL) { + if (impl->mode == MODE_CAPTURE || impl->mode == MODE_SINK) + str = " { matches = { media.class = \"Audio/Sink\" } " + " actions = { create-stream = {} } } "; + else if (impl->mode == MODE_PLAYBACK || impl->mode == MODE_SOURCE) + str = " { matches = { media.class = \"Audio/Source\" } " + " actions = { create-stream = {} } } "; + } + pw_conf_match_rules(str, strlen(str), NAME, props, rule_matched, &info); +} + +static void registry_event_global_remove(void *data, uint32_t id) +{ + struct impl *impl = data; + struct stream *s; + + s = find_stream(impl, id); + if (s == NULL) + return; + + destroy_stream(s); +} + +static const struct pw_registry_events registry_events = { + PW_VERSION_REGISTRY_EVENTS, + .global = registry_event_global, + .global_remove = registry_event_global_remove, +}; + +static void combine_destroy(void *d) +{ + struct impl *impl = d; + spa_hook_remove(&impl->combine_listener); + impl->combine = NULL; +} + +static void combine_state_changed(void *d, enum pw_stream_state old, + enum pw_stream_state state, const char *error) +{ + struct impl *impl = d; + switch (state) { + case PW_STREAM_STATE_ERROR: + case PW_STREAM_STATE_UNCONNECTED: + pw_impl_module_schedule_destroy(impl->module); + break; + case PW_STREAM_STATE_PAUSED: + impl->combine_id = pw_stream_get_node_id(impl->combine); + pw_log_info("got combine id %d", impl->combine_id); + break; + case PW_STREAM_STATE_STREAMING: + break; + default: + break; + } +} + +static void combine_input_process(void *d) +{ + struct impl *impl = d; + struct pw_buffer *in, *out; + struct stream *s; + + if ((in = pw_stream_dequeue_buffer(impl->combine)) == NULL) { + pw_log_debug("out of buffers: %m"); + return; + } + + spa_list_for_each(s, &impl->streams, link) { + uint32_t j; + + if (s->stream == NULL) + continue; + + if ((out = pw_stream_dequeue_buffer(s->stream)) == NULL) { + pw_log_warn("out of playback buffers: %m"); + goto do_trigger; + } + + for (j = 0; j < out->buffer->n_datas; j++) { + struct spa_data *ds, *dd; + uint32_t outsize = 0, remap; + int32_t stride = 0; + + dd = &out->buffer->datasj; + + remap = s->remapj; + if (remap < in->buffer->n_datas) { + uint32_t offs, size; + + ds = &in->buffer->datasremap; + + offs = SPA_MIN(ds->chunk->offset, ds->maxsize); + size = SPA_MIN(ds->chunk->size, ds->maxsize - offs); + + memcpy(dd->data, + SPA_PTROFF(ds->data, offs, void), size); + + outsize = SPA_MAX(outsize, size); + stride = SPA_MAX(stride, ds->chunk->stride); + } else { + memset(dd->data, 0, outsize); + } + dd->chunk->offset = 0; + dd->chunk->size = outsize; + dd->chunk->stride = stride; + } + pw_stream_queue_buffer(s->stream, out); +do_trigger: + pw_stream_trigger_process(s->stream); + } + pw_stream_queue_buffer(impl->combine, in); +} + +static void combine_output_process(void *d) +{ + struct impl *impl = d; + struct pw_buffer *in, *out; + struct stream *s; + + if ((out = pw_stream_dequeue_buffer(impl->combine)) == NULL) { + pw_log_debug("out of buffers: %m"); + return; + } + + spa_list_for_each(s, &impl->streams, link) { + uint32_t j; + + if (s->stream == NULL) + continue; + + if ((in = pw_stream_dequeue_buffer(s->stream)) == NULL) { + pw_log_warn("%p: out of capture buffers: %m", s); + continue; + } + s->ready = false; + + for (j = 0; j < in->buffer->n_datas; j++) { + struct spa_data *ds, *dd; + uint32_t outsize = 0, remap; + int32_t stride = 0; + + ds = &in->buffer->datasj; + + /* FIXME, need to do mixing for overlapping streams */ + remap = s->remapj; + if (remap < out->buffer->n_datas) { + uint32_t offs, size; + + dd = &out->buffer->datasremap; + + offs = SPA_MIN(ds->chunk->offset, ds->maxsize); + size = SPA_MIN(ds->chunk->size, ds->maxsize - offs); + size = SPA_MIN(size, dd->maxsize); + + memcpy(dd->data, + SPA_PTROFF(ds->data, offs, void), size); + + outsize = SPA_MAX(outsize, size); + stride = SPA_MAX(stride, ds->chunk->stride); + + dd->chunk->offset = 0; + dd->chunk->size = outsize; + dd->chunk->stride = stride; + } + } + pw_stream_queue_buffer(s->stream, in); + } + pw_stream_queue_buffer(impl->combine, out); +} + +static const struct pw_stream_events combine_events = { + PW_VERSION_STREAM_EVENTS, + .destroy = combine_destroy, + .state_changed = combine_state_changed, +}; + +static int create_combine(struct impl *impl) +{ + int res; + uint32_t n_params; + const struct spa_pod *params1; + uint8_t buffer1024; + struct spa_pod_builder b; + enum pw_direction direction; + enum pw_stream_flags flags; + + impl->combine = pw_stream_new(impl->core, "Combine stream", impl->combine_props); + impl->combine_props = NULL; + + if (impl->combine == NULL) + return -errno; + + flags = PW_STREAM_FLAG_AUTOCONNECT | + PW_STREAM_FLAG_MAP_BUFFERS | + PW_STREAM_FLAG_RT_PROCESS; + + impl->combine_events = combine_events; + + if (impl->mode == MODE_SINK || impl->mode == MODE_CAPTURE) { + direction = PW_DIRECTION_INPUT; + impl->combine_events.process = combine_input_process; + } else { + direction = PW_DIRECTION_OUTPUT; + impl->combine_events.process = combine_output_process; + flags |= PW_STREAM_FLAG_TRIGGER; + } + + pw_stream_add_listener(impl->combine, + &impl->combine_listener, + &impl->combine_events, impl); + + n_params = 0; + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + paramsn_params++ = spa_format_audio_raw_build(&b, + SPA_PARAM_EnumFormat, &impl->info); + + if ((res = pw_stream_connect(impl->combine, + direction, PW_ID_ANY, flags, params, n_params)) < 0) + return res; + + return 0; +} + +static void core_error(void *data, uint32_t id, int seq, int res, const char *message) +{ + struct impl *impl = data; + + pw_log_error("error id:%u seq:%d res:%d (%s): %s", + id, seq, res, spa_strerror(res), message); + + if (id == PW_ID_CORE && res == -EPIPE) + pw_impl_module_schedule_destroy(impl->module); +} + +static const struct pw_core_events core_events = { + PW_VERSION_CORE_EVENTS, + .error = core_error, +}; + +static void core_removed(void *d) +{ + struct impl *impl = d; + if (impl->core) { + spa_hook_remove(&impl->core_listener); + impl->core = NULL; + } + if (impl->registry) { + spa_hook_remove(&impl->registry_listener); + pw_proxy_destroy((struct pw_proxy*)impl->registry); + impl->registry = NULL; + } + pw_impl_module_schedule_destroy(impl->module); +} + +static const struct pw_proxy_events core_proxy_events = { + .removed = core_removed, +}; + +static void impl_destroy(struct impl *impl) +{ + struct stream *s; + + spa_list_consume(s, &impl->streams, link) + destroy_stream(s); + + if (impl->combine) + pw_stream_destroy(impl->combine); + + if (impl->registry) { + spa_hook_remove(&impl->registry_listener); + pw_proxy_destroy((struct pw_proxy*)impl->registry); + impl->registry = NULL; + } + if (impl->core) { + spa_hook_remove(&impl->core_listener); + if (impl->do_disconnect) + pw_core_disconnect(impl->core); + impl->core = NULL; + } + + pw_properties_free(impl->stream_props); + pw_properties_free(impl->combine_props); + pw_properties_free(impl->props); + + free(impl); +} + +static void module_destroy(void *data) +{ + struct impl *impl = data; + spa_hook_remove(&impl->module_listener); + impl_destroy(impl); +} + +static const struct pw_impl_module_events module_events = { + PW_VERSION_IMPL_MODULE_EVENTS, + .destroy = module_destroy, +}; + +static void copy_props(const struct pw_properties *props, struct pw_properties *target, + const char *key) +{ + const char *str; + if ((str = pw_properties_get(props, key)) != NULL) { + if (pw_properties_get(target, key) == NULL) + pw_properties_set(target, key, str); + } +} + +SPA_EXPORT +int pipewire__module_init(struct pw_impl_module *module, const char *args) +{ + struct pw_context *context = pw_impl_module_get_context(module); + struct pw_properties *props = NULL; + uint32_t id = pw_global_get_id(pw_impl_module_get_global(module)); + uint32_t pid = getpid(); + struct impl *impl; + const char *str, *prefix; + int res; + + PW_LOG_TOPIC_INIT(mod_topic); + + impl = calloc(1, sizeof(struct impl)); + if (impl == NULL) + return -errno; + + pw_log_debug("module %p: new %s", impl, args); + impl->data_loop = pw_context_get_data_loop(context); + + spa_list_init(&impl->streams); + + if (args == NULL) + args = ""; + + props = pw_properties_new_string(args); + if (props == NULL) { + res = -errno; + pw_log_error( "can't create properties: %m"); + goto error; + } + impl->props = props; + + if ((str = pw_properties_get(props, "combine.mode")) == NULL) + str = "sink"; + + if (spa_streq(str, "sink")) { + impl->mode = MODE_SINK; + prefix = "sink"; + } else if (spa_streq(str, "capture")) { + impl->mode = MODE_CAPTURE; + prefix = "capture"; + } else if (spa_streq(str, "source")) { + impl->mode = MODE_SOURCE; + prefix = "source"; + } else if (spa_streq(str, "playback")) { + impl->mode = MODE_PLAYBACK; + prefix = "playback"; + } else { + pw_log_warn("unknown combine.mode '%s', using 'sink'", str); + impl->mode = MODE_SINK; + prefix = "sink"; + } + + impl->combine_props = pw_properties_new(NULL, NULL); + impl->stream_props = pw_properties_new(NULL, NULL); + if (impl->combine_props == NULL || impl->stream_props == NULL) { + res = -errno; + pw_log_error( "can't create properties: %m"); + goto error; + } + + impl->module = module; + impl->context = context; + + if (pw_properties_get(props, PW_KEY_NODE_GROUP) == NULL) + pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine-%s-%u-%u", + prefix, pid, id); + if (pw_properties_get(props, PW_KEY_NODE_LINK_GROUP) == NULL) + pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine-%s-%u-%u", + prefix, pid, id); + if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL) + pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); + if (pw_properties_get(props, "resample.prefill") == NULL) + pw_properties_set(props, "resample.prefill", "true"); + + if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL) { + if (impl->mode == MODE_SINK) + pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink"); + else if (impl->mode == MODE_SOURCE) + pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Source"); + } + + if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL) + pw_properties_setf(props, PW_KEY_NODE_NAME, "combine-%s-%u-%u", + prefix, pid, id); + if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL) + pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, + "Combine %s", prefix); + + if ((str = pw_properties_get(props, "combine.props")) != NULL) + pw_properties_update_string(impl->combine_props, str, strlen(str)); + if ((str = pw_properties_get(props, "stream.props")) != NULL) + pw_properties_update_string(impl->stream_props, str, strlen(str)); + + copy_props(props, impl->combine_props, PW_KEY_AUDIO_CHANNELS); + copy_props(props, impl->combine_props, SPA_KEY_AUDIO_POSITION); + copy_props(props, impl->combine_props, PW_KEY_NODE_NAME); + copy_props(props, impl->combine_props, PW_KEY_NODE_DESCRIPTION); + copy_props(props, impl->combine_props, PW_KEY_NODE_GROUP); + copy_props(props, impl->combine_props, PW_KEY_NODE_LINK_GROUP); + copy_props(props, impl->combine_props, PW_KEY_NODE_LATENCY); + copy_props(props, impl->combine_props, PW_KEY_NODE_VIRTUAL); + copy_props(props, impl->combine_props, PW_KEY_MEDIA_CLASS); + copy_props(props, impl->combine_props, "resample.prefill"); + + parse_audio_info(impl->combine_props, &impl->info); + + copy_props(props, impl->stream_props, PW_KEY_NODE_GROUP); + copy_props(props, impl->stream_props, PW_KEY_NODE_VIRTUAL); + copy_props(props, impl->stream_props, PW_KEY_NODE_LINK_GROUP); + copy_props(props, impl->stream_props, "resample.prefill"); + + if (pw_properties_get(impl->stream_props, PW_KEY_MEDIA_ROLE) == NULL) + pw_properties_set(props, PW_KEY_MEDIA_ROLE, "filter"); + if (pw_properties_get(impl->stream_props, PW_KEY_NODE_PASSIVE) == NULL) + pw_properties_set(impl->stream_props, PW_KEY_NODE_PASSIVE, "true"); + if (pw_properties_get(impl->stream_props, PW_KEY_NODE_DONT_RECONNECT) == NULL) + pw_properties_set(impl->stream_props, PW_KEY_NODE_DONT_RECONNECT, "true"); + + impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core); + if (impl->core == NULL) { + str = pw_properties_get(props, PW_KEY_REMOTE_NAME); + impl->core = pw_context_connect(impl->context, + pw_properties_new( + PW_KEY_REMOTE_NAME, str, + NULL), + 0); + impl->do_disconnect = true; + } + if (impl->core == NULL) { + res = -errno; + pw_log_error("can't connect: %m"); + goto error; + } + + pw_proxy_add_listener((struct pw_proxy*)impl->core, + &impl->core_proxy_listener, + &core_proxy_events, impl); + pw_core_add_listener(impl->core, + &impl->core_listener, + &core_events, impl); + + if ((res = create_combine(impl)) < 0) + goto error; + + impl->registry = pw_core_get_registry(impl->core, PW_VERSION_REGISTRY, 0); + pw_registry_add_listener(impl->registry, &impl->registry_listener, + ®istry_events, impl); + + pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl); + + pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props)); + + return 0; + +error: + impl_destroy(impl); + return res; +}
View file
pipewire-0.3.64.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.65.tar.gz/src/modules/module-echo-cancel.c
Changed
@@ -38,10 +38,10 @@ #include <sys/stat.h> #include <unistd.h> -#include <spa/debug/pod.h> +#include <spa/debug/types.h> #include <spa/param/audio/format-utils.h> #include <spa/param/audio/raw.h> -#include <spa/param/profiler.h> +#include <spa/param/latency-utils.h> #include <spa/pod/builder.h> #include <spa/pod/dynamic.h> #include <spa/support/plugin.h> @@ -53,7 +53,6 @@ #include <spa/support/plugin-loader.h> #include <spa/interfaces/audio/aec.h> -#include <pipewire/private.h> #include <pipewire/impl.h> #include <pipewire/pipewire.h> @@ -76,6 +75,8 @@ * - `library.name = <str>`: the echo cancellation library Currently supported: * `aec/libspa-aec-webrtc`. Leave unset to use the default method (`aec/libspa-aec-webrtc`). * - `aec.args = <str>`: arguments to pass to the echo cancellation method + * - `monitor.mode`: Instead of making a sink, make a stream that captures from + * the monitor ports of the default sink. * * ## General options * @@ -101,6 +102,7 @@ * args = { * # library.name = aec/libspa-aec-webrtc * # node.latency = 1024/48000 + * # monitor.mode = false * capture.props = { * node.name = "Echo Cancellation Capture" * } @@ -177,10 +179,12 @@ struct pw_properties *capture_props; struct pw_stream *capture; struct spa_hook capture_listener; + struct spa_audio_info_raw capture_info; struct pw_properties *source_props; struct pw_stream *source; struct spa_hook source_listener; + struct spa_audio_info_raw source_info; void *rec_bufferSPA_AUDIO_MAX_CHANNELS; uint32_t rec_ringsize; @@ -189,6 +193,7 @@ struct pw_properties *playback_props; struct pw_stream *playback; struct spa_hook playback_listener; + struct spa_audio_info_raw playback_info; struct pw_properties *sink_props; struct pw_stream *sink; @@ -197,6 +202,7 @@ uint32_t play_ringsize; struct spa_ringbuffer play_ring; struct spa_ringbuffer play_delayed_ring; + struct spa_audio_info_raw sink_info; void *out_bufferSPA_AUDIO_MAX_CHANNELS; uint32_t out_ringsize; @@ -826,7 +832,7 @@ spa_pod_dynamic_builder_init(&b, NULL, 0, 4096); offsetsn_params++ = b.b.state.offset; - spa_format_audio_raw_build(&b.b, SPA_PARAM_EnumFormat, &impl->info); + spa_format_audio_raw_build(&b.b, SPA_PARAM_EnumFormat, &impl->capture_info); int nbr_of_external_props = spa_audio_aec_enum_props(impl->aec, 0, NULL); if (nbr_of_external_props > 0) { @@ -837,9 +843,8 @@ get_props_param(impl, &b.b); } - for (i = 0; i < n_params; i++) { + for (i = 0; i < n_params; i++) paramsi = spa_pod_builder_deref(&b.b, offsetsi); - } if ((res = pw_stream_connect(impl->capture, PW_DIRECTION_INPUT, @@ -852,6 +857,12 @@ return res; } + offsets0 = b.b.state.offset; + spa_format_audio_raw_build(&b.b, SPA_PARAM_EnumFormat, &impl->source_info); + + for (i = 0; i < n_params; i++) + paramsi = spa_pod_builder_deref(&b.b, offsetsi); + if ((res = pw_stream_connect(impl->source, PW_DIRECTION_OUTPUT, PW_ID_ANY, @@ -862,6 +873,12 @@ return res; } + offsets0 = b.b.state.offset; + spa_format_audio_raw_build(&b.b, SPA_PARAM_EnumFormat, &impl->sink_info); + + for (i = 0; i < n_params; i++) + paramsi = spa_pod_builder_deref(&b.b, offsetsi); + if ((res = pw_stream_connect(impl->sink, PW_DIRECTION_INPUT, PW_ID_ANY, @@ -873,6 +890,12 @@ return res; } + offsets0 = b.b.state.offset; + spa_format_audio_raw_build(&b.b, SPA_PARAM_EnumFormat, &impl->playback_info); + + for (i = 0; i < n_params; i++) + paramsi = spa_pod_builder_deref(&b.b, offsetsi); + if (impl->playback != NULL && (res = pw_stream_connect(impl->playback, PW_DIRECTION_OUTPUT, PW_ID_ANY, @@ -1104,6 +1127,11 @@ parse_audio_info(props, &impl->info); + impl->capture_info = impl->info; + impl->source_info = impl->info; + impl->sink_info = impl->info; + impl->playback_info = impl->info; + if ((str = pw_properties_get(props, "capture.props")) != NULL) pw_properties_update_string(impl->capture_props, str, strlen(str)); if ((str = pw_properties_get(props, "source.props")) != NULL) @@ -1157,17 +1185,21 @@ if ((path = pw_properties_get(props, "library.name")) == NULL) path = "aec/libspa-aec-webrtc"; - struct spa_dict_item info_items = { - { SPA_KEY_LIBRARY_NAME, path }, - }; - struct spa_dict info = SPA_DICT_INIT_ARRAY(info_items); + const struct spa_support *support; + uint32_t n_support; - impl->loader = spa_support_find(context->support, context->n_support, SPA_TYPE_INTERFACE_PluginLoader); + support = pw_context_get_support(context, &n_support); + impl->loader = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_PluginLoader); if (impl->loader == NULL) { pw_log_error("a plugin loader is needed"); return -EINVAL; } + struct spa_dict_item info_items = { + { SPA_KEY_LIBRARY_NAME, path }, + }; + struct spa_dict info = SPA_DICT_INIT_ARRAY(info_items); + handle = spa_plugin_loader_load(impl->loader, SPA_NAME_AEC, &info); if (handle == NULL) { pw_log_error("aec plugin %s not available library.name %s", SPA_NAME_AEC, path); @@ -1257,6 +1289,24 @@ copy_props(impl, props, SPA_KEY_AUDIO_POSITION); copy_props(impl, props, "resample.prefill"); + if ((str = pw_properties_get(impl->capture_props, SPA_KEY_AUDIO_POSITION)) != NULL) + parse_position(&impl->capture_info, str, strlen(str)); + if ((str = pw_properties_get(impl->source_props, SPA_KEY_AUDIO_POSITION)) != NULL) + parse_position(&impl->source_info, str, strlen(str)); + if ((str = pw_properties_get(impl->sink_props, SPA_KEY_AUDIO_POSITION)) != NULL) + parse_position(&impl->sink_info, str, strlen(str)); + if ((str = pw_properties_get(impl->playback_props, SPA_KEY_AUDIO_POSITION)) != NULL) + parse_position(&impl->playback_info, str, strlen(str)); + + if (impl->capture_info.channels != impl->info.channels) + impl->capture_info = impl->info; + if (impl->source_info.channels != impl->info.channels) + impl->source_info = impl->info; + if (impl->sink_info.channels != impl->info.channels) + impl->sink_info = impl->info; + if (impl->playback_info.channels != impl->info.channels) + impl->playback_info = impl->info; + impl->max_buffer_size = pw_properties_get_uint32(props,"buffer.max_size", MAX_BUFSIZE_MS); if ((str = pw_properties_get(props, "buffer.play_delay")) != NULL) {
View file
pipewire-0.3.64.tar.gz/src/modules/module-example-sink.c -> pipewire-0.3.65.tar.gz/src/modules/module-example-sink.c
Changed
@@ -40,7 +40,7 @@ #include <spa/utils/string.h> #include <spa/utils/json.h> #include <spa/utils/ringbuffer.h> -#include <spa/debug/pod.h> +#include <spa/debug/types.h> #include <spa/pod/builder.h> #include <spa/param/audio/format-utils.h> #include <spa/param/audio/raw.h> @@ -126,7 +126,6 @@ struct pw_properties *props; struct pw_impl_module *module; - struct pw_work_queue *work; struct spa_hook module_listener; @@ -141,23 +140,8 @@ uint32_t frame_size; unsigned int do_disconnect:1; - unsigned int unloading:1; }; -static void do_unload_module(void *obj, void *data, int res, uint32_t id) -{ - struct impl *impl = data; - pw_impl_module_destroy(impl->module); -} - -static void unload_module(struct impl *impl) -{ - if (!impl->unloading) { - impl->unloading = true; - pw_work_queue_add(impl->work, impl, 0, do_unload_module, impl); - } -} - static void stream_destroy(void *d) { struct impl *impl = d; @@ -172,7 +156,7 @@ switch (state) { case PW_STREAM_STATE_ERROR: case PW_STREAM_STATE_UNCONNECTED: - unload_module(impl); + pw_impl_module_schedule_destroy(impl->module); break; case PW_STREAM_STATE_PAUSED: case PW_STREAM_STATE_STREAMING: @@ -257,7 +241,7 @@ id, seq, res, spa_strerror(res), message); if (id == PW_ID_CORE && res == -EPIPE) - unload_module(impl); + pw_impl_module_schedule_destroy(impl->module); } static const struct pw_core_events core_events = { @@ -270,7 +254,7 @@ struct impl *impl = d; spa_hook_remove(&impl->core_listener); impl->core = NULL; - unload_module(impl); + pw_impl_module_schedule_destroy(impl->module); } static const struct pw_proxy_events core_proxy_events = { @@ -287,15 +271,12 @@ pw_properties_free(impl->stream_props); pw_properties_free(impl->props); - if (impl->work) - pw_work_queue_cancel(impl->work, impl, SPA_ID_INVALID); free(impl); } static void module_destroy(void *data) { struct impl *impl = data; - impl->unloading = true; spa_hook_remove(&impl->module_listener); impl_destroy(impl); } @@ -444,7 +425,6 @@ impl->module = module; impl->context = context; - impl->work = pw_context_get_work_queue(context); if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL) pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
View file
pipewire-0.3.64.tar.gz/src/modules/module-example-source.c -> pipewire-0.3.65.tar.gz/src/modules/module-example-source.c
Changed
@@ -40,7 +40,7 @@ #include <spa/utils/string.h> #include <spa/utils/json.h> #include <spa/utils/ringbuffer.h> -#include <spa/debug/pod.h> +#include <spa/debug/types.h> #include <spa/pod/builder.h> #include <spa/param/audio/format-utils.h> #include <spa/param/audio/raw.h> @@ -126,7 +126,6 @@ struct pw_properties *props; struct pw_impl_module *module; - struct pw_work_queue *work; struct spa_hook module_listener; @@ -144,20 +143,6 @@ unsigned int unloading:1; }; -static void do_unload_module(void *obj, void *data, int res, uint32_t id) -{ - struct impl *impl = data; - pw_impl_module_destroy(impl->module); -} - -static void unload_module(struct impl *impl) -{ - if (!impl->unloading) { - impl->unloading = true; - pw_work_queue_add(impl->work, impl, 0, do_unload_module, impl); - } -} - static void stream_destroy(void *d) { struct impl *impl = d; @@ -172,7 +157,7 @@ switch (state) { case PW_STREAM_STATE_ERROR: case PW_STREAM_STATE_UNCONNECTED: - unload_module(impl); + pw_impl_module_schedule_destroy(impl->module); break; case PW_STREAM_STATE_PAUSED: case PW_STREAM_STATE_STREAMING: @@ -261,7 +246,7 @@ id, seq, res, spa_strerror(res), message); if (id == PW_ID_CORE && res == -EPIPE) - unload_module(impl); + pw_impl_module_schedule_destroy(impl->module); } static const struct pw_core_events core_events = { @@ -274,7 +259,7 @@ struct impl *impl = d; spa_hook_remove(&impl->core_listener); impl->core = NULL; - unload_module(impl); + pw_impl_module_schedule_destroy(impl->module); } static const struct pw_proxy_events core_proxy_events = { @@ -291,8 +276,6 @@ pw_properties_free(impl->stream_props); pw_properties_free(impl->props); - if (impl->work) - pw_work_queue_cancel(impl->work, impl, SPA_ID_INVALID); free(impl); } @@ -448,7 +431,6 @@ impl->module = module; impl->context = context; - impl->work = pw_context_get_work_queue(context); if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL) pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
View file
pipewire-0.3.64.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.65.tar.gz/src/modules/module-filter-chain.c
Changed
@@ -39,12 +39,11 @@ #include <spa/utils/string.h> #include <spa/utils/json.h> #include <spa/support/cpu.h> -#include <spa/param/profiler.h> +#include <spa/param/latency-utils.h> #include <spa/pod/dynamic.h> -#include <spa/debug/pod.h> +#include <spa/debug/types.h> #include <pipewire/utils.h> -#include <pipewire/private.h> #include <pipewire/impl.h> #include <pipewire/extensions/profiler.h> @@ -2337,6 +2336,18 @@ parse_audio_info(impl->capture_props, &impl->capture_info); parse_audio_info(impl->playback_props, &impl->playback_info); + if (impl->capture_info.rate && !impl->playback_info.rate) + impl->playback_info.rate = impl->capture_info.rate; + else if (impl->playback_info.rate && !impl->capture_info.rate) + impl->capture_info.rate = !impl->playback_info.rate; + else if (impl->capture_info.rate != impl->playback_info.rate) { + pw_log_warn("Both capture and playback rate are set, but" + " they are different. Using the highest of two. This behaviour" + " is deprecated, please use equal rates in the module config"); + impl->playback_info.rate = impl->capture_info.rate = + SPA_MAX(impl->playback_info.rate, impl->capture_info.rate); + } + if ((str = pw_properties_get(props, PW_KEY_NODE_NAME)) == NULL) { pw_properties_setf(props, PW_KEY_NODE_NAME, "filter-chain-%u-%u", pid, id);
View file
pipewire-0.3.64.tar.gz/src/modules/module-filter-chain/builtin_plugin.c -> pipewire-0.3.65.tar.gz/src/modules/module-filter-chain/builtin_plugin.c
Changed
@@ -44,6 +44,8 @@ #include "convolver.h" #include "dsp-ops.h" +#define MAX_RATES 32u + static struct dsp_ops *dsp_ops; struct builtin { @@ -439,22 +441,12 @@ struct convolver *conv; }; -static float *read_samples(const char *filename, float gain, int delay, int offset, - int length, int channel, long unsigned *rate, int *n_samples) -{ - float *samples; #ifdef HAVE_SNDFILE - SF_INFO info; - SNDFILE *f; +static float *read_samples_from_sf(SNDFILE *f, SF_INFO info, float gain, int delay, + int offset, int length, int channel, long unsigned *rate, int *n_samples) { + float *samples; int i, n; - spa_zero(info); - f = sf_open(filename, SFM_READ, &info) ; - if (f == NULL) { - pw_log_error("can't open %s", filename); - return NULL; - } - if (length <= 0) length = info.frames; else @@ -467,13 +459,12 @@ return NULL; samples = calloc(n * info.channels, sizeof(float)); - if (samples == NULL) + if (samples == NULL) return NULL; if (offset > 0) sf_seek(f, offset, SEEK_SET); sf_readf_float(f, samples + (delay * info.channels), length); - sf_close(f); channel = channel % info.channels; @@ -483,10 +474,47 @@ *n_samples = n; *rate = info.samplerate; return samples; +} +#endif + +static float *read_closest(char **filenames, float gain, int delay, int offset, + int length, int channel, long unsigned *rate, int *n_samples) +{ +#ifdef HAVE_SNDFILE + SF_INFO infosMAX_RATES; + SNDFILE *fsMAX_RATES; + + spa_zero(infos); + spa_zero(fs); + + int diff = INT_MAX; + uint32_t best = 0, i; + + for (i = 0; i < MAX_RATES && filenamesi && filenamesi0; i++) { + fsi = sf_open(filenamesi, SFM_READ, &infosi); + if (!fsi) + continue; + + if (labs((long)infosi.samplerate - (long)*rate) < diff) { + best = i; + diff = labs((long)infosi.samplerate - (long)*rate); + pw_log_debug("new closest match: %d", infosi.samplerate); + } + } + + pw_log_debug("loading %s", filenamesbest); + float *samples = read_samples_from_sf(fsbest, infosbest, gain, delay, + offset, length, channel, rate, n_samples); + + for (i = 0; i < MAX_RATES; i++) + if (fsi) + sf_close(fsi); + + return samples; #else pw_log_error("compiled without sndfile support, can't load samples: " "using dirac impulse"); - samples = calloc(1, sizeof(float)); + float *samples = calloc(1, sizeof(float)); samples0 = gain; *n_samples = 1; return samples; @@ -597,6 +625,11 @@ resample_free(&r); *n_samples = total_out; + + float gain = (float)in_rate / (float)out_rate; + for (uint32_t i = 0; i < total_out; i++) + out_samplesi = out_samplesi * gain; + return out_samples; error: @@ -611,11 +644,12 @@ { struct convolver_impl *impl; float *samples; - int offset = 0, length = 0, channel = index, n_samples; - struct spa_json it2; + int offset = 0, length = 0, channel = index, n_samples, len; + uint32_t i = 0; + struct spa_json it3; const char *val; - char key256; - char filenamePATH_MAX = ""; + char key256, v256; + char *filenamesMAX_RATES = { 0 }; int blocksize = 0, tailsize = 0; int delay = 0; int resample_quality = RESAMPLE_DEFAULT_QUALITY; @@ -656,10 +690,24 @@ } } else if (spa_streq(key, "filename")) { - if (spa_json_get_string(&it1, filename, sizeof(filename)) <= 0) { - pw_log_error("convolver:filename requires a string"); + if ((len = spa_json_next(&it1, &val)) <= 0) { + pw_log_error("convolver:filename requires a string or an array"); return NULL; } + if (spa_json_is_array(val, len)) { + spa_json_enter(&it1, &it2); + while (spa_json_get_string(&it2, v, sizeof(v)) > 0 && + i < SPA_N_ELEMENTS(filenames)) { + filenamesi = strdup(v); + i++; + } + } + else if (spa_json_parse_stringn(val, len, v, sizeof(v)) <= 0) { + pw_log_error("convolver:filename requires a string or an array"); + return NULL; + } else { + filenamesi = strdup(v); + } } else if (spa_streq(key, "offset")) { if (spa_json_get_int(&it1, &offset) <= 0) { @@ -688,7 +736,7 @@ else if (spa_json_next(&it1, &val) < 0) break; } - if (!filename0) { + if (filenames0 == NULL) { pw_log_error("convolver:filename was not given"); return NULL; } @@ -698,17 +746,17 @@ if (offset < 0) offset = 0; - if (spa_streq(filename, "/hilbert")) { - samples = create_hilbert(filename, gain, delay, offset, + if (spa_streq(filenames0, "/hilbert")) { + samples = create_hilbert(filenames0, gain, delay, offset, length, &n_samples); - } else if (spa_streq(filename, "/dirac")) { - samples = create_dirac(filename, gain, delay, offset, + } else if (spa_streq(filenames0, "/dirac")) { + samples = create_dirac(filenames0, gain, delay, offset, length, &n_samples); } else { rate = SampleRate; - samples = read_samples(filename, gain, delay, offset, + samples = read_closest(filenames, gain, delay, offset, length, channel, &rate, &n_samples); - if (rate != SampleRate) + if (samples != NULL && rate != SampleRate) samples = resample_buffer(samples, &n_samples, rate, SampleRate, resample_quality); } @@ -717,13 +765,17 @@ return NULL; } + for (i = 0; i < MAX_RATES; i++) + if (filenamesi) + free(filenamesi); + if (blocksize <= 0) blocksize = SPA_CLAMP(n_samples, 64, 256); if (tailsize <= 0) tailsize = SPA_CLAMP(4096, blocksize, 32768); - pw_log_info("using n_samples:%u %d:%d blocksize ir:%s", n_samples, - blocksize, tailsize, filename); + pw_log_info("using n_samples:%u %d:%d blocksize", n_samples, + blocksize, tailsize); impl = calloc(1, sizeof(*impl)); if (impl == NULL)
View file
pipewire-0.3.64.tar.gz/src/modules/module-filter-chain/dsp-ops-avx.c -> pipewire-0.3.65.tar.gz/src/modules/module-filter-chain/dsp-ops-avx.c
Changed
@@ -59,7 +59,7 @@ _mm256_store_ps(&rn+24, in3); } } else { - for (n = 0; n < unrolled; n += 16) { + for (n = 0; n < unrolled; n += 32) { in0 = _mm256_loadu_ps(&an+ 0); in1 = _mm256_loadu_ps(&an+ 8); in2 = _mm256_loadu_ps(&an+16);
View file
pipewire-0.3.64.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.65.tar.gz/src/modules/module-loopback.c
Changed
@@ -36,10 +36,9 @@ #include <spa/utils/string.h> #include <spa/utils/json.h> #include <spa/utils/ringbuffer.h> -#include <spa/param/profiler.h> -#include <spa/debug/pod.h> +#include <spa/param/latency-utils.h> +#include <spa/debug/types.h> -#include <pipewire/private.h> #include <pipewire/impl.h> #include <pipewire/extensions/profiler.h>
View file
pipewire-0.3.64.tar.gz/src/modules/module-pipe-tunnel.c -> pipewire-0.3.65.tar.gz/src/modules/module-pipe-tunnel.c
Changed
@@ -42,7 +42,7 @@ #include <spa/utils/json.h> #include <spa/utils/ringbuffer.h> #include <spa/utils/dll.h> -#include <spa/debug/pod.h> +#include <spa/debug/types.h> #include <spa/pod/builder.h> #include <spa/param/audio/format-utils.h> #include <spa/param/latency-utils.h> @@ -50,7 +50,6 @@ #include <pipewire/impl.h> #include <pipewire/i18n.h> -#include <pipewire/private.h> /** \page page_module_pipe_tunnel PipeWire Module: Unix Pipe Tunnel * @@ -665,6 +664,7 @@ copy_props(impl, props, PW_KEY_NODE_VIRTUAL); copy_props(impl, props, PW_KEY_MEDIA_CLASS); copy_props(impl, props, PW_KEY_TARGET_OBJECT); + copy_props(impl, props, "pipe.filename"); parse_audio_info(impl->stream_props, &impl->info);
View file
pipewire-0.3.64.tar.gz/src/modules/module-portal.c -> pipewire-0.3.65.tar.gz/src/modules/module-portal.c
Changed
@@ -36,6 +36,7 @@ #include <dbus/dbus.h> #include <spa/utils/string.h> +#include <spa/utils/result.h> #include <spa/support/dbus.h> #include "pipewire/context.h" @@ -43,7 +44,6 @@ #include "pipewire/log.h" #include "pipewire/module.h" #include "pipewire/utils.h" -#include "pipewire/private.h" /** \page page_module_portal PipeWire Module: Portal *
View file
pipewire-0.3.64.tar.gz/src/modules/module-profiler.c -> pipewire-0.3.65.tar.gz/src/modules/module-profiler.c
Changed
@@ -35,7 +35,6 @@ #include <spa/utils/result.h> #include <spa/utils/ringbuffer.h> #include <spa/param/profiler.h> -#include <spa/debug/pod.h> #include <pipewire/private.h> #include <pipewire/impl.h>
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-native.c
Changed
@@ -1287,11 +1287,10 @@ { const char *name = NULL; - if (props) + name = getenv("PIPEWIRE_CORE"); + if (name == NULL && props != NULL) name = spa_dict_lookup(props, PW_KEY_CORE_NAME); if (name == NULL) - name = getenv("PIPEWIRE_CORE"); - if (name == NULL) name = PW_DEFAULT_REMOTE; return name; } @@ -1466,10 +1465,9 @@ { const char *val = NULL; - if (props) + val = getenv("PIPEWIRE_DAEMON"); + if (val == NULL && props != NULL) val = spa_dict_lookup(props, PW_KEY_CORE_DAEMON); - if (val == NULL) - val = getenv("PIPEWIRE_DAEMON"); if (val && pw_properties_parse_bool(val)) return 1; return 0;
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-native/local-socket.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-native/local-socket.c
Changed
@@ -49,13 +49,12 @@ static const char * get_remote(const struct spa_dict *props) { - const char *name = NULL; + const char *name; - if (props) + name = getenv("PIPEWIRE_REMOTE"); + if ((name == NULL || name0 == '\0') && props) name = spa_dict_lookup(props, PW_KEY_REMOTE_NAME); if (name == NULL || name0 == '\0') - name = getenv("PIPEWIRE_REMOTE"); - if (name == NULL || name0 == '\0') name = PW_DEFAULT_REMOTE; return name; }
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-native/v0/protocol-native.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-native/v0/protocol-native.c
Changed
@@ -27,7 +27,7 @@ #include "spa/pod/parser.h" #include "spa/pod/builder.h" -#include "spa/debug/pod.h" +#include "spa/debug/types.h" #include "spa/utils/string.h" #include "pipewire/pipewire.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/format.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/format.c
Changed
@@ -189,16 +189,31 @@ { switch (ss->format) { case SPA_AUDIO_FORMAT_U8: + case SPA_AUDIO_FORMAT_U8P: + case SPA_AUDIO_FORMAT_S8: + case SPA_AUDIO_FORMAT_S8P: case SPA_AUDIO_FORMAT_ULAW: case SPA_AUDIO_FORMAT_ALAW: return ss->channels; case SPA_AUDIO_FORMAT_S16_LE: case SPA_AUDIO_FORMAT_S16_BE: case SPA_AUDIO_FORMAT_S16P: + case SPA_AUDIO_FORMAT_U16_LE: + case SPA_AUDIO_FORMAT_U16_BE: return 2 * ss->channels; case SPA_AUDIO_FORMAT_S24_LE: case SPA_AUDIO_FORMAT_S24_BE: case SPA_AUDIO_FORMAT_S24P: + case SPA_AUDIO_FORMAT_U24_LE: + case SPA_AUDIO_FORMAT_U24_BE: + case SPA_AUDIO_FORMAT_S20_LE: + case SPA_AUDIO_FORMAT_S20_BE: + case SPA_AUDIO_FORMAT_U20_LE: + case SPA_AUDIO_FORMAT_U20_BE: + case SPA_AUDIO_FORMAT_S18_LE: + case SPA_AUDIO_FORMAT_S18_BE: + case SPA_AUDIO_FORMAT_U18_LE: + case SPA_AUDIO_FORMAT_U18_BE: return 3 * ss->channels; case SPA_AUDIO_FORMAT_F32_LE: case SPA_AUDIO_FORMAT_F32_BE: @@ -206,10 +221,18 @@ case SPA_AUDIO_FORMAT_S32_LE: case SPA_AUDIO_FORMAT_S32_BE: case SPA_AUDIO_FORMAT_S32P: + case SPA_AUDIO_FORMAT_U32_LE: + case SPA_AUDIO_FORMAT_U32_BE: case SPA_AUDIO_FORMAT_S24_32_LE: case SPA_AUDIO_FORMAT_S24_32_BE: case SPA_AUDIO_FORMAT_S24_32P: + case SPA_AUDIO_FORMAT_U24_32_LE: + case SPA_AUDIO_FORMAT_U24_32_BE: return 4 * ss->channels; + case SPA_AUDIO_FORMAT_F64_LE: + case SPA_AUDIO_FORMAT_F64_BE: + case SPA_AUDIO_FORMAT_F64P: + return 8 * ss->channels; default: return 0; }
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c
Changed
@@ -24,6 +24,7 @@ */ #include <spa/param/audio/format-utils.h> +#include <spa/utils/json.h> #include <pipewire/pipewire.h> #include <pipewire/utils.h> @@ -49,130 +50,38 @@ "slaves=<sinks to combine> " "rate=<sample rate> " "channels=<number of channels> " - "channel_map=<channel map> " }, + "channel_map=<channel map> " + "remix=<remix channels> " }, { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, }; struct module_combine_sink_data; -/* This goes to the stream event listener to be able to identify the stream on - * which the event occurred and to have a link to the module data */ -struct combine_stream { - struct pw_stream *stream; - struct spa_hook stream_listener; - struct module_combine_sink_data *data; - bool cleanup; - bool started; -}; - struct module_combine_sink_data { struct module *module; struct pw_core *core; - struct pw_manager *manager; - - struct pw_stream *sink; - struct spa_hook core_listener; + struct pw_manager *manager; struct spa_hook manager_listener; - struct spa_hook sink_listener; + + struct pw_impl_module *mod; + struct spa_hook mod_listener; char *sink_name; char **sink_names; - struct combine_stream streamsMAX_SINKS; + struct pw_properties *combine_props; - struct spa_source *cleanup; struct spa_source *sinks_timeout; struct spa_audio_info_raw info; unsigned int sinks_pending; - unsigned int source_started:1; + unsigned int remix:1; unsigned int load_emitted:1; unsigned int start_error:1; }; -/* Core connection: mainly to unload the module if the connection errors out */ -static void on_core_error(void *data, uint32_t id, int seq, int res, const char *message) -{ - struct module_combine_sink_data *d = data; - struct module *module = d->module; - - pw_log_error("error id:%u seq:%d res:%d (%s): %s", - id, seq, res, spa_strerror(res), message); - - if (id == PW_ID_CORE && res == -EPIPE) - module_schedule_unload(module); -} - -static const struct pw_core_events core_events = { - PW_VERSION_CORE_EVENTS, - .error = on_core_error, -}; - -/* Input stream: the "combine sink" */ -static void capture_process(void *d) -{ - struct module_combine_sink_data *data = d; - struct pw_buffer *in; - int i; - - if ((in = pw_stream_dequeue_buffer(data->sink)) == NULL) { - pw_log_warn("out of capture buffers: %m"); - return; - } - - for (i = 0; i < MAX_SINKS; i++) { - struct pw_buffer *out; - uint32_t j; - - if (data->streamsi.stream == NULL || data->streamsi.cleanup) - continue; - - if ((out = pw_stream_dequeue_buffer(data->streamsi.stream)) == NULL) { - pw_log_warn("out of playback buffers: %m"); - continue; - } - - if (in->buffer->n_datas != out->buffer->n_datas) { - pw_log_error("incompatible buffer planes"); - continue; - } - - for (j = 0; j < out->buffer->n_datas; j++) { - struct spa_data *ds, *dd; - uint32_t outsize = 0; - int32_t stride = 0; - - dd = &out->buffer->datasj; - - if (j < in->buffer->n_datas) { - uint32_t offs, size; - - ds = &in->buffer->datasj; - - offs = SPA_MIN(ds->chunk->offset, ds->maxsize); - size = SPA_MIN(ds->chunk->size, ds->maxsize - offs); - - memcpy(dd->data, - SPA_PTROFF(ds->data, offs, void), size); - - outsize = SPA_MAX(outsize, size); - stride = SPA_MAX(stride, ds->chunk->stride); - } else { - memset(dd->data, 0, outsize); - } - dd->chunk->offset = 0; - dd->chunk->size = outsize; - dd->chunk->stride = stride; - } - - pw_stream_queue_buffer(data->streamsi.stream, out); - } - - pw_stream_queue_buffer(data->sink, in); -} - static void check_initialized(struct module_combine_sink_data *data) { struct module *module = data->module; @@ -184,174 +93,38 @@ pw_log_debug("module load error"); data->load_emitted = true; module_emit_loaded(module, -EIO); - } else if (data->sinks_pending == 0 && data->source_started) { + } else if (data->sinks_pending == 0) { pw_log_debug("module loaded"); data->load_emitted = true; module_emit_loaded(module, 0); } } -static void on_in_stream_state_changed(void *d, enum pw_stream_state old, - enum pw_stream_state state, const char *error) -{ - struct module_combine_sink_data *data = d; - struct module *module = data->module; - uint32_t i; - - if (!data->source_started && state != PW_STREAM_STATE_CONNECTING) { - /* Input stream appears on server */ - data->source_started = true; - if (state < PW_STREAM_STATE_PAUSED) - data->start_error = true; - check_initialized(data); - } - - switch (state) { - case PW_STREAM_STATE_PAUSED: - pw_stream_flush(data->sink, false); - for (i = 0; i < MAX_SINKS; i++) { - struct combine_stream *s = &data->streamsi; - if (s->stream == NULL || s->cleanup) - continue; - pw_stream_flush(s->stream, false); - } - break; - case PW_STREAM_STATE_UNCONNECTED: - pw_log_info("stream disconnected, unloading"); - module_schedule_unload(module); - break; - default: - break; - } -} - -static const struct pw_stream_events in_stream_events = { - PW_VERSION_STREAM_EVENTS, - .state_changed = on_in_stream_state_changed, - .process = capture_process -}; - -/* Output streams: one per sink we have combined output to */ -static void on_out_stream_state_changed(void *data, enum pw_stream_state old, - enum pw_stream_state state, const char *error) -{ - struct combine_stream *s = data; - - if (!s->started && state != PW_STREAM_STATE_CONNECTING) { - /* Output stream appears on server */ - s->started = true; - if (s->data->sinks_pending > 0) - --s->data->sinks_pending; - if (state < PW_STREAM_STATE_PAUSED) - s->data->start_error = true; - check_initialized(s->data); - } - - if (state == PW_STREAM_STATE_UNCONNECTED) { - s->cleanup = true; - pw_loop_signal_event(s->data->module->impl->loop, s->data->cleanup); - } -} - -static const struct pw_stream_events out_stream_events = { - PW_VERSION_STREAM_EVENTS, - .state_changed = on_out_stream_state_changed, -}; - static void manager_added(void *d, struct pw_manager_object *o) { struct module_combine_sink_data *data = d; - struct combine_stream *cstream; - struct pw_properties *props; - const struct spa_pod *params1; - const char *sink_name; - struct spa_pod_builder b; - uint32_t n_params; - char buffer1024; - int i, res; - - if (!pw_manager_object_is_sink(o)) - return; - - sink_name = pw_properties_get(o->props, PW_KEY_NODE_NAME); + const char *str; + uint32_t val = 0; + struct pw_node_info *info; - if (strcmp(sink_name, data->sink_name) == 0) { - /* That's the sink we created */ + if (!spa_streq(o->type, PW_TYPE_INTERFACE_Node) || + (info = o->info) == NULL || info->props == NULL) return; - } - - if (data->sink_names) { - int i; - - for (i = 0; data->sink_namesi != NULL; i++) { - if (strcmp(data->sink_namesi, sink_name) == 0) { - i = -1; - break; - } - } - - /* This sink isn't in our list */ - if (i > -1) - return; - } - - pw_log_info("Adding %s to combine outputs", sink_name); - for (i = 0; i < MAX_SINKS; i++) - if (data->streamsi.stream == NULL) - break; - - if (i == MAX_SINKS) { - pw_log_error("Cannot combine more than %u sinks", MAX_SINKS); + str = spa_dict_lookup(info->props, "pulse.module.id"); + if (str == NULL || !spa_atou32(str, &val, 0) || val != data->module->index) return; - } else { - cstream = &data->streamsi; - } - props = pw_properties_new(NULL, NULL); - pw_properties_setf(props, PW_KEY_NODE_NAME, - "combine_output.sink-%u.%s", data->module->index, sink_name); - pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, data->sink_name); - pw_properties_set(props, PW_KEY_TARGET_OBJECT, sink_name); - pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->index); - pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->index); - pw_properties_set(props, PW_KEY_NODE_DONT_RECONNECT, "true"); - pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); - pw_properties_set(props, PW_KEY_NODE_PASSIVE, "true"); - pw_properties_setf(props, "pulse.module.id", "%u", data->module->index); - - cstream->data = data; - cstream->stream = pw_stream_new(data->core, NULL, props); - if (cstream->stream == NULL) { - pw_log_error("Could not create stream"); - goto error; - } + pw_log_info("found our %s, pending:%d", + pw_properties_get(o->props, PW_KEY_NODE_NAME), + data->sinks_pending); - pw_stream_add_listener(cstream->stream, - &cstream->stream_listener, - &out_stream_events, cstream); - - n_params = 0; - b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - paramsn_params++ = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, - &data->info); - - if ((res = pw_stream_connect(cstream->stream, - PW_DIRECTION_OUTPUT, - PW_ID_ANY, - PW_STREAM_FLAG_AUTOCONNECT | - PW_STREAM_FLAG_MAP_BUFFERS | - PW_STREAM_FLAG_RT_PROCESS, - params, n_params)) < 0) { - pw_log_error("Could not connect to sink '%s'", sink_name); - goto error; + if (!pw_manager_object_is_sink(o)) { + if (data->sinks_pending > 0) + data->sinks_pending--; } - - return; - -error: - data->start_error = true; check_initialized(data); + return; } static const struct pw_manager_events manager_events = { @@ -359,27 +132,6 @@ .added = manager_added, }; -static void cleanup_stream(struct combine_stream *s) -{ - spa_hook_remove(&s->stream_listener); - pw_stream_destroy(s->stream); - - s->stream = NULL; - s->data = NULL; - s->cleanup = false; -} - -static void on_cleanup(void *d, uint64_t count) -{ - struct module_combine_sink_data *data = d; - int i; - - for (i = 0; i < MAX_SINKS; i++) { - if (data->streamsi.cleanup) - cleanup_stream(&data->streamsi); - } -} - static void on_sinks_timeout(void *d, uint64_t count) { struct module_combine_sink_data *data = d; @@ -391,57 +143,84 @@ check_initialized(data); } +static void module_destroy(void *data) +{ + struct module_combine_sink_data *d = data; + spa_hook_remove(&d->mod_listener); + d->mod = NULL; + module_schedule_unload(d->module); +} + +static const struct pw_impl_module_events module_events = { + PW_VERSION_IMPL_MODULE_EVENTS, + .destroy = module_destroy +}; + static int module_combine_sink_load(struct module *module) { struct module_combine_sink_data *data = module->user_data; - struct pw_properties *props; - int res; - uint32_t n_params; - const struct spa_pod *params1; - uint8_t buffer1024; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - const char *str; + uint32_t i; + FILE *f; + char *args; + size_t size; data->core = pw_context_connect(module->impl->context, NULL, 0); if (data->core == NULL) return -errno; - pw_core_add_listener(data->core, - &data->core_listener, - &core_events, data); - - props = pw_properties_new(NULL, NULL); + if ((f = open_memstream(&args, &size)) == NULL) + return -errno; - pw_properties_set(props, PW_KEY_NODE_NAME, data->sink_name); - pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, data->sink_name); - pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink"); - pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->index); - pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->index); - pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); - pw_properties_setf(props, "pulse.module.id", "%u", module->index); + fprintf(f, "{"); + fprintf(f, " node.name = %s", data->sink_name); + fprintf(f, " node.description = %s", data->sink_name); + if (data->info.rate != 0) + fprintf(f, " audio.rate = %u", data->info.rate); + if (data->info.channels != 0) { + fprintf(f, " audio.channels = %u", data->info.channels); + if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) { + fprintf(f, " audio.position = "); + for (i = 0; i < data->info.channels; i++) + fprintf(f, "%s%s", i == 0 ? "" : ",", + channel_id2name(data->info.positioni)); + fprintf(f, " "); + } + } + fprintf(f, " combine.props = {"); + fprintf(f, " pulse.module.id = %u", module->index); + pw_properties_serialize_dict(f, &data->combine_props->dict, 0); + fprintf(f, " } stream.props = {"); + if (!data->remix) + fprintf(f, " "PW_KEY_STREAM_DONT_REMIX" = true"); + fprintf(f, " pulse.module.id = %u", module->index); + fprintf(f, " } stream.rules = "); + if (data->sink_names == NULL) { + fprintf(f, " { matches = { media.class = \"Audio/Sink\" } "); + fprintf(f, " actions = { create-stream = { } } }"); + } else { + for (i = 0; data->sink_namesi != NULL; i++) { + char name1024; + spa_json_encode_string(name, sizeof(name)-1, data->sink_namesi); + fprintf(f, " { matches = { media.class = \"Audio/Sink\" "); + fprintf(f, " node.name = %s } ", name); + fprintf(f, " actions = { create-stream = { } } }"); + } + } + fprintf(f, " "); + fprintf(f, "}"); + fclose(f); - if ((str = pw_properties_get(module->props, "sink_properties")) != NULL) - module_args_add_props(props, str); + data->mod = pw_context_load_module(module->impl->context, + "libpipewire-module-combine-stream", + args, NULL); + free(args); - data->sink = pw_stream_new(data->core, data->sink_name, props); - if (data->sink == NULL) + if (data->mod == NULL) return -errno; - pw_stream_add_listener(data->sink, - &data->sink_listener, - &in_stream_events, data); - - n_params = 0; - paramsn_params++ = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, - &data->info); - - if ((res = pw_stream_connect(data->sink, - PW_DIRECTION_INPUT, - PW_ID_ANY, - PW_STREAM_FLAG_MAP_BUFFERS | - PW_STREAM_FLAG_RT_PROCESS, - params, n_params)) < 0) - return res; + pw_impl_module_add_listener(data->mod, + &data->mod_listener, + &module_events, data); data->manager = pw_manager_new(data->core); if (data->manager == NULL) @@ -450,55 +229,39 @@ pw_manager_add_listener(data->manager, &data->manager_listener, &manager_events, data); - data->cleanup = pw_loop_add_event(module->impl->loop, on_cleanup, data); - data->sinks_timeout = pw_loop_add_timer(module->impl->loop, on_sinks_timeout, data); if (data->sinks_timeout) { - struct timespec timeout = {0}, interval = {0}; + struct timespec timeout = {0}; timeout.tv_sec = TIMEOUT_SINKS_MSEC / 1000; timeout.tv_nsec = (TIMEOUT_SINKS_MSEC % 1000) * SPA_NSEC_PER_MSEC; - pw_loop_update_timer(module->impl->loop, data->sinks_timeout, &timeout, &interval, false); + pw_loop_update_timer(module->impl->loop, data->sinks_timeout, &timeout, NULL, false); } - return data->load_emitted ? 0 : SPA_RESULT_RETURN_ASYNC(0); } static int module_combine_sink_unload(struct module *module) { struct module_combine_sink_data *d = module->user_data; - int i; - - if (d->cleanup != NULL) - pw_loop_destroy_source(module->impl->loop, d->cleanup); if (d->sinks_timeout != NULL) pw_loop_destroy_source(module->impl->loop, d->sinks_timeout); - /* Note that we explicitly disconnect the hooks to avoid having the - * cleanup triggered again in those callbacks */ - if (d->sink != NULL) { - spa_hook_remove(&d->sink_listener); - pw_stream_destroy(d->sink); - } - - for (i = 0; i < MAX_SINKS; i++) { - if (d->streamsi.stream) - cleanup_stream(&d->streamsi); + if (d->mod != NULL) { + spa_hook_remove(&d->mod_listener); + pw_impl_module_destroy(d->mod); + d->mod = NULL; } - if (d->manager != NULL) { spa_hook_remove(&d->manager_listener); pw_manager_destroy(d->manager); } - if (d->core != NULL) { spa_hook_remove(&d->core_listener); pw_core_disconnect(d->core); } - pw_free_strv(d->sink_names); free(d->sink_name); - + pw_properties_free(d->combine_props); return 0; } @@ -506,14 +269,17 @@ { struct module_combine_sink_data * const d = module->user_data; struct pw_properties * const props = module->props; + struct pw_properties *combine_props = NULL; const char *str; char *sink_name = NULL, **sink_names = NULL; struct spa_audio_info_raw info = { 0 }; - int i, res; + int res; int num_sinks = 0; PW_LOG_TOPIC_INIT(mod_topic); + combine_props = pw_properties_new(NULL, NULL); + if ((str = pw_properties_get(props, "sink_name")) != NULL) { sink_name = strdup(str); pw_properties_set(props, "sink_name", NULL); @@ -521,10 +287,18 @@ sink_name = strdup("combined"); } + if ((str = pw_properties_get(module->props, "sink_properties")) != NULL) + module_args_add_props(combine_props, str); + if ((str = pw_properties_get(props, "slaves")) != NULL) { sink_names = pw_split_strv(str, ",", MAX_SINKS, &num_sinks); pw_properties_set(props, "slaves", NULL); } + d->remix = true; + if ((str = pw_properties_get(props, "remix")) != NULL) { + d->remix = pw_properties_parse_bool(str); + pw_properties_set(props, "remix", NULL); + } if ((str = pw_properties_get(props, "adjust_time")) != NULL) { pw_log_info("The `adjust_time` modarg is ignored"); @@ -546,15 +320,13 @@ d->sink_name = sink_name; d->sink_names = sink_names; d->sinks_pending = (sink_names == NULL) ? 0 : num_sinks; - for (i = 0; i < MAX_SINKS; i++) { - d->streamsi.stream = NULL; - d->streamsi.cleanup = false; - } + d->combine_props = combine_props; return 0; out: free(sink_name); pw_free_strv(sink_names); + pw_properties_free(combine_props); return res; }
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c
Changed
@@ -27,7 +27,6 @@ #include <spa/utils/hook.h> #include <spa/utils/json.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c
Changed
@@ -22,11 +22,11 @@ * DEALINGS IN THE SOFTWARE. */ -#include <spa/param/audio/format-utils.h> #include <spa/utils/hook.h> #include <spa/utils/json.h> +#include <spa/param/audio/format-utils.h> + #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c
Changed
@@ -22,11 +22,11 @@ * DEALINGS IN THE SOFTWARE. */ -#include <spa/param/audio/format-utils.h> #include <spa/utils/hook.h> #include <spa/utils/json.h> +#include <spa/param/audio/format-utils.h> + #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c
Changed
@@ -27,7 +27,6 @@ #include <spa/utils/hook.h> #include <spa/utils/json.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c
Changed
@@ -28,7 +28,6 @@ #include <unistd.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include <spa/param/audio/format-utils.h> #include <spa/utils/hook.h> @@ -96,8 +95,9 @@ fprintf(f, " ,"); } } + fprintf(f, " \"stream.props\": {"); pw_properties_serialize_dict(f, &data->capture_props->dict, 0); - fprintf(f, " }"); + fprintf(f, " } }"); fclose(f); data->mod = pw_context_load_module(module->impl->context, @@ -181,6 +181,12 @@ filename = strdup(str); pw_properties_set(props, "file", NULL); } + if ((str = pw_properties_get(capture_props, PW_KEY_DEVICE_ICON_NAME)) == NULL) + pw_properties_set(capture_props, PW_KEY_DEVICE_ICON_NAME, + "audio-card"); + if ((str = pw_properties_get(capture_props, PW_KEY_NODE_NAME)) == NULL) + pw_properties_set(capture_props, PW_KEY_NODE_NAME, + "fifo_output"); d->module = module; d->capture_props = capture_props;
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c
Changed
@@ -28,7 +28,6 @@ #include <unistd.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include <spa/param/audio/format-utils.h> #include <spa/utils/hook.h> @@ -96,8 +95,9 @@ fprintf(f, " ,"); } } + fprintf(f, " \"stream.props\": {"); pw_properties_serialize_dict(f, &data->playback_props->dict, 0); - fprintf(f, " }"); + fprintf(f, " } }"); fclose(f); data->mod = pw_context_load_module(module->impl->context, @@ -181,6 +181,12 @@ filename = strdup(str); pw_properties_set(props, "file", NULL); } + if ((str = pw_properties_get(playback_props, PW_KEY_DEVICE_ICON_NAME)) == NULL) + pw_properties_set(playback_props, PW_KEY_DEVICE_ICON_NAME, + "audio-input-microphone"); + if ((str = pw_properties_get(playback_props, PW_KEY_NODE_NAME)) == NULL) + pw_properties_set(playback_props, PW_KEY_NODE_NAME, + "fifo_input"); d->module = module; d->playback_props = playback_props;
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-raop-discover.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-raop-discover.c
Changed
@@ -24,7 +24,6 @@ #include <spa/utils/hook.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c
Changed
@@ -26,7 +26,6 @@ #include <spa/utils/hook.h> #include <spa/utils/json.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c
Changed
@@ -26,7 +26,6 @@ #include <spa/utils/hook.h> #include <spa/utils/json.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink-input.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink-input.c
Changed
@@ -25,7 +25,6 @@ #include <spa/utils/hook.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c
Changed
@@ -25,7 +25,6 @@ #include <spa/utils/hook.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c
Changed
@@ -25,7 +25,6 @@ #include <spa/utils/hook.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-rtp-recv.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-rtp-recv.c
Changed
@@ -24,7 +24,6 @@ #include <spa/utils/hook.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-rtp-send.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-rtp-send.c
Changed
@@ -24,7 +24,6 @@ #include <spa/utils/hook.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c
Changed
@@ -27,7 +27,6 @@ #include <spa/utils/json.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include <pipewire/i18n.h> #include "../defs.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c
Changed
@@ -27,7 +27,6 @@ #include <spa/utils/json.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include <pipewire/i18n.h> #include "../defs.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-discover.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-discover.c
Changed
@@ -24,7 +24,6 @@ #include <spa/utils/hook.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include "../defs.h" #include "../module.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
@@ -34,7 +34,6 @@ #include <pipewire/log.h> #include "log.h" -#define spa_debug pw_log_debug #include <spa/support/cpu.h> #include <spa/utils/result.h> @@ -50,7 +49,6 @@ #include <spa/utils/json.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> #include <pipewire/extensions/metadata.h> #include "pulse-server.h" @@ -3746,6 +3744,13 @@ return 0; } +static bool validate_device_info(struct device_info *dev_info) +{ + return sample_spec_valid(&dev_info->ss) && + channel_map_valid(&dev_info->map) && + volume_valid(&dev_info->volume_info.volume); +} + static int fill_sink_info(struct client *client, struct message *m, struct pw_manager_object *o) { @@ -3796,9 +3801,7 @@ collect_device_info(o, card, &dev_info, false, &impl->defs); - if (!sample_spec_valid(&dev_info.ss) || - !channel_map_valid(&dev_info.map) || - !volume_valid(&dev_info.volume_info.volume)) { + if (!validate_device_info(&dev_info)) { pw_log_warn("%d: sink not ready: sample:%d map:%d volume:%d", o->id, sample_spec_valid(&dev_info.ss), channel_map_valid(&dev_info.map), @@ -4011,9 +4014,7 @@ collect_device_info(o, card, &dev_info, is_monitor, &impl->defs); - if (!sample_spec_valid(&dev_info.ss) || - !channel_map_valid(&dev_info.map) || - !volume_valid(&dev_info.volume_info.volume)) { + if (!validate_device_info(&dev_info)) { pw_log_warn("%d: source not ready: sample:%d map:%d volume:%d", o->id, sample_spec_valid(&dev_info.ss), channel_map_valid(&dev_info.map), @@ -4154,9 +4155,7 @@ collect_device_info(o, NULL, &dev_info, false, &impl->defs); - if (!sample_spec_valid(&dev_info.ss) || - !channel_map_valid(&dev_info.map) || - !volume_valid(&dev_info.volume_info.volume)) + if (!validate_device_info(&dev_info)) return -ENOENT; peer_index = get_temporary_move_target(client, o); @@ -4237,9 +4236,7 @@ collect_device_info(o, NULL, &dev_info, false, &impl->defs); - if (!sample_spec_valid(&dev_info.ss) || - !channel_map_valid(&dev_info.map) || - !volume_valid(&dev_info.volume_info.volume)) + if (!validate_device_info(&dev_info)) return -ENOENT; peer_index = get_temporary_move_target(client, o);
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/remap.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/remap.c
Changed
@@ -53,5 +53,6 @@ { PW_KEY_APP_PROCESS_MACHINE_ID, "application.process.machine_id" }, { PW_KEY_APP_PROCESS_SESSION_ID, "application.process.session_id" }, { PW_KEY_MEDIA_ROLE, "media.role", media_role_map }, + { "pipe.filename", "device.string" }, { NULL, NULL }, };
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/stream.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/stream.c
Changed
@@ -31,7 +31,6 @@ #include <pipewire/log.h> #include <pipewire/loop.h> #include <pipewire/map.h> -#include <pipewire/private.h> #include <pipewire/properties.h> #include <pipewire/stream.h> #include <pipewire/work-queue.h>
View file
pipewire-0.3.64.tar.gz/src/modules/module-protocol-pulse/utils.c -> pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/utils.c
Changed
@@ -171,11 +171,10 @@ const char *name = NULL; const struct pw_properties *props = pw_context_get_properties(context); - if (props) + name = getenv("PIPEWIRE_REMOTE"); + if ((name == NULL || name0 == '\0') && props != NULL) name = pw_properties_get(props, PW_KEY_REMOTE_NAME); if (name == NULL || name0 == '\0') - name = getenv("PIPEWIRE_REMOTE"); - if (name == NULL || name0 == '\0') name = PW_DEFAULT_REMOTE; return name; }
View file
pipewire-0.3.64.tar.gz/src/modules/module-pulse-tunnel.c -> pipewire-0.3.65.tar.gz/src/modules/module-pulse-tunnel.c
Changed
@@ -41,7 +41,7 @@ #include <spa/utils/json.h> #include <spa/utils/ringbuffer.h> #include <spa/utils/dll.h> -#include <spa/debug/pod.h> +#include <spa/debug/types.h> #include <spa/pod/builder.h> #include <spa/param/audio/format-utils.h> #include <spa/param/latency-utils.h>
View file
pipewire-0.3.64.tar.gz/src/modules/module-raop-discover.c -> pipewire-0.3.65.tar.gz/src/modules/module-raop-discover.c
Changed
@@ -37,7 +37,6 @@ #include <spa/utils/json.h> #include <pipewire/impl.h> -#include <pipewire/private.h> #include <pipewire/i18n.h> #include <avahi-client/lookup.h>
View file
pipewire-0.3.64.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.65.tar.gz/src/modules/module-raop-sink.c
Changed
@@ -50,7 +50,7 @@ #include <spa/utils/string.h> #include <spa/utils/json.h> #include <spa/utils/ringbuffer.h> -#include <spa/debug/pod.h> +#include <spa/debug/types.h> #include <spa/pod/builder.h> #include <spa/param/audio/format-utils.h> #include <spa/param/audio/raw.h> @@ -58,7 +58,6 @@ #include <pipewire/impl.h> #include <pipewire/i18n.h> -#include <pipewire/private.h> #include "module-raop/rtsp-client.h"
View file
pipewire-0.3.64.tar.gz/src/modules/module-roc-sink.c -> pipewire-0.3.65.tar.gz/src/modules/module-roc-sink.c
Changed
@@ -29,10 +29,9 @@ #include "config.h" -#include <pipewire/pipewire.h> -#include <pipewire/private.h> -#include <spa/param/audio/format-utils.h> #include <spa/utils/hook.h> +#include <spa/utils/result.h> +#include <spa/param/audio/format-utils.h> #include <roc/config.h> #include <roc/log.h> @@ -40,6 +39,9 @@ #include <roc/log.h> #include <roc/sender.h> +#include <pipewire/pipewire.h> +#include <pipewire/impl.h> + #include "module-roc/common.h" /** \page page_module_roc_sink PipeWire Module: ROC sink
View file
pipewire-0.3.64.tar.gz/src/modules/module-roc-source.c -> pipewire-0.3.65.tar.gz/src/modules/module-roc-source.c
Changed
@@ -29,10 +29,9 @@ #include "config.h" -#include <pipewire/pipewire.h> -#include <pipewire/private.h> -#include <spa/param/audio/format-utils.h> #include <spa/utils/hook.h> +#include <spa/utils/result.h> +#include <spa/param/audio/format-utils.h> #include <roc/config.h> #include <roc/log.h> @@ -40,6 +39,9 @@ #include <roc/log.h> #include <roc/receiver.h> +#include <pipewire/pipewire.h> +#include <pipewire/impl.h> + #include "module-roc/common.h" /** \page page_module_roc_source PipeWire Module: ROC source
View file
pipewire-0.3.64.tar.gz/src/modules/module-rt.c -> pipewire-0.3.65.tar.gz/src/modules/module-rt.c
Changed
@@ -133,7 +133,8 @@ #define IS_VALID_NICE_LEVEL(l) ((l)>=-20 && (l)<=19) -#define DEFAULT_NICE_LEVEL 20 +#define DEFAULT_NICE_LEVEL 20 +#define DEFAULT_RT_PRIO_MIN 11 #define DEFAULT_RT_PRIO 88 #define DEFAULT_RT_TIME_SOFT -1 #define DEFAULT_RT_TIME_HARD -1 @@ -550,42 +551,82 @@ .destroy = module_destroy, }; +static int get_rt_priority_range(int *out_min, int *out_max) +{ + int min, max; + + if ((min = sched_get_priority_min(REALTIME_POLICY)) < 0) + return -errno; + if ((max = sched_get_priority_max(REALTIME_POLICY)) < 0) + return -errno; + + if (out_min) + *out_min = min; + if (out_max) + *out_max = max; + + return 0; +} /** * Check if the current user has permissions to use realtime scheduling at the * specified priority. */ -static bool check_realtime_privileges(rlim_t priority) +static bool check_realtime_privileges(struct impl *impl) { - int err, old_policy, new_policy = REALTIME_POLICY; + rlim_t priority = impl->rt_prio; + int err, old_policy, new_policy, min, max; struct sched_param old_sched_params; struct sched_param new_sched_params; + int try = 0; + + while (try++ < 2) { + /* We could check `RLIMIT_RTPRIO`, but the BSDs generally don't have + * that available, and there are also other ways to use realtime + * scheduling without that rlimit being set such as `CAP_SYS_NICE` or + * running as root. Instead of checking a bunch of preconditions, we + * just try if setting realtime scheduling works or not. */ + if ((err = pthread_getschedparam(pthread_self(), &old_policy, &old_sched_params)) != 0) { + pw_log_warn("Failed to check RLIMIT_RTPRIO: %s", strerror(err)); + return false; + } + if ((err = get_rt_priority_range(&min, &max)) < 0) { + pw_log_warn("Failed to get priority range: %s", strerror(err)); + return false; + } + if (try == 2) { + struct rlimit rlim; + /* second try, try to clamp to RLIMIT_RTPRIO */ + if (getrlimit(RLIMIT_RTPRIO, &rlim) == 0 && max > (int)rlim.rlim_max) { + pw_log_info("Clamp rtprio %d to %d", (int)priority, (int)rlim.rlim_max); + max = (int)rlim.rlim_max; + } + else + break; + } + if (max < DEFAULT_RT_PRIO_MIN) { + pw_log_info("Priority max (%d) must be at least %d", max, DEFAULT_RT_PRIO_MIN); + return false; + } - /* We could check `RLIMIT_RTPRIO`, but the BSDs generally don't have - * that available, and there are also other ways to use realtime - * scheduling without that rlimit being set such as `CAP_SYS_NICE` or - * running as root. Instead of checking a bunch of preconditions, we - * just try if setting realtime scheduling works or not. */ - if ((err = pthread_getschedparam(pthread_self(),&old_policy,&old_sched_params)) != 0) { - pw_log_warn("Failed to check RLIMIT_RTPRIO: %s", strerror(err)); - return false; - } - - /* If the current scheduling policy has `SCHED_RESET_ON_FORK` set, then - * this also needs to be set here or `pthread_setschedparam()` will return - * an error code. Similarly, if it is not set, then we don't want to set - * it here as it would irreversible change the current thread's - * scheduling policy. */ - spa_zero(new_sched_params); - new_sched_params.sched_priority = priority; - if ((old_policy & PW_SCHED_RESET_ON_FORK) != 0) - new_policy |= PW_SCHED_RESET_ON_FORK; - - if (pthread_setschedparam(pthread_self(), new_policy, &new_sched_params) == 0) { - pthread_setschedparam(pthread_self(), old_policy, &old_sched_params); - return true; - } else { - return false; + /* If the current scheduling policy has `SCHED_RESET_ON_FORK` set, then + * this also needs to be set here or `pthread_setschedparam()` will return + * an error code. Similarly, if it is not set, then we don't want to set + * it here as it would irreversible change the current thread's + * scheduling policy. */ + spa_zero(new_sched_params); + new_sched_params.sched_priority = SPA_CLAMP((int)priority, min, max); + new_policy = REALTIME_POLICY; + if ((old_policy & PW_SCHED_RESET_ON_FORK) != 0) + new_policy |= PW_SCHED_RESET_ON_FORK; + + if (pthread_setschedparam(pthread_self(), new_policy, &new_sched_params) == 0) { + impl->rt_prio = new_sched_params.sched_priority; + pthread_setschedparam(pthread_self(), old_policy, &old_sched_params); + return true; + } } + pw_log_info("Can't set rt prio to %d: %m (try increasing rlimits)", (int)priority); + return false; } static int sched_set_nice(int nice_level) @@ -657,16 +698,19 @@ return res; } -static int impl_acquire_rt_sched(struct spa_thread *thread, int priority) +static int acquire_rt_sched(struct spa_thread *thread, int priority) { - int err; + int err, min, max; struct sched_param sp; pthread_t pt = (pthread_t)thread; - if (priority < sched_get_priority_min(REALTIME_POLICY) || - priority > sched_get_priority_max(REALTIME_POLICY)) { - pw_log_warn("invalid priority %d for policy %d", priority, REALTIME_POLICY); - return -EINVAL; + if ((err = get_rt_priority_range(&min, &max)) < 0) + return err; + + if (priority < min || priority > max) { + pw_log_info("clamping priority %d to range %d - %d for policy %d", + priority, min, max, REALTIME_POLICY); + priority = SPA_CLAMP(priority, min, max); } spa_zero(sp); @@ -769,23 +813,30 @@ return pthread_join(pt, retval); } + +static int get_rtkit_priority_range(struct impl *impl, int *min, int *max) +{ + if (min) + *min = 1; + if (max) { + if ((*max = pw_rtkit_get_max_realtime_priority(impl)) < 0) + return *max; + if (*max < 1) + *max = 1; + } + return 0; +} + static int impl_get_rt_range(void *object, const struct spa_dict *props, int *min, int *max) { struct impl *impl = object; - if (impl->use_rtkit) { - if (min) - *min = 1; - if (max) - *max = pw_rtkit_get_max_realtime_priority(impl); - } else { - if (min) - *min = sched_get_priority_min(REALTIME_POLICY); - if (max) - *max = sched_get_priority_max(REALTIME_POLICY); - } - - return 0; + int res; + if (impl->use_rtkit) + res = get_rtkit_priority_range(impl, min, max); + else + res = get_rt_priority_range(min, max); + return res; } static pid_t impl_gettid(struct impl *impl, pthread_t pt) @@ -807,7 +858,7 @@ { struct impl *impl = object; struct sched_param sp; - int err, rtprio_limit; + int err; pthread_t pt = (pthread_t)thread; pid_t pid; @@ -817,11 +868,17 @@ } if (impl->use_rtkit) { + int min, max; + + if ((err = get_rtkit_priority_range(impl, &min, &max)) < 0) + return err; + pid = impl_gettid(impl, pt); - rtprio_limit = pw_rtkit_get_max_realtime_priority(impl); - if (rtprio_limit >= 0 && rtprio_limit < priority) { - pw_log_info("dropping requested priority %d for thread %d down to %d because of RTKit limits", priority, pid, rtprio_limit); - priority = rtprio_limit; + + if (priority < min || priority > max) { + pw_log_info("clamping requested priority %d for thread %d " + "between %d and %d", priority, pid, min, max); + priority = SPA_CLAMP(priority, min, max); } spa_zero(sp); @@ -839,7 +896,7 @@ pw_log_info("acquired realtime priority %d for thread %d using RTKit", priority, pid); return 0; } else { - return impl_acquire_rt_sched(thread, priority); + return acquire_rt_sched(thread, priority); } } @@ -868,11 +925,7 @@ static int impl_get_rt_range(void *object, const struct spa_dict *props, int *min, int *max) { - if (min) - *min = sched_get_priority_min(REALTIME_POLICY); - if (max) - *max = sched_get_priority_max(REALTIME_POLICY); - return 0; + return get_rt_priority_range(min, max); } static int impl_acquire_rt(void *object, struct spa_thread *thread, int priority) @@ -880,11 +933,10 @@ struct impl *impl = object; /* See the docstring on `spa_thread_utils_methods::acquire_rt` */ - if (priority == -1) { + if (priority == -1) priority = impl->rt_prio; - } - return impl_acquire_rt_sched(thread, priority); + return acquire_rt_sched(thread, priority); } static const struct spa_thread_utils_methods impl_thread_utils = { @@ -955,7 +1007,7 @@ #endif /* If the user has permissions to use regular realtime scheduling, as well as * the nice level we want, then we'll use that instead of RTKit */ - if (!check_realtime_privileges(impl->rt_prio)) { + if (!check_realtime_privileges(impl)) { if (!can_use_rtkit) { res = -ENOTSUP; pw_log_warn("regular realtime scheduling not available (RTKit fallback disabled)");
View file
pipewire-0.3.64.tar.gz/src/modules/module-rtp-sink.c -> pipewire-0.3.65.tar.gz/src/modules/module-rtp-sink.c
Changed
@@ -35,14 +35,15 @@ #include <net/if.h> #include <ctype.h> -#include <spa/param/audio/format-utils.h> #include <spa/utils/hook.h> +#include <spa/utils/result.h> #include <spa/utils/ringbuffer.h> #include <spa/utils/json.h> -#include <spa/debug/pod.h> +#include <spa/param/audio/format-utils.h> +#include <spa/debug/types.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> +#include <pipewire/impl.h> #include <module-rtp/sap.h> #include <module-rtp/rtp.h> @@ -66,6 +67,8 @@ * - `net.mtu = <int>`: MTU to use, default 1280 * - `net.ttl = <int>`: TTL to use, default 1 * - `net.loop = <bool>`: loopback multicast, default false + * - `sess.min-ptime = <int>`: minimum packet time in milliseconds, default 2 + * - `sess.max-ptime = <int>`: maximum packet time in milliseconds, default 20 * - `sess.name = <str>`: a session name * - `stream.props = {}`: properties to be passed to the stream * @@ -100,6 +103,8 @@ * #net.mtu = 1280 * #net.ttl = 1 * #net.loop = false + * #sess.min-ptime = 2 + * #sess.max-ptime = 20 * #sess.name = "PipeWire RTP stream" * #audio.format = "S16BE" * #audio.rate = 48000 @@ -154,6 +159,8 @@ "net.ttl=<desired TTL, default:"SPA_STRINGIFY(DEFAULT_TTL)"> " \ "net.loop=<desired loopback, default:"SPA_STRINGIFY(DEFAULT_LOOP)"> " \ "sess.name=<a name for the session> " \ + "sess.min-ptime=<minimum packet time in milliseconds, default:2> " \ + "sess.max-ptime=<maximum packet time in milliseconds, default:20> " \ "audio.format=<format, default:"DEFAULT_FORMAT"> " \ "audio.rate=<sample rate, default:"SPA_STRINGIFY(DEFAULT_RATE)"> " \ "audio.channels=<number of channels, default:"SPA_STRINGIFY(DEFAULT_CHANNELS)"> "\ @@ -215,6 +222,7 @@ bool mcast_loop; uint32_t min_ptime; uint32_t max_ptime; + uint32_t pbytes; struct sockaddr_storage src_addr; socklen_t src_len; @@ -275,7 +283,7 @@ avail = spa_ringbuffer_get_read_index(&impl->ring, &index); - tosend = SPA_ROUND_DOWN(impl->mtu, impl->frame_size); + tosend = impl->pbytes; if (avail < tosend) return; @@ -442,6 +450,7 @@ goto error; } if (is_multicast((struct sockaddr*)dst, dst_len)) { + val = loop; if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &val, sizeof(val)) < 0) pw_log_warn("setsockopt(IP_MULTICAST_LOOP) failed: %m"); @@ -480,7 +489,7 @@ if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL) { pw_properties_setf(props, PW_KEY_NODE_LATENCY, - "%d/%d", impl->mtu / impl->frame_size, + "%d/%d", impl->pbytes / impl->frame_size, impl->info.rate); } pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", impl->info.rate); @@ -578,16 +587,20 @@ "c=IN %s %s%s\n" "t=%u 0\n" "a=recvonly\n" + "a=tool:PipeWire %s\n" "m=audio %u RTP/AVP %i\n" "a=rtpmap:%i %s/%u/%u\n" - "a=type:broadcast\n", + "a=type:broadcast\n" + "a=ptime:%d\n", user_name, impl->ntp, af, src_addr, impl->session_name, af, dst_addr, dst_ttl, impl->ntp, + pw_get_library_version(), impl->port, impl->payload, impl->payload, impl->format_info->mime, - impl->info.rate, impl->info.channels); + impl->info.rate, impl->info.channels, + (impl->pbytes / impl->frame_size) * 1000 / impl->info.rate); iov3.iov_base = buffer; iov3.iov_len = strlen(buffer); @@ -780,7 +793,7 @@ struct impl *impl; struct pw_properties *props = NULL, *stream_props = NULL; uint32_t id = pw_global_get_id(pw_impl_module_get_global(module)); - uint32_t pid = getpid(), port; + uint32_t pid = getpid(), port, min_bytes, max_bytes; char addr64; const char *str; int res = 0; @@ -897,6 +910,12 @@ impl->min_ptime = pw_properties_get_uint32(props, "sess.min-ptime", DEFAULT_MIN_PTIME); impl->max_ptime = pw_properties_get_uint32(props, "sess.max-ptime", DEFAULT_MAX_PTIME); + min_bytes = (impl->min_ptime * impl->info.rate / 1000) * impl->frame_size; + max_bytes = (impl->max_ptime * impl->info.rate / 1000) * impl->frame_size; + + impl->pbytes = SPA_ROUND_DOWN(impl->mtu, impl->frame_size); + impl->pbytes = SPA_CLAMP(impl->pbytes, min_bytes, max_bytes); + if ((str = pw_properties_get(props, "sess.name")) == NULL) pw_properties_setf(props, "sess.name", "PipeWire RTP Stream on %s", pw_get_host_name()); @@ -911,6 +930,8 @@ pw_properties_setf(stream_props, "rtp.destination.port", "%u", impl->port); pw_properties_setf(stream_props, "rtp.mtu", "%u", impl->mtu); pw_properties_setf(stream_props, "rtp.ttl", "%u", impl->ttl); + pw_properties_setf(stream_props, "rtp.ptime", "%u", + (impl->pbytes / impl->frame_size) * 1000 / impl->info.rate); impl->core = pw_context_get_object(impl->module_context, PW_TYPE_INTERFACE_Core); if (impl->core == NULL) {
View file
pipewire-0.3.64.tar.gz/src/modules/module-rtp-source.c -> pipewire-0.3.65.tar.gz/src/modules/module-rtp-source.c
Changed
@@ -34,14 +34,15 @@ #include <net/if.h> #include <ctype.h> -#include <spa/param/audio/format-utils.h> #include <spa/utils/hook.h> +#include <spa/utils/result.h> #include <spa/utils/ringbuffer.h> #include <spa/utils/dll.h> +#include <spa/param/audio/format-utils.h> #include <spa/debug/mem.h> #include <pipewire/pipewire.h> -#include <pipewire/private.h> +#include <pipewire/impl.h> #include <module-rtp/sap.h> #include <module-rtp/rtp.h> @@ -77,19 +78,38 @@ * ## Example configuration *\code{.unparsed} * context.modules = - * { name = libpipewire-module-rtp-source - * args = { - * #sap.ip = 224.0.0.56 - * #sap.port = 9875 - * #local.ifname = eth0 - * sess.latency.msec = 100 - * stream.props = { - * node.name = "rtp-source" - * #media.class = "Audio/Source" - * } - * } - * } - * + * { name = libpipewire-module-rtp-source + * args = { + * #sap.ip = 224.0.0.56 + * #sap.port = 9875 + * #local.ifname = eth0 + * sess.latency.msec = 100 + * stream.props = { + * #media.class = "Audio/Source" + * #node.name = "rtp-source" + * } + * stream.rules = + * { matches = + * # any of the items in matches needs to match, if one does, + * # actions are emited. + * { # all keys must match the value. ~ in value starts regex. + * #rtp.origin = "wim 3883629975 0 IN IP4 0.0.0.0" + * #rtp.payload = "127" + * #rtp.fmt = "L16/48000/2" + * #rtp.session = "PipeWire RTP Stream on fedora" + * } + * + * actions = { + * create-stream = { + * #sess.latency.msec = 100 + * #target.object = "" + * } + * } + * } + * + * } + * } + * *\endcode * * \since 0.3.60 @@ -100,24 +120,25 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); #define PW_LOG_TOPIC_DEFAULT mod_topic -#define SAP_MIME_TYPE "application/sdp" +#define SAP_MIME_TYPE "application/sdp" -#define ERROR_MSEC 2 -#define MAX_SESSIONS 16 -#define CLEANUP_INTERVAL_SEC 20 +#define ERROR_MSEC 2 +#define MAX_SESSIONS 16 -#define DEFAULT_SAP_IP "224.0.0.56" -#define DEFAULT_SAP_PORT 9875 -#define DEFAULT_SESS_LATENCY 100 +#define DEFAULT_CLEANUP_INTERVAL_SEC 90 +#define DEFAULT_SAP_IP "224.0.0.56" +#define DEFAULT_SAP_PORT 9875 +#define DEFAULT_SESS_LATENCY 100 -#define BUFFER_SIZE (1u<<22) -#define BUFFER_MASK (BUFFER_SIZE-1) +#define BUFFER_SIZE (1u<<22) +#define BUFFER_MASK (BUFFER_SIZE-1) #define USAGE "sap.ip=<SAP IP address to listen on, default "DEFAULT_SAP_IP"> " \ "sap.port=<SAP port to listen on, default "SPA_STRINGIFY(DEFAULT_SAP_PORT)"> " \ "local.ifname=<local interface name to use> " \ "sess.latency.msec=<target network latency, default "SPA_STRINGIFY(DEFAULT_SESS_LATENCY)"> " \ - "stream.props= { key=value ... }" + "stream.props= { key=value ... } " \ + "stream.rules=<rules> " static const struct spa_dict_item module_info = { { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, @@ -150,6 +171,7 @@ char *sap_ip; int sap_port; int sess_latency_msec; + uint32_t cleanup_interval; struct spa_list sessions; uint32_t n_sessions; @@ -217,8 +239,10 @@ struct spa_io_rate_match *rate_match; struct spa_dll dll; uint32_t target_buffer; + uint32_t last_packet_size; float max_error; unsigned buffering:1; + unsigned first:1; }; static void stream_destroy(void *d) @@ -233,8 +257,8 @@ struct session *sess = data; struct pw_buffer *buf; struct spa_data *d; - uint32_t index; - int32_t avail, wanted; + uint32_t index, target_buffer; + int32_t avail, wanted; if ((buf = pw_stream_dequeue_buffer(sess->stream)) == NULL) { pw_log_debug("Out of stream buffers: %m"); @@ -248,27 +272,39 @@ avail = spa_ringbuffer_get_read_index(&sess->ring, &index); - if (avail < wanted || sess->buffering) { - memset(d0.data, 0, wanted); + target_buffer = sess->target_buffer + sess->last_packet_size / 2; + + if (avail < wanted || sess->buffering) { + memset(d0.data, 0, wanted); if (!sess->buffering && sess->have_sync) { - pw_log_info("underrun %u/%u < %u, buffering...", - avail, sess->target_buffer, wanted); + pw_log_debug("underrun %u/%u < %u, buffering...", + avail, target_buffer, wanted); sess->buffering = true; } - } else { + } else { float error, corr; - if (avail > (int32_t)BUFFER_SIZE) { - index += avail - sess->target_buffer; - avail = sess->target_buffer; - pw_log_warn("overrun %u > %u", avail, BUFFER_SIZE); + if (avail > (int32_t)SPA_MIN(target_buffer * 8, BUFFER_SIZE)) { + pw_log_warn("overrun %u > %u", avail, target_buffer * 8); + index += avail - target_buffer; + avail = target_buffer; } else { - error = (float)sess->target_buffer - (float)avail; + if (sess->first) { + if ((uint32_t)avail > target_buffer) { + uint32_t skip = avail - target_buffer; + pw_log_debug("first: avail:%d skip:%u target:%u", + avail, skip, target_buffer); + index += skip; + avail = target_buffer; + } + sess->first = false; + } + error = (float)target_buffer - (float)avail; error = SPA_CLAMP(error, -sess->max_error, sess->max_error); corr = spa_dll_update(&sess->dll, error); pw_log_debug("avail:%u target:%u error:%f corr:%f", avail, - sess->target_buffer, error, corr); + target_buffer, error, corr); if (sess->rate_match) { SPA_FLAG_SET(sess->rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE); @@ -278,16 +314,16 @@ spa_ringbuffer_read_data(&sess->ring, sess->buffer, BUFFER_SIZE, - index & BUFFER_MASK, - d0.data, wanted); + index & BUFFER_MASK, + d0.data, wanted); - index += wanted; - spa_ringbuffer_read_update(&sess->ring, index); - } - d0.chunk->size = wanted; - d0.chunk->stride = sess->info.stride; - d0.chunk->offset = 0; - buf->size = wanted / sess->info.stride; + index += wanted; + spa_ringbuffer_read_update(&sess->ring, index); + } + d0.chunk->size = wanted; + d0.chunk->stride = sess->info.stride; + d0.chunk->offset = 0; + buf->size = wanted / sess->info.stride; pw_stream_queue_buffer(sess->stream, buf); } @@ -342,7 +378,6 @@ uint16_t seq; int32_t filled; - pw_log_trace("got rtp"); if ((len = recv(fd, buffer, sizeof(buffer), 0)) < 0) goto receive_error; @@ -378,17 +413,19 @@ expected_index = timestamp * sess->info.stride; if (!sess->have_sync) { + pw_log_trace("got rtp, no sync"); sess->ring.readindex = sess->ring.writeindex = index = expected_index; filled = 0; sess->have_sync = true; sess->buffering = true; - pw_log_info("sync to timestamp %u", index); + pw_log_debug("sync to timestamp %u", index); spa_dll_init(&sess->dll); spa_dll_set_bw(&sess->dll, SPA_DLL_BW_MIN, 128, sess->info.info.rate); } else if (expected_index != index) { + pw_log_trace("got rtp, wrong timestamp"); pw_log_debug("unexpected timestamp (%u != %u)", index / sess->info.stride, expected_index / sess->info.stride); @@ -397,9 +434,12 @@ } if (filled + len > BUFFER_SIZE) { - pw_log_warn("capture overrun %u %zd", filled, len); + pw_log_debug("got rtp, capture overrun %u %zd", filled, len); sess->have_sync = false; } else { + uint32_t target_buffer; + + pw_log_trace("got rtp packet len:%zd", len); spa_ringbuffer_write_data(&sess->ring, sess->buffer, BUFFER_SIZE, @@ -409,10 +449,13 @@ filled += len; spa_ringbuffer_write_update(&sess->ring, index); - if (sess->buffering && (uint32_t)filled > sess->target_buffer) { + sess->last_packet_size = len; + target_buffer = sess->target_buffer + len/2; + + if (sess->buffering && (uint32_t)filled > target_buffer) { sess->buffering = false; - pw_log_info("buffering done %u > %u", - filled, sess->target_buffer); + pw_log_debug("buffering done %u > %u", + filled, target_buffer); } } } @@ -527,8 +570,8 @@ static void session_free(struct session *sess) { - pw_log_info("free session %s %s", sess->info.origin, sess->info.session); if (sess->impl) { + pw_log_info("free session %s %s", sess->info.origin, sess->info.session); sess->impl->n_sessions--; spa_list_remove(&sess->link); } @@ -539,6 +582,25 @@ free(sess); } +struct session_info { + struct session *session; + struct pw_properties *props; + bool matched; +}; + +static int rule_matched(void *data, const char *location, const char *action, + const char *str, size_t len) +{ + struct session_info *i = data; + int res = 0; + + i->matched = true; + if (spa_streq(action, "create-stream")) { + pw_properties_update_string(i->props, str, len); + } + return res; +} + static int session_new(struct impl *impl, struct sdp_info *info) { struct session *session; @@ -547,7 +609,8 @@ uint32_t n_params; uint8_t buffer1024; struct pw_properties *props; - int res, fd; + int res, fd, sess_latency_msec; + const char *str; if (impl->n_sessions >= MAX_SESSIONS) { pw_log_warn("too many sessions (%u >= %u)", impl->n_sessions, MAX_SESSIONS); @@ -559,12 +622,7 @@ return -errno; session->info = *info; - - session->target_buffer = msec_to_bytes(info, impl->sess_latency_msec); - session->max_error = msec_to_bytes(info, ERROR_MSEC); - - spa_dll_init(&session->dll); - spa_dll_set_bw(&session->dll, SPA_DLL_BW_MIN, 128, session->info.info.rate); + session->first = true; props = pw_properties_copy(impl->stream_props); if (props == NULL) { @@ -572,9 +630,6 @@ goto error; } - pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", info->info.rate); - pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%d/%d", - session->target_buffer / (2 * info->stride), info->info.rate); pw_properties_set(props, "rtp.origin", info->origin); pw_properties_setf(props, "rtp.payload", "%u", info->payload); pw_properties_setf(props, "rtp.fmt", "%s/%u/%u", info->format_info->mime, @@ -583,12 +638,42 @@ pw_properties_set(props, "rtp.session", info->session); pw_properties_setf(props, PW_KEY_MEDIA_NAME, "RTP Stream (%s)", info->session); + pw_properties_setf(props, PW_KEY_NODE_NAME, "%s", + info->session); } else { pw_properties_set(props, PW_KEY_MEDIA_NAME, "RTP Stream"); } + if ((str = pw_properties_get(impl->props, "stream.rules")) != NULL) { + struct session_info sinfo = { + .session = session, + .props = props, + }; + pw_conf_match_rules(str, strlen(str), NAME, &props->dict, + rule_matched, &sinfo); + + if (!sinfo.matched) { + res = 0; + pw_log_info("session '%s' was not matched", info->session); + goto error; + } + } + pw_log_info("new session %s %s", info->origin, info->session); + sess_latency_msec = pw_properties_get_uint32(props, + "sess.latency.msec", impl->sess_latency_msec); + + session->target_buffer = msec_to_bytes(info, sess_latency_msec); + session->max_error = msec_to_bytes(info, ERROR_MSEC); + + pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", info->info.rate); + pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%d/%d", + session->target_buffer / (2 * info->stride), info->info.rate); + + spa_dll_init(&session->dll); + spa_dll_set_bw(&session->dll, SPA_DLL_BW_MIN, 128, session->info.info.rate); + session->stream = pw_stream_new(impl->core, "rtp-source playback", props); if (session->stream == NULL) { @@ -938,11 +1023,14 @@ clock_gettime(CLOCK_MONOTONIC, &now); timestamp = SPA_TIMESPEC_TO_NSEC(&now); - interval = CLEANUP_INTERVAL_SEC * SPA_NSEC_PER_SEC; + interval = impl->cleanup_interval * SPA_NSEC_PER_SEC; spa_list_for_each_safe(sess, tmp, &impl->sessions, link) { - if (sess->timestamp + interval < timestamp) + if (sess->timestamp + interval < timestamp) { + pw_log_debug("More than %lu elapsed from last advertisement at %lu", interval, sess->timestamp); + pw_log_info("No advertisement packets found for timeout, closing RTP source"); session_free(sess); + } } } @@ -1013,7 +1101,6 @@ { struct pw_context *context = pw_impl_module_get_context(module); struct impl *impl; - struct pw_properties *props = NULL, *stream_props = NULL; const char *str; struct timespec value, interval; int res = 0; @@ -1024,52 +1111,47 @@ if (impl == NULL) return -errno; + spa_list_init(&impl->sessions); + if (args == NULL) args = ""; - props = pw_properties_new_string(args); - if (props == NULL) { - res = -errno; - pw_log_error( "can't create properties: %m"); - goto out; - } - spa_list_init(&impl->sessions); - impl->props = props; - - stream_props = pw_properties_new(NULL, NULL); - if (stream_props == NULL) { + impl->props = pw_properties_new_string(args); + impl->stream_props = pw_properties_new(NULL, NULL); + if (impl->props == NULL || impl->stream_props == NULL) { res = -errno; pw_log_error( "can't create properties: %m"); goto out; } - impl->stream_props = stream_props; impl->module = module; impl->module_context = context; impl->loop = pw_context_get_main_loop(context); impl->data_loop = pw_data_loop_get_loop(pw_context_get_data_loop(context)); - if (pw_properties_get(stream_props, PW_KEY_NODE_VIRTUAL) == NULL) - pw_properties_set(stream_props, PW_KEY_NODE_VIRTUAL, "true"); - if (pw_properties_get(stream_props, PW_KEY_NODE_NETWORK) == NULL) - pw_properties_set(stream_props, PW_KEY_NODE_NETWORK, "true"); + if (pw_properties_get(impl->stream_props, PW_KEY_NODE_VIRTUAL) == NULL) + pw_properties_set(impl->stream_props, PW_KEY_NODE_VIRTUAL, "true"); + if (pw_properties_get(impl->stream_props, PW_KEY_NODE_NETWORK) == NULL) + pw_properties_set(impl->stream_props, PW_KEY_NODE_NETWORK, "true"); - if ((str = pw_properties_get(props, "stream.props")) != NULL) - pw_properties_update_string(stream_props, str, strlen(str)); + if ((str = pw_properties_get(impl->props, "stream.props")) != NULL) + pw_properties_update_string(impl->stream_props, str, strlen(str)); - str = pw_properties_get(props, "local.ifname"); + str = pw_properties_get(impl->props, "local.ifname"); impl->ifname = str ? strdup(str) : NULL; - str = pw_properties_get(props, "sap.ip"); + str = pw_properties_get(impl->props, "sap.ip"); impl->sap_ip = strdup(str ? str : DEFAULT_SAP_IP); - impl->sap_port = pw_properties_get_uint32(props, + impl->sap_port = pw_properties_get_uint32(impl->props, "sap.port", DEFAULT_SAP_PORT); - impl->sess_latency_msec = pw_properties_get_uint32(props, + impl->sess_latency_msec = pw_properties_get_uint32(impl->props, "sess.latency.msec", DEFAULT_SESS_LATENCY); + impl->cleanup_interval = pw_properties_get_uint32(impl->props, + "sap.interval.sec", DEFAULT_CLEANUP_INTERVAL_SEC); impl->core = pw_context_get_object(impl->module_context, PW_TYPE_INTERFACE_Core); if (impl->core == NULL) { - str = pw_properties_get(props, PW_KEY_REMOTE_NAME); + str = pw_properties_get(impl->props, PW_KEY_REMOTE_NAME); impl->core = pw_context_connect(impl->module_context, pw_properties_new( PW_KEY_REMOTE_NAME, str, @@ -1098,7 +1180,7 @@ } value.tv_sec = 0; value.tv_nsec = 1; - interval.tv_sec = CLEANUP_INTERVAL_SEC; + interval.tv_sec = impl->cleanup_interval; interval.tv_nsec = 0; pw_loop_update_timer(impl->loop, impl->timer, &value, &interval, false);
View file
pipewire-0.3.64.tar.gz/src/modules/module-x11-bell.c -> pipewire-0.3.65.tar.gz/src/modules/module-x11-bell.c
Changed
@@ -46,7 +46,6 @@ #include <pipewire/pipewire.h> #include <pipewire/impl.h> -#include <pipewire/private.h> /** \page page_module_x11_bell PipeWire Module: X11 Bell *
View file
pipewire-0.3.64.tar.gz/src/modules/module-zeroconf-discover.c -> pipewire-0.3.65.tar.gz/src/modules/module-zeroconf-discover.c
Changed
@@ -35,9 +35,9 @@ #include <spa/utils/result.h> #include <spa/utils/string.h> #include <spa/utils/json.h> +#include <spa/param/audio/format-utils.h> #include <pipewire/impl.h> -#include <pipewire/private.h> #include <pipewire/i18n.h> #include <avahi-client/lookup.h>
View file
pipewire-0.3.64.tar.gz/src/pipewire/buffers.c -> pipewire-0.3.65.tar.gz/src/pipewire/buffers.c
Changed
@@ -27,10 +27,6 @@ #include <spa/param/param.h> #include <spa/buffer/alloc.h> -#include <spa/debug/node.h> -#include <spa/debug/pod.h> -#include <spa/debug/format.h> - #include "pipewire/keys.h" #include "pipewire/private.h"
View file
pipewire-0.3.64.tar.gz/src/pipewire/conf.c -> pipewire-0.3.65.tar.gz/src/pipewire/conf.c
Changed
@@ -361,7 +361,7 @@ } SPA_EXPORT -int pw_conf_save_state(const char *prefix, const char *name, struct pw_properties *conf) +int pw_conf_save_state(const char *prefix, const char *name, const struct pw_properties *conf) { char pathPATH_MAX; char *tmp_name; @@ -1013,12 +1013,6 @@ return res == 0 ? data.count : res; } -struct match { - const struct spa_dict *props; - int (*matched) (void *data, const char *location, const char *action, - const char *val, size_t len); - void *data; -}; /* * { @@ -1080,7 +1074,7 @@ } /** - * rules = + * * { * matches = * # any of the items in matches needs to match, if one does, @@ -1099,11 +1093,13 @@ * } * */ -static int match_rules(void *data, const char *location, const char *section, - const char *str, size_t len) +SPA_EXPORT +int pw_conf_match_rules(const char *str, size_t len, const char *location, + const struct spa_dict *props, + int (*callback) (void *data, const char *location, const char *action, + const char *str, size_t len), + void *data) { - struct match *match = data; - const struct spa_dict *props = match->props; const char *val; struct spa_json it4, actions; @@ -1142,13 +1138,28 @@ if (spa_json_is_container(val, len)) len = spa_json_container_len(&actions, val, len); - if ((res = match->matched(match->data, location, key, val, len)) < 0) + if ((res = callback(data, location, key, val, len)) < 0) return res; } } return 0; } +struct match { + const struct spa_dict *props; + int (*matched) (void *data, const char *location, const char *action, + const char *val, size_t len); + void *data; +}; + +static int match_rules(void *data, const char *location, const char *section, + const char *str, size_t len) +{ + struct match *match = data; + return pw_conf_match_rules(str, len, location, + match->props, match->matched, match->data); +} + SPA_EXPORT int pw_context_conf_section_match_rules(struct pw_context *context, const char *section, const struct spa_dict *props,
View file
pipewire-0.3.64.tar.gz/src/pipewire/conf.h -> pipewire-0.3.65.tar.gz/src/pipewire/conf.h
Changed
@@ -38,6 +38,11 @@ int pw_conf_load_state(const char *prefix, const char *name, struct pw_properties *conf); int pw_conf_save_state(const char *prefix, const char *name, const struct pw_properties *conf); +int pw_conf_match_rules(const char *str, size_t len, const char *location, + const struct spa_dict *props, + int (*callback) (void *data, const char *location, const char *action, + const char *str, size_t len), + void *data); /** * \}
View file
pipewire-0.3.64.tar.gz/src/pipewire/context.c -> pipewire-0.3.65.tar.gz/src/pipewire/context.c
Changed
@@ -38,7 +38,6 @@ #include <spa/node/utils.h> #include <spa/utils/names.h> #include <spa/utils/string.h> -#include <spa/debug/format.h> #include <spa/debug/types.h> #include <pipewire/impl.h>
View file
pipewire-0.3.64.tar.gz/src/pipewire/filter.c -> pipewire-0.3.65.tar.gz/src/pipewire/filter.c
Changed
@@ -36,9 +36,7 @@ #include <spa/utils/string.h> #include <spa/pod/filter.h> #include <spa/pod/dynamic.h> -#include <spa/debug/format.h> #include <spa/debug/types.h> -#include <spa/debug/pod.h> #include "pipewire/pipewire.h" #include "pipewire/filter.h"
View file
pipewire-0.3.64.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.65.tar.gz/src/pipewire/impl-link.c
Changed
@@ -31,14 +31,11 @@ #include <spa/pod/parser.h> #include <spa/pod/compare.h> #include <spa/param/param.h> +#include <spa/debug/types.h> #include "pipewire/impl-link.h" #include "pipewire/private.h" -#include <spa/debug/node.h> -#include <spa/debug/pod.h> -#include <spa/debug/format.h> - PW_LOG_TOPIC_EXTERN(log_link); #define PW_LOG_TOPIC_DEFAULT log_link
View file
pipewire-0.3.64.tar.gz/src/pipewire/impl-module.h -> pipewire-0.3.65.tar.gz/src/pipewire/impl-module.h
Changed
@@ -106,6 +106,9 @@ /** Destroy a module */ void pw_impl_module_destroy(struct pw_impl_module *module); +/** Schedule a destroy later on the main thread */ +void pw_impl_module_schedule_destroy(struct pw_impl_module *module); + /** * \} */
View file
pipewire-0.3.64.tar.gz/src/pipewire/impl-node.h -> pipewire-0.3.65.tar.gz/src/pipewire/impl-node.h
Changed
@@ -175,6 +175,10 @@ /** Check if a node is active, Since 0.3.39 */ int pw_impl_node_send_command(struct pw_impl_node *node, const struct spa_command *command); + +/** Set a param on the node, Since 0.3.65 */ +int pw_impl_node_set_param(struct pw_impl_node *node, + uint32_t id, uint32_t flags, const struct spa_pod *param); /** * \} */
View file
pipewire-0.3.64.tar.gz/src/pipewire/keys.h -> pipewire-0.3.65.tar.gz/src/pipewire/keys.h
Changed
@@ -29,6 +29,7 @@ extern "C" { #endif +#include <pipewire/utils.h> /** * \defgroup pw_keys Key Names * @@ -197,6 +198,9 @@ * but it will be triggered explicitly. */ #define PW_KEY_NODE_CHANNELNAMES "node.channel-names" /**< names of node's * channels (unrelated to positions) */ +#define PW_KEY_NODE_DEVICE_PORT_NAME_PREFIX "node.device-port-name-prefix" /** override + * port name prefix for device ports, like capture and playback + * or disable the prefix completely if an empty string is provided */ /** Port keys */ #define PW_KEY_PORT_ID "port.id" /**< port id */ @@ -334,14 +338,14 @@ #define PW_KEY_VIDEO_FORMAT "video.format" /**< a video format */ #define PW_KEY_VIDEO_SIZE "video.size" /**< a video size as "<width>x<height" */ -#ifdef PW_ENABLE_DEPRECATED -#define PW_KEY_PRIORITY_MASTER "priority.master" /**< deprecated */ -#define PW_KEY_NODE_TARGET "node.target" /**< deprecated since 0.3.64, use target.object. */ -#endif /* PW_ENABLE_DEPRECATED */ - #define PW_KEY_TARGET_OBJECT "target.object" /**< a target object to link to. This can be * and object name or object.serial */ +#ifndef PW_REMOVE_DEPRECATED +#define PW_KEY_PRIORITY_MASTER PW_DEPRECATED("priority.master") /**< deprecated, use priority.driver */ +#define PW_KEY_NODE_TARGET PW_DEPRECATED("node.target") /**< deprecated since 0.3.64, use target.object. */ +#endif /* PW_REMOVE_DEPRECATED */ + /** \} */
View file
pipewire-0.3.64.tar.gz/src/pipewire/log.c -> pipewire-0.3.65.tar.gz/src/pipewire/log.c
Changed
@@ -232,187 +232,21 @@ * realtime threads */ -struct log_ctx { - enum spa_log_level level; - const char *file; - int line; - const char *func; -}; - -#define _log(_c,fmt,...) pw_log_log(_c->level, _c->file, _c->line, _c->func, \ - "%*s" fmt, indent, "", ## __VA_ARGS__) - -static inline int -log_pod_value(struct log_ctx *ctx, int indent, const struct spa_type_info *info, - uint32_t type, void *body, uint32_t size) -{ - switch (type) { - case SPA_TYPE_Bool: - _log(ctx, "Bool %s", (*(int32_t *) body) ? "true" : "false"); - break; - case SPA_TYPE_Id: - _log(ctx, "Id %-8d (%s)", *(int32_t *) body, - spa_debug_type_find_name(info, *(int32_t *) body)); - break; - case SPA_TYPE_Int: - _log(ctx, "Int %d", *(int32_t *) body); - break; - case SPA_TYPE_Long: - _log(ctx, "Long %" PRIi64 "", *(int64_t *) body); - break; - case SPA_TYPE_Float: - _log(ctx, "Float %f", *(float *) body); - break; - case SPA_TYPE_Double: - _log(ctx, "Double %f", *(double *) body); - break; - case SPA_TYPE_String: - _log(ctx, "String \"%s\"", (char *) body); - break; - case SPA_TYPE_Fd: - _log(ctx, "Fd %d", *(int *) body); - break; - case SPA_TYPE_Pointer: - { - struct spa_pod_pointer_body *b = (struct spa_pod_pointer_body *)body; - _log(ctx, "Pointer %s %p", - spa_debug_type_find_name(SPA_TYPE_ROOT, b->type), b->value); - break; - } - case SPA_TYPE_Rectangle: - { - struct spa_rectangle *r = (struct spa_rectangle *)body; - _log(ctx, "Rectangle %dx%d", r->width, r->height); - break; - } - case SPA_TYPE_Fraction: - { - struct spa_fraction *f = (struct spa_fraction *)body; - _log(ctx, "Fraction %d/%d", f->num, f->denom); - break; - } - case SPA_TYPE_Bitmap: - _log(ctx, "Bitmap"); - break; - case SPA_TYPE_Array: - { - struct spa_pod_array_body *b = (struct spa_pod_array_body *)body; - void *p; - const struct spa_type_info *ti = spa_debug_type_find(SPA_TYPE_ROOT, b->child.type); - - _log(ctx, "Array: child.size %d, child.type %s", b->child.size, - ti ? ti->name : "unknown"); - - SPA_POD_ARRAY_BODY_FOREACH(b, size, p) - log_pod_value(ctx, indent + 2, info, b->child.type, p, b->child.size); - break; - } - case SPA_TYPE_Choice: - { - struct spa_pod_choice_body *b = (struct spa_pod_choice_body *)body; - void *p; - const struct spa_type_info *ti = spa_debug_type_find(spa_type_choice, b->type); - - _log(ctx, "Choice: type %s, flags %08x %d %d", - ti ? ti->name : "unknown", b->flags, size, b->child.size); - - SPA_POD_CHOICE_BODY_FOREACH(b, size, p) - log_pod_value(ctx, indent + 2, info, b->child.type, p, b->child.size); - break; - } - case SPA_TYPE_Struct: - { - struct spa_pod *b = (struct spa_pod *)body, *p; - _log(ctx, "Struct: size %d", size); - SPA_POD_FOREACH(b, size, p) - log_pod_value(ctx, indent + 2, info, p->type, SPA_POD_BODY(p), p->size); - break; - } - case SPA_TYPE_Object: - { - struct spa_pod_object_body *b = (struct spa_pod_object_body *)body; - struct spa_pod_prop *p; - const struct spa_type_info *ti, *ii; - - ti = spa_debug_type_find(info, b->type); - ii = ti ? spa_debug_type_find(ti->values, 0) : NULL; - ii = ii ? spa_debug_type_find(ii->values, b->id) : NULL; - - _log(ctx, "Object: size %d, type %s (%d), id %s (%d)", size, - ti ? ti->name : "unknown", b->type, ii ? ii->name : "unknown", b->id); - - info = ti ? ti->values : info; - - indent += 2; - SPA_POD_OBJECT_BODY_FOREACH(b, size, p) { - ii = spa_debug_type_find(info, p->key); - - _log(ctx, "Prop: key %s (%d), flags %08x", - ii ? ii->name : "unknown", p->key, p->flags); - - log_pod_value(ctx, indent + 2, ii ? ii->values : NULL, - p->value.type, - SPA_POD_CONTENTS(struct spa_pod_prop, p), - p->value.size); - } - indent -= 2; - break; - } - case SPA_TYPE_Sequence: - { - struct spa_pod_sequence_body *b = (struct spa_pod_sequence_body *)body; - const struct spa_type_info *ti, *ii; - struct spa_pod_control *c; - - ti = spa_debug_type_find(info, b->unit); - - _log(ctx, "%*s" "Sequence: size %d, unit %s", indent, "", size, - ti ? ti->name : "unknown"); - - indent +=2; - SPA_POD_SEQUENCE_BODY_FOREACH(b, size, c) { - ii = spa_debug_type_find(spa_type_control, c->type); - - _log(ctx, "Control: offset %d, type %s", - c->offset, ii ? ii->name : "unknown"); - - log_pod_value(ctx, indent + 2, ii ? ii->values : NULL, - c->value.type, - SPA_POD_CONTENTS(struct spa_pod_control, c), - c->value.size); - } - indent -=2; - break; - } - case SPA_TYPE_Bytes: - _log(ctx, "Bytes"); - break; - case SPA_TYPE_None: - _log(ctx, "None"); - break; - default: - _log(ctx, "unhandled POD type %d", type); - break; - } - return 0; -} +#include <spa/debug/pod.h> +#include <spa/debug/log.h> void pw_log_log_object(enum spa_log_level level, - const char *file, - int line, - const char *func, - uint32_t flags, const void *object) + const struct spa_log_topic *topic, const char *file, + int line, const char *func, uint32_t flags, const void *object) { - struct log_ctx ctx = { level, file, 0, func, }; + struct spa_debug_log_ctx ctx = SPA_LOGF_DEBUG_INIT(global_log, level, + topic, file, line, func ); if (flags & PW_LOG_OBJECT_POD) { const struct spa_pod *pod = object; if (pod == NULL) { - pw_log_log(level, file, line, func, "NULL"); + pw_log_logt(level, topic, file, line, func, "NULL"); } else { - log_pod_value(&ctx, 0, SPA_TYPE_ROOT, - SPA_POD_TYPE(pod), - SPA_POD_BODY(pod), - SPA_POD_BODY_SIZE(pod)); + spa_debugc_pod(&ctx.ctx, 0, SPA_TYPE_ROOT, pod); } } }
View file
pipewire-0.3.64.tar.gz/src/pipewire/pipewire.h -> pipewire-0.3.65.tar.gz/src/pipewire/pipewire.h
Changed
@@ -33,6 +33,7 @@ #include <pipewire/array.h> #include <pipewire/client.h> +#include <pipewire/conf.h> #include <pipewire/context.h> #include <pipewire/device.h> #include <pipewire/buffers.h>
View file
pipewire-0.3.64.tar.gz/src/pipewire/private.h -> pipewire-0.3.65.tar.gz/src/pipewire/private.h
Changed
@@ -45,10 +45,6 @@ }; #endif -#ifndef spa_debug -#define spa_debug(...) pw_log_trace(__VA_ARGS__) -#endif - #define MAX_RATES 32u #define CLOCK_MIN_QUANTUM 4u #define CLOCK_MAX_QUANTUM 65536u @@ -1249,8 +1245,6 @@ /** Change the state of the node */ int pw_impl_node_set_state(struct pw_impl_node *node, enum pw_node_state state); -int pw_impl_node_set_param(struct pw_impl_node *node, - uint32_t id, uint32_t flags, const struct spa_pod *param); int pw_impl_node_update_ports(struct pw_impl_node *node); @@ -1282,17 +1276,19 @@ void pw_impl_client_unref(struct pw_impl_client *client); #define PW_LOG_OBJECT_POD (1<<0) -void pw_log_log_object(enum spa_log_level level, const char *file, int line, - const char *func, uint32_t flags, const void *object); +void pw_log_log_object(enum spa_log_level level, const struct spa_log_topic *topic, + const char *file, int line, const char *func, uint32_t flags, + const void *object); -#define pw_log_object(lev,fl,obj) \ -({ \ - if (SPA_UNLIKELY(pw_log_level_enabled (lev))) \ - pw_log_log_object(lev,__FILE__,__LINE__,__func__,(fl),(obj)); \ +#define pw_log_object(lev,t,fl,obj) \ +({ \ + if (SPA_UNLIKELY(pw_log_topic_enabled(lev,t))) \ + pw_log_log_object(lev,t,__FILE__,__LINE__, \ + __func__,(fl),(obj)); \ }) -#define pw_log_pod(lev,pod) pw_log_object(lev,PW_LOG_OBJECT_POD,pod) -#define pw_log_format(lev,pod) pw_log_object(lev,PW_LOG_OBJECT_POD,pod) +#define pw_log_pod(lev,pod) pw_log_object(lev,PW_LOG_TOPIC_DEFAULT,PW_LOG_OBJECT_POD,pod) +#define pw_log_format(lev,pod) pw_log_object(lev,PW_LOG_TOPIC_DEFAULT,PW_LOG_OBJECT_POD,pod) bool pw_log_is_default(void); @@ -1303,8 +1299,6 @@ int pw_settings_expose(struct pw_context *context); void pw_settings_clean(struct pw_context *context); -void pw_impl_module_schedule_destroy(struct pw_impl_module *module); - pthread_attr_t *pw_thread_fill_attr(const struct spa_dict *props, pthread_attr_t *attr); /** \endcond */
View file
pipewire-0.3.64.tar.gz/src/pipewire/stream.c -> pipewire-0.3.65.tar.gz/src/pipewire/stream.c
Changed
@@ -30,14 +30,13 @@ #include <spa/buffer/alloc.h> #include <spa/param/props.h> +#include <spa/param/format-utils.h> #include <spa/node/io.h> #include <spa/node/utils.h> #include <spa/utils/ringbuffer.h> #include <spa/pod/filter.h> #include <spa/pod/dynamic.h> -#include <spa/debug/format.h> #include <spa/debug/types.h> -#include <spa/debug/pod.h> #define PW_ENABLE_DEPRECATED @@ -637,8 +636,10 @@ if (stream->state == PW_STREAM_STATE_PAUSED) { pw_log_debug("%p: start %d", stream, impl->direction); - if (impl->direction == SPA_DIRECTION_INPUT) - impl->io->status = SPA_STATUS_NEED_DATA; + if (impl->direction == SPA_DIRECTION_INPUT) { + if (impl->io != NULL) + impl->io->status = SPA_STATUS_NEED_DATA; + } else if (!impl->process_rt && !impl->driving) { copy_position(impl, impl->queued.incount); call_process(impl); @@ -998,6 +999,9 @@ struct spa_io_buffers *io = impl->io; struct buffer *b; + if (io == NULL) + return -EIO; + pw_log_trace_fp("%p: process in status:%d id:%d ticks:%"PRIu64" delay:%"PRIi64, stream, io->status, io->buffer_id, impl->time.ticks, impl->time.delay); @@ -1038,6 +1042,9 @@ int res; bool ask_more; + if (io == NULL) + return -EIO; + again: pw_log_trace_fp("%p: process out status:%d id:%d", stream, io->status, io->buffer_id); @@ -1397,7 +1404,8 @@ return; if (impl->draining && impl->drained) { impl->draining = false; - impl->io->status = SPA_STATUS_NEED_DATA; + if (impl->io != NULL) + impl->io->status = SPA_STATUS_NEED_DATA; call_drained(impl); } } @@ -1891,11 +1899,12 @@ impl->disconnecting = false; stream_set_state(stream, PW_STREAM_STATE_CONNECTING, NULL); - if (target_id != PW_ID_ANY) + if ((str = getenv("PIPEWIRE_NODE")) != NULL) + pw_properties_set(stream->properties, PW_KEY_TARGET_OBJECT, str); + else if (target_id != PW_ID_ANY) /* XXX this is deprecated but still used by the portal and its apps */ pw_properties_setf(stream->properties, PW_KEY_NODE_TARGET, "%d", target_id); - else if ((str = getenv("PIPEWIRE_NODE")) != NULL) - pw_properties_set(stream->properties, PW_KEY_TARGET_OBJECT, str); + if ((flags & PW_STREAM_FLAG_AUTOCONNECT) && pw_properties_get(stream->properties, PW_KEY_NODE_AUTOCONNECT) == NULL) { str = getenv("PIPEWIRE_AUTOCONNECT");
View file
pipewire-0.3.64.tar.gz/src/pipewire/utils.h -> pipewire-0.3.65.tar.gz/src/pipewire/utils.h
Changed
@@ -94,6 +94,12 @@ void* pw_reallocarray(void *ptr, size_t nmemb, size_t size); +#ifdef PW_ENABLE_DEPRECATED +#define PW_DEPRECATED(v) (v) +#else +#define PW_DEPRECATED(v) ({ __typeof__(v) _v SPA_DEPRECATED = (v); (void)_v; (v); }) +#endif /* PW_ENABLE_DEPRECATED */ + /** * \} */
View file
pipewire-0.3.64.tar.gz/src/tools/meson.build -> pipewire-0.3.65.tar.gz/src/tools/meson.build
Changed
@@ -32,9 +32,18 @@ endif build_pw_cat = false +build_pw_cat_with_ffmpeg = false +pwcat_deps = sndfile_dep + if get_option('pw-cat').allowed() and sndfile_dep.found() build_pw_cat = true + if pw_cat_ffmpeg.allowed() and avcodec_dep.found() and avformat_dep.found() + pwcat_deps += avcodec_dep + pwcat_deps += avformat_dep + build_pw_cat_with_ffmpeg = true + endif + pwcat_sources = 'pw-cat.c', 'midifile.c', @@ -52,7 +61,7 @@ executable('pw-cat', pwcat_sources, install: true, - dependencies : sndfile_dep, pipewire_dep, mathlib, + dependencies : pwcat_deps, pipewire_dep, mathlib, ) foreach alias : pwcat_aliases @@ -64,6 +73,9 @@ error('pw-cat is enabled but required dependency `sndfile` was not found.') endif summary({'Build pw-cat tool': build_pw_cat}, bool_yn: true, section: 'pw-cat/pw-play/pw-dump tool') +if build_pw_cat + summary({'Build pw-cat with FFmpeg integration': build_pw_cat_with_ffmpeg}, bool_yn: true, section: 'pw-cat/pw-play/pw-dump tool') +endif if dbus_dep.found() executable('pw-reserve',
View file
pipewire-0.3.64.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.65.tar.gz/src/tools/pw-cat.c
Changed
@@ -46,12 +46,18 @@ #include <spa/utils/string.h> #include <spa/utils/json.h> #include <spa/debug/types.h> -#include <spa/debug/pod.h> #include <pipewire/pipewire.h> #include <pipewire/i18n.h> #include <pipewire/extensions/metadata.h> +#include "config.h" + +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION +#include <libavformat/avformat.h> +#include <libavcodec/avcodec.h> +#endif + #include "midifile.h" #include "dsffile.h" @@ -109,6 +115,9 @@ #define TYPE_PCM 0 #define TYPE_MIDI 1 #define TYPE_DSD 2 +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION +#define TYPE_ENCODED 3 +#endif int data_type; const char *remote_name; const char *media_type; @@ -123,6 +132,7 @@ const char *filename; SNDFILE *file; + unsigned int bitrate; unsigned int rate; int channels; struct channelmap channelmap; @@ -151,6 +161,14 @@ struct dsf_file_info info; struct dsf_layout layout; } dsf; + +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION + FILE *encoded_file; + AVFormatContext *fmt_context; + AVStream *astream; + AVCodecContext *ctx; + enum AVSampleFormat sfmt; +#endif }; #define STR_FMTS "(ulaw|alaw|u8|s8|s16|s32|f32|f64)" @@ -233,6 +251,117 @@ return (int)rn; } +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION +static int encoded_playback_fill(struct data *d, void *dest, unsigned int n_frames) +{ + int ret, size = 0; + uint8_t buffer16384 = { 0 }; + + ret = fread(buffer, 1, 16384, d->encoded_file); + if (ret > 0) { + memcpy(dest, buffer, ret); + size = ret; + } + + return (int)size; +} + +static int avcodec_ctx_to_info(struct data *data, AVCodecContext *ctx, struct spa_audio_info *info) +{ + int32_t profile; + + switch (ctx->codec_id) { + case AV_CODEC_ID_VORBIS: + info->media_subtype = SPA_MEDIA_SUBTYPE_vorbis; + info->info.vorbis.rate = data->rate; + info->info.vorbis.channels = data->channels; + break; + case AV_CODEC_ID_MP3: + info->media_subtype = SPA_MEDIA_SUBTYPE_mp3; + info->info.mp3.rate = data->rate; + info->info.mp3.channels = data->channels; + break; + case AV_CODEC_ID_AAC: + info->media_subtype = SPA_MEDIA_SUBTYPE_aac; + info->info.aac.rate = data->rate; + info->info.aac.channels = data->channels; + info->info.aac.bitrate = data->bitrate; + info->info.aac.stream_format = SPA_AUDIO_AAC_STREAM_FORMAT_RAW; + break; + case AV_CODEC_ID_WMAV1: + case AV_CODEC_ID_WMAV2: + case AV_CODEC_ID_WMAPRO: + case AV_CODEC_ID_WMAVOICE: + case AV_CODEC_ID_WMALOSSLESS: + info->media_subtype = SPA_MEDIA_SUBTYPE_wma; + switch (ctx->codec_tag) { + /* TODO see if these hex constants can be replaced by named constants from FFmpeg */ + case 0x161: + profile = SPA_AUDIO_WMA_PROFILE_WMA9; + break; + case 0x162: + profile = SPA_AUDIO_WMA_PROFILE_WMA9_PRO; + break; + case 0x163: + profile = SPA_AUDIO_WMA_PROFILE_WMA9_LOSSLESS; + break; + case 0x166: + profile = SPA_AUDIO_WMA_PROFILE_WMA10; + break; + case 0x167: + profile = SPA_AUDIO_WMA_PROFILE_WMA10_LOSSLESS; + break; + default: + fprintf(stderr, "error: invalid WMA profile\n"); + return -EINVAL; + } + info->info.wma.rate = data->rate; + info->info.wma.channels = data->channels; + info->info.wma.bitrate = data->bitrate; + info->info.wma.block_align = ctx->block_align; + info->info.wma.profile = profile; + break; + case AV_CODEC_ID_FLAC: + info->media_subtype = SPA_MEDIA_SUBTYPE_flac; + info->info.flac.rate = data->rate; + info->info.flac.channels = data->channels; + break; + case AV_CODEC_ID_ALAC: + info->media_subtype = SPA_MEDIA_SUBTYPE_alac; + info->info.alac.rate = data->rate; + info->info.alac.channels = data->channels; + break; + case AV_CODEC_ID_APE: + info->media_subtype = SPA_MEDIA_SUBTYPE_ape; + info->info.ape.rate = data->rate; + info->info.ape.channels = data->channels; + break; + case AV_CODEC_ID_RA_144: + case AV_CODEC_ID_RA_288: + info->media_subtype = SPA_MEDIA_SUBTYPE_ra; + info->info.ra.rate = data->rate; + info->info.ra.channels = data->channels; + break; + case AV_CODEC_ID_AMR_NB: + info->media_subtype = SPA_MEDIA_SUBTYPE_amr; + info->info.amr.rate = data->rate; + info->info.amr.channels = data->channels; + info->info.amr.band_mode = SPA_AUDIO_AMR_BAND_MODE_NB; + break; + case AV_CODEC_ID_AMR_WB: + info->media_subtype = SPA_MEDIA_SUBTYPE_amr; + info->info.amr.rate = data->rate; + info->info.amr.channels = data->channels; + info->info.amr.band_mode = SPA_AUDIO_AMR_BAND_MODE_WB; + break; + default: + fprintf(stderr, "Unsupported encoded media subtype\n"); + return -EINVAL; + } + return 0; +} +#endif + static inline fill_fn playback_fill_fn(uint32_t fmt) { @@ -265,6 +394,10 @@ if (sizeof(double) != 8) return NULL; return sf_playback_fill_f64; +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION + case SPA_AUDIO_FORMAT_ENCODED: + return encoded_playback_fill; +#endif default: break; } @@ -650,10 +783,34 @@ return; if (data->mode == mode_playback) { - n_frames = d->maxsize / data->stride; n_frames = SPA_MIN(n_frames, (int)b->requested); +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION + n_fill_frames = data->fill(data, p, n_frames); + + if (n_fill_frames > 0 || n_frames == 0) { + d->chunk->offset = 0; + if (data->data_type == TYPE_ENCODED) { + d->chunk->stride = 0; + // encoded_playback_fill returns number of bytes + // read and not number of frames like other + // functions for raw audio. + d->chunk->size = n_fill_frames; + b->size = n_fill_frames; + } else { + d->chunk->stride = data->stride; + d->chunk->size = n_fill_frames * data->stride; + b->size = n_frames; + } + have_data = true; + } else if (n_fill_frames < 0) { + fprintf(stderr, "fill error %d\n", n_fill_frames); + } else { + if (data->verbose) + printf("drain start\n"); + } +#else n_fill_frames = data->fill(data, p, n_frames); if (n_fill_frames > 0 || n_frames == 0) { @@ -668,6 +825,7 @@ if (data->verbose) printf("drain start\n"); } +#endif } else { offset = SPA_MIN(d->chunk->offset, d->maxsize); size = SPA_MIN(d->chunk->size, d->maxsize - offset); @@ -825,6 +983,9 @@ " -r, --record Recording mode\n" " -m, --midi Midi mode\n" " -d, --dsd DSD mode\n" +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION + " -o, --encoded Encoded mode\n" +#endif "\n"), fp); } } @@ -1112,6 +1273,94 @@ info->format = (info->format & ~SF_FORMAT_SUBMASK) | SF_FORMAT_VORBIS; } +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION +static int setup_encodedfile(struct data *data) +{ + int ret; + int bits_per_sample; + int num_channels; + char path256 = { 0 }; + + /* We do not support record with encoded media */ + if (data->mode == mode_record) { + return -EINVAL; + } + + strcpy(path, "file:"); + strcat(path, data->filename); + + data->fmt_context = NULL; + ret = avformat_open_input(&data->fmt_context, path, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "Failed to open input\n"); + return -EINVAL; + } + + avformat_find_stream_info (data->fmt_context, NULL); + + data->ctx = avcodec_alloc_context3(NULL); + if (!data->ctx) { + fprintf(stderr, "Could not allocate audio codec context\n"); + avformat_close_input(&data->fmt_context); + return -EINVAL; + } + + // We expect only one stream with audio + data->astream = data->fmt_context->streams0; + avcodec_parameters_to_context (data->ctx, data->astream->codecpar); + + if (data->ctx->codec_type != AVMEDIA_TYPE_AUDIO) { + fprintf(stderr, "Not an audio file\n"); + avformat_close_input(&data->fmt_context); + return -EINVAL; + } + + printf("Number of streams: %d Codec id: %x\n", data->fmt_context->nb_streams, + data->ctx->codec_id); + + /* FFmpeg 5.1 (which contains libavcodec 59.37.100) introduced + * a new channel layout API and deprecated the old one. */ +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 37, 100) + num_channels = data->ctx->ch_layout.nb_channels; +#else + num_channels = data->ctx->channels; +#endif + + data->rate = data->ctx->sample_rate; + data->channels = num_channels; + data->sfmt = data->ctx->sample_fmt; + data->stride = 1; // Don't care + + bits_per_sample = av_get_bits_per_sample(data->ctx->codec_id); + data->bitrate = bits_per_sample ? + data->ctx->sample_rate * num_channels * bits_per_sample : data->ctx->bit_rate; + + data->spa_format = SPA_AUDIO_FORMAT_ENCODED; + data->fill = playback_fill_fn(data->spa_format); + + if (data->verbose) + printf("Opened file \"%s\" sample format %08x channels:%d rate:%d bitrate: %d\n", + data->filename, data->ctx->sample_fmt, data->channels, + data->rate, data->bitrate); + + if (data->fill == NULL) { + fprintf(stderr, "Unhandled encoded format %d\n", data->spa_format); + avformat_close_input(&data->fmt_context); + return -EINVAL; + } + + avformat_close_input(&data->fmt_context); + + data->encoded_file = fopen(data->filename, "rb"); + if (!data->encoded_file) { + fprintf(stderr, "Failed to open file\n"); + return -EINVAL; + } + + return 0; +} +#endif + static int setup_sndfile(struct data *data) { const struct format_info *fi = NULL; @@ -1335,7 +1584,11 @@ goto error_no_props; } +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION + while ((c = getopt_long(argc, argv, "hvprmdoR:q:P:", long_options, NULL)) != -1) { +#else while ((c = getopt_long(argc, argv, "hvprmdR:q:P:", long_options, NULL)) != -1) { +#endif switch (c) { @@ -1372,6 +1625,12 @@ data.data_type = TYPE_DSD; break; +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION + case 'o': + data.data_type = TYPE_ENCODED; + break; +#endif + case 'R': data.remote_name = optarg; break; @@ -1543,6 +1802,11 @@ case TYPE_DSD: ret = setup_dsffile(&data); break; +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION + case TYPE_ENCODED: + ret = setup_encodedfile(&data); + break; +#endif default: ret = -ENOTSUP; break; @@ -1561,6 +1825,25 @@ ret = setup_properties(&data); switch (data.data_type) { +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION + case TYPE_ENCODED: + { + struct spa_audio_info info; + + spa_zero(info); + info.media_type = SPA_MEDIA_TYPE_audio; + + ret = avcodec_ctx_to_info(&data, data.ctx, &info); + if (ret < 0) { + if (data.encoded_file) { + fclose(data.encoded_file); + } + goto error_bad_file; + } + params0 = spa_format_audio_build(&b, SPA_PARAM_EnumFormat, &info); + break; + } +#endif case TYPE_PCM: { struct spa_audio_info_raw info; @@ -1650,6 +1933,11 @@ /* and wait while we let things run */ pw_main_loop_run(data.loop); +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION + if (data.encoded_file) + fclose(data.encoded_file); +#endif + /* we're returning OK only if got to the point to drain */ if (data.drained) exit_code = EXIT_SUCCESS;
View file
pipewire-0.3.64.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.65.tar.gz/src/tools/pw-cli.c
Changed
@@ -271,7 +271,8 @@ } id = pw_map_insert_new(&data->vars, module); - printf("%d = @module:%d\n", id, pw_global_get_id(pw_impl_module_get_global(module))); + if (data->interactive) + printf("%d = @module:%d\n", id, pw_global_get_id(pw_impl_module_get_global(module))); return true; } @@ -796,7 +797,7 @@ { struct proxy_data *pd = data; struct remote_data *rd = pd->rd; - if (pd->info) + if (pd->info && rd->data->monitoring) printf("remote %d core %d changed\n", rd->id, info->id); pd->info = pw_core_info_update(pd->info, info); if (pd->global == NULL) @@ -817,7 +818,7 @@ { struct proxy_data *pd = data; struct remote_data *rd = pd->rd; - if (pd->info) + if (pd->info && rd->data->monitoring) printf("remote %d module %d changed\n", rd->id, info->id); pd->info = pw_module_info_update(pd->info, info); if (pd->global == NULL) @@ -837,7 +838,7 @@ { struct proxy_data *pd = data; struct remote_data *rd = pd->rd; - if (pd->info) + if (pd->info && rd->data->monitoring) printf("remote %d node %d changed\n", rd->id, info->id); pd->info = pw_node_info_update(pd->info, info); if (pd->global == NULL) @@ -872,7 +873,7 @@ { struct proxy_data *pd = data; struct remote_data *rd = pd->rd; - if (pd->info) + if (pd->info && rd->data->monitoring) printf("remote %d port %d changed\n", rd->id, info->id); pd->info = pw_port_info_update(pd->info, info); if (pd->global == NULL) @@ -893,7 +894,7 @@ { struct proxy_data *pd = data; struct remote_data *rd = pd->rd; - if (pd->info) + if (pd->info && rd->data->monitoring) printf("remote %d factory %d changed\n", rd->id, info->id); pd->info = pw_factory_info_update(pd->info, info); if (pd->global == NULL) @@ -913,7 +914,7 @@ { struct proxy_data *pd = data; struct remote_data *rd = pd->rd; - if (pd->info) + if (pd->info && rd->data->monitoring) printf("remote %d client %d changed\n", rd->id, info->id); pd->info = pw_client_info_update(pd->info, info); if (pd->global == NULL) @@ -954,7 +955,7 @@ { struct proxy_data *pd = data; struct remote_data *rd = pd->rd; - if (pd->info) + if (pd->info && rd->data->monitoring) printf("remote %d link %d changed\n", rd->id, info->id); pd->info = pw_link_info_update(pd->info, info); if (pd->global == NULL) @@ -975,7 +976,7 @@ { struct proxy_data *pd = data; struct remote_data *rd = pd->rd; - if (pd->info) + if (pd->info && rd->data->monitoring) printf("remote %d device %d changed\n", rd->id, info->id); pd->info = pw_device_info_update(pd->info, info); if (pd->global == NULL) @@ -1422,7 +1423,8 @@ pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd); id = pw_map_insert_new(&data->vars, proxy); - printf("%d = @proxy:%d\n", id, pw_proxy_get_id(proxy)); + if (rd->data->interactive) + printf("%d = @proxy:%d\n", id, pw_proxy_get_id(proxy)); return true; } @@ -1461,7 +1463,8 @@ pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd); id = pw_map_insert_new(&data->vars, proxy); - printf("%d = @proxy:%d\n", id, pw_proxy_get_id(proxy)); + if (rd->data->interactive) + printf("%d = @proxy:%d\n", id, pw_proxy_get_id(proxy)); return true; } @@ -1541,7 +1544,8 @@ pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd); id = pw_map_insert_new(&data->vars, proxy); - printf("%d = @proxy:%d\n", id, pw_proxy_get_id((struct pw_proxy*)proxy)); + if (rd->data->interactive) + printf("%d = @proxy:%d\n", id, pw_proxy_get_id((struct pw_proxy*)proxy)); } static bool do_create_link(struct data *data, const char *cmd, char *args, char **error) @@ -1657,7 +1661,8 @@ proxy = pw_core_export(rd->core, PW_TYPE_INTERFACE_Node, NULL, node, 0); id = pw_map_insert_new(&data->vars, proxy); - printf("%d = @proxy:%d\n", id, pw_proxy_get_id((struct pw_proxy*)proxy)); + if (rd->data->interactive) + printf("%d = @proxy:%d\n", id, pw_proxy_get_id((struct pw_proxy*)proxy)); return true; @@ -1810,8 +1815,9 @@ } p = strtol(a2, NULL, 0); - printf("setting permissions: "PW_PERMISSION_FORMAT"\n", - PW_PERMISSION_ARGS(p)); + if (rd->data->interactive) + printf("setting permissions: "PW_PERMISSION_FORMAT"\n", + PW_PERMISSION_ARGS(p)); permissions0 = PW_PERMISSION_INIT(atoi(a1), p); pw_client_update_permissions((struct pw_client*)global->proxy, @@ -2231,7 +2237,8 @@ " -h, --help Show this help\n" " --version Show version\n" " -d, --daemon Start as daemon (Default false)\n" - " -r, --remote Remote daemon name\n\n"), + " -r, --remote Remote daemon name\n" + " -m, --monitor Monitor activity\n\n"), name); do_help(data, "help", "", NULL);
View file
pipewire-0.3.64.tar.gz/src/tools/pw-dot.c -> pipewire-0.3.65.tar.gz/src/tools/pw-dot.c
Changed
@@ -35,8 +35,6 @@ #include <spa/utils/result.h> #include <spa/utils/string.h> #include <spa/utils/json.h> -#include <spa/debug/pod.h> -#include <spa/debug/format.h> #include <spa/debug/types.h> #include <pipewire/pipewire.h>
View file
pipewire-0.3.64.tar.gz/src/tools/pw-profiler.c -> pipewire-0.3.65.tar.gz/src/tools/pw-profiler.c
Changed
@@ -30,7 +30,7 @@ #include <spa/utils/result.h> #include <spa/utils/string.h> #include <spa/pod/parser.h> -#include <spa/debug/pod.h> +#include <spa/debug/types.h> #include <pipewire/impl.h> #include <pipewire/extensions/profiler.h>
View file
pipewire-0.3.64.tar.gz/src/tools/pw-top.c -> pipewire-0.3.65.tar.gz/src/tools/pw-top.c
Changed
@@ -31,7 +31,7 @@ #include <spa/utils/result.h> #include <spa/utils/string.h> #include <spa/pod/parser.h> -#include <spa/debug/pod.h> +#include <spa/debug/types.h> #include <spa/param/format-utils.h> #include <spa/param/audio/format-utils.h> #include <spa/param/video/format-utils.h>
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.