Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 10
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Thu Jul 7 18:13:40 UTC 2022 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.53 + +------------------------------------------------------------------- Tue Jun 21 11:57:28 UTC 2022 - Bjørn Lie <zaitor@opensuse.org> - Update to version 0.3.52
View file
pipewire-aptx.spec
Changed
@@ -7,7 +7,7 @@ %define soversion 0_2 Name: pipewire-aptx -Version: 0.3.52 +Version: 0.3.53 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/channelmix.c
Deleted
@@ -1,1786 +0,0 @@ -/* Spa - * - * 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. - */ - -#include <errno.h> -#include <string.h> -#include <stdio.h> - -#include <spa/support/plugin.h> -#include <spa/support/log.h> -#include <spa/support/cpu.h> -#include <spa/utils/list.h> -#include <spa/utils/names.h> -#include <spa/utils/json.h> -#include <spa/utils/string.h> -#include <spa/node/keys.h> -#include <spa/node/node.h> -#include <spa/node/io.h> -#include <spa/node/utils.h> -#include <spa/param/audio/format-utils.h> -#include <spa/param/param.h> -#include <spa/pod/filter.h> -#include <spa/debug/types.h> - -#include "channelmix-ops.h" - - -#define DEFAULT_RATE 48000 -#define DEFAULT_CHANNELS 2 - -#define MAX_BUFFERS 32 -#define MAX_DATAS SPA_AUDIO_MAX_CHANNELS -#define MAX_ALIGN CHANNELMIX_OPS_MAX_ALIGN - -#define DEFAULT_CONTROL_BUFFER_SIZE 32768 - -struct impl; - -#define DEFAULT_MUTE false -#define DEFAULT_VOLUME 1.0f - -struct volumes { - bool mute; - uint32_t n_volumes; - float volumesSPA_AUDIO_MAX_CHANNELS; -}; - -static void init_volumes(struct volumes *vol) -{ - uint32_t i; - vol->mute = DEFAULT_MUTE; - vol->n_volumes = 0; - for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) - vol->volumesi = DEFAULT_VOLUME; -} - -struct props { - float volume; - uint32_t n_channels; - uint32_t channel_mapSPA_AUDIO_MAX_CHANNELS; - struct volumes channel; - struct volumes soft; - struct volumes monitor; - unsigned int have_soft_volume:1; - unsigned int disabled:1; -}; - -static void props_reset(struct props *props) -{ - uint32_t i; - props->volume = DEFAULT_VOLUME; - props->n_channels = 0; - for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) - props->channel_mapi = SPA_AUDIO_CHANNEL_UNKNOWN; - init_volumes(&props->channel); - init_volumes(&props->soft); - init_volumes(&props->monitor); -} - -struct buffer { - uint32_t id; -#define BUFFER_FLAG_OUT (1 << 0) - uint32_t flags; - struct spa_list link; - struct spa_buffer *outbuf; - struct spa_meta_header *h; - void *datasMAX_DATAS; -}; - -struct port { - uint32_t direction; - uint32_t id; - - uint64_t info_all; - struct spa_port_info info; -#define IDX_EnumFormat 0 -#define IDX_Meta 1 -#define IDX_IO 2 -#define IDX_Format 3 -#define IDX_Buffers 4 - struct spa_param_info params5; - - struct spa_io_buffers *io; - - bool have_format; - struct spa_audio_info format; - uint32_t stride; - uint32_t blocks; - uint32_t size; - - struct buffer buffersMAX_BUFFERS; - uint32_t n_buffers; - - struct spa_list queue; - - struct spa_pod_sequence *ctrl; - uint32_t ctrl_offset; -}; - -struct impl { - struct spa_handle handle; - struct spa_node node; - - struct spa_log *log; - struct spa_cpu *cpu; - uint32_t quantum_limit; - - enum spa_direction direction; - struct spa_io_position *io_position; - - struct spa_hook_list hooks; - - uint64_t info_all; - struct spa_node_info info; - struct props props; -#define IDX_PropInfo 0 -#define IDX_Props 1 - struct spa_param_info params2; - - - struct port control_port; - struct port in_port; - struct port out_port; - - struct channelmix mix; - unsigned int started:1; - unsigned int is_passthrough:1; - uint32_t cpu_flags; - uint32_t max_align; -}; - -#define IS_CONTROL_PORT(this,d,id) (id == 1 && d == SPA_DIRECTION_INPUT) -#define IS_DATA_PORT(this,d,id) (id == 0) - -#define CHECK_PORT(this,d,id) (IS_CONTROL_PORT(this,d,id) || IS_DATA_PORT(this,d,id)) -#define GET_CONTROL_PORT(this,id) (&this->control_port) -#define GET_IN_PORT(this,id) (&this->in_port) -#define GET_OUT_PORT(this,id) (&this->out_port) -#define GET_PORT(this,d,id) (IS_CONTROL_PORT(this,d,id) ? GET_CONTROL_PORT(this,id) : (d == SPA_DIRECTION_INPUT ? GET_IN_PORT(this,id) : GET_OUT_PORT(this,id))) - -#define _MASK(ch) (1ULL << SPA_AUDIO_CHANNEL_ ## ch) -#define STEREO (_MASK(FL)|_MASK(FR)) - -static void emit_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) { - spa_node_emit_info(&this->hooks, &this->info); - this->info.change_mask = old; - } -} - -static void emit_props_changed(struct impl *this) -{ - this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; - this->paramsIDX_Props.flags ^= SPA_PARAM_INFO_SERIAL; - emit_info(this, false); -} - -static uint64_t default_mask(uint32_t channels) -{ - uint64_t mask = 0; - switch (channels) { - case 7: - case 8: - mask |= _MASK(RL); - mask |= _MASK(RR); - SPA_FALLTHROUGH - case 5: - case 6: - mask |= _MASK(SL); - mask |= _MASK(SR); - if ((channels & 1) == 0) - mask |= _MASK(LFE); - SPA_FALLTHROUGH - case 3: - mask |= _MASK(FC); - SPA_FALLTHROUGH - case 2: - mask |= _MASK(FL); - mask |= _MASK(FR); - break; - case 1: - mask |= _MASK(MONO); - break; - case 4: - mask |= _MASK(FL); - mask |= _MASK(FR); - mask |= _MASK(RL); - mask |= _MASK(RR); - break; - } - return mask; -} - -static void fix_volumes(struct volumes *vols, uint32_t channels) -{ - float s; - uint32_t i; - if (vols->n_volumes > 0) { - s = 0.0f; - for (i = 0; i < vols->n_volumes; i++) - s += vols->volumesi; - s /= vols->n_volumes; - } else { - s = 1.0f; - } - vols->n_volumes = channels; - for (i = 0; i < vols->n_volumes; i++) - vols->volumesi = s; -} - -static int remap_volumes(struct impl *this, const struct spa_audio_info *info) -{ - struct props *p = &this->props; - uint32_t i, j, target = info->info.raw.channels; - - for (i = 0; i < p->n_channels; i++) { - for (j = i; j < target; j++) { - spa_log_debug(this->log, "%d %d: %d <-> %d", i, j, - p->channel_mapi, info->info.raw.positionj); - if (p->channel_mapi != info->info.raw.positionj) - continue; - if (i != j) { - SPA_SWAP(p->channel_mapi, p->channel_mapj); - SPA_SWAP(p->channel.volumesi, p->channel.volumesj); - SPA_SWAP(p->soft.volumesi, p->soft.volumesj); - SPA_SWAP(p->monitor.volumesi, p->monitor.volumesj); - } - break; - } - } - p->n_channels = target; - for (i = 0; i < p->n_channels; i++) - p->channel_mapi = info->info.raw.positioni; - - if (target == 0) - return 0; - if (p->channel.n_volumes != target) - fix_volumes(&p->channel, target); - if (p->soft.n_volumes != target) - fix_volumes(&p->soft, target); - if (p->monitor.n_volumes != target) - fix_volumes(&p->monitor, target); - - return 1; -} - -static void set_volume(struct impl *this) -{ - struct volumes *vol; - - if (this->mix.set_volume == NULL || - this->props.disabled) - return; - - if (this->props.have_soft_volume) - vol = &this->props.soft; - else - vol = &this->props.channel; - - channelmix_set_volume(&this->mix, this->props.volume, vol->mute, - vol->n_volumes, vol->volumes); -} - -static int setup_convert(struct impl *this, - enum spa_direction direction, - const struct spa_audio_info *info) -{ - const struct spa_audio_info *src_info, *dst_info; - uint32_t i, src_chan, dst_chan, p; - uint64_t src_mask, dst_mask; - int res; - - if (direction == SPA_DIRECTION_INPUT) { - src_info = info; - dst_info = &GET_OUT_PORT(this, 0)->format; - } else { - src_info = &GET_IN_PORT(this, 0)->format; - dst_info = info; - } - - src_chan = src_info->info.raw.channels; - dst_chan = dst_info->info.raw.channels; - - for (i = 0, src_mask = 0; i < src_chan; i++) { - p = src_info->info.raw.positioni; - src_mask |= 1ULL << (p < 64 ? p : 0); - } - for (i = 0, dst_mask = 0; i < dst_chan; i++) { - p = dst_info->info.raw.positioni; - dst_mask |= 1ULL << (p < 64 ? p : 0); - } - - if (src_mask & 1) - src_mask = default_mask(src_chan); - if (dst_mask & 1) - dst_mask = default_mask(dst_chan); - - spa_log_info(this->log, "%p: %s/%d@%d->%s/%d@%d %08"PRIx64":%08"PRIx64, this, - spa_debug_type_find_name(spa_type_audio_format, src_info->info.raw.format), - src_chan, - src_info->info.raw.rate, - spa_debug_type_find_name(spa_type_audio_format, dst_info->info.raw.format), - dst_chan, - dst_info->info.raw.rate, - src_mask, dst_mask); - - if (src_info->info.raw.rate != dst_info->info.raw.rate) - return -EINVAL; - - this->mix.src_chan = src_chan; - this->mix.src_mask = src_mask; - this->mix.dst_chan = dst_chan; - this->mix.dst_mask = dst_mask; - this->mix.cpu_flags = this->cpu_flags; - this->mix.log = this->log; - this->mix.freq = src_info->info.raw.rate; - - if ((res = channelmix_init(&this->mix)) < 0) - return res; - - remap_volumes(this, this->direction == SPA_DIRECTION_INPUT ? src_info : dst_info); - set_volume(this); - - emit_props_changed(this); - - this->is_passthrough = SPA_FLAG_IS_SET(this->mix.flags, CHANNELMIX_FLAG_IDENTITY); - if (!this->is_passthrough && this->props.disabled) - return -EINVAL; - - spa_log_debug(this->log, "%p: got channelmix features %08x:%08x flags:%08x passthrough:%d", - this, this->cpu_flags, this->mix.cpu_flags, - this->mix.flags, this->is_passthrough); - - - return 0; -} - -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_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_volume), - SPA_PROP_INFO_description, SPA_POD_String("Volume"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0)); - break; - case 1: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_mute), - SPA_PROP_INFO_description, SPA_POD_String("Mute"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->channel.mute)); - break; - case 2: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_channelVolumes), - SPA_PROP_INFO_description, SPA_POD_String("Channel Volumes"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), - SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); - break; - case 3: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_channelMap), - SPA_PROP_INFO_description, SPA_POD_String("Channel Map"), - SPA_PROP_INFO_type, SPA_POD_Id(SPA_AUDIO_CHANNEL_UNKNOWN), - SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); - break; - case 4: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_softMute), - SPA_PROP_INFO_description, SPA_POD_String("Soft Mute"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->soft.mute)); - break; - case 5: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_softVolumes), - SPA_PROP_INFO_description, SPA_POD_String("Soft Volumes"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), - SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); - break; - case 6: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_monitorMute), - SPA_PROP_INFO_description, SPA_POD_String("Monitor Mute"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->monitor.mute)); - break; - case 7: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_monitorVolumes), - SPA_PROP_INFO_description, SPA_POD_String("Monitor Volumes"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), - SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); - break; - case 8: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_name, SPA_POD_String("channelmix.disable"), - SPA_PROP_INFO_description, SPA_POD_String("Disable Channel mixing"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->disabled), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; - case 9: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_name, SPA_POD_String("channelmix.normalize"), - SPA_PROP_INFO_description, SPA_POD_String("Normalize Volumes"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool( - SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_NORMALIZE)), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; - case 10: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_name, SPA_POD_String("channelmix.mix-lfe"), - SPA_PROP_INFO_description, SPA_POD_String("Mix LFE into channels"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool( - SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_MIX_LFE)), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; - case 11: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_name, SPA_POD_String("channelmix.upmix"), - SPA_PROP_INFO_description, SPA_POD_String("Enable upmixing"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool( - SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_UPMIX)), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; - case 12: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_name, SPA_POD_String("channelmix.lfe-cutoff"), - SPA_PROP_INFO_description, SPA_POD_String("LFE cutoff frequency (Hz)"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float( - this->mix.lfe_cutoff, 0.0, 1000.0), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; - case 13: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_name, SPA_POD_String("channelmix.fc-cutoff"), - SPA_PROP_INFO_description, SPA_POD_String("FC cutoff frequency (Hz)"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float( - this->mix.fc_cutoff, 0.0, 48000.0), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; - case 14: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_name, SPA_POD_String("channelmix.rear-delay"), - SPA_PROP_INFO_description, SPA_POD_String("Rear channels delay (ms)"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float( - this->mix.rear_delay, 0.0, 1000.0), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; - case 15: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_name, SPA_POD_String("channelmix.stereo-widen"), - SPA_PROP_INFO_description, SPA_POD_String("Stereo widen"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float( - this->mix.widen, 0.0, 1.0), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; - case 16: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_name, SPA_POD_String("channelmix.hilbert-taps"), - SPA_PROP_INFO_description, SPA_POD_String("Taps for phase shift of rear"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int( - this->mix.hilbert_taps, 0, MAX_TAPS), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; - case 17: - { - struct spa_pod_frame f2; - uint32_t i; - spa_pod_builder_push_object(&b, &f0, - SPA_TYPE_OBJECT_PropInfo, id); - spa_pod_builder_add(&b, - SPA_PROP_INFO_name, SPA_POD_String("channelmix.upmix-method"), - SPA_PROP_INFO_description, SPA_POD_String("Upmix Method to use"), - SPA_PROP_INFO_type, SPA_POD_String( - channelmix_upmix_infothis->mix.upmix.label), - 0); - spa_pod_builder_prop(&b, SPA_PROP_INFO_labels, 0); - spa_pod_builder_push_struct(&b, &f1); - for (i = 0; i < SPA_N_ELEMENTS(channelmix_upmix_info); i++) { - spa_pod_builder_string(&b, channelmix_upmix_infoi.label); - spa_pod_builder_string(&b, channelmix_upmix_infoi.description); - } - spa_pod_builder_pop(&b, &f1); - spa_pod_builder_add(&b, - SPA_PROP_INFO_params, SPA_POD_Bool(true), - 0); - param = spa_pod_builder_pop(&b, &f0); - break; - } - default: - return 0; - } - break; - } - case SPA_PARAM_Props: - { - struct props *p = &this->props; - struct spa_pod_frame f2; - - switch (result.index) { - case 0: - spa_pod_builder_push_object(&b, &f0, - SPA_TYPE_OBJECT_Props, id); - spa_pod_builder_add(&b, - SPA_PROP_volume, SPA_POD_Float(p->volume), - SPA_PROP_mute, SPA_POD_Bool(p->channel.mute), - SPA_PROP_channelVolumes, SPA_POD_Array(sizeof(float), - SPA_TYPE_Float, - p->channel.n_volumes, - p->channel.volumes), - SPA_PROP_channelMap, SPA_POD_Array(sizeof(uint32_t), - SPA_TYPE_Id, - p->n_channels, - p->channel_map), - SPA_PROP_softMute, SPA_POD_Bool(p->soft.mute), - SPA_PROP_softVolumes, SPA_POD_Array(sizeof(float), - SPA_TYPE_Float, - p->soft.n_volumes, - p->soft.volumes), - SPA_PROP_monitorMute, SPA_POD_Bool(p->monitor.mute), - SPA_PROP_monitorVolumes, SPA_POD_Array(sizeof(float), - SPA_TYPE_Float, - p->monitor.n_volumes, - p->monitor.volumes), - 0); - spa_pod_builder_prop(&b, SPA_PROP_params, 0); - spa_pod_builder_push_struct(&b, &f1); - spa_pod_builder_string(&b, "channelmix.disable"); - spa_pod_builder_bool(&b, this->props.disabled); - spa_pod_builder_string(&b, "channelmix.normalize"); - spa_pod_builder_bool(&b, SPA_FLAG_IS_SET(this->mix.options, - CHANNELMIX_OPTION_NORMALIZE)); - spa_pod_builder_string(&b, "channelmix.mix-lfe"); - spa_pod_builder_bool(&b, SPA_FLAG_IS_SET(this->mix.options, - CHANNELMIX_OPTION_MIX_LFE)); - spa_pod_builder_string(&b, "channelmix.upmix"); - spa_pod_builder_bool(&b, SPA_FLAG_IS_SET(this->mix.options, - CHANNELMIX_OPTION_UPMIX)); - spa_pod_builder_string(&b, "channelmix.lfe-cutoff"); - spa_pod_builder_float(&b, this->mix.lfe_cutoff); - spa_pod_builder_string(&b, "channelmix.fc-cutoff"); - spa_pod_builder_float(&b, this->mix.fc_cutoff); - spa_pod_builder_string(&b, "channelmix.rear-delay"); - spa_pod_builder_float(&b, this->mix.rear_delay); - spa_pod_builder_string(&b, "channelmix.stereo-widen"); - spa_pod_builder_float(&b, this->mix.widen); - spa_pod_builder_string(&b, "channelmix.hilbert-taps"); - spa_pod_builder_int(&b, this->mix.hilbert_taps); - spa_pod_builder_string(&b, "channelmix.upmix-method"); - spa_pod_builder_string(&b, channelmix_upmix_infothis->mix.upmix.label); - spa_pod_builder_pop(&b, &f1); - param = spa_pod_builder_pop(&b, &f0); - 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 channelmix_set_param(struct impl *this, const char *k, const char *s) -{ - if (spa_streq(k, "channelmix.disable")) - this->props.disabled = spa_atob(s); - else if (spa_streq(k, "channelmix.normalize")) - SPA_FLAG_UPDATE(this->mix.options, CHANNELMIX_OPTION_NORMALIZE, spa_atob(s)); - else if (spa_streq(k, "channelmix.mix-lfe")) - SPA_FLAG_UPDATE(this->mix.options, CHANNELMIX_OPTION_MIX_LFE, spa_atob(s)); - else if (spa_streq(k, "channelmix.upmix")) - SPA_FLAG_UPDATE(this->mix.options, CHANNELMIX_OPTION_UPMIX, spa_atob(s)); - else if (spa_streq(k, "channelmix.lfe-cutoff")) - spa_atof(s, &this->mix.lfe_cutoff); - else if (spa_streq(k, "channelmix.fc-cutoff")) - spa_atof(s, &this->mix.fc_cutoff); - else if (spa_streq(k, "channelmix.rear-delay")) - spa_atof(s, &this->mix.rear_delay); - else if (spa_streq(k, "channelmix.stereo-widen")) - spa_atof(s, &this->mix.widen); - else if (spa_streq(k, "channelmix.hilbert-taps")) - spa_atou32(s, &this->mix.hilbert_taps, 0); - else if (spa_streq(k, "channelmix.upmix-method")) - this->mix.upmix = channelmix_upmix_from_label(s); - else - return 0; - return 1; -} - -static int parse_prop_params(struct impl *this, struct spa_pod *params) -{ - struct spa_pod_parser prs; - struct spa_pod_frame f; - int changed = 0; - - spa_pod_parser_pod(&prs, params); - if (spa_pod_parser_push_struct(&prs, &f) < 0) - return 0; - - while (true) { - const char *name; - struct spa_pod *pod; - char value512, buf128; - - if (spa_pod_parser_get_string(&prs, &name) < 0) - break; - - if (spa_pod_parser_get_pod(&prs, &pod) < 0) - break; - - if (spa_pod_is_string(pod)) { - spa_pod_copy_string(pod, sizeof(value), value); - } else if (spa_pod_is_float(pod)) { - snprintf(value, sizeof(value), "%s", - spa_json_format_float(buf, sizeof(buf), - SPA_POD_VALUE(struct spa_pod_float, pod))); - } else if (spa_pod_is_int(pod)) { - snprintf(value, sizeof(value), "%d", - SPA_POD_VALUE(struct spa_pod_int, pod)); - } else if (spa_pod_is_bool(pod)) { - snprintf(value, sizeof(value), "%s", - SPA_POD_VALUE(struct spa_pod_bool, pod) ? - "true" : "false"); - } else - continue; - - spa_log_info(this->log, "key:'%s' val:'%s'", name, value); - changed += channelmix_set_param(this, name, value); - } - if (changed && !this->props.disabled) - channelmix_init(&this->mix); - return changed; -} - -static int apply_props(struct impl *this, const struct spa_pod *param) -{ - struct spa_pod_prop *prop; - struct spa_pod_object *obj = (struct spa_pod_object *) param; - struct props *p = &this->props; - int changed = 0; - bool have_channel_volume = false; - bool have_soft_volume = false; - uint32_t n; - - if (param == NULL) - return 0; - - SPA_POD_OBJECT_FOREACH(obj, prop) { - switch (prop->key) { - case SPA_PROP_volume: - if (spa_pod_get_float(&prop->value, &p->volume) == 0) - changed++; - break; - case SPA_PROP_mute: - if (spa_pod_get_bool(&prop->value, &p->channel.mute) == 0) { - changed++; - have_channel_volume = true; - } - break; - case SPA_PROP_channelVolumes: - if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, - p->channel.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) { - p->channel.n_volumes = n; - changed++; - have_channel_volume = true; - } - break; - case SPA_PROP_channelMap: - if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Id, - p->channel_map, SPA_AUDIO_MAX_CHANNELS)) > 0) { - p->n_channels = n; - changed++; - } - break; - case SPA_PROP_softMute: - if (spa_pod_get_bool(&prop->value, &p->soft.mute) == 0) { - changed++; - have_soft_volume = true; - } - break; - case SPA_PROP_softVolumes: - if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, - p->soft.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) { - p->soft.n_volumes = n; - changed++; - have_soft_volume = true; - } - break; - case SPA_PROP_monitorMute: - if (spa_pod_get_bool(&prop->value, &p->monitor.mute) == 0) - changed++; - break; - case SPA_PROP_monitorVolumes: - if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, - p->monitor.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) { - p->monitor.n_volumes = n; - changed++; - } - break; - case SPA_PROP_params: - changed += parse_prop_params(this, &prop->value); - break; - default: - break; - } - } - - if (changed) { - struct port *port = GET_PORT(this, this->direction, 0); - if (have_soft_volume) - p->have_soft_volume = true; - else if (have_channel_volume) - p->have_soft_volume = false; - - if (port->have_format) - remap_volumes(this, &port->format); - - set_volume(this); - } - return changed; -} - -static int apply_midi(struct impl *this, const struct spa_pod *value) -{ - const uint8_t *val = SPA_POD_BODY(value); - uint32_t size = SPA_POD_BODY_SIZE(value); - struct props *p = &this->props; - - if (size < 3) - return -EINVAL; - - if ((val0 & 0xf0) != 0xb0 || val1 != 7) - return 0; - - p->volume = val2 / 127.0; - set_volume(this); - return 1; -} - -static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size) -{ - struct impl *this = object; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - spa_log_debug(this->log, "%p: io %d %p/%zd", this, id, data, size); - - switch (id) { - case SPA_IO_Position: - this->io_position = data; - break; - default: - return -ENOENT; - } - return 0; -} - -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) - emit_props_changed(this); - break; - default: - return -ENOENT; - } - return 0; -} - -static int impl_node_send_command(void *object, const struct spa_command *command) -{ - struct impl *this = object; - - 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: - this->started = true; - break; - case SPA_NODE_COMMAND_Suspend: - case SPA_NODE_COMMAND_Flush: - case SPA_NODE_COMMAND_Pause: - this->started = false; - break; - default: - return -ENOTSUP; - } - return 0; -} - -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; - struct spa_dict_item items2; - uint32_t n_items = 0; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - spa_hook_list_isolate(&this->hooks, &save, listener, events, data); - - emit_info(this, true); - emit_port_info(this, GET_IN_PORT(this, 0), true); - emit_port_info(this, GET_OUT_PORT(this, 0), true); - - struct port *control_port = GET_CONTROL_PORT(this, 1); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, "control"); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi"); - control_port->info.props = &SPA_DICT_INIT(items, n_items); - emit_port_info(this, control_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 *user_data) -{ - 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 port_enum_formats(void *object, - enum spa_direction direction, uint32_t port_id, - uint32_t index, - struct spa_pod **param, - struct spa_pod_builder *builder) -{ - struct impl *this = object; - - switch (index) { - case 0: - if (IS_CONTROL_PORT(this, direction, port_id)) { - *param = spa_pod_builder_add_object(builder, - 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)); - } else { - struct spa_pod_frame f; - struct port *other; - int32_t channels, min = 1, max = INT32_MAX; - - other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), 0); - - spa_pod_builder_push_object(builder, &f, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat); - 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), - SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_F32P), - 0); - - if (other->have_format) { - channels = other->format.info.raw.channels; - if (this->props.disabled) - min = max = channels; - - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_rate, SPA_POD_Int(other->format.info.raw.rate), - SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int( - channels, min, max), - 0); - } else { - uint32_t rate = this->io_position ? - this->io_position->clock.rate.denom : DEFAULT_RATE; - channels = DEFAULT_CHANNELS; - - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int(rate, 0, INT32_MAX), - SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int( - channels, min, max), - 0); - } - *param = spa_pod_builder_pop(builder, &f); - } - break; - default: - return 0; - } - 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, *other; - struct spa_pod *param; - struct spa_pod_builder b = { 0 }; - uint8_t buffer1024; - 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 = GET_PORT(this, direction, port_id); - other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), port_id); - - spa_log_debug(this->log, "%p: enum params port %d.%d %d %u", - this, direction, port_id, seq, 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 ((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; - - if (IS_CONTROL_PORT(this, direction, port_id)) - 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)); - else - param = spa_format_audio_raw_build(&b, id, &port->format.info.raw); - break; - - case SPA_PARAM_Buffers: - { - uint32_t buffers, size; - - if (!port->have_format) - return -EIO; - if (result.index > 0) - return 0; - - if (IS_CONTROL_PORT(this, direction, port_id)) { - 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(1), - SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - DEFAULT_CONTROL_BUFFER_SIZE, - 1024, - INT32_MAX), - SPA_PARAM_BUFFERS_stride, SPA_POD_Int(1)); - } else { - if (other->n_buffers > 0) { - buffers = other->n_buffers; - size = other->size / other->stride; - } else { - buffers = 1; - size = this->quantum_limit; - } - - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_ParamBuffers, id, - SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(buffers, 1, MAX_BUFFERS), - SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(port->blocks), - SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - size * port->stride, - 16 * port->stride, - INT32_MAX), - SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); - } - break; - } - case SPA_PARAM_Meta: - switch (result.index) { - case 0: - if (IS_CONTROL_PORT(this, direction, port_id)) - return -EINVAL; - - 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; - 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_debug(this->log, "%p: clear buffers %p", this, port); - port->n_buffers = 0; - spa_list_init(&port->queue); - } - return 0; -} - -static int port_set_format(void *object, - enum spa_direction direction, - uint32_t port_id, - uint32_t flags, - const struct spa_pod *format) -{ - struct impl *this = object; - struct port *port, *other; - int res = 0; - - port = GET_PORT(this, direction, port_id); - other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), port_id); - - if (format == NULL) { - if (port->have_format) { - port->have_format = false; - clear_buffers(this, port); - if (this->mix.process) - channelmix_free(&this->mix); - } - } else { - struct spa_audio_info info = { 0 }; - - if ((res = spa_format_parse(format, &info.media_type, &info.media_subtype)) < 0) - return res; - - if (IS_CONTROL_PORT(this, direction, port_id)) { - if (info.media_type != SPA_MEDIA_TYPE_application || - info.media_subtype != SPA_MEDIA_SUBTYPE_control) - return -EINVAL; - } else { - if (info.media_type != SPA_MEDIA_TYPE_audio || - info.media_subtype != SPA_MEDIA_SUBTYPE_raw) - return -EINVAL; - - if (spa_format_audio_raw_parse(format, &info.info.raw) < 0) - return -EINVAL; - - if (info.info.raw.format != SPA_AUDIO_FORMAT_F32P) - return -EINVAL; - - port->stride = sizeof(float); - port->blocks = info.info.raw.channels; - - if (other->have_format) { - if ((res = setup_convert(this, direction, &info)) < 0) - return res; - } - } - port->format = info; - port->have_format = true; - - spa_log_debug(this->log, "%p: set format on port %d %d", this, port_id, res); - } - - 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 res; -} - -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(object, direction, port_id, flags, param); - default: - break; - } - - return -ENOENT; -} - -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, j, size = SPA_ID_INVALID; - - 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); - - if (IS_DATA_PORT(this, direction, port_id)) - spa_return_val_if_fail(port->have_format, -EIO); - - spa_log_debug(this->log, "%p: use buffers %d on port %d", this, n_buffers, port_id); - - clear_buffers(this, port); - - for (i = 0; i < n_buffers; i++) { - struct buffer *b; - uint32_t n_datas = buffersi->n_datas; - struct spa_data *d = buffersi->datas; - - b = &port->buffersi; - b->id = i; - b->flags = 0; - b->outbuf = buffersi; - b->h = spa_buffer_find_meta_data(buffersi, SPA_META_Header, sizeof(*b->h)); - - for (j = 0; j < n_datas; j++) { - if (size == SPA_ID_INVALID) - size = dj.maxsize; - else if (size != dj.maxsize) - return -EINVAL; - - if (dj.data == NULL) { - spa_log_error(this->log, "%p: invalid memory on buffer %p", this, - buffersi); - return -EINVAL; - } - if (!SPA_IS_ALIGNED(dj.data, this->max_align)) { - spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned", - this, j, i); - } - b->datasj = dj.data; - if (direction == SPA_DIRECTION_OUTPUT && - !SPA_FLAG_IS_SET(dj.flags, SPA_DATA_FLAG_DYNAMIC)) - this->is_passthrough = false; - } - if (direction == SPA_DIRECTION_OUTPUT) - spa_list_append(&port->queue, &b->link); - else - SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT); - } - port->n_buffers = n_buffers; - port->size = size; - - 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 void recycle_buffer(struct impl *this, uint32_t id) -{ - struct port *port = GET_OUT_PORT(this, 0); - struct buffer *b = &port->buffersid; - - if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUT)) { - spa_list_append(&port->queue, &b->link); - SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT); - spa_log_trace_fp(this->log, "%p: recycle buffer %d", this, id); - } -} - -static struct buffer *dequeue_buffer(struct impl *this, struct port *port) -{ - struct buffer *b; - - if (spa_list_is_empty(&port->queue)) - return NULL; - - b = spa_list_first(&port->queue, struct buffer, link); - spa_list_remove(&b->link); - SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT); - - return b; -} - - -static int impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id) -{ - struct impl *this = object; - - spa_return_val_if_fail(this != NULL, -EINVAL); - spa_return_val_if_fail(CHECK_PORT(this, SPA_DIRECTION_OUTPUT, port_id), -EINVAL); - - recycle_buffer(this, buffer_id); - - return 0; -} - -static int channelmix_process_control(struct impl *this, struct port *ctrlport, - void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, - uint32_t n_samples) -{ - struct spa_pod_control *c, *prev = NULL; - uint32_t avail_samples = n_samples; - uint32_t i; - const float **s = (const float **)src; - float **d = (float **)dst; - - SPA_POD_SEQUENCE_FOREACH(ctrlport->ctrl, c) { - uint32_t chunk; - - if (avail_samples == 0) - return 0; - - /* ignore old control offsets */ - if (c->offset <= ctrlport->ctrl_offset) { - prev = c; - continue; - } - - switch (c->type) { - case SPA_CONTROL_Midi: - { - if (prev) - apply_midi(this, &prev->value); - break; - } - case SPA_CONTROL_Properties: - { - if (prev) - apply_props(this, &prev->value); - break; - } - default: - continue; - } - - chunk = SPA_MIN(avail_samples, c->offset - ctrlport->ctrl_offset); - - spa_log_trace_fp(this->log, "%p: process %d %d", this, - c->offset, chunk); - - channelmix_process(&this->mix, dst, src, chunk); - for (i = 0; i < this->mix.src_chan; i++) - si += chunk; - for (i = 0; i < this->mix.dst_chan; i++) - di += chunk; - - avail_samples -= chunk; - ctrlport->ctrl_offset += chunk; - - prev = c; - } - - /* when we get here we run out of control points but still have some - * remaining samples */ - spa_log_trace_fp(this->log, "%p: remain %d", this, avail_samples); - if (avail_samples > 0) - channelmix_process(&this->mix, dst, src, avail_samples); - - return 1; -} - -static int impl_node_process(void *object) -{ - struct impl *this = object; - struct port *outport, *inport, *ctrlport; - struct spa_io_buffers *outio, *inio, *ctrlio; - struct buffer *sbuf, *dbuf; - struct spa_pod_sequence *ctrl = NULL; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - outport = GET_OUT_PORT(this, 0); - inport = GET_IN_PORT(this, 0); - ctrlport = GET_CONTROL_PORT(this, 1); - - outio = outport->io; - inio = inport->io; - ctrlio = ctrlport->io; - - spa_return_val_if_fail(outio != NULL, -EIO); - spa_return_val_if_fail(inio != NULL, -EIO); - - spa_log_trace_fp(this->log, "%p: status %p %d %d -> %p %d %d", this, - inio, inio->status, inio->buffer_id, - outio, outio->status, outio->buffer_id); - - if (SPA_UNLIKELY(outio->status == SPA_STATUS_HAVE_DATA)) - return SPA_STATUS_HAVE_DATA; - /* recycle */ - if (SPA_LIKELY(outio->buffer_id < outport->n_buffers)) { - recycle_buffer(this, outio->buffer_id); - outio->buffer_id = SPA_ID_INVALID; - } - if (SPA_UNLIKELY(inio->status != SPA_STATUS_HAVE_DATA)) - return outio->status = inio->status; - - if (SPA_UNLIKELY(inio->buffer_id >= inport->n_buffers)) - return inio->status = -EINVAL; - - if (SPA_UNLIKELY((dbuf = dequeue_buffer(this, outport)) == NULL)) - return outio->status = -EPIPE; - - sbuf = &inport->buffersinio->buffer_id; - - if (ctrlio != NULL && - ctrlio->status == SPA_STATUS_HAVE_DATA && - ctrlio->buffer_id < ctrlport->n_buffers) { - struct buffer *cbuf = &ctrlport->buffersctrlio->buffer_id; - struct spa_data *d = &cbuf->outbuf->datas0; - - ctrl = spa_pod_from_data(d->data, d->maxsize, d->chunk->offset, d->chunk->size); - if (ctrl && !spa_pod_is_sequence(&ctrl->pod)) - ctrl = NULL; - if (ctrl != ctrlport->ctrl) { - ctrlport->ctrl = ctrl; - ctrlport->ctrl_offset = 0; - } - } - - { - uint32_t i, n_samples; - struct spa_buffer *sb = sbuf->outbuf, *db = dbuf->outbuf; - uint32_t n_src_datas = sb->n_datas; - uint32_t n_dst_datas = db->n_datas; - const void *src_datasn_src_datas; - void *dst_datasn_dst_datas; - bool is_passthrough; - - is_passthrough = this->is_passthrough && - SPA_FLAG_IS_SET(this->mix.flags, CHANNELMIX_FLAG_IDENTITY) && - ctrlport->ctrl == NULL; - - n_samples = sb->datas0.chunk->size / inport->stride; - - for (i = 0; i < n_src_datas; i++) - src_datasi = sb->datasi.data; - for (i = 0; i < n_dst_datas; i++) { - dst_datasi = is_passthrough ? (void*)src_datasi : dbuf->datasi; - db->datasi.data = dst_datasi; - db->datasi.chunk->size = n_samples * outport->stride; - } - - spa_log_trace_fp(this->log, "%p: n_src:%d n_dst:%d n_samples:%d p:%d", - this, n_src_datas, n_dst_datas, n_samples, is_passthrough); - - if (!is_passthrough) { - if (ctrlport->ctrl != NULL) { - /* if return value is 1, the sequence has been processed */ - if (channelmix_process_control(this, ctrlport, dst_datas, - src_datas, n_samples) == 1) { - ctrlio->status = SPA_STATUS_OK; - ctrlport->ctrl = NULL; - } - } else { - channelmix_process(&this->mix, dst_datas, - src_datas, n_samples); - } - } - } - - outio->status = SPA_STATUS_HAVE_DATA; - outio->buffer_id = dbuf->id; - - inio->status = SPA_STATUS_NEED_DATA; - - return SPA_STATUS_HAVE_DATA | SPA_STATUS_NEED_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_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 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 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 inline uint32_t parse_position(uint32_t *pos, const char *val, size_t len) -{ - struct spa_json it2; - char v256; - uint32_t i = 0; - - spa_json_init(&it0, val, len); - if (spa_json_enter_array(&it0, &it1) <= 0) - spa_json_init(&it1, val, len); - - while (spa_json_get_string(&it1, v, sizeof(v)) > 0 && - i < SPA_AUDIO_MAX_CHANNELS) { - posi++ = channel_from_name(v); - } - return i; -} - -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; - 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_log_topic_init(this->log, log_topic); - - this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU); - if (this->cpu) { - this->cpu_flags = spa_cpu_get_flags(this->cpu); - this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu)); - } - - spa_hook_list_init(&this->hooks); - - props_reset(&this->props); - - this->mix.options = CHANNELMIX_OPTION_UPMIX; - this->mix.upmix = CHANNELMIX_UPMIX_PSD; - this->mix.log = this->log; - this->mix.lfe_cutoff = 150.0f; - this->mix.fc_cutoff = 12000.0f; - this->mix.rear_delay = 12.0f; - this->mix.widen = 0.0f; - - 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, SPA_KEY_AUDIO_POSITION)) - this->props.n_channels = parse_position(this->props.channel_map, s, strlen(s)); - else if (spa_streq(k, "clock.quantum-limit")) - spa_atou32(s, &this->quantum_limit, 0); - else if (spa_streq(k, "factory.mode")) { - if (spa_streq(s, "merge")) - this->direction = SPA_DIRECTION_OUTPUT; - else - this->direction = SPA_DIRECTION_INPUT; - } - else - channelmix_set_param(this, k, s); - - } - this->props.channel.n_volumes = this->props.n_channels; - this->props.soft.n_volumes = this->props.n_channels; - this->props.monitor.n_volumes = this->props.n_channels; - - 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.flags = SPA_NODE_FLAG_RT; - this->info.max_input_ports = 2; - this->info.max_output_ports = 1; - 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->info.params = this->params; - this->info.n_params = 2; - - port = GET_OUT_PORT(this, 0); - port->direction = SPA_DIRECTION_OUTPUT; - port->id = 0; - 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_DYNAMIC_DATA; - 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->info.params = port->params; - port->info.n_params = 5; - spa_list_init(&port->queue); - - port = GET_IN_PORT(this, 0); - port->direction = SPA_DIRECTION_INPUT; - port->id = 0; - 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_DYNAMIC_DATA; - 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->info.params = port->params; - port->info.n_params = 0; - spa_list_init(&port->queue); - - port = GET_CONTROL_PORT(this, 1); - port->direction = SPA_DIRECTION_INPUT; - port->id = 1; - 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.flags = SPA_PORT_FLAG_NO_REF | - SPA_PORT_FLAG_DYNAMIC_DATA; - port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); - port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, 0); - 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->info.params = port->params; - port->info.n_params = 4; - spa_list_init(&port->queue); - - 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; -} - -const struct spa_handle_factory spa_channelmix_factory = { - SPA_VERSION_HANDLE_FACTORY, - SPA_NAME_AUDIO_PROCESS_CHANNELMIX, - NULL, - impl_get_size, - impl_init, - impl_enum_interface_info, -};
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/fmtconvert.c
Deleted
@@ -1,1161 +0,0 @@ -/* Spa - * - * 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. - */ - -#include <errno.h> -#include <string.h> -#include <stdio.h> -#include <limits.h> - -#include <spa/support/plugin.h> -#include <spa/support/log.h> -#include <spa/support/cpu.h> -#include <spa/utils/list.h> -#include <spa/utils/names.h> -#include <spa/utils/string.h> -#include <spa/node/node.h> -#include <spa/node/io.h> -#include <spa/node/utils.h> -#include <spa/param/audio/format-utils.h> -#include <spa/param/latency-utils.h> -#include <spa/param/param.h> -#include <spa/pod/filter.h> -#include <spa/debug/types.h> -#include <spa/debug/format.h> - -#include "fmt-ops.h" - -#undef SPA_LOG_TOPIC_DEFAULT -#define SPA_LOG_TOPIC_DEFAULT log_topic -static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.fmtconvert"); - -#define DEFAULT_RATE 48000 -#define DEFAULT_CHANNELS 2 - -#define MAX_BUFFERS 32 -#define MAX_ALIGN FMT_OPS_MAX_ALIGN -#define MAX_DATAS SPA_AUDIO_MAX_CHANNELS - -#define PROP_DEFAULT_TRUNCATE false -#define PROP_DEFAULT_DITHER 0 - -struct impl; - -struct props { - bool truncate; - uint32_t dither; -}; - -static void props_reset(struct props *props) -{ - props->truncate = PROP_DEFAULT_TRUNCATE; - props->dither = PROP_DEFAULT_DITHER; -} - -struct buffer { - uint32_t id; -#define BUFFER_FLAG_OUT (1 << 0) - uint32_t flags; - struct spa_list link; - struct spa_buffer *outbuf; - struct spa_meta_header *h; - void *datasMAX_DATAS; -}; - -struct port { - uint32_t direction; - uint32_t id; - - struct spa_io_buffers *io; - - uint64_t info_all; - struct spa_port_info info; -#define PORT_EnumFormat 0 -#define PORT_Meta 1 -#define PORT_IO 2 -#define PORT_Format 3 -#define PORT_Buffers 4 -#define PORT_Latency 5 -#define N_PORT_PARAMS 6 - struct spa_param_info paramsN_PORT_PARAMS; - - struct spa_audio_info format; - uint32_t stride; - uint32_t blocks; - uint32_t size; - unsigned int have_format:1; - - struct buffer buffersMAX_BUFFERS; - uint32_t n_buffers; - - struct spa_list queue; -}; - -struct impl { - struct spa_handle handle; - struct spa_node node; - - struct spa_log *log; - struct spa_cpu *cpu; - uint32_t cpu_flags; - uint32_t max_align; - uint32_t quantum_limit; - - struct spa_io_position *io_position; - - uint64_t info_all; - struct spa_node_info info; - struct props props; -#define N_NODE_PARAMS 0 - struct spa_param_info params1; - - struct spa_hook_list hooks; - - struct port ports21; - - uint32_t src_remapSPA_AUDIO_MAX_CHANNELS; - uint32_t dst_remapSPA_AUDIO_MAX_CHANNELS; - - struct spa_latency_info latency2; - - struct convert conv; - unsigned int started:1; - unsigned int is_passthrough:1; -}; - -#define CHECK_PORT(this,d,id) (id == 0) -#define GET_PORT(this,d,id) (&this->portsdid) -#define GET_IN_PORT(this,id) GET_PORT(this,SPA_DIRECTION_INPUT,id) -#define GET_OUT_PORT(this,id) GET_PORT(this,SPA_DIRECTION_OUTPUT,id) - -static int can_convert(const struct spa_audio_info *info1, const struct spa_audio_info *info2) -{ - if (info1->info.raw.channels != info2->info.raw.channels || - info1->info.raw.rate != info2->info.raw.rate) { - return 0; - } - return 1; -} - -static int setup_convert(struct impl *this) -{ - uint32_t src_fmt, dst_fmt; - struct spa_audio_info informat, outformat; - struct port *inport, *outport; - uint32_t i, j; - int res; - - inport = GET_IN_PORT(this, 0); - outport = GET_OUT_PORT(this, 0); - - if (!inport->have_format || !outport->have_format) - return -EIO; - - informat = inport->format; - outformat = outport->format; - - src_fmt = informat.info.raw.format; - dst_fmt = outformat.info.raw.format; - - spa_log_info(this->log, "%p: %s/%d@%d->%s/%d@%d", this, - spa_debug_type_find_name(spa_type_audio_format, src_fmt), - informat.info.raw.channels, - informat.info.raw.rate, - spa_debug_type_find_name(spa_type_audio_format, dst_fmt), - outformat.info.raw.channels, - outformat.info.raw.rate); - - if (!can_convert(&informat, &outformat)) - return -EINVAL; - - for (i = 0; i < informat.info.raw.channels; i++) { - for (j = 0; j < outformat.info.raw.channels; j++) { - if (informat.info.raw.positioni != - outformat.info.raw.positionj) - continue; - if (inport->blocks > 1) { - this->src_remapj = i; - if (outport->blocks > 1) - this->dst_remapj = j; - else - this->dst_remapj = 0; - } else { - this->src_remapj = 0; - if (outport->blocks > 1) - this->dst_remapi = j; - else - this->dst_remapj = 0; - } - spa_log_debug(this->log, "%p: channel %d -> %d (%s -> %s)", this, - i, j, - spa_debug_type_find_short_name(spa_type_audio_channel, - informat.info.raw.positioni), - spa_debug_type_find_short_name(spa_type_audio_channel, - outformat.info.raw.positionj)); - outformat.info.raw.positionj = -1; - break; - } - } - this->conv.src_fmt = src_fmt; - this->conv.dst_fmt = dst_fmt; - this->conv.n_channels = outformat.info.raw.channels; - this->conv.cpu_flags = this->cpu_flags; - - if ((res = convert_init(&this->conv)) < 0) - return res; - - this->is_passthrough = this->conv.is_passthrough; - - spa_log_debug(this->log, "%p: got converter features %08x:%08x passthrough:%d", this, - this->cpu_flags, this->conv.cpu_flags, this->is_passthrough); - - return 0; -} - -static int impl_node_enum_params(void *object, int seq, - uint32_t id, uint32_t start, uint32_t num, - const struct spa_pod *filter) -{ - return -ENOTSUP; -} - -static int impl_node_set_param(void *object, uint32_t id, uint32_t flags, - const struct spa_pod *param) -{ - return -ENOTSUP; -} - -static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size) -{ - struct impl *this = object; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - spa_log_debug(this->log, "%p: io %d %p/%zd", this, id, data, size); - - switch (id) { - case SPA_IO_Position: - this->io_position = data; - break; - default: - return -ENOENT; - } - return 0; -} - -static int impl_node_send_command(void *object, const struct spa_command *command) -{ - struct impl *this = object; - - 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: - this->started = true; - break; - case SPA_NODE_COMMAND_Suspend: - case SPA_NODE_COMMAND_Flush: - case SPA_NODE_COMMAND_Pause: - this->started = false; - break; - default: - return -ENOTSUP; - } - return 0; -} - -static void emit_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) { - 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; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - spa_hook_list_isolate(&this->hooks, &save, listener, events, data); - - emit_info(this, true); - emit_port_info(this, GET_IN_PORT(this, 0), true); - emit_port_info(this, GET_OUT_PORT(this, 0), 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 *user_data) -{ - 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 int32_cmp(const void *v1, const void *v2) -{ - int32_t a1 = *(int32_t*)v1; - int32_t a2 = *(int32_t*)v2; - if (a1 == 0 && a2 != 0) - return 1; - if (a2 == 0 && a1 != 0) - return -1; - return a1 - a2; -} - -static int port_enum_formats(void *object, - enum spa_direction direction, uint32_t port_id, - uint32_t index, - struct spa_pod **param, - struct spa_pod_builder *builder) -{ - struct impl *this = object; - struct port *port, *other; - - port = GET_PORT(this, direction, port_id); - other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), 0); - - spa_log_debug(this->log, "%p: enum %p %d %d", this, other, port->have_format, other->have_format); - switch (index) { - case 0: - if (port->have_format) { - *param = spa_format_audio_raw_build(builder, - SPA_PARAM_EnumFormat, &port->format.info.raw); - } - else { - struct spa_pod_frame f; - struct spa_audio_info info; - - spa_pod_builder_push_object(builder, &f, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat); - - 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 (other->have_format) - info = other->format; - else - info.info.raw.format = SPA_AUDIO_FORMAT_F32P; - - if (!other->have_format || - info.info.raw.format == SPA_AUDIO_FORMAT_F32P || - info.info.raw.format == SPA_AUDIO_FORMAT_F32) { - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(29, - info.info.raw.format, - SPA_AUDIO_FORMAT_F32P, - SPA_AUDIO_FORMAT_F32, - SPA_AUDIO_FORMAT_F32_OE, - SPA_AUDIO_FORMAT_F64P, - SPA_AUDIO_FORMAT_F64, - SPA_AUDIO_FORMAT_F64_OE, - SPA_AUDIO_FORMAT_S32P, - SPA_AUDIO_FORMAT_S32, - SPA_AUDIO_FORMAT_S32_OE, - SPA_AUDIO_FORMAT_U32, - SPA_AUDIO_FORMAT_S24_32P, - SPA_AUDIO_FORMAT_S24_32, - SPA_AUDIO_FORMAT_S24_32_OE, - SPA_AUDIO_FORMAT_U24_32, - SPA_AUDIO_FORMAT_S24P, - SPA_AUDIO_FORMAT_S24, - SPA_AUDIO_FORMAT_S24_OE, - SPA_AUDIO_FORMAT_U24, - SPA_AUDIO_FORMAT_S16P, - SPA_AUDIO_FORMAT_S16, - SPA_AUDIO_FORMAT_S16_OE, - SPA_AUDIO_FORMAT_U16, - SPA_AUDIO_FORMAT_S8P, - SPA_AUDIO_FORMAT_S8, - SPA_AUDIO_FORMAT_U8P, - SPA_AUDIO_FORMAT_U8, - SPA_AUDIO_FORMAT_ULAW, - SPA_AUDIO_FORMAT_ALAW), - 0); - } else { - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(5, - info.info.raw.format, - info.info.raw.format, - SPA_AUDIO_FORMAT_F32, - SPA_AUDIO_FORMAT_F32P, - SPA_AUDIO_FORMAT_F32_OE), - 0); - } - if (other->have_format) { - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info.info.raw.rate), - SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info.info.raw.channels), - 0); - if (!SPA_FLAG_IS_SET(info.info.raw.flags, SPA_AUDIO_FLAG_UNPOSITIONED)) { - qsort(info.info.raw.position, info.info.raw.channels, - sizeof(uint32_t), int32_cmp); - spa_pod_builder_prop(builder, SPA_FORMAT_AUDIO_position, 0); - spa_pod_builder_array(builder, sizeof(uint32_t), SPA_TYPE_Id, - info.info.raw.channels, info.info.raw.position); - } - } else { - uint32_t rate = this->io_position ? - this->io_position->clock.rate.denom : DEFAULT_RATE; - - spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int( - rate, 1, INT32_MAX), - SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int( - DEFAULT_CHANNELS, 1, INT32_MAX), - 0); - } - *param = spa_pod_builder_pop(builder, &f); - } - break; - default: - return 0; - } - - 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, *other; - struct spa_pod *param; - struct spa_pod_builder b = { 0 }; - uint8_t buffer4096; - 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 = GET_PORT(this, direction, port_id); - other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), port_id); - - spa_log_debug(this->log, "%p: enum params port %d.%d %d %u", - this, direction, port_id, seq, 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 ((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_raw_build(&b, id, &port->format.info.raw); - break; - - case SPA_PARAM_Buffers: - { - if (!port->have_format) - return -EIO; - if (result.index > 0) - return 0; - - if (other->n_buffers > 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(port->blocks), - SPA_PARAM_BUFFERS_size, SPA_POD_Int(other->size / other->stride * port->stride), - SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); - - - } else { - 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(port->blocks), - SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - this->quantum_limit * 2 * port->stride, - 16 * port->stride, - INT32_MAX), - SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); - } - 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: case 1: - param = spa_latency_build(&b, id, &this->latencyresult.index); - 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 calc_width(struct spa_audio_info *info) -{ - switch (info->info.raw.format) { - case SPA_AUDIO_FORMAT_U8P: - case SPA_AUDIO_FORMAT_U8: - case SPA_AUDIO_FORMAT_S8P: - case SPA_AUDIO_FORMAT_S8: - case SPA_AUDIO_FORMAT_ALAW: - case SPA_AUDIO_FORMAT_ULAW: - return 1; - case SPA_AUDIO_FORMAT_S16P: - case SPA_AUDIO_FORMAT_S16: - case SPA_AUDIO_FORMAT_S16_OE: - case SPA_AUDIO_FORMAT_U16: - return 2; - case SPA_AUDIO_FORMAT_S24P: - case SPA_AUDIO_FORMAT_S24: - case SPA_AUDIO_FORMAT_S24_OE: - case SPA_AUDIO_FORMAT_U24: - return 3; - case SPA_AUDIO_FORMAT_F64P: - case SPA_AUDIO_FORMAT_F64: - case SPA_AUDIO_FORMAT_F64_OE: - return 8; - default: - return 4; - } -} - -static int clear_buffers(struct impl *this, struct port *port) -{ - if (port->n_buffers > 0) { - spa_log_debug(this->log, "%p: clear buffers %p", this, port); - port->n_buffers = 0; - spa_list_init(&port->queue); - } - return 0; -} -static int port_set_format(void *object, - enum spa_direction direction, - uint32_t port_id, - uint32_t flags, - const struct spa_pod *format) -{ - struct impl *this = object; - struct port *port, *other; - int res; - - port = GET_PORT(this, direction, port_id); - other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), port_id); - - if (format == NULL) { - if (port->have_format) { - port->have_format = false; - clear_buffers(this, port); - if (this->conv.process) - convert_free(&this->conv); - } - } else { - struct spa_audio_info info = { 0 }; - - if ((res = spa_format_parse(format, &info.media_type, &info.media_subtype)) < 0) - return res; - - if (info.media_type != SPA_MEDIA_TYPE_audio || - info.media_subtype != SPA_MEDIA_SUBTYPE_raw) - return -EINVAL; - - if (spa_format_audio_raw_parse(format, &info.info.raw) < 0) - return -EINVAL; - - if (other->have_format) { - spa_log_debug(this->log, "%p: channels:%d<>%d rate:%d<>%d format:%d<>%d", this, - info.info.raw.channels, other->format.info.raw.channels, - info.info.raw.rate, other->format.info.raw.rate, - info.info.raw.format, other->format.info.raw.format); - if (!can_convert(&info, &other->format)) - return -ENOTSUP; - } - - port->stride = calc_width(&info); - - if (SPA_AUDIO_FORMAT_IS_PLANAR(info.info.raw.format)) { - port->blocks = info.info.raw.channels; - } else { - port->stride *= info.info.raw.channels; - port->blocks = 1; - } - - port->have_format = true; - port->format = info; - - if (other->have_format && port->have_format) - if ((res = setup_convert(this)) < 0) - return res; - - spa_log_debug(this->log, "%p: set format on port %d:%d res:%d stride:%d", - this, direction, port_id, res, port->stride); - } - if (port->have_format) { - port->paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); - port->paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ); - } else { - port->paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); - port->paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); - } - port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; - 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(object != NULL, -EINVAL); - spa_return_val_if_fail(CHECK_PORT(object, direction, port_id), -EINVAL); - - port = GET_PORT(this, direction, port_id); - - spa_log_debug(this->log, "%p: set param %u on port %d:%d %p", - this, id, direction, port_id, param); - - switch (id) { - case SPA_PARAM_Latency: - { - struct spa_latency_info info; - if (param == NULL) - return 0; - if ((res = spa_latency_parse(param, &info)) < 0) - return res; - if (direction == info.direction) - return -EINVAL; - - this->latencyinfo.direction = info; - port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; - port->paramsPORT_Latency.flags ^= SPA_PARAM_INFO_SERIAL; - emit_port_info(this, port, false); - break; - } - case SPA_PARAM_Format: - res = port_set_format(object, direction, port_id, flags, param); - break; - default: - res = -ENOENT; - } - 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, size = SPA_ID_INVALID, j; - - 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_return_val_if_fail(port->have_format, -EIO); - - spa_log_debug(this->log, "%p: use buffers %d on port %d", this, n_buffers, port_id); - - clear_buffers(this, port); - - for (i = 0; i < n_buffers; i++) { - struct buffer *b; - uint32_t n_datas = buffersi->n_datas; - struct spa_data *d = buffersi->datas; - - b = &port->buffersi; - b->id = i; - b->flags = 0; - b->outbuf = buffersi; - b->h = spa_buffer_find_meta_data(buffersi, SPA_META_Header, sizeof(*b->h)); - - if (n_datas != port->blocks) { - spa_log_error(this->log, "%p: expected %d blocks on buffer %d", this, - port->blocks, i); - return -EINVAL; - } - - for (j = 0; j < n_datas; j++) { - if (size == SPA_ID_INVALID) - size = dj.maxsize; - else if (size != dj.maxsize) { - spa_log_error(this->log, "%p: expected size %d on buffer %d", - this, size, i); - return -EINVAL; - } - - if (dj.data == NULL) { - spa_log_error(this->log, "%p: invalid memory %d on buffer %d", - this, j, i); - return -EINVAL; - } - if (!SPA_IS_ALIGNED(dj.data, this->max_align)) { - spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned", - this, j, i); - } - b->datasj = dj.data; - if (direction == SPA_DIRECTION_OUTPUT && - !SPA_FLAG_IS_SET(dj.flags, SPA_DATA_FLAG_DYNAMIC)) - this->is_passthrough = false; - } - - if (direction == SPA_DIRECTION_OUTPUT) - spa_list_append(&port->queue, &b->link); - else - SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT); - } - port->n_buffers = n_buffers; - port->size = size; - - spa_log_debug(this->log, "%p: buffer size %d", this, size); - - 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); - - spa_log_debug(this->log, "%p: port %d:%d update io %d %p", - this, direction, port_id, id, data); - - switch (id) { - case SPA_IO_Buffers: - port->io = data; - break; - default: - return -ENOENT; - } - return 0; -} - -static void recycle_buffer(struct impl *this, struct port *port, uint32_t id) -{ - struct buffer *b = &port->buffersid; - - if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUT)) { - spa_list_append(&port->queue, &b->link); - SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT); - spa_log_trace_fp(this->log, "%p: recycle buffer %d", this, id); - } -} - -static inline struct buffer *dequeue_buffer(struct impl *this, struct port *port) -{ - struct buffer *b; - - if (spa_list_is_empty(&port->queue)) - return NULL; - b = spa_list_first(&port->queue, struct buffer, link); - spa_list_remove(&b->link); - SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT); - return b; -} - -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_OUT_PORT(this, port_id); - - recycle_buffer(this, port, buffer_id); - - return 0; -} - -static int impl_node_process(void *object) -{ - struct impl *this = object; - struct port *inport, *outport; - struct spa_io_buffers *inio, *outio; - struct buffer *inbuf, *outbuf; - struct spa_buffer *inb, *outb; - const void **src_datas; - void **dst_datas; - uint32_t i, n_src_datas, n_dst_datas; - uint32_t n_samples, size, maxsize, offs; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - outport = GET_OUT_PORT(this, 0); - inport = GET_IN_PORT(this, 0); - - outio = outport->io; - inio = inport->io; - - spa_log_trace_fp(this->log, "%p: io %p %p", this, inio, outio); - - spa_return_val_if_fail(outio != NULL, -EIO); - spa_return_val_if_fail(inio != NULL, -EIO); - - spa_log_trace_fp(this->log, "%p: status %p %d %d -> %p %d %d", this, - inio, inio->status, inio->buffer_id, - outio, outio->status, outio->buffer_id); - - if (SPA_UNLIKELY(outio->status == SPA_STATUS_HAVE_DATA)) - return inio->status | outio->status; - - if (SPA_LIKELY(outio->buffer_id < outport->n_buffers)) { - recycle_buffer(this, outport, outio->buffer_id); - outio->buffer_id = SPA_ID_INVALID; - } - if (SPA_UNLIKELY(inio->status != SPA_STATUS_HAVE_DATA)) - return outio->status = inio->status; - - if (SPA_UNLIKELY(inio->buffer_id >= inport->n_buffers)) - return inio->status = -EINVAL; - - if (SPA_UNLIKELY((outbuf = dequeue_buffer(this, outport)) == NULL)) - return outio->status = -EPIPE; - - inbuf = &inport->buffersinio->buffer_id; - inb = inbuf->outbuf; - - n_src_datas = inb->n_datas; - src_datas = alloca(sizeof(void*) * n_src_datas); - - outb = outbuf->outbuf; - - n_dst_datas = outb->n_datas; - dst_datas = alloca(sizeof(void*) * n_dst_datas); - - size = UINT32_MAX; - for (i = 0; i < n_src_datas; i++) { - uint32_t src_remap = this->src_remapi; - struct spa_data *sd = &inb->datassrc_remap; - offs = SPA_MIN(sd->chunk->offset, sd->maxsize); - size = SPA_MIN(size, SPA_MIN(sd->maxsize - offs, sd->chunk->size)); - src_datasi = SPA_PTROFF(sd->data, offs, void); - } - n_samples = size / inport->stride; - - maxsize = outb->datas0.maxsize; - n_samples = SPA_MIN(n_samples, maxsize / outport->stride); - - spa_log_trace_fp(this->log, "%p: n_src:%d n_dst:%d size:%d maxsize:%d n_samples:%d p:%d", - this, n_src_datas, n_dst_datas, size, maxsize, n_samples, - this->is_passthrough); - - for (i = 0; i < n_dst_datas; i++) { - uint32_t dst_remap = this->dst_remapi; - struct spa_data *dd = outb->datas; - - if (this->is_passthrough) - ddi.data = (void *)src_datasi; - else - dst_datasi = dddst_remap.data = outbuf->datasdst_remap; - - ddi.chunk->offset = 0; - ddi.chunk->size = n_samples * outport->stride; - } - if (!this->is_passthrough) - convert_process(&this->conv, dst_datas, src_datas, n_samples); - - inio->status = SPA_STATUS_NEED_DATA; - - outio->status = SPA_STATUS_HAVE_DATA; - outio->buffer_id = outbuf->id; - - return SPA_STATUS_NEED_DATA | 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_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 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 int init_port(struct impl *this, enum spa_direction direction, uint32_t port_id) -{ - struct port *port; - - port = GET_PORT(this, direction, port_id); - port->direction = direction; - port->id = port_id; - - spa_list_init(&port->queue); - 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_DYNAMIC_DATA; - port->paramsPORT_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); - port->paramsPORT_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ); - port->paramsPORT_IO = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ); - port->paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); - port->paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); - port->paramsPORT_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE); - port->info.params = port->params; - port->info.n_params = N_PORT_PARAMS; - port->have_format = false; - - 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; - 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_log_topic_init(this->log, log_topic); - - this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU); - if (this->cpu) { - this->cpu_flags = spa_cpu_get_flags(this->cpu); - this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu)); - } - - 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); - } - - this->node.iface = SPA_INTERFACE_INIT( - SPA_TYPE_INTERFACE_Node, - SPA_VERSION_NODE, - &impl_node, this); - spa_hook_list_init(&this->hooks); - - this->info_all = SPA_PORT_CHANGE_MASK_FLAGS; - this->info = SPA_NODE_INFO_INIT(); - this->info.flags = SPA_NODE_FLAG_RT; - this->info.params = this->params; - this->info.n_params = N_NODE_PARAMS; - props_reset(&this->props); - - this->latencySPA_DIRECTION_INPUT = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); - this->latencySPA_DIRECTION_OUTPUT = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); - - init_port(this, SPA_DIRECTION_OUTPUT, 0); - init_port(this, SPA_DIRECTION_INPUT, 0); - - 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; -} - -const struct spa_handle_factory spa_fmtconvert_factory = { - SPA_VERSION_HANDLE_FACTORY, - SPA_NAME_AUDIO_PROCESS_FORMAT, - NULL, - impl_get_size, - impl_init, - impl_enum_interface_info, -};
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/merger.c
Deleted
@@ -1,1550 +0,0 @@ -/* Spa - * - * 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. - */ - -#include <errno.h> -#include <string.h> -#include <stdio.h> -#include <limits.h> - -#include <spa/support/plugin.h> -#include <spa/support/cpu.h> -#include <spa/support/log.h> -#include <spa/utils/result.h> -#include <spa/utils/list.h> -#include <spa/utils/names.h> -#include <spa/utils/string.h> -#include <spa/node/node.h> -#include <spa/node/io.h> -#include <spa/node/utils.h> -#include <spa/node/keys.h> -#include <spa/param/audio/format-utils.h> -#include <spa/param/param.h> -#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" - -#undef SPA_LOG_TOPIC_DEFAULT -#define SPA_LOG_TOPIC_DEFAULT log_topic -static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.merger"); - -#define DEFAULT_RATE 48000 -#define DEFAULT_CHANNELS 2 - -#define MAX_ALIGN FMT_OPS_MAX_ALIGN -#define MAX_BUFFERS 32 -#define MAX_DATAS SPA_AUDIO_MAX_CHANNELS -#define MAX_PORTS SPA_AUDIO_MAX_CHANNELS - -#define DEFAULT_MUTE false -#define DEFAULT_VOLUME VOLUME_NORM - -struct volumes { - bool mute; - uint32_t n_volumes; - float volumesSPA_AUDIO_MAX_CHANNELS; -}; - -static void init_volumes(struct volumes *vol) -{ - uint32_t i; - vol->mute = DEFAULT_MUTE; - vol->n_volumes = 0; - for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) - vol->volumesi = DEFAULT_VOLUME; -} - -struct props { - float volume; - uint32_t n_channels; - uint32_t channel_mapSPA_AUDIO_MAX_CHANNELS; - struct volumes channel; - struct volumes soft; - struct volumes monitor; -}; - -static void props_reset(struct props *props) -{ - uint32_t i; - props->volume = DEFAULT_VOLUME; - props->n_channels = 0; - for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) - props->channel_mapi = SPA_AUDIO_CHANNEL_UNKNOWN; - init_volumes(&props->channel); - init_volumes(&props->soft); - init_volumes(&props->monitor); -} - -struct buffer { - uint32_t id; -#define BUFFER_FLAG_QUEUED (1<<0) - uint32_t flags; - struct spa_list link; - struct spa_buffer *buf; - void *datasMAX_DATAS; -}; - -struct port { - uint32_t direction; - uint32_t id; - - struct spa_io_buffers *io; - - uint64_t info_all; - struct spa_port_info info; -#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; - char position16; - - struct spa_audio_info format; - uint32_t blocks; - uint32_t stride; - - struct buffer buffersMAX_BUFFERS; - uint32_t n_buffers; - - struct spa_list queue; - - unsigned int have_format:1; -}; - -struct impl { - struct spa_handle handle; - struct spa_node node; - - struct spa_log *log; - struct spa_cpu *cpu; - - uint32_t cpu_flags; - uint32_t max_align; - uint32_t quantum_limit; - - struct spa_io_position *io_position; - - uint64_t info_all; - struct spa_node_info info; -#define IDX_PortConfig 0 -#define IDX_PropInfo 1 -#define IDX_Props 2 -#define N_NODE_PARAMS 3 - struct spa_param_info paramsN_NODE_PARAMS; - - struct spa_hook_list hooks; - - uint32_t port_count; - uint32_t monitor_count; - struct port *in_portsMAX_PORTS; - struct port *out_portsMAX_PORTS + 1; - - struct spa_audio_info format; - unsigned int have_profile:1; - - struct convert conv; - unsigned int is_passthrough:1; - unsigned int started:1; - unsigned int monitor:1; - unsigned int monitor_channel_volumes:1; - - struct volume volume; - struct props props; - - uint32_t src_remapSPA_AUDIO_MAX_CHANNELS; - uint32_t dst_remapSPA_AUDIO_MAX_CHANNELS; - - struct spa_latency_info latency2; - - uint32_t empty_size; - float *empty; -}; - -#define CHECK_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < this->port_count) -#define CHECK_OUT_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) <= this->monitor_count) -#define CHECK_PORT(this,d,p) (CHECK_OUT_PORT(this,d,p) || CHECK_IN_PORT (this,d,p)) -#define GET_IN_PORT(this,p) (this->in_portsp) -#define GET_OUT_PORT(this,p) (this->out_portsp) -#define GET_PORT(this,d,p) (d == SPA_DIRECTION_INPUT ? GET_IN_PORT(this,p) : GET_OUT_PORT(this,p)) - -#define PORT_IS_DSP(d,p) (p != 0 || d != SPA_DIRECTION_OUTPUT) - -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) { - 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) { - struct spa_dict_item items3; - uint32_t n_items = 0; - - if (PORT_IS_DSP(port->direction, port->id)) { - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "32 bit float mono audio"); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_AUDIO_CHANNEL, port->position); - if (port->direction == SPA_DIRECTION_OUTPUT) - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_MONITOR, "true"); - } - port->info.props = &SPA_DICT_INIT(items, n_items); - - spa_node_emit_port_info(&this->hooks, port->direction, port->id, &port->info); - port->info.change_mask = old; - } -} - -static int init_port(struct impl *this, enum spa_direction direction, uint32_t port_id, - uint32_t position) -{ - struct port *port = GET_PORT(this, direction, port_id); - const char *name; - - if (port == NULL) { - port = calloc(1, sizeof(struct port)); - if (port == NULL) - return -errno; - if (direction == SPA_DIRECTION_INPUT) - this->in_portsport_id = port; - else - this->out_portsport_id = port; - } - port->direction = direction; - port->id = port_id; - - name = spa_debug_type_find_short_name(spa_type_audio_channel, position); - snprintf(port->position, sizeof(port->position), "%s", name ? name : "UNK"); - - 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.flags = SPA_PORT_FLAG_NO_REF | - SPA_PORT_FLAG_DYNAMIC_DATA; - 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->n_buffers = 0; - port->have_format = false; - port->format.media_type = SPA_MEDIA_TYPE_audio; - port->format.media_subtype = SPA_MEDIA_SUBTYPE_dsp; - port->format.info.dsp.format = SPA_AUDIO_FORMAT_DSP_F32; - spa_list_init(&port->queue); - - spa_log_debug(this->log, "%p: add port %d:%d position:%s", - this, direction, port_id, port->position); - emit_port_info(this, port, true); - - return 0; -} - -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_PortConfig: - return -ENOTSUP; - - case SPA_PARAM_PropInfo: - { - switch (result.index) { - default: - return 0; - } - break; - } - - case SPA_PARAM_Props: - { - switch (result.index) { - default: - return 0; - } - break; - } - default: - return 0; - } - - 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_set_io(void *object, uint32_t id, void *data, size_t size) -{ - struct impl *this = object; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - spa_log_debug(this->log, "%p: io %d %p/%zd", this, id, data, size); - - switch (id) { - case SPA_IO_Position: - this->io_position = data; - break; - default: - return -ENOENT; - } - return 0; -} - -static int merger_set_param(struct impl *this, const char *k, const char *s) -{ - if (spa_streq(k, "monitor.channel-volumes")) - this->monitor_channel_volumes = spa_atob(s); - return 0; -} - -static int parse_prop_params(struct impl *this, struct spa_pod *params) -{ - struct spa_pod_parser prs; - struct spa_pod_frame f; - - spa_pod_parser_pod(&prs, params); - if (spa_pod_parser_push_struct(&prs, &f) < 0) - return 0; - - while (true) { - const char *name; - struct spa_pod *pod; - char value512; - - if (spa_pod_parser_get_string(&prs, &name) < 0) - break; - - if (spa_pod_parser_get_pod(&prs, &pod) < 0) - break; - - if (spa_pod_is_bool(pod)) { - snprintf(value, sizeof(value), "%s", - SPA_POD_VALUE(struct spa_pod_bool, pod) ? - "true" : "false"); - } else - continue; - - spa_log_info(this->log, "key:'%s' val:'%s'", name, value); - merger_set_param(this, name, value); - } - return 0; -} - -static int apply_props(struct impl *this, const struct spa_pod *param) -{ - struct spa_pod_prop *prop; - struct spa_pod_object *obj = (struct spa_pod_object *) param; - struct props *p = &this->props; - int changed = 0; - uint32_t n; - - SPA_POD_OBJECT_FOREACH(obj, prop) { - switch (prop->key) { - case SPA_PROP_volume: - if (spa_pod_get_float(&prop->value, &p->volume) == 0) - changed++; - break; - case SPA_PROP_mute: - if (spa_pod_get_bool(&prop->value, &p->channel.mute) == 0) - changed++; - break; - case SPA_PROP_channelVolumes: - if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, - p->channel.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) { - p->channel.n_volumes = n; - changed++; - } - break; - case SPA_PROP_channelMap: - if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Id, - p->channel_map, SPA_AUDIO_MAX_CHANNELS)) > 0) { - p->n_channels = n; - changed++; - } - break; - case SPA_PROP_softMute: - if (spa_pod_get_bool(&prop->value, &p->soft.mute) == 0) - changed++; - break; - case SPA_PROP_softVolumes: - if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, - p->soft.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) { - p->soft.n_volumes = n; - changed++; - } - break; - case SPA_PROP_monitorMute: - if (spa_pod_get_bool(&prop->value, &p->monitor.mute) == 0) - changed++; - break; - case SPA_PROP_monitorVolumes: - if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, - p->monitor.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) { - p->monitor.n_volumes = n; - changed++; - } - break; - case SPA_PROP_params: - parse_prop_params(this, &prop->value); - break; - default: - break; - } - } - return changed; -} - -static int int32_cmp(const void *v1, const void *v2) -{ - int32_t a1 = *(int32_t*)v1; - int32_t a2 = *(int32_t*)v2; - if (a1 == 0 && a2 != 0) - return 1; - if (a2 == 0 && a1 != 0) - return -1; - return a1 - a2; -} - -static int impl_node_set_param(void *object, uint32_t id, uint32_t flags, - const struct spa_pod *param) -{ - struct impl *this = object; - int res; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - if (param == NULL) - return 0; - - switch (id) { - case SPA_PARAM_PortConfig: - { - struct spa_audio_info info = { 0, }; - struct port *port; - struct spa_pod *format; - enum spa_direction direction; - enum spa_param_port_config_mode mode; - bool monitor = false; - uint32_t i; - - if (spa_pod_parse_object(param, - SPA_TYPE_OBJECT_ParamPortConfig, NULL, - SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(&direction), - SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(&mode), - SPA_PARAM_PORT_CONFIG_monitor, SPA_POD_OPT_Bool(&monitor), - SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(&format)) < 0) - return -EINVAL; - - if (!spa_pod_is_object_type(format, SPA_TYPE_OBJECT_Format)) - return -EINVAL; - - if (mode != SPA_PARAM_PORT_CONFIG_MODE_dsp) - return -ENOTSUP; - if (direction != SPA_DIRECTION_INPUT) - return -EINVAL; - - if ((res = spa_format_parse(format, &info.media_type, &info.media_subtype)) < 0) - return res; - - if (info.media_type != SPA_MEDIA_TYPE_audio || - info.media_subtype != SPA_MEDIA_SUBTYPE_raw) - return -EINVAL; - - if (spa_format_audio_raw_parse(format, &info.info.raw) < 0) - return -EINVAL; - - info.info.raw.rate = 0; - - if (this->have_profile && - memcmp(&this->format, &info, sizeof(info)) == 0 && - this->monitor == monitor) - return 0; - - spa_log_debug(this->log, "%p: port config %d/%d %d", this, - info.info.raw.rate, info.info.raw.channels, monitor); - - for (i = 0; i < this->port_count; i++) { - spa_node_emit_port_info(&this->hooks, - SPA_DIRECTION_INPUT, i, NULL); - if (this->monitor) - spa_node_emit_port_info(&this->hooks, - SPA_DIRECTION_OUTPUT, i+1, NULL); - } - - this->monitor = monitor; - this->format = info; - this->have_profile = true; - this->port_count = info.info.raw.channels; - this->monitor_count = this->monitor ? this->port_count : 0; - for (i = 0; i < this->port_count; i++) - this->props.channel_mapi = info.info.raw.positioni; - this->props.channel.n_volumes = this->port_count; - this->props.monitor.n_volumes = this->port_count; - this->props.soft.n_volumes = this->port_count; - this->props.n_channels = this->port_count; - - for (i = 0; i < this->port_count; i++) { - init_port(this, SPA_DIRECTION_INPUT, i, info.info.raw.positioni); - if (this->monitor) - init_port(this, SPA_DIRECTION_OUTPUT, i+1, - info.info.raw.positioni); - } - - port = GET_OUT_PORT(this, 0); - qsort(info.info.raw.position, info.info.raw.channels, - sizeof(uint32_t), int32_cmp); - port->format = info; - port->have_format = true; - - this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; - this->paramsIDX_Props.flags ^= SPA_PARAM_INFO_SERIAL; - emit_node_info(this, false); - return 0; - } - 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; - - 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: - this->started = true; - break; - case SPA_NODE_COMMAND_Suspend: - case SPA_NODE_COMMAND_Flush: - case SPA_NODE_COMMAND_Pause: - this->started = false; - 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; - uint32_t i; - struct spa_hook_list save; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - spa_log_trace(this->log, "%p: add listener %p", this, listener); - spa_hook_list_isolate(&this->hooks, &save, listener, events, data); - - emit_node_info(this, true); - emit_port_info(this, GET_OUT_PORT(this, 0), true); - for (i = 0; i < this->port_count; i++) { - emit_port_info(this, GET_IN_PORT(this, i), true); - if (this->monitor) - emit_port_info(this, GET_OUT_PORT(this, i+1), 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 *user_data) -{ - 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 port_enum_formats(void *object, - enum spa_direction direction, uint32_t port_id, - uint32_t index, - struct spa_pod **param, - struct spa_pod_builder *builder) -{ - struct impl *this = object; - struct port *port = GET_PORT(this, direction, port_id); - - switch (index) { - case 0: - if (PORT_IS_DSP(direction, port_id)) { - *param = spa_format_audio_dsp_build(builder, - SPA_PARAM_EnumFormat, &port->format.info.dsp); - } else if (port->have_format) { - *param = spa_format_audio_raw_build(builder, - SPA_PARAM_EnumFormat, &port->format.info.raw); - } - else { - uint32_t rate = this->io_position ? - this->io_position->clock.rate.denom : DEFAULT_RATE; - - *param = spa_pod_builder_add_object(builder, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), - SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(25, - SPA_AUDIO_FORMAT_F32P, - SPA_AUDIO_FORMAT_F32P, - SPA_AUDIO_FORMAT_F32, - SPA_AUDIO_FORMAT_F32_OE, - SPA_AUDIO_FORMAT_F64P, - SPA_AUDIO_FORMAT_F64, - SPA_AUDIO_FORMAT_F64_OE, - SPA_AUDIO_FORMAT_S32P, - SPA_AUDIO_FORMAT_S32, - SPA_AUDIO_FORMAT_S32_OE, - SPA_AUDIO_FORMAT_S24_32P, - SPA_AUDIO_FORMAT_S24_32, - SPA_AUDIO_FORMAT_S24_32_OE, - SPA_AUDIO_FORMAT_S24P, - SPA_AUDIO_FORMAT_S24, - SPA_AUDIO_FORMAT_S24_OE, - SPA_AUDIO_FORMAT_S16P, - SPA_AUDIO_FORMAT_S16, - SPA_AUDIO_FORMAT_S16_OE, - SPA_AUDIO_FORMAT_S8P, - SPA_AUDIO_FORMAT_S8, - SPA_AUDIO_FORMAT_U8P, - SPA_AUDIO_FORMAT_U8, - SPA_AUDIO_FORMAT_ULAW, - SPA_AUDIO_FORMAT_ALAW), - SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int( - rate, 1, INT32_MAX), - SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int( - DEFAULT_CHANNELS, 1, MAX_PORTS)); - } - break; - default: - return 0; - } - 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 *param; - struct spa_pod_builder b = { 0 }; - uint8_t buffer2048; - 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_log_debug(this->log, "%p: enum params port %d.%d %d %u", - this, direction, port_id, seq, id); - - 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 ((res = port_enum_formats(object, 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; - - if (PORT_IS_DSP(direction, port_id)) - param = spa_format_audio_dsp_build(&b, id, &port->format.info.dsp); - else - param = spa_format_audio_raw_build(&b, id, &port->format.info.raw); - 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(port->blocks), - SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - this->quantum_limit * port->stride, - 16 * port->stride, - INT32_MAX), - SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); - 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: case 1: - param = spa_latency_build(&b, id, &this->latencyresult.index); - 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_debug(this->log, "%p: clear buffers %p", this, port); - port->n_buffers = 0; - spa_list_init(&port->queue); - } - return 0; -} - -static int setup_convert(struct impl *this) -{ - struct port *outport; - struct spa_audio_info informat, outformat; - uint32_t i, j, src_fmt, dst_fmt; - int res; - - outport = GET_OUT_PORT(this, 0); - - informat = this->format; - outformat = outport->format; - - src_fmt = SPA_AUDIO_FORMAT_DSP_F32; - dst_fmt = outformat.info.raw.format; - - spa_log_info(this->log, "%p: %s/%d@%dx%d->%s/%d@%d", this, - spa_debug_type_find_name(spa_type_audio_format, src_fmt), - 1, - informat.info.raw.rate, - informat.info.raw.channels, - spa_debug_type_find_name(spa_type_audio_format, dst_fmt), - outformat.info.raw.channels, - outformat.info.raw.rate); - - for (i = 0; i < informat.info.raw.channels; i++) { - for (j = 0; j < outformat.info.raw.channels; j++) { - if (informat.info.raw.positioni != - outformat.info.raw.positionj) - continue; - this->src_remapj = i; - this->dst_remapi = j; - spa_log_debug(this->log, "%p: channel %d -> %d (%s -> %s)", this, - i, j, - spa_debug_type_find_short_name(spa_type_audio_channel, - informat.info.raw.positioni), - spa_debug_type_find_short_name(spa_type_audio_channel, - outformat.info.raw.positionj)); - outformat.info.raw.positionj = -1; - break; - } - } - - this->conv.src_fmt = src_fmt; - this->conv.dst_fmt = dst_fmt; - this->conv.n_channels = outformat.info.raw.channels; - this->conv.cpu_flags = this->cpu_flags; - - if ((res = convert_init(&this->conv)) < 0) - return res; - - this->is_passthrough = this->conv.is_passthrough; - - spa_log_debug(this->log, "%p: got converter features %08x:%08x passthrough:%d", this, - this->cpu_flags, this->conv.cpu_flags, this->is_passthrough); - - return 0; -} - -static int calc_width(struct spa_audio_info *info) -{ - switch (info->info.raw.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 1; - case SPA_AUDIO_FORMAT_S16P: - case SPA_AUDIO_FORMAT_S16: - case SPA_AUDIO_FORMAT_S16_OE: - return 2; - case SPA_AUDIO_FORMAT_S24P: - case SPA_AUDIO_FORMAT_S24: - case SPA_AUDIO_FORMAT_S24_OE: - return 3; - case SPA_AUDIO_FORMAT_F64P: - case SPA_AUDIO_FORMAT_F64: - case SPA_AUDIO_FORMAT_F64_OE: - return 8; - default: - return 4; - } -} - -static int port_set_latency(void *object, - enum spa_direction direction, - uint32_t port_id, - uint32_t flags, - const struct spa_pod *latency) -{ - struct impl *this = object; - struct port *port; - enum spa_direction other = SPA_DIRECTION_REVERSE(direction); - uint32_t i; - - spa_log_debug(this->log, "%p: set latency direction:%d id:%d", - this, direction, port_id); - - if (direction == SPA_DIRECTION_OUTPUT && port_id != 0) - return 0; - - if (latency == NULL) { - this->latencyother = SPA_LATENCY_INFO(other); - } else { - struct spa_latency_info info; - if (spa_latency_parse(latency, &info) < 0 || - info.direction != other) - return -EINVAL; - this->latencyother = info; - } - for (i = 0; i < this->port_count; i++) { - port = GET_IN_PORT(this, i); - port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; - port->paramsIDX_Latency.flags ^= SPA_PARAM_INFO_SERIAL; - emit_port_info(this, port, false); - } - port = GET_OUT_PORT(this, 0); - port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; - port->paramsIDX_Latency.flags ^= SPA_PARAM_INFO_SERIAL; - emit_port_info(this, port, false); - return 0; -} - -static int port_set_format(void *object, - enum spa_direction direction, - uint32_t port_id, - uint32_t flags, - const struct spa_pod *format) -{ - struct impl *this = object; - struct port *port; - int res; - - port = GET_PORT(this, direction, port_id); - - spa_log_debug(this->log, "%p: set format", this); - - if (format == NULL) { - if (port->have_format) { - if (PORT_IS_DSP(direction, port_id)) - port->have_format = false; - else - port->have_format = this->have_profile; - port->format.info.raw.rate = 0; - clear_buffers(this, port); - } - } else { - struct spa_audio_info info = { 0 }; - - if ((res = spa_format_parse(format, &info.media_type, &info.media_subtype)) < 0) { - spa_log_error(this->log, "can't parse format %s", spa_strerror(res)); - return res; - } - if (PORT_IS_DSP(direction, port_id)) { - if (info.media_type != SPA_MEDIA_TYPE_audio || - info.media_subtype != SPA_MEDIA_SUBTYPE_dsp) { - spa_log_error(this->log, "unexpected types %d/%d", - info.media_type, info.media_subtype); - return -EINVAL; - } - if ((res = spa_format_audio_dsp_parse(format, &info.info.dsp)) < 0) { - spa_log_error(this->log, "can't parse format %s", spa_strerror(res)); - return res; - } - if (info.info.dsp.format != SPA_AUDIO_FORMAT_DSP_F32) { - spa_log_error(this->log, "unexpected format %d<->%d", - info.info.dsp.format, SPA_AUDIO_FORMAT_DSP_F32); - return -EINVAL; - } - port->blocks = 1; - port->stride = 4; - } - else { - if (info.media_type != SPA_MEDIA_TYPE_audio || - info.media_subtype != SPA_MEDIA_SUBTYPE_raw) { - spa_log_error(this->log, "unexpected types %d/%d", - info.media_type, info.media_subtype); - return -EINVAL; - } - if ((res = spa_format_audio_raw_parse(format, &info.info.raw)) < 0) { - spa_log_error(this->log, "can't parse format %s", spa_strerror(res)); - return res; - } - if (info.info.raw.channels != this->port_count) { - spa_log_error(this->log, "unexpected channels %d<->%d", - info.info.raw.channels, this->port_count); - return -EINVAL; - } - port->stride = calc_width(&info); - if (SPA_AUDIO_FORMAT_IS_PLANAR(info.info.raw.format)) { - port->blocks = info.info.raw.channels; - } - else { - port->stride *= info.info.raw.channels; - port->blocks = 1; - } - } - port->format = info; - - spa_log_debug(this->log, "%p: %d %d %d", this, - port_id, port->stride, port->blocks); - - if (!PORT_IS_DSP(direction, port_id)) - if ((res = setup_convert(this)) < 0) - return res; - - port->have_format = true; - } - - 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; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - spa_log_debug(this->log, "%p: set param port %d.%d %u", - this, direction, port_id, id); - - spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); - - switch (id) { - case SPA_PARAM_Latency: - return port_set_latency(this, direction, port_id, flags, param); - case SPA_PARAM_Format: - return port_set_format(this, direction, port_id, flags, param); - default: - return -ENOENT; - } -} - -static void queue_buffer(struct impl *this, struct port *port, uint32_t id) -{ - struct buffer *b = &port->buffersid; - - spa_log_trace_fp(this->log, "%p: queue buffer %d on port %d %d", - this, id, port->id, b->flags); - if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_QUEUED)) - return; - - spa_list_append(&port->queue, &b->link); - SPA_FLAG_SET(b->flags, BUFFER_FLAG_QUEUED); -} - -static struct buffer *dequeue_buffer(struct impl *this, struct port *port) -{ - struct buffer *b; - - if (spa_list_is_empty(&port->queue)) - return NULL; - - b = spa_list_first(&port->queue, struct buffer, link); - spa_list_remove(&b->link); - SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_QUEUED); - spa_log_trace_fp(this->log, "%p: dequeue buffer %d on port %d %u", - this, b->id, port->id, b->flags); - - return b; -} - -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, j, maxsize; - - 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_return_val_if_fail(port->have_format, -EIO); - - spa_log_debug(this->log, "%p: use buffers %d on port %d:%d", - this, n_buffers, direction, port_id); - - clear_buffers(this, port); - - maxsize = 0; - for (i = 0; i < n_buffers; i++) { - struct buffer *b; - uint32_t n_datas = buffersi->n_datas; - struct spa_data *d = buffersi->datas; - - b = &port->buffersi; - b->id = i; - b->flags = 0; - b->buf = buffersi; - - if (n_datas != port->blocks) { - spa_log_error(this->log, "%p: invalid blocks %d on buffer %d", - this, n_datas, i); - return -EINVAL; - } - - for (j = 0; j < n_datas; j++) { - if (dj.data == NULL) { - spa_log_error(this->log, "%p: invalid memory %d on buffer %d %d %p", - this, j, i, dj.type, dj.data); - return -EINVAL; - } - if (!SPA_IS_ALIGNED(dj.data, this->max_align)) { - spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned", - this, j, i); - } - b->datasj = dj.data; - if (direction == SPA_DIRECTION_OUTPUT && - !SPA_FLAG_IS_SET(dj.flags, SPA_DATA_FLAG_DYNAMIC)) - this->is_passthrough = false; - - maxsize = SPA_MAX(maxsize, dj.maxsize); - } - if (direction == SPA_DIRECTION_OUTPUT) - queue_buffer(this, port, i); - } - if (maxsize > this->empty_size) { - this->empty = realloc(this->empty, maxsize + MAX_ALIGN); - if (this->empty == NULL) - return -errno; - memset(this->empty, 0, maxsize + MAX_ALIGN); - this->empty_size = maxsize; - } - 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_log_debug(this->log, "%p: set io %d on port %d:%d %p", - this, id, direction, port_id, data); - - 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_OUT_PORT(this, port_id); - queue_buffer(this, port, buffer_id); - - return 0; -} - -static inline int get_in_buffer(struct impl *this, struct port *port, struct buffer **buf) -{ - struct spa_io_buffers *io; - - if ((io = port->io) == NULL) { - spa_log_trace_fp(this->log, "%p: no io on port %d", - this, port->id); - return -EIO; - } - if (io->status != SPA_STATUS_HAVE_DATA || - io->buffer_id >= port->n_buffers) { - spa_log_trace_fp(this->log, "%p: empty port %d %p %d %d %d", - this, port->id, io, io->status, io->buffer_id, - port->n_buffers); - return -EPIPE; - } - - *buf = &port->buffersio->buffer_id; - io->status = SPA_STATUS_NEED_DATA; - - return 0; -} - -static inline int get_out_buffer(struct impl *this, struct port *port, struct buffer **buf) -{ - struct spa_io_buffers *io; - - if (SPA_UNLIKELY((io = port->io) == NULL || - io->status == SPA_STATUS_HAVE_DATA)) - return SPA_STATUS_HAVE_DATA; - - if (SPA_LIKELY(io->buffer_id < port->n_buffers)) - queue_buffer(this, port, io->buffer_id); - - if (SPA_UNLIKELY((*buf = dequeue_buffer(this, port)) == NULL)) - return -EPIPE; - - io->status = SPA_STATUS_HAVE_DATA; - io->buffer_id = (*buf)->id; - - return 0; -} - -static inline int handle_monitor(struct impl *this, const void *data, float volume, int n_samples, struct port *outport) -{ - struct buffer *dbuf; - struct spa_data *dd; - int res, size; - - if (SPA_UNLIKELY((res = get_out_buffer(this, outport, &dbuf)) != 0)) - return res; - - dd = &dbuf->buf->datas0; - size = SPA_MIN(dd->maxsize, n_samples * outport->stride); - dd->chunk->offset = 0; - dd->chunk->size = size; - - spa_log_trace(this->log, "%p: io %p %08x", this, outport->io, dd->flags); - - if (SPA_FLAG_IS_SET(dd->flags, SPA_DATA_FLAG_DYNAMIC) && volume == VOLUME_NORM) - dd->data = (void*)data; - else - volume_process(&this->volume, dd->data, data, volume, size / outport->stride); - - return res; -} - -static int impl_node_process(void *object) -{ - struct impl *this = object; - struct port *outport; - struct spa_io_buffers *outio; - uint32_t i, maxsize, n_samples; - struct spa_data *sd, *dd; - struct buffer *sbuf, *dbuf; - uint32_t n_src_datas, n_dst_datas; - const void **src_datas; - void **dst_datas; - int res; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - outport = GET_OUT_PORT(this, 0); - outio = outport->io; - spa_return_val_if_fail(outio != NULL, -EIO); - spa_return_val_if_fail(this->conv.process != NULL, -EIO); - - spa_log_trace_fp(this->log, "%p: status %p %d %d", this, - outio, outio->status, outio->buffer_id); - - if (SPA_UNLIKELY((res = get_out_buffer(this, outport, &dbuf)) != 0)) - return res; - - dd = &dbuf->buf->datas0; - - maxsize = dd->maxsize; - - if (SPA_LIKELY(this->io_position)) - n_samples = this->io_position->clock.duration; - else - n_samples = maxsize / outport->stride; - - - n_dst_datas = dbuf->buf->n_datas; - dst_datas = alloca(sizeof(void*) * n_dst_datas); - - n_src_datas = this->port_count; - src_datas = alloca(sizeof(void*) * this->port_count); - - /* produce more output if possible */ - for (i = 0; i < n_src_datas; i++) { - struct port *inport = GET_IN_PORT(this, i); - - if (SPA_UNLIKELY(get_in_buffer(this, inport, &sbuf) < 0)) { - src_datasi = SPA_PTR_ALIGN(this->empty, MAX_ALIGN, void); - continue; - } - - sd = &sbuf->buf->datas0; - - src_datasi = SPA_PTROFF(sd->data, sd->chunk->offset, void); - - n_samples = SPA_MIN(n_samples, sd->chunk->size / inport->stride); - - spa_log_trace_fp(this->log, "%p: %d %d %d %p", this, - sd->chunk->size, maxsize, n_samples, src_datasi); - } - - for (i = 0; i < this->monitor_count; i++) { - float volume; - - volume = this->props.monitor.mute ? 0.0f : this->props.monitor.volumesi; - if (this->monitor_channel_volumes) - volume *= this->props.channel.mute ? 0.0f : this->props.channel.volumesi; - - handle_monitor(this, src_datasi, volume, n_samples, - GET_OUT_PORT(this, i + 1)); - } - - for (i = 0; i < n_dst_datas; i++) { - uint32_t dst_remap = this->dst_remapi; - uint32_t src_remap = this->src_remapi; - struct spa_data *dd = dbuf->buf->datas; - - if (this->is_passthrough) - ddi.data = (void *)src_datassrc_remap; - else - dst_datasdst_remap = ddi.data = dbuf->datasi; - - ddi.chunk->offset = 0; - ddi.chunk->size = n_samples * outport->stride; - } - - spa_log_trace_fp(this->log, "%p: n_src:%d n_dst:%d n_samples:%d max:%d p:%d", this, - n_src_datas, n_dst_datas, n_samples, maxsize, this->is_passthrough); - - if (!this->is_passthrough) - convert_process(&this->conv, dst_datas, src_datas, n_samples); - - return SPA_STATUS_NEED_DATA | 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_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 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; - uint32_t i; - - spa_return_val_if_fail(handle != NULL, -EINVAL); - - this = (struct impl *) handle; - - for (i = 0; i < MAX_PORTS; i++) - free(this->in_portsi); - for (i = 0; i < MAX_PORTS+1; i++) - free(this->out_portsi); - free(this->empty); - 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; - 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_log_topic_init(this->log, log_topic); - - this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU); - if (this->cpu) { - this->cpu_flags = spa_cpu_get_flags(this->cpu); - this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu)); - } - - 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 - merger_set_param(this, k, s); - } - - this->latencySPA_DIRECTION_INPUT = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); - this->latencySPA_DIRECTION_OUTPUT = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); - - this->node.iface = SPA_INTERFACE_INIT( - SPA_TYPE_INTERFACE_Node, - SPA_VERSION_NODE, - &impl_node, this); - spa_hook_list_init(&this->hooks); - - 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 = MAX_PORTS+1; - this->info.flags = SPA_NODE_FLAG_RT | - SPA_NODE_FLAG_IN_PORT_CONFIG; - this->paramsIDX_PortConfig = SPA_PARAM_INFO(SPA_PARAM_PortConfig, SPA_PARAM_INFO_WRITE); - 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->info.params = this->params; - this->info.n_params = N_NODE_PARAMS; - - init_port(this, SPA_DIRECTION_OUTPUT, 0, 0); - - this->volume.cpu_flags = this->cpu_flags; - volume_init(&this->volume); - props_reset(&this->props); - - 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; -} - -const struct spa_handle_factory spa_merger_factory = { - SPA_VERSION_HANDLE_FACTORY, - SPA_NAME_AUDIO_PROCESS_INTERLEAVE, - NULL, - impl_get_size, - impl_init, - impl_enum_interface_info, -};
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/resample.c
Deleted
@@ -1,1307 +0,0 @@ -/* Spa - * - * 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. - */ - -#include <errno.h> -#include <string.h> -#include <stdio.h> - -#include <spa/support/plugin.h> -#include <spa/support/log.h> -#include <spa/utils/list.h> -#include <spa/utils/names.h> -#include <spa/utils/string.h> -#include <spa/node/node.h> -#include <spa/node/io.h> -#include <spa/node/utils.h> -#include <spa/param/audio/format-utils.h> -#include <spa/param/param.h> -#include <spa/pod/filter.h> -#include <spa/debug/types.h> - -#include "resample.h" - -#undef SPA_LOG_TOPIC_DEFAULT -#define SPA_LOG_TOPIC_DEFAULT log_topic -static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.resample"); - -#define DEFAULT_RATE 48000 -#define DEFAULT_CHANNELS 2 - -#define MAX_BUFFERS 32 - -struct impl; - -struct props { - double rate; - int quality; - bool disabled; -}; - -static void props_reset(struct props *props) -{ - props->rate = 1.0; - props->quality = RESAMPLE_DEFAULT_QUALITY; - props->disabled = false; -} - -struct buffer { - uint32_t id; -#define BUFFER_FLAG_OUT (1 << 0) - uint32_t flags; - struct spa_list link; - struct spa_buffer *outbuf; - struct spa_meta_header *h; -}; - -struct port { - uint32_t direction; - uint32_t id; - - uint64_t info_all; - struct spa_port_info info; - struct spa_param_info params8; - - struct spa_io_buffers *io; - - struct spa_audio_info format; - uint32_t stride; - uint32_t blocks; - uint32_t size; - unsigned int have_format:1; - - struct buffer buffersMAX_BUFFERS; - uint32_t n_buffers; - - uint32_t offset; - struct spa_list queue; -}; - -struct impl { - struct spa_handle handle; - struct spa_node node; - - struct spa_log *log; - struct spa_cpu *cpu; - - uint32_t quantum_limit; - - struct spa_io_position *io_position; - struct spa_io_rate_match *io_rate_match; - - uint64_t info_all; - struct spa_node_info info; - struct props props; - - struct spa_hook_list hooks; - - struct port in_port; - struct port out_port; - -#define MODE_SPLIT 0 -#define MODE_MERGE 1 -#define MODE_CONVERT 2 - int mode; - unsigned int started:1; - unsigned int peaks:1; - unsigned int drained:1; - - struct resample resample; - - double rate_scale; -}; - -#define CHECK_PORT(this,d,id) (id == 0) -#define GET_IN_PORT(this,id) (&this->in_port) -#define GET_OUT_PORT(this,id) (&this->out_port) -#define GET_PORT(this,d,id) (d == SPA_DIRECTION_INPUT ? GET_IN_PORT(this,id) : GET_OUT_PORT(this,id)) - -static int setup_convert(struct impl *this, - enum spa_direction direction, - const struct spa_audio_info *info) -{ - const struct spa_audio_info *src_info, *dst_info; - int err; - - if (direction == SPA_DIRECTION_INPUT) { - src_info = info; - dst_info = &GET_OUT_PORT(this, 0)->format; - } else { - src_info = &GET_IN_PORT(this, 0)->format; - dst_info = info; - } - - spa_log_info(this->log, "%p: %s/%d@%d->%s/%d@%d", this, - spa_debug_type_find_name(spa_type_audio_format, src_info->info.raw.format), - src_info->info.raw.channels, - src_info->info.raw.rate, - spa_debug_type_find_name(spa_type_audio_format, dst_info->info.raw.format), - dst_info->info.raw.channels, - dst_info->info.raw.rate); - - if (src_info->info.raw.channels != dst_info->info.raw.channels) - return -EINVAL; - - if (this->resample.free) - resample_free(&this->resample); - - this->resample.channels = src_info->info.raw.channels; - this->resample.i_rate = src_info->info.raw.rate; - this->resample.o_rate = dst_info->info.raw.rate; - this->resample.log = this->log; - this->resample.quality = this->props.quality; - - if (this->peaks) - err = resample_peaks_init(&this->resample); - else - err = resample_native_init(&this->resample); - - return err; -} - -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_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_rate), - SPA_PROP_INFO_description, SPA_POD_String("Rate scaler"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Double(p->rate, 0.0, 10.0)); - break; - case 1: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_quality), - SPA_PROP_INFO_name, SPA_POD_String("resample.quality"), - SPA_PROP_INFO_description, SPA_POD_String("Resample Quality"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->quality, 0, 14), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; - case 2: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_name, SPA_POD_String("resample.disable"), - SPA_PROP_INFO_description, SPA_POD_String("Disable Resampling"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->disabled), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; - default: - return 0; - } - break; - } - case SPA_PARAM_Props: - { - struct props *p = &this->props; - struct spa_pod_frame f2; - - switch (result.index) { - case 0: - spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_Props, id); - spa_pod_builder_add(&b, - SPA_PROP_rate, SPA_POD_Double(p->rate), - SPA_PROP_quality, SPA_POD_Int(p->quality), - 0); - spa_pod_builder_prop(&b, SPA_PROP_params, 0); - spa_pod_builder_push_struct(&b, &f1); - spa_pod_builder_string(&b, "resample.quality"); - spa_pod_builder_int(&b, p->quality); - spa_pod_builder_string(&b, "resample.disable"); - spa_pod_builder_bool(&b, p->disabled); - spa_pod_builder_pop(&b, &f1); - param = spa_pod_builder_pop(&b, &f0); - 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 resample_set_param(struct impl *this, const char *k, const char *s) -{ - if (spa_streq(k, "resample.quality")) - this->props.quality = atoi(s); - else if (spa_streq(k, "resample.disable")) - this->props.disabled = spa_atob(s); - return 0; -} - -static int parse_prop_params(struct impl *this, struct spa_pod *params) -{ - struct spa_pod_parser prs; - struct spa_pod_frame f; - - spa_pod_parser_pod(&prs, params); - if (spa_pod_parser_push_struct(&prs, &f) < 0) - return 0; - - while (true) { - const char *name; - struct spa_pod *pod; - char value512; - - if (spa_pod_parser_get_string(&prs, &name) < 0) - break; - - if (spa_pod_parser_get_pod(&prs, &pod) < 0) - break; - - if (spa_pod_is_string(pod)) { - spa_pod_copy_string(pod, sizeof(value), value); - } else if (spa_pod_is_int(pod)) { - snprintf(value, sizeof(value), "%d", - SPA_POD_VALUE(struct spa_pod_int, pod)); - } else if (spa_pod_is_bool(pod)) { - snprintf(value, sizeof(value), "%s", - SPA_POD_VALUE(struct spa_pod_bool, pod) ? - "true" : "false"); - } else - continue; - - spa_log_info(this->log, "key:'%s' val:'%s'", name, value); - resample_set_param(this, name, value); - } - return 0; -} - -static int apply_props(struct impl *this, const struct spa_pod *param) -{ - struct spa_pod_prop *prop; - struct spa_pod_object *obj = (struct spa_pod_object *) param; - struct props *p = &this->props; - int changed = 0; - - SPA_POD_OBJECT_FOREACH(obj, prop) { - switch (prop->key) { - case SPA_PROP_rate: - if (spa_pod_get_double(&prop->value, &p->rate) == 0) { - resample_update_rate(&this->resample, p->rate); - changed++; - } - break; - case SPA_PROP_quality: - if (spa_pod_get_int(&prop->value, &p->quality) == 0) - changed++; - break; - case SPA_PROP_params: - changed += parse_prop_params(this, &prop->value); - break; - default: - break; - } - } - 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; - int res = 0; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - switch (id) { - case SPA_PARAM_Props: - apply_props(this, param); - break; - default: - return -ENOTSUP; - } - - return res; -} - -static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size) -{ - struct impl *this = object; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - spa_log_debug(this->log, "%p: io %d %p/%zd", this, id, data, size); - - switch (id) { - case SPA_IO_Position: - this->io_position = data; - break; - default: - return -ENOENT; - } - return 0; -} - -static void update_rate_match(struct impl *this, bool passthrough, uint32_t out_size, uint32_t in_queued) -{ - double r = this->rate_scale / this->props.rate; - - if (this->io_rate_match) { - uint32_t delay, match_size; - - if (passthrough) { - delay = in_queued; - match_size = out_size; - } else { - if (SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)) - resample_update_rate(&this->resample, r * this->io_rate_match->rate); - else - resample_update_rate(&this->resample, r); - - delay = resample_delay(&this->resample) + in_queued; - match_size = resample_in_len(&this->resample, out_size); - } - match_size -= SPA_MIN(match_size, in_queued); - this->io_rate_match->size = match_size; - this->io_rate_match->delay = delay; - spa_log_trace_fp(this->log, "%p: next match:%u queued:%u delay:%u", this, match_size, - in_queued, delay); - } else { - resample_update_rate(&this->resample, r); - } -} -static inline bool is_passthrough(struct impl *this) -{ - return this->resample.i_rate == this->resample.o_rate && - this->rate_scale == 1.0 && this->props.rate == 1.0 && - (this->io_rate_match == NULL || this->props.disabled || - !SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)); -} - -static void recalc_rate_match(struct impl *this) -{ - bool passthrough = is_passthrough(this); - uint32_t out_size = this->io_position ? this->io_position->clock.duration : 1024; - update_rate_match(this, passthrough, out_size, 0); -} - -static void reset_node(struct impl *this) -{ - struct port *outport, *inport; - outport = GET_OUT_PORT(this, 0); - inport = GET_IN_PORT(this, 0); - - if (this->resample.reset) - resample_reset(&this->resample); - outport->offset = 0; - inport->offset = 0; -} - -static int impl_node_send_command(void *object, const struct spa_command *command) -{ - struct impl *this = object; - - 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: - recalc_rate_match(this); - this->started = true; - break; - case SPA_NODE_COMMAND_Suspend: - case SPA_NODE_COMMAND_Flush: - reset_node(this); - SPA_FALLTHROUGH; - case SPA_NODE_COMMAND_Pause: - this->started = false; - break; - default: - return -ENOTSUP; - } - return 0; -} - -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) { - 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; - - 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, GET_IN_PORT(this, 0), true); - emit_port_info(this, GET_OUT_PORT(this, 0), 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 *user_data) -{ - 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 port_enum_formats(void *object, - enum spa_direction direction, uint32_t port_id, - uint32_t index, - struct spa_pod **param, - struct spa_pod_builder *builder) -{ - struct impl *this = object; - struct port *other; - struct spa_pod_frame f; - uint32_t rate, min = 1, max = INT32_MAX; - - other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), 0); - - switch (index) { - case 0: - if (other->have_format) { - rate = other->format.info.raw.rate; - if (this->props.disabled) - min = max = rate; - - spa_pod_builder_push_object(builder, &f, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat); - 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), - SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_F32P), - SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int(rate, min, max), - SPA_FORMAT_AUDIO_channels, SPA_POD_Int(other->format.info.raw.channels), - 0); - spa_pod_builder_prop(builder, SPA_FORMAT_AUDIO_position, 0); - spa_pod_builder_array(builder, sizeof(uint32_t), SPA_TYPE_Id, - other->format.info.raw.channels, other->format.info.raw.position); - *param = spa_pod_builder_pop(builder, &f); - } else { - rate = this->io_position ? - this->io_position->clock.rate.denom : DEFAULT_RATE; - if (this->props.disabled) - min = max = rate; - - *param = spa_pod_builder_add_object(builder, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), - SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_F32P), - SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int(rate, min, max), - SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(DEFAULT_CHANNELS, 1, INT32_MAX)); - } - break; - default: - return 0; - } - 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, *other; - struct spa_pod *param; - struct spa_pod_builder b = { 0 }; - uint8_t buffer1024; - 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 = GET_PORT(this, direction, port_id); - other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), port_id); - - spa_log_debug(this->log, "%p: enum params port %d.%d %d %u", - this, direction, port_id, seq, 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 ((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_raw_build(&b, id, &port->format.info.raw); - break; - case SPA_PARAM_Buffers: - { - uint32_t buffers, size; - uint32_t rate; - - if (!port->have_format || !other->have_format) - return -EIO; - if (result.index > 0) - return 0; - - if (direction == SPA_DIRECTION_OUTPUT) { - rate = (this->resample.o_rate + this->resample.i_rate - 1) / this->resample.i_rate; - } else { - rate = (this->resample.i_rate + this->resample.o_rate - 1) / this->resample.o_rate; - } - if (other->n_buffers > 0) { - buffers = other->n_buffers; - size = (other->size / other->stride) * rate; - } else { - buffers = 1; - size = this->quantum_limit * rate; - } - size = SPA_MAX(size, this->quantum_limit) * 2; - - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_ParamBuffers, id, - SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(buffers, 1, MAX_BUFFERS), - SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(port->blocks), - SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - size * port->stride, - 16 * port->stride, - INT32_MAX), - SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); - 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; - 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_debug(this->log, "%p: clear buffers %p", this, port); - port->n_buffers = 0; - spa_list_init(&port->queue); - } - return 0; -} - -static int port_set_format(void *object, - enum spa_direction direction, - uint32_t port_id, - uint32_t flags, - const struct spa_pod *format) -{ - struct impl *this = object; - struct port *port, *other; - int res = 0; - - port = GET_PORT(this, direction, port_id); - other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), port_id); - - if (format == NULL) { - if (port->have_format) { - port->have_format = false; - clear_buffers(this, port); - } - } else { - struct spa_audio_info info = { 0 }; - - if ((res = spa_format_parse(format, &info.media_type, &info.media_subtype)) < 0) - return res; - - if (info.media_type != SPA_MEDIA_TYPE_audio || - info.media_subtype != SPA_MEDIA_SUBTYPE_raw) - return -EINVAL; - - if (spa_format_audio_raw_parse(format, &info.info.raw) < 0) - return -EINVAL; - - if (info.info.raw.format != SPA_AUDIO_FORMAT_F32P) - return -EINVAL; - - port->stride = sizeof(float); - port->blocks = info.info.raw.channels; - - if (other->have_format) { - if ((res = setup_convert(this, direction, &info)) < 0) - return res; - } - port->format = info; - port->have_format = true; - - spa_log_debug(this->log, "%p: set format on port %d %d", this, port_id, res); - } - - port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; - if (port->have_format) { - port->params3 = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); - port->params4 = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); - } else { - port->params3 = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); - port->params4 = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ); - } - emit_port_info(this, port, false); - - return res; -} - -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) -{ - spa_return_val_if_fail(object != NULL, -EINVAL); - - spa_return_val_if_fail(CHECK_PORT(object, direction, port_id), -EINVAL); - - if (id == SPA_PARAM_Format) { - return port_set_format(object, direction, port_id, flags, param); - } - else - return -ENOENT; -} - -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, j, size = SPA_ID_INVALID; - - 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_return_val_if_fail(port->have_format, -EIO); - - spa_log_debug(this->log, "%p: use buffers %d on port %d:%d", this, - n_buffers, direction, port_id); - - 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; - b->h = spa_buffer_find_meta_data(buffersi, SPA_META_Header, sizeof(*b->h)); - - for (j = 0; j < buffersi->n_datas; j++) { - if (size == SPA_ID_INVALID) - size = dj.maxsize; - else - if (size != dj.maxsize) { - spa_log_error(this->log, "%p: invalid size %d on buffer %p", this, - size, buffersi); - return -EINVAL; - } - - if (dj.data == NULL) { - spa_log_error(this->log, "%p: invalid memory on buffer %p", this, - buffersi); - return -EINVAL; - } - } - - if (direction == SPA_DIRECTION_OUTPUT) - spa_list_append(&port->queue, &b->link); - else - SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT); - - port->offset = 0; - } - port->n_buffers = n_buffers; - port->size = size; - - 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); - - spa_log_trace_fp(this->log, "%p: %d:%d io %d", this, direction, port_id, id); - - port = GET_PORT(this, direction, port_id); - - switch (id) { - case SPA_IO_Buffers: - port->io = data; - break; - case SPA_IO_RateMatch: - this->io_rate_match = data; - break; - default: - return -ENOENT; - } - return 0; -} - -static void recycle_buffer(struct impl *this, uint32_t id) -{ - struct port *port = GET_OUT_PORT(this, 0); - struct buffer *b = &port->buffersid; - - if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUT)) { - spa_list_append(&port->queue, &b->link); - SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT); - spa_log_trace_fp(this->log, "%p: recycle buffer %d", this, id); - } -} - -static struct buffer *peek_buffer(struct impl *this, struct port *port) -{ - struct buffer *b; - - if (spa_list_is_empty(&port->queue)) - return NULL; - - b = spa_list_first(&port->queue, struct buffer, link); - return b; -} - -static void dequeue_buffer(struct impl *this, struct buffer *b) -{ - spa_list_remove(&b->link); - SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT); -} - -static int impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id) -{ - struct impl *this = object; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - spa_return_val_if_fail(CHECK_PORT(this, SPA_DIRECTION_OUTPUT, port_id), -EINVAL); - - recycle_buffer(this, buffer_id); - - return 0; -} - -static int impl_node_process(void *object) -{ - struct impl *this = object; - struct port *outport, *inport; - struct spa_io_buffers *outio, *inio; - struct buffer *sbuf, *dbuf; - struct spa_buffer *sb, *db; - uint32_t i, size, in_len, out_len, maxsize, max; -#ifndef FASTPATH - uint32_t pin_len, pout_len; -#endif - int res = 0; - const void **src_datas; - void **dst_datas; - bool flush_out = false; - bool flush_in = false; - bool draining = false; - bool passthrough; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - outport = GET_OUT_PORT(this, 0); - inport = GET_IN_PORT(this, 0); - - outio = outport->io; - inio = inport->io; - - spa_return_val_if_fail(outio != NULL, -EIO); - spa_return_val_if_fail(inio != NULL, -EIO); - - spa_log_trace_fp(this->log, "%p: status %p %d %d -> %p %d %d", this, - inio, inio->status, inio->buffer_id, - outio, outio->status, outio->buffer_id); - - if (SPA_UNLIKELY(outio->status == SPA_STATUS_HAVE_DATA)) - return SPA_STATUS_HAVE_DATA; - /* recycle */ - if (SPA_LIKELY(outio->buffer_id < outport->n_buffers)) { - recycle_buffer(this, outio->buffer_id); - outio->buffer_id = SPA_ID_INVALID; - } - if (SPA_UNLIKELY(inio->status != SPA_STATUS_HAVE_DATA)) { - if (inio->status != SPA_STATUS_DRAINED || this->drained) { - recalc_rate_match(this); - return outio->status = inio->status; - } - inio->buffer_id = 0; - inport->buffers0.outbuf->datas0.chunk->size = -1; - } - - if (SPA_UNLIKELY(inio->buffer_id >= inport->n_buffers)) - return inio->status = -EINVAL; - - if (SPA_UNLIKELY((dbuf = peek_buffer(this, outport)) == NULL)) - return outio->status = -EPIPE; - - sbuf = &inport->buffersinio->buffer_id; - - sb = sbuf->outbuf; - db = dbuf->outbuf; - - maxsize = db->datas0.maxsize; - - if (SPA_LIKELY(this->io_position)) { - double r = this->rate_scale; - - max = this->io_position->clock.duration * sizeof(float); - if (this->mode == MODE_SPLIT) { - if (this->io_position->clock.rate.denom != this->resample.o_rate) - r = (double) this->io_position->clock.rate.denom / this->resample.o_rate; - else - r = 1.0; - } else { - if (this->io_position->clock.rate.denom != this->resample.i_rate) - r = (double) this->resample.i_rate / this->io_position->clock.rate.denom; - else - r = 1.0; - } - if (this->rate_scale != r) { - spa_log_info(this->log, "scale %f->%f", this->rate_scale, r); - this->rate_scale = r; - } - } - else - max = maxsize; - - switch (this->mode) { - case MODE_SPLIT: - /* in split mode we need to output exactly the size of the - * duration so we don't try to flush early */ - maxsize = SPA_MIN(maxsize, max); - flush_out = false; - break; - case MODE_MERGE: - default: - /* in merge mode we consume one duration of samples and - * always output the resulting data */ - flush_out = true; - break; - } - src_datas = alloca(sizeof(void*) * this->resample.channels); - dst_datas = alloca(sizeof(void*) * this->resample.channels); - - if (outport->offset > maxsize) - outport->offset = maxsize; - - size = sb->datas0.chunk->size; - if (size == (uint32_t)-1) { - size = sb->datas0.maxsize; - memset(sb->datas0.data, 0, size); - for (i = 0; i < sb->n_datas; i++) - src_datasi = sb->datas0.data; - inport->offset = 0; - flush_in = draining = true; - } else { - size = SPA_MIN(size, sb->datas0.maxsize); - if (inport->offset > size) - inport->offset = size; - for (i = 0; i < sb->n_datas; i++) - src_datasi = SPA_PTROFF(sb->datasi.data, inport->offset, void); - } - for (i = 0; i < db->n_datas; i++) - dst_datasi = SPA_PTROFF(db->datasi.data, outport->offset, void); - - in_len = (size - inport->offset) / sizeof(float); - out_len = (maxsize - outport->offset) / sizeof(float); - -#ifndef FASTPATH - pin_len = in_len; - pout_len = out_len; -#endif - passthrough = is_passthrough(this); - - if (passthrough) { - uint32_t len = SPA_MIN(in_len, out_len); - for (i = 0; i < sb->n_datas; i++) - spa_memcpy(dst_datasi, src_datasi, len * sizeof(float)); - out_len = in_len = len; - } else { - resample_process(&this->resample, src_datas, &in_len, dst_datas, &out_len); - } - -#ifndef FASTPATH - spa_log_trace_fp(this->log, "%p: in %d/%d %zd %d out %d/%d %zd %d max:%d", - this, pin_len, in_len, size / sizeof(float), inport->offset, - pout_len, out_len, maxsize / sizeof(float), outport->offset, - max); -#endif - - for (i = 0; i < db->n_datas; i++) { - db->datasi.chunk->size = outport->offset + (out_len * sizeof(float)); - db->datasi.chunk->offset = 0; - } - - inport->offset += in_len * sizeof(float); - if (inport->offset >= size || flush_in) { - inio->status = SPA_STATUS_NEED_DATA; - spa_log_trace_fp(this->log, "%p: return input buffer of %zd samples", - this, size / sizeof(float)); - inport->offset = 0; - size = 0; - SPA_FLAG_SET(res, inio->status); - } - - outport->offset += out_len * sizeof(float); - if (outport->offset > 0 && (outport->offset >= maxsize || flush_out)) { - outio->status = SPA_STATUS_HAVE_DATA; - outio->buffer_id = dbuf->id; - spa_log_trace_fp(this->log, "%p: have output buffer of %zd samples", - this, outport->offset / sizeof(float)); - dequeue_buffer(this, dbuf); - outport->offset = 0; - this->drained = draining; - SPA_FLAG_SET(res, SPA_STATUS_HAVE_DATA); - } - if (out_len == 0 && this->peaks) { - outio->status = SPA_STATUS_HAVE_DATA; - outio->buffer_id = SPA_ID_INVALID; - SPA_FLAG_SET(res, SPA_STATUS_HAVE_DATA); - spa_log_trace_fp(this->log, "%p: no output buffer", this); - } - - update_rate_match(this, passthrough, (max - outport->offset) / sizeof(float), - (size - inport->offset) / sizeof(float)); - return res; -} - -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_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 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; - - spa_return_val_if_fail(handle != NULL, -EINVAL); - - this = (struct impl *) handle; - - if (this->resample.free) - resample_free(&this->resample); - 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; - 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_log_topic_init(this->log, log_topic); - - this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU); - if (this->cpu) - this->resample.cpu_flags = spa_cpu_get_flags(this->cpu); - - props_reset(&this->props); - - 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, "resample.peaks")) - this->peaks = spa_atob(s); - else if (spa_streq(k, "factory.mode")) { - if (spa_streq(s, "split")) - this->mode = MODE_SPLIT; - else if (spa_streq(s, "merge")) - this->mode = MODE_MERGE; - else - this->mode = MODE_CONVERT; - } else - resample_set_param(this, k, s); - - } - - spa_log_debug(this->log, "mode:%d", this->mode); - - this->node.iface = SPA_INTERFACE_INIT( - SPA_TYPE_INTERFACE_Node, - SPA_VERSION_NODE, - &impl_node, this); - - spa_hook_list_init(&this->hooks); - - this->rate_scale = 1.0; - - this->info = SPA_NODE_INFO_INIT(); - this->info_all = SPA_NODE_CHANGE_MASK_FLAGS; - this->info.max_input_ports = 1; - this->info.max_output_ports = 1; - this->info.flags = SPA_NODE_FLAG_RT; - - port = GET_OUT_PORT(this, 0); - port->direction = SPA_DIRECTION_OUTPUT; - port->id = 0; - port->info_all = SPA_PORT_CHANGE_MASK_FLAGS | - SPA_PORT_CHANGE_MASK_PARAMS; - port->info = SPA_PORT_INFO_INIT(); - port->info.flags = 0; - port->params0 = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); - port->params1 = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ); - port->params2 = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ); - port->params3 = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); - port->params4 = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); - port->info.params = port->params; - port->info.n_params = 5; - spa_list_init(&port->queue); - - port = GET_IN_PORT(this, 0); - port->direction = SPA_DIRECTION_INPUT; - port->id = 0; - 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_DYNAMIC_DATA; - port->params0 = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); - port->params1 = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ); - port->params2 = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ); - port->params3 = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); - port->params4 = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); - port->info.params = port->params; - port->info.n_params = 5; - spa_list_init(&port->queue); - - 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; -} - -const struct spa_handle_factory spa_resample_factory = { - SPA_VERSION_HANDLE_FACTORY, - SPA_NAME_AUDIO_PROCESS_RESAMPLE, - NULL, - impl_get_size, - impl_init, - impl_enum_interface_info, -};
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/splitter.c
Deleted
@@ -1,1251 +0,0 @@ -/* Spa - * - * 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. - */ - -#include <errno.h> -#include <string.h> -#include <stdio.h> -#include <limits.h> - -#include <spa/support/plugin.h> -#include <spa/support/cpu.h> -#include <spa/support/log.h> -#include <spa/utils/list.h> -#include <spa/utils/names.h> -#include <spa/utils/string.h> -#include <spa/node/node.h> -#include <spa/node/utils.h> -#include <spa/node/io.h> -#include <spa/param/audio/format-utils.h> -#include <spa/param/latency-utils.h> -#include <spa/param/param.h> -#include <spa/pod/filter.h> -#include <spa/debug/types.h> -#include <spa/debug/pod.h> - -#include "fmt-ops.h" - -#undef SPA_LOG_TOPIC_DEFAULT -#define SPA_LOG_TOPIC_DEFAULT log_topic -static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.splitter"); - -#define DEFAULT_RATE 48000 -#define DEFAULT_CHANNELS 2 -#define DEFAULT_MASK (1LL << SPA_AUDIO_CHANNEL_FL) | (1LL << SPA_AUDIO_CHANNEL_FR) - -#define MAX_ALIGN FMT_OPS_MAX_ALIGN -#define MAX_BUFFERS 32 -#define MAX_DATAS SPA_AUDIO_MAX_CHANNELS -#define MAX_PORTS SPA_AUDIO_MAX_CHANNELS - -struct buffer { - uint32_t id; -#define BUFFER_FLAG_QUEUED (1<<0) - uint32_t flags; - struct spa_list link; - struct spa_buffer *buf; - void *datasMAX_DATAS; -}; - -struct port { - uint32_t direction; - uint32_t id; - - struct spa_io_buffers *io; - - uint64_t info_all; - struct spa_port_info info; -#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 spa_dict info_props; - struct spa_dict_item info_props_items2; - char position16; - - bool have_format; - struct spa_audio_info format; - uint32_t blocks; - uint32_t stride; - - struct buffer buffersMAX_BUFFERS; - uint32_t n_buffers; - - struct spa_list queue; -}; - -struct impl { - struct spa_handle handle; - struct spa_node node; - - struct spa_log *log; - struct spa_cpu *cpu; - - uint32_t cpu_flags; - uint32_t max_align; - uint32_t quantum_limit; - - struct spa_io_position *io_position; - - uint64_t info_all; - struct spa_node_info info; -#define IDX_PortConfig 0 -#define N_NODE_PARAMS 1 - struct spa_param_info paramsN_NODE_PARAMS; - - struct spa_hook_list hooks; - - struct port in_ports1; - struct port *out_portsMAX_PORTS; - uint32_t port_count; - - struct spa_audio_info format; - unsigned int have_profile:1; - - struct convert conv; - unsigned int is_passthrough:1; - unsigned int started:1; - - struct spa_latency_info latency2; - - uint32_t src_remapSPA_AUDIO_MAX_CHANNELS; - uint32_t dst_remapSPA_AUDIO_MAX_CHANNELS; - - uint32_t empty_size; - float *empty; -}; - -#define CHECK_OUT_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < this->port_count) -#define CHECK_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) == 0) -#define CHECK_PORT(this,d,p) (CHECK_OUT_PORT(this,d,p) || CHECK_IN_PORT (this,d,p)) -#define GET_IN_PORT(this,p) (&this->in_portsp) -#define GET_OUT_PORT(this,p) (this->out_portsp) -#define GET_PORT(this,d,p) (d == SPA_DIRECTION_INPUT ? GET_IN_PORT(this,p) : GET_OUT_PORT(this,p)) - -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) { - 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 init_port(struct impl *this, enum spa_direction direction, - uint32_t port_id, uint32_t position) -{ - struct port *port = GET_OUT_PORT(this, port_id); - const char *name; - - if (port == NULL) { - port = calloc(1, sizeof(struct port)); - if (port == NULL) - return -errno; - this->out_portsport_id = port; - } - port->direction = direction; - port->id = port_id; - - name = spa_debug_type_find_short_name(spa_type_audio_channel, position); - snprintf(port->position, sizeof(port->position), "%s", name ? name : "UNK"); - - 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.flags = SPA_PORT_FLAG_DYNAMIC_DATA; - port->info_props_items0 = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "32 bit float mono audio"); - port->info_props_items1 = SPA_DICT_ITEM_INIT(SPA_KEY_AUDIO_CHANNEL, port->position); - port->info_props = SPA_DICT_INIT(port->info_props_items, 2); - port->info.props = &port->info_props; - 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; - - spa_list_init(&port->queue); - - port->n_buffers = 0; - port->have_format = false; - port->format.media_type = SPA_MEDIA_TYPE_audio; - port->format.media_subtype = SPA_MEDIA_SUBTYPE_dsp; - port->format.info.dsp.format = SPA_AUDIO_FORMAT_DSP_F32; - - spa_log_debug(this->log, "%p: init port %d:%d position:%s", - this, direction, port_id, port->position); - emit_port_info(this, port, true); - - return 0; -} - -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) { - default: - return 0; - } - - 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_set_io(void *object, uint32_t id, void *data, size_t size) -{ - struct impl *this = object; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - spa_log_debug(this->log, "%p: io %d %p/%zd", this, id, data, size); - - switch (id) { - case SPA_IO_Position: - this->io_position = data; - break; - default: - return -ENOENT; - } - return 0; -} - -static int int32_cmp(const void *v1, const void *v2) -{ - int32_t a1 = *(int32_t*)v1; - int32_t a2 = *(int32_t*)v2; - if (a1 == 0 && a2 != 0) - return 1; - if (a2 == 0 && a1 != 0) - return -1; - return a1 - a2; -} - -static int impl_node_set_param(void *object, uint32_t id, uint32_t flags, - const struct spa_pod *param) -{ - struct impl *this = object; - int res; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - if (param == NULL) - return 0; - - switch (id) { - case SPA_PARAM_PortConfig: - { - struct port *port; - struct spa_audio_info info = { 0, }; - struct spa_pod *format; - enum spa_direction direction; - enum spa_param_port_config_mode mode; - uint32_t i; - - if (spa_pod_parse_object(param, - SPA_TYPE_OBJECT_ParamPortConfig, NULL, - SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(&direction), - SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(&mode), - SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(&format)) < 0) - return -EINVAL; - - if (!spa_pod_is_object_type(format, SPA_TYPE_OBJECT_Format)) - return -EINVAL; - - if (mode != SPA_PARAM_PORT_CONFIG_MODE_dsp) - return -ENOTSUP; - if (direction != SPA_DIRECTION_OUTPUT) - return -EINVAL; - - if ((res = spa_format_parse(format, &info.media_type, &info.media_subtype)) < 0) - return res; - - if (info.media_type != SPA_MEDIA_TYPE_audio || - info.media_subtype != SPA_MEDIA_SUBTYPE_raw) - return -ENOTSUP; - - if (spa_format_audio_raw_parse(format, &info.info.raw) < 0) - return -EINVAL; - - info.info.raw.rate = 0; - - if (this->have_profile && memcmp(&this->format, &info, sizeof(info)) == 0) - return 0; - - spa_log_debug(this->log, "%p: port config %d/%d", this, - info.info.raw.rate, info.info.raw.channels); - - for (i = 0; i < this->port_count; i++) - spa_node_emit_port_info(&this->hooks, - SPA_DIRECTION_OUTPUT, i, NULL); - - this->have_profile = true; - this->is_passthrough = true; - this->format = info; - - this->port_count = info.info.raw.channels; - for (i = 0; i < this->port_count; i++) { - init_port(this, SPA_DIRECTION_OUTPUT, i, - info.info.raw.positioni); - } - port = GET_IN_PORT(this, 0); - qsort(info.info.raw.position, info.info.raw.channels, - sizeof(uint32_t), int32_cmp); - port->format = info; - port->have_format = true; - return 0; - } - default: - return -ENOENT; - } - return 0; -} - -static int impl_node_send_command(void *object, const struct spa_command *command) -{ - struct impl *this = object; - - 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: - this->started = true; - break; - case SPA_NODE_COMMAND_Suspend: - case SPA_NODE_COMMAND_Flush: - case SPA_NODE_COMMAND_Pause: - this->started = false; - 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; - uint32_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); - emit_port_info(this, GET_IN_PORT(this, 0), true); - for (i = 0; i < this->port_count; i++) - emit_port_info(this, GET_OUT_PORT(this, i), 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 *user_data) -{ - 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 port_enum_formats(void *object, - enum spa_direction direction, uint32_t port_id, - uint32_t index, - struct spa_pod **param, - struct spa_pod_builder *builder) -{ - struct impl *this = object; - struct port *port = GET_PORT(this, direction, port_id); - - switch (index) { - case 0: - if (direction == SPA_DIRECTION_OUTPUT) { - *param = spa_format_audio_dsp_build(builder, - SPA_PARAM_EnumFormat, &port->format.info.dsp); - } else if (port->have_format) { - *param = spa_format_audio_raw_build(builder, - SPA_PARAM_EnumFormat, &port->format.info.raw); - } - else { - uint32_t rate = this->io_position ? - this->io_position->clock.rate.denom : DEFAULT_RATE; - - *param = spa_pod_builder_add_object(builder, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), - SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(25, - SPA_AUDIO_FORMAT_F32P, - SPA_AUDIO_FORMAT_F32P, - SPA_AUDIO_FORMAT_F32, - SPA_AUDIO_FORMAT_F32_OE, - SPA_AUDIO_FORMAT_F64P, - SPA_AUDIO_FORMAT_F64, - SPA_AUDIO_FORMAT_F64_OE, - SPA_AUDIO_FORMAT_S32P, - SPA_AUDIO_FORMAT_S32, - SPA_AUDIO_FORMAT_S32_OE, - SPA_AUDIO_FORMAT_S24_32P, - SPA_AUDIO_FORMAT_S24_32, - SPA_AUDIO_FORMAT_S24_32_OE, - SPA_AUDIO_FORMAT_S24P, - SPA_AUDIO_FORMAT_S24, - SPA_AUDIO_FORMAT_S24_OE, - SPA_AUDIO_FORMAT_S16P, - SPA_AUDIO_FORMAT_S16, - SPA_AUDIO_FORMAT_S16_OE, - SPA_AUDIO_FORMAT_S8P, - SPA_AUDIO_FORMAT_S8, - SPA_AUDIO_FORMAT_U8P, - SPA_AUDIO_FORMAT_U8, - SPA_AUDIO_FORMAT_ULAW, - SPA_AUDIO_FORMAT_ALAW), - SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int( - rate, 1, INT32_MAX), - SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int( - DEFAULT_CHANNELS, 1, MAX_PORTS)); - } - break; - default: - return 0; - } - 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 *param; - struct spa_pod_builder b = { 0 }; - uint8_t buffer2048; - 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 = GET_PORT(this, direction, port_id); - - spa_log_debug(this->log, "%p: enum params port %d.%d %d %u", - this, direction, port_id, seq, 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 ((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; - - if (direction == SPA_DIRECTION_OUTPUT) - param = spa_format_audio_dsp_build(&b, id, &port->format.info.dsp); - else - param = spa_format_audio_raw_build(&b, id, &port->format.info.raw); - 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(port->blocks), - SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - this->quantum_limit * port->stride, - 16 * port->stride, - INT32_MAX), - SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); - 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: case 1: - param = spa_latency_build(&b, id, &this->latencyresult.index); - 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_debug(this->log, "%p: clear buffers %p", this, port); - port->n_buffers = 0; - spa_list_init(&port->queue); - } - return 0; -} - -static int setup_convert(struct impl *this) -{ - struct port *inport; - struct spa_audio_info informat, outformat; - uint32_t i, j, src_fmt, dst_fmt; - int res; - - inport = GET_IN_PORT(this, 0); - - informat = inport->format; - outformat = this->format; - - src_fmt = informat.info.raw.format; - dst_fmt = SPA_AUDIO_FORMAT_DSP_F32; - - spa_log_info(this->log, "%p: %s/%d@%d->%s/%d@%dx%d", this, - spa_debug_type_find_name(spa_type_audio_format, src_fmt), - informat.info.raw.channels, - informat.info.raw.rate, - spa_debug_type_find_name(spa_type_audio_format, dst_fmt), - 1, - outformat.info.raw.rate, - outformat.info.raw.channels); - - for (i = 0; i < informat.info.raw.channels; i++) { - for (j = 0; j < outformat.info.raw.channels; j++) { - if (informat.info.raw.positioni != - outformat.info.raw.positionj) - continue; - this->src_remapi = j; - this->dst_remapj = i; - spa_log_debug(this->log, "%p: channel %d -> %d (%s -> %s)", this, - i, j, - spa_debug_type_find_short_name(spa_type_audio_channel, - informat.info.raw.positioni), - spa_debug_type_find_short_name(spa_type_audio_channel, - outformat.info.raw.positionj)); - outformat.info.raw.positionj = -1; - break; - } - } - - this->conv.src_fmt = src_fmt; - this->conv.dst_fmt = dst_fmt; - this->conv.n_channels = informat.info.raw.channels; - this->conv.cpu_flags = this->cpu_flags; - - if ((res = convert_init(&this->conv)) < 0) - return res; - - this->is_passthrough &= this->conv.is_passthrough; - - spa_log_debug(this->log, "%p: got converter features %08x:%08x passthrough:%d", this, - this->cpu_flags, this->conv.cpu_flags, this->is_passthrough); - - return 0; -} - -static int calc_width(struct spa_audio_info *info) -{ - switch (info->info.raw.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 1; - case SPA_AUDIO_FORMAT_S16P: - case SPA_AUDIO_FORMAT_S16: - case SPA_AUDIO_FORMAT_S16_OE: - return 2; - case SPA_AUDIO_FORMAT_S24P: - case SPA_AUDIO_FORMAT_S24: - case SPA_AUDIO_FORMAT_S24_OE: - return 3; - case SPA_AUDIO_FORMAT_F64P: - case SPA_AUDIO_FORMAT_F64: - case SPA_AUDIO_FORMAT_F64_OE: - return 8; - default: - return 4; - } -} - -static int port_set_latency(void *object, - enum spa_direction direction, - uint32_t port_id, - uint32_t flags, - const struct spa_pod *latency) -{ - struct impl *this = object; - struct port *port; - enum spa_direction other = SPA_DIRECTION_REVERSE(direction); - uint32_t i; - - spa_log_debug(this->log, "%p: set latency direction:%d", this, direction); - - if (latency == NULL) { - this->latencyother = SPA_LATENCY_INFO(other); - } else { - struct spa_latency_info info; - if (spa_latency_parse(latency, &info) < 0 || - info.direction != other) - return -EINVAL; - this->latencyother = info; - } - for (i = 0; i < this->port_count; i++) { - port = GET_OUT_PORT(this, i); - port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; - port->paramsIDX_Latency.flags ^= SPA_PARAM_INFO_SERIAL; - emit_port_info(this, port, false); - } - port = GET_IN_PORT(this, 0); - port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; - port->paramsIDX_Latency.flags ^= SPA_PARAM_INFO_SERIAL; - emit_port_info(this, port, false); - return 0; -} - -static int port_set_format(void *object, - enum spa_direction direction, - uint32_t port_id, - uint32_t flags, - const struct spa_pod *format) -{ - struct impl *this = object; - struct port *port; - int res; - - port = GET_PORT(this, direction, port_id); - - spa_log_debug(this->log, "%p: set format", this); - - if (format == NULL) { - if (port->have_format) { - if (direction == SPA_DIRECTION_INPUT) - port->have_format = this->have_profile; - else - port->have_format = false; - port->format.info.raw.rate = 0; - clear_buffers(this, port); - } - } else { - struct spa_audio_info info = { 0 }; - - if ((res = spa_format_parse(format, &info.media_type, &info.media_subtype)) < 0) - return res; - - if (direction == SPA_DIRECTION_OUTPUT) { - if (info.media_type != SPA_MEDIA_TYPE_audio || - info.media_subtype != SPA_MEDIA_SUBTYPE_dsp) - return -EINVAL; - if (spa_format_audio_dsp_parse(format, &info.info.dsp) < 0) - return -EINVAL; - if (info.info.dsp.format != SPA_AUDIO_FORMAT_DSP_F32) - return -EINVAL; - - port->stride = 4; - port->blocks = 1; - } - else { - if (info.media_type != SPA_MEDIA_TYPE_audio || - info.media_subtype != SPA_MEDIA_SUBTYPE_raw) - return -EINVAL; - if (spa_format_audio_raw_parse(format, &info.info.raw) < 0) - return -EINVAL; - if (info.info.raw.channels != this->port_count) - return -EINVAL; - - port->stride = calc_width(&info); - if (SPA_AUDIO_FORMAT_IS_PLANAR(info.info.raw.format)) { - port->blocks = info.info.raw.channels; - } else { - port->stride *= info.info.raw.channels; - port->blocks = 1; - } - } - - port->format = info; - - spa_log_debug(this->log, "%p: %d %d %d", this, port_id, port->stride, port->blocks); - - if (direction == SPA_DIRECTION_INPUT) - if ((res = setup_convert(this)) < 0) - return res; - - port->have_format = true; - } - 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; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - spa_log_debug(this->log, "%p: set param port %d.%d %u", - this, direction, port_id, id); - - spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); - - switch (id) { - case SPA_PARAM_Latency: - return port_set_latency(this, direction, port_id, flags, param); - case SPA_PARAM_Format: - return port_set_format(this, direction, port_id, flags, param); - default: - return -ENOENT; - } -} - -static void queue_buffer(struct impl *this, struct port *port, uint32_t id) -{ - struct buffer *b = &port->buffersid; - - spa_log_trace_fp(this->log, "%p: queue buffer %d on port %d %d", - this, id, port->id, b->flags); - if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_QUEUED)) - return; - - spa_list_append(&port->queue, &b->link); - SPA_FLAG_SET(b->flags, BUFFER_FLAG_QUEUED); -} - -static struct buffer *dequeue_buffer(struct impl *this, struct port *port) -{ - struct buffer *b; - - if (spa_list_is_empty(&port->queue)) - return NULL; - - b = spa_list_first(&port->queue, struct buffer, link); - spa_list_remove(&b->link); - SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_QUEUED); - spa_log_trace_fp(this->log, "%p: dequeue buffer %d on port %d %u", - this, b->id, port->id, b->flags); - - return b; -} - -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, j, maxsize; - - 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_return_val_if_fail(port->have_format, -EIO); - - spa_log_debug(this->log, "%p: use buffers %d on port %d", this, n_buffers, port_id); - - clear_buffers(this, port); - - maxsize = 0; - for (i = 0; i < n_buffers; i++) { - struct buffer *b; - uint32_t n_datas = buffersi->n_datas; - struct spa_data *d = buffersi->datas; - - b = &port->buffersi; - b->id = i; - b->buf = buffersi; - b->flags = 0; - - for (j = 0; j < n_datas; j++) { - if (dj.data == NULL) { - spa_log_error(this->log, "%p: invalid memory %d on buffer %d %d %p", - this, j, i, dj.type, dj.data); - return -EINVAL; - } - if (!SPA_IS_ALIGNED(dj.data, this->max_align)) { - spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned", - this, j, i); - } - b->datasj = dj.data; - if (direction == SPA_DIRECTION_OUTPUT && - !SPA_FLAG_IS_SET(dj.flags, SPA_DATA_FLAG_DYNAMIC)) - this->is_passthrough = false; - - spa_log_debug(this->log, "%p: buffer %d data %d flags:%08x %p", - this, i, j, dj.flags, b->datasj); - - maxsize = SPA_MAX(maxsize, dj.maxsize); - } - if (direction == SPA_DIRECTION_OUTPUT) - queue_buffer(this, port, i); - } - if (maxsize > this->empty_size) { - this->empty = realloc(this->empty, maxsize + MAX_ALIGN); - if (this->empty == NULL) - return -errno; - memset(this->empty, 0, maxsize + MAX_ALIGN); - this->empty_size = maxsize; - } - 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 = 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_OUT_PORT(this, port_id); - queue_buffer(this, port, buffer_id); - - return 0; -} - -static int impl_node_process(void *object) -{ - struct impl *this = object; - struct port *inport; - struct spa_io_buffers *inio; - uint32_t i, maxsize, n_samples; - struct spa_data *sd, *dd; - struct buffer *sbuf, *dbuf; - uint32_t n_src_datas, n_dst_datas; - const void **src_datas; - void **dst_datas; - - spa_return_val_if_fail(this != NULL, -EINVAL); - - inport = GET_IN_PORT(this, 0); - inio = inport->io; - spa_return_val_if_fail(inio != NULL, -EIO); - spa_return_val_if_fail(this->conv.process != NULL, -EIO); - - spa_log_trace_fp(this->log, "%p: status %p %d %d", this, - inio, inio->status, inio->buffer_id); - - if (SPA_UNLIKELY(inio->status != SPA_STATUS_HAVE_DATA)) - return inio->status; - - if (SPA_UNLIKELY(inio->buffer_id >= inport->n_buffers)) - return inio->status = -EINVAL; - - sbuf = &inport->buffersinio->buffer_id; - sd = sbuf->buf->datas; - - n_src_datas = sbuf->buf->n_datas; - src_datas = alloca(sizeof(void*) * n_src_datas); - - maxsize = INT_MAX; - for (i = 0; i < n_src_datas; i++) { - src_datasi = SPA_PTROFF(sdi.data, - sdi.chunk->offset, void); - maxsize = SPA_MIN(sdi.chunk->size, maxsize); - } - n_samples = maxsize / inport->stride; - - n_dst_datas = this->port_count; - dst_datas = alloca(sizeof(void*) * n_dst_datas); - - for (i = 0; i < n_dst_datas; i++) { - struct port *outport = GET_OUT_PORT(this, i); - struct spa_io_buffers *outio; - uint32_t src_remap = this->src_remapi; - uint32_t dst_remap = this->dst_remapi; - - if (SPA_UNLIKELY((outio = outport->io) == NULL)) - goto empty; - - spa_log_trace_fp(this->log, "%p: %d %p %d %d %d", this, i, - outio, outio->status, outio->buffer_id, outport->stride); - - if (SPA_UNLIKELY(outio->status == SPA_STATUS_HAVE_DATA)) - goto empty; - - if (SPA_LIKELY(outio->buffer_id < outport->n_buffers)) { - queue_buffer(this, outport, outio->buffer_id); - outio->buffer_id = SPA_ID_INVALID; - } - - if (SPA_UNLIKELY((dbuf = dequeue_buffer(this, outport)) == NULL)) { - outio->status = -EPIPE; - empty: - spa_log_trace_fp(this->log, "%p: %d skip output", this, i); - dst_datasdst_remap = SPA_PTR_ALIGN(this->empty, MAX_ALIGN, void); - continue; - } - - dd = dbuf->buf->datas; - - maxsize = dd->maxsize; - n_samples = SPA_MIN(n_samples, maxsize / outport->stride); - - if (this->is_passthrough) - dd0.data = (void *)src_datassrc_remap; - else - dst_datasdst_remap = dd0.data = dbuf->datas0; - - dd0.chunk->offset = 0; - dd0.chunk->size = n_samples * outport->stride; - - outio->status = SPA_STATUS_HAVE_DATA; - outio->buffer_id = dbuf->id; - } - - spa_log_trace_fp(this->log, "%p: n_src:%d n_dst:%d n_samples:%d max:%d stride:%d p:%d", this, - n_src_datas, n_dst_datas, n_samples, maxsize, inport->stride, - this->is_passthrough); - - if (!this->is_passthrough) - convert_process(&this->conv, dst_datas, src_datas, n_samples); - - inio->status = SPA_STATUS_NEED_DATA; - - return SPA_STATUS_NEED_DATA | 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_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 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; - uint32_t i; - - spa_return_val_if_fail(handle != NULL, -EINVAL); - - this = (struct impl *) handle; - - for (i = 0; i < MAX_PORTS; i++) - free(this->out_portsi); - free(this->empty); - 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; - 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_log_topic_init(this->log, log_topic); - - this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU); - if (this->cpu) { - this->cpu_flags = spa_cpu_get_flags(this->cpu); - this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu)); - } - - 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); - } - - spa_hook_list_init(&this->hooks); - - this->latencySPA_DIRECTION_INPUT = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); - this->latencySPA_DIRECTION_OUTPUT = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); - - 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 = 1; - this->info.max_output_ports = MAX_PORTS; - this->info.flags = SPA_NODE_FLAG_RT | - SPA_NODE_FLAG_OUT_PORT_CONFIG; - this->paramsIDX_PortConfig = SPA_PARAM_INFO(SPA_PARAM_PortConfig, SPA_PARAM_INFO_WRITE); - this->info.params = this->params; - this->info.n_params = N_NODE_PARAMS; - - port = GET_IN_PORT(this, 0); - port->info_all = SPA_PORT_CHANGE_MASK_FLAGS | - SPA_PORT_CHANGE_MASK_PARAMS; - port->direction = SPA_DIRECTION_INPUT; - port->id = 0; - port->info = SPA_PORT_INFO_INIT(); - port->info.flags = SPA_PORT_FLAG_NO_REF | - SPA_PORT_FLAG_DYNAMIC_DATA; - 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; - - 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; -} - -const struct spa_handle_factory spa_splitter_factory = { - SPA_VERSION_HANDLE_FACTORY, - SPA_NAME_AUDIO_PROCESS_DEINTERLEAVE, - NULL, - impl_get_size, - impl_init, - impl_enum_interface_info, -};
View file
pipewire-0.3.52.tar.gz/INSTALL.md -> pipewire-0.3.53.tar.gz/INSTALL.md
Changed
@@ -1,8 +1,8 @@ ## Building -PipeWire uses a build tool called *Meson* as a basis for its build +PipeWire uses a build tool called *Meson*(https://mesonbuild.com) as a basis for its build process. It's a tool with some resemblance to Autotools and CMake. Meson -again generates build files for a lower level build tool called *Ninja*, +again generates build files for a lower level build tool called *Ninja*(https://ninja-build.org/), working in about the same level of abstraction as more familiar GNU Make does. @@ -39,7 +39,7 @@ Finally, invoke the build: ``` -$ ninja -C builddir +$ meson compile -C builddir ``` Just to avoid any confusion: `autogen.sh` is a script invoked by *Jhbuild*, @@ -68,10 +68,10 @@ ``` This will use the default config file to configure and start the daemon. -The default config will also start pipewire-media-session, a default -example media session and pipewire-pulse, a PulseAudio compatible server. +The default config will also start `pipewire-media-session`, a default +example media session and `pipewire-pulse`, a PulseAudio compatible server. -You can also enable more debugging with the PIPEWIRE_DEBUG environment +You can also enable more debugging with the `PIPEWIRE_DEBUG` environment variable like so: ``` @@ -92,14 +92,15 @@ ## Installing -PipeWire comes with quite a bit of libraries and tools, run -inside `builddir`: +PipeWire comes with quite a bit of libraries and tools, run: ``` -sudo meson install +meson install -C builddir ``` to install everything onto the system into the specified prefix. +Depending on the configured installation prefix, the above command +may need to be run with elevated privileges (e.g. with `sudo`). Some additional steps will have to be performed to integrate with the distribution as shown below. @@ -111,7 +112,7 @@ systemd unit using socket activation or as a service. Configuration of the PipeWire daemon can be found in -/usr/share/pipewire/pipewire.conf. Please refer to the comments in the +`/usr/share/pipewire/pipewire.conf`. Please refer to the comments in the config file for more information about the configuration options. The daemon is started with: @@ -150,14 +151,14 @@ ``` The plugin will be picked up by alsa when the following files -are in /etc/alsa/conf.d/ +are in `/etc/alsa/conf.d/`: ``` /etc/alsa/conf.d/50-pipewire.conf -> /usr/share/alsa/alsa.conf.d/50-pipewire.conf /etc/alsa/conf.d/99-pipewire-default.conf ``` -With this setup, aplay -l should list a pipewire: device that can be used as +With this setup, `aplay -l` should list a pipewire device that can be used as a regular alsa device for playback and record. ### JACK emulation @@ -180,7 +181,7 @@ ``` -The provided pw-jack script uses LD_LIBRARY_PATH to set the library +The provided `pw-jack` script uses `LD_LIBRARY_PATH` to set the library search path to these replacement libraries. This allows you to run jack apps on both the real JACK server or on PipeWire with the script. @@ -193,7 +194,7 @@ ``` Note that when JACK is replaced by PipeWire, the SPA JACK plugin (installed -in /usr/lib64/spa-0.2/jack/libspa-jack.so) is not useful anymore and +in `/usr/lib64/spa-0.2/jack/libspa-jack.so`) is not useful anymore and distributions should make them conflict. @@ -216,14 +217,21 @@ ``` You can also start additional PulseAudio servers listening on other -sockets with the -a option. See `pipewire-pulse -h` for more info. +sockets with the `-a` option. See `pipewire-pulse -h` for more info. ## Uninstalling -To uninstall, in the `builddir` directory run: +To uninstall, run: ``` -sudo ninja uninstall +ninja -C builddir uninstall ``` +Depending on the configured installation prefix, the above command +may need to be run with elevated privileges (e.g. with `sudo`). + +Note that at the time of writing uninstallation only works with the +same build directory that was used for installation. Meson stores the +list of installed files in the build directory, and this list is +necessary for uninstallation to work.
View file
pipewire-0.3.52.tar.gz/NEWS -> pipewire-0.3.53.tar.gz/NEWS
Changed
@@ -1,3 +1,81 @@ +# PipeWire 0.3.53 (2022-06-30) + +This is a bugfix release that is API and ABI compatible with previous +0.3.x releases. + +## Highlights + - The 44.1KHz samplerate was removed again from the defaults, it caused + all kinds of problems with various hardware. + - The ALSA plugin should now be able to deal with unsupported samplerates + and fall back to the nearest supported one. + - The rlimits performance tuning wiki page was updated. Please check + you limits.conf file, the version on the wiki used to give all + processes a -19 nice level instead of just the pipewire daemon. + - The audioconvert plugin was rewritten to be more maintainable and + faster. It also gained support for control ports and dithering with + optional noise shaping. + - An impossible buffering situation is avoided in pulse-server that would + cause some applications (sunshine, ...) to stutter. + + +## PipeWire + - 44.1KHz was removed from the allowed rates again. It caused all kinds + of regressions due to driver bugs and timing issues on HDMI. + +## modules + - filter-chain now does some more error checking and reporting to + avoid some crashes. + - filter-chain now supports more channel layouts for input and output + that does not need to match the plugin layout. + - Format parsing is now more consistent in the modules. + +## Tools + - pw-cli can now also work without readline support. + - pw-cat can now also read multichannel ulaw/alaw/u8/s8. + +## SPA + - The audioconvert plugin was rewritten. This should make it more + maintainable. It also fixed some issues such as CPU spikes in some + cases and crashes in others. The old plugins were removed, for a + code reduction of some 6000 lines. + - The audioconvert plugin now supports control ports, which can be + enabled on nodes in the session manager. This makes it possible to + control audioconvert properties using timed events or midi. + - NoteOn 0-velocity MIDI events are no longer filtered out. This is + a valid event, nodes that can't deal with it should fix it up + themselves. The JACK layer still filters out these events by default + but this can now be configured with a per-client property. + - The running status on midi events is now disabled to match what + JACK does. + - The ALSA plugin will now deal with driver bugs when a driver announces + support for a samplerate but then refuses to use it later. + - The ALSA plugin has been optimized a little for sample IO. + - V4L2 now doesn't error when there are no controls. + - Error handling was improved in the audio converter. + - The audioconvert plugin now supports rectangular dithering and + noise shaping. + - The audioconvert plugin can now insert additional inaudible noise + that can be used to keep some amplifiers alive. (#705) + - The audioconvert format conversion was changed so that it now produces + the full 32 bits range in the C fallback conversion code as well. + - The resampler window function was changed to a cosh() window + function. (#2483) + - Vendor and device id are now in hex. + +## pulse-server + - Tweak the record buffer attributes some more and make sure we don't + end up in impossible buffering situations. Fixes an issue with + distorted sound in sunshine. (#2447) + - Fix a potential crash when updating the client property list. + - Some properties on cards were aligned with pulseaudio. + +## Wiki + - Change "priority" to "nice" in the example limits.conf file. It was + giving a -19 nice level to all processes, not just the pipewire + daemon. + +Older versions: + # PipeWire 0.3.52 (2022-06-09) This is a bugfix release that is API and ABI compatible with previous @@ -112,9 +190,6 @@ - Fixes to the source and fd use. - It is now possible to set client properties as well. (#1573) - -Older versions: - # PipeWire 0.3.51 (2022-04-28) This is a bugfix release that is API and ABI compatible with previous
View file
pipewire-0.3.52.tar.gz/meson.build -> pipewire-0.3.53.tar.gz/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '0.3.52', + version : '0.3.53', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.59.0', default_options : 'warning_level=3', @@ -266,6 +266,7 @@ endif 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) sndfile_dep = dependency('sndfile', version : '>= 1.0.20', required : get_option('sndfile')) summary({'sndfile': sndfile_dep.found()}, bool_yn: true, section: 'pw-cat/pw-play/pw-dump/filter-chain') @@ -335,16 +336,16 @@ summary({'WebRTC Echo Canceling': webrtc_dep.found()}, bool_yn: true, section: 'Misc dependencies') cdata.set('HAVE_WEBRTC', webrtc_dep.found()) -# On FreeBSD, epoll-shim library is required for eventfd() and timerfd() -epoll_shim_dep = (build_machine.system() == 'freebsd' +# On FreeBSD and MidnightBSD, epoll-shim library is required for eventfd() and timerfd() +epoll_shim_dep = (build_machine.system() == 'freebsd' or build_machine.system() == 'midnightbsd' ? dependency('epoll-shim', required: true) : dependency('', required: false)) -libinotify_dep = (build_machine.system() == 'freebsd' +libinotify_dep = (build_machine.system() == 'freebsd' or build_machine.system() == 'midnightbsd' ? dependency('libinotify', required: true) : dependency('', required: false)) -# On FreeBSD, libintl library is required for gettext +# On FreeBSD and MidnightBSD, libintl library is required for gettext libintl_dep = cc.find_library('intl', required: false) if not libintl_dep.found() libintl_dep = dependency('intl', required: false) @@ -355,8 +356,8 @@ alsa_dep = dependency('alsa', version : '>=1.1.7', required: need_alsa) summary({'pipewire-alsa': alsa_dep.found()}, bool_yn: true) -if build_machine.system() == 'freebsd' -# On FreeBSD the OpenSSL library may come from base or a package. +if build_machine.system() == 'freebsd' or build_machine.system() == 'midnightbsd' +# On FreeBSD and MidnightBSD the OpenSSL library may come from base or a package. # Check for a package first and fallback to the base library if we can't find it via pkgconfig openssl_lib = dependency('openssl', required: false) if not openssl_lib.found()
View file
pipewire-0.3.52.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c -> pipewire-0.3.53.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c
Changed
@@ -25,7 +25,7 @@ #define __USE_GNU #include <limits.h> -#ifndef __FreeBSD__ +#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) #include <byteswap.h> #endif #include <sys/shm.h>
View file
pipewire-0.3.52.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.53.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
@@ -400,6 +400,7 @@ unsigned int default_as_system:1; int self_connect_mode; int rt_max; + unsigned int fix_midi_events:1; jack_position_t jack_position; jack_transport_state_t jack_state; @@ -985,10 +986,20 @@ return b.state.offset; } -static void convert_to_midi(struct spa_pod_sequence **seq, uint32_t n_seq, void *midi) +static inline void fix_midi_event(uint8_t *data, size_t size) +{ + /* fixup NoteOn with vel 0 */ + if (size > 2 && (data0 & 0xF0) == 0x90 && data2 == 0x00) { + data0 = 0x80 + (data0 & 0x0F); + data2 = 0x40; + } +} + +static void convert_to_midi(struct spa_pod_sequence **seq, uint32_t n_seq, void *midi, bool fix) { struct spa_pod_control *cn_seq; uint32_t i; + int res; for (i = 0; i < n_seq; i++) ci = spa_pod_control_first(&seqi->body); @@ -996,6 +1007,8 @@ while (true) { struct spa_pod_control *next = NULL; uint32_t next_index = 0; + uint8_t *data; + size_t size; for (i = 0; i < n_seq; i++) { if (!spa_pod_control_is_inside(&seqi->body, @@ -1010,12 +1023,17 @@ if (SPA_UNLIKELY(next == NULL)) break; + data = SPA_POD_BODY(&next->value); + size = SPA_POD_BODY_SIZE(&next->value); + switch(next->type) { case SPA_CONTROL_Midi: - jack_midi_event_write(midi, - next->offset, - SPA_POD_BODY(&next->value), - SPA_POD_BODY_SIZE(&next->value)); + if (fix) + fix_midi_event(data, size); + + if ((res = jack_midi_event_write(midi, next->offset, data, size)) < 0) + pw_log_warn("midi %p: can't write event: %s", midi, + spa_strerror(res)); break; } cnext_index = spa_pod_control_next(cnext_index); @@ -3383,6 +3401,7 @@ client->filter_name = pw_properties_get_bool(client->props, "jack.filter-name", false); client->locked_process = pw_properties_get_bool(client->props, "jack.locked-process", true); client->default_as_system = pw_properties_get_bool(client->props, "jack.default-as-system", false); + client->fix_midi_events = pw_properties_get_bool(client->props, "jack.fix-midi-events", true); client->self_connect_mode = SELF_CONNECT_ALLOW; if ((str = pw_properties_get(client->props, "jack.self-connect-mode")) != NULL) { @@ -4462,7 +4481,7 @@ if (n_seq == MAX_MIDI_MIX) break; } - convert_to_midi(seq, n_seq, ptr); + convert_to_midi(seq, n_seq, ptr, p->client->fix_midi_events); return ptr; }
View file
pipewire-0.3.52.tar.gz/pipewire-v4l2/src/pipewire-v4l2.c -> pipewire-0.3.53.tar.gz/pipewire-v4l2/src/pipewire-v4l2.c
Changed
@@ -1756,7 +1756,7 @@ if ((file = find_file(fd)) == NULL) return globals.old_fops.ioctl(fd, request, arg); -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__MidnightBSD__) if (arg == NULL && (request & IOC_DIRMASK != IOC_VOID)) { #else if (arg == NULL && (_IOC_DIR(request) & (_IOC_WRITE | _IOC_READ))) {
View file
pipewire-0.3.52.tar.gz/po/uk.po -> pipewire-0.3.53.tar.gz/po/uk.po
Changed
@@ -7,8 +7,8 @@ "Project-Id-Version: pipewire\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/issue" "s\n" -"POT-Creation-Date: 2022-05-05 03:28+0000\n" -"PO-Revision-Date: 2022-05-05 21:06+0300\n" +"POT-Creation-Date: 2022-05-20 15:26+0000\n" +"PO-Revision-Date: 2022-06-18 13:07+0300\n" "Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n" "Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\n" "Language: uk\n" @@ -48,7 +48,6 @@ msgstr "Тунель до %s/%s" #: src/modules/module-fallback-sink.c:51 -#| msgid "Game Output" msgid "Dummy Output" msgstr "Фіктивний вихід" @@ -71,23 +70,29 @@ msgid "%s on %s" msgstr "%s на %s" -#: src/tools/pw-cat.c:871 +#: src/tools/pw-cat.c:872 #, c-format +#| msgid "" +#| "%s options <file>\n" +#| " -h, --help Show this help\n" +#| " --version Show version\n" +#| " -v, --verbose Enable verbose operations\n" +#| "\n" msgid "" -"%s options <file>\n" +"%s options <file>|-\n" " -h, --help Show this help\n" " --version Show version\n" " -v, --verbose Enable verbose operations\n" "\n" msgstr "" -"%s параметри <файл>\n" +"%s параметри <файл>|-\n" " -h, --help вивести довідку\n" " --version вивести дані щодо версії\n" " -v, --verbose ввімкнути відображення докладної " "інформації\n" "\n" -#: src/tools/pw-cat.c:878 +#: src/tools/pw-cat.c:879 #, c-format #| msgid "" #| " -R, --remote Remote daemon name\n" @@ -101,8 +106,6 @@ #| " or direct samples (256)\n" #| " the rate is the one of the " #| "source file\n" -#| " --list-targets List available targets for --" -#| "target\n" #| "\n" msgid "" " -R, --remote Remote daemon name\n" @@ -116,6 +119,7 @@ " or direct samples (256)\n" " the rate is the one of the source " "file\n" +" -P --properties Set node properties\n" "\n" msgstr "" " -R, --remote назва віддаленої фонової служби\n" @@ -133,9 +137,10 @@ "ns)\n" " або безпосередні семпли (256)\n" " частота — частота з файла джерела\n" +" -P --properties встановити властивості вузла\n" "\n" -#: src/tools/pw-cat.c:895 +#: src/tools/pw-cat.c:897 #, c-format msgid "" " --rate Sample rate (req. for rec) (default " @@ -171,7 +176,7 @@ "(типово, %d)\n" "\n" -#: src/tools/pw-cat.c:912 +#: src/tools/pw-cat.c:914 msgid "" " -p, --playback Playback mode\n" " -r, --record Recording mode\n"
View file
pipewire-0.3.52.tar.gz/spa/examples/adapter-control.c -> pipewire-0.3.53.tar.gz/spa/examples/adapter-control.c
Changed
@@ -62,7 +62,9 @@ static SPA_LOG_IMPL(default_log); -#define MIN_LATENCY 1024 +#define MIN_LATENCY 1024 +#define CONTROL_BUFFER_SIZE 32768 + struct buffer { struct spa_buffer buffer; @@ -95,10 +97,19 @@ struct spa_node *sink_follower_node; // alsa-pcm-sink struct spa_node *sink_node; // adapter for alsa-pcm-sink + struct spa_io_position position; struct spa_io_buffers source_sink_io1; struct spa_buffer *source_buffers1; struct buffer source_buffer1; - uint8_t ctrl1024; + + struct spa_io_buffers control_io; + struct spa_buffer *control_buffers1; + struct buffer control_buffer1; + + int buffer_count; + bool start_fade_in; + double volume_accum; + uint32_t volume_offs; bool running; pthread_t thread; @@ -168,6 +179,11 @@ str = PLUGINDIR; data->plugin_dir = str; + /* start not doing fade-in */ + data->start_fade_in = true; + data->volume_accum = 0.0; + data->volume_offs = 0; + /* init the graph */ spa_graph_init(&data->graph, &data->graph_state); @@ -274,29 +290,104 @@ return res; } -static int on_sink_node_ready(void *_data, int status) +static int fade_in(struct data *data) { - struct data *data = _data; + struct spa_pod_builder b; + struct spa_pod_frame f1; + void *buffer = data->control_buffer->datas0.data; + uint32_t buffer_size = data->control_buffer->datas0.maxsize; + data->control_buffer->datas0.chunk0.size = buffer_size; + + printf ("fading in\n"); + + spa_pod_builder_init(&b, buffer, buffer_size); + spa_pod_builder_push_sequence(&b, &f0, 0); + data->volume_offs = 0; + do { + spa_pod_builder_control(&b, data->volume_offs, SPA_CONTROL_Properties); + spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_Props, 0, + SPA_PROP_volume, SPA_POD_Float(data->volume_accum)); + data->volume_accum += 0.003; + data->volume_offs += 200; + } while (data->volume_accum < 1.0); + spa_pod_builder_pop(&b, &f0); - spa_graph_node_process(&data->graph_source_node); - spa_graph_node_process(&data->graph_sink_node); return 0; } -static int -on_sink_node_reuse_buffer(void *_data, uint32_t port_id, uint32_t buffer_id) +static int fade_out(struct data *data) +{ + struct spa_pod_builder b; + struct spa_pod_frame f1; + void *buffer = data->control_buffer->datas0.data; + uint32_t buffer_size = data->control_buffer->datas0.maxsize; + data->control_buffer->datas0.chunk0.size = buffer_size; + + printf ("fading out\n"); + + spa_pod_builder_init(&b, buffer, buffer_size); + spa_pod_builder_push_sequence(&b, &f0, 0); + data->volume_offs = 200; + do { + spa_pod_builder_control(&b, data->volume_offs, SPA_CONTROL_Properties); + spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_Props, 0, + SPA_PROP_volume, SPA_POD_Float(data->volume_accum)); + data->volume_accum -= 0.003; + data->volume_offs += 200; + } while (data->volume_accum > 0.0); + spa_pod_builder_pop(&b, &f0); + + return 0; +} + +static void do_fade(struct data *data) +{ + switch (data->control_io.status) { + case SPA_STATUS_OK: + case SPA_STATUS_NEED_DATA: + break; + case SPA_STATUS_HAVE_DATA: + case SPA_STATUS_STOPPED: + default: + return; + } + + /* fade */ + if (data->start_fade_in) + fade_in(data); + else + fade_out(data); + + data->control_io.status = SPA_STATUS_HAVE_DATA; + data->control_io.buffer_id = 0; + + /* alternate */ + data->start_fade_in = !data->start_fade_in; +} + +static int on_sink_node_ready(void *_data, int status) { struct data *data = _data; - printf ("reuse_buffer: port_id=%d\n", port_id); - data->source_sink_io0.buffer_id = buffer_id; + /* only do fade in/out when buffer count is 0 */ + if (data->buffer_count == 0) + do_fade(data); + + /* update buffer count */ + data->buffer_count++; + if (data->buffer_count > 64) + data->buffer_count = 0; + + spa_graph_node_process(&data->graph_source_node); + spa_graph_node_process(&data->graph_sink_node); return 0; } static const struct spa_node_callbacks sink_node_callbacks = { SPA_VERSION_NODE_CALLBACKS, .ready = on_sink_node_ready, - .reuse_buffer = on_sink_node_reuse_buffer }; static int make_nodes(struct data *data, const char *device) @@ -306,15 +397,17 @@ struct spa_pod_builder b = { 0 }; uint8_t buffer1024; char value32; - struct spa_dict_item items1; + struct spa_dict_item items2; struct spa_audio_info_raw info; struct spa_pod *param; + items0 = SPA_DICT_ITEM_INIT("clock.quantum-limit", "8192"); + /* make the source node (audiotestsrc) */ if ((res = make_node(data, &data->source_follower_node, - "audiotestsrc/libspa-audiotestsrc.so", - "audiotestsrc", - NULL)) < 0) { + "audiotestsrc/libspa-audiotestsrc.so", + "audiotestsrc", + &SPA_DICT_INIT(items, 1))) < 0) { printf("can't create source follower node (audiotestsrc): %d\n", res); return res; } @@ -335,11 +428,11 @@ /* make the sink adapter node */ snprintf(value, sizeof(value), "pointer:%p", data->source_follower_node); - items0 = SPA_DICT_ITEM_INIT("audio.adapt.follower", value); + items1 = SPA_DICT_ITEM_INIT("audio.adapt.follower", value); if ((res = make_node(data, &data->source_node, - "audioconvert/libspa-audioconvert.so", - SPA_NAME_AUDIO_ADAPT, - &SPA_DICT_INIT(items, 1))) < 0) { + "audioconvert/libspa-audioconvert.so", + SPA_NAME_AUDIO_ADAPT, + &SPA_DICT_INIT(items, 2))) < 0) { printf("can't create source adapter node: %d\n", res); return res; } @@ -376,20 +469,20 @@ /* make the sink follower node (alsa-pcm-sink) */ if ((res = make_node(data, &data->sink_follower_node, - "alsa/libspa-alsa.so", - SPA_NAME_API_ALSA_PCM_SINK, - NULL)) < 0) { + "alsa/libspa-alsa.so", + SPA_NAME_API_ALSA_PCM_SINK, + &SPA_DICT_INIT(items, 1))) < 0) { printf("can't create sink follower node (alsa-pcm-sink): %d\n", res); return res; } /* make the sink adapter node */ snprintf(value, sizeof(value), "pointer:%p", data->sink_follower_node); - items0 = SPA_DICT_ITEM_INIT("audio.adapt.follower", value); + items1 = SPA_DICT_ITEM_INIT("audio.adapt.follower", value); if ((res = make_node(data, &data->sink_node, - "audioconvert/libspa-audioconvert.so", - SPA_NAME_AUDIO_ADAPT, - &SPA_DICT_INIT(items, 1))) < 0) { + "audioconvert/libspa-audioconvert.so", + SPA_NAME_AUDIO_ADAPT, + &SPA_DICT_INIT(items, 2))) < 0) { printf("can't create sink adapter node: %d\n", res); return res; } @@ -420,6 +513,7 @@ SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(SPA_DIRECTION_INPUT), SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp), + SPA_PARAM_PORT_CONFIG_control, SPA_POD_Bool(true), SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param)); if ((res = spa_node_set_param(data->sink_node, SPA_PARAM_PortConfig, 0, param) < 0)) { printf("can't setup sink node %d\n", res); @@ -442,6 +536,42 @@ printf("can't set io buffers on port 0 of sink node: %d\n", res); return res; } + /* set io position and clock on source and sink nodes */ + data->position.clock.rate = SPA_FRACTION(1, 48000); + data->position.clock.duration = 1024; + if ((res = spa_node_set_io(data->source_node, + SPA_IO_Position, + &data->position, sizeof(data->position))) < 0) { + printf("can't set io position on source node: %d\n", res); + return res; + } + if ((res = spa_node_set_io(data->sink_node, + SPA_IO_Position, + &data->position, sizeof(data->position))) < 0) { + printf("can't set io position on sink node: %d\n", res); + return res; + } + if ((res = spa_node_set_io(data->source_node, + SPA_IO_Clock, + &data->position.clock, sizeof(data->position.clock))) < 0) { + printf("can't set io clock on source node: %d\n", res); + return res; + } + if ((res = spa_node_set_io(data->sink_node, + SPA_IO_Clock, + &data->position.clock, sizeof(data->position.clock))) < 0) { + printf("can't set io clock on sink node: %d\n", res); + return res; + } + + /* set io buffers on control port of sink node */ + if ((res = spa_node_port_set_io(data->sink_node, + SPA_DIRECTION_INPUT, 1, + SPA_IO_Buffers, + &data->control_io, sizeof(data->control_io))) < 0) { + printf("can't set io buffers on control port 1 of sink node\n"); + return res; + } /* add source node to the graph */ spa_graph_node_init(&data->graph_source_node, &data->graph_source_state); @@ -508,17 +638,6 @@ uint32_t state = 0; size_t buffer_size = 1024; - /* get the source follower node buffer size */ - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - if (spa_node_port_enum_params_sync(data->source_follower_node, - SPA_DIRECTION_OUTPUT, 0, - SPA_PARAM_Buffers, &state, filter, ¶m, &b) != 1) - return -ENOTSUP; - spa_pod_fixate(param); - if ((res = spa_pod_parse_object(param, SPA_TYPE_OBJECT_ParamBuffers, NULL, - SPA_PARAM_BUFFERS_size, SPA_POD_Int(&buffer_size))) < 0) - return res; - /* set the sink and source formats */ spa_pod_builder_init(&b, buffer, sizeof(buffer)); param = spa_format_audio_dsp_build(&b, 0, @@ -531,6 +650,26 @@ SPA_DIRECTION_INPUT, 0, SPA_PARAM_Format, 0, param)) < 0) return res; + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + 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)); + if ((res = spa_node_port_set_param(data->sink_node, + SPA_DIRECTION_INPUT, 1, SPA_PARAM_Format, 0, param)) < 0) + return res; + + /* get the source node buffer size */ + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + if ((res = spa_node_port_enum_params_sync(data->source_node, + SPA_DIRECTION_OUTPUT, 0, + SPA_PARAM_Buffers, &state, filter, ¶m, &b)) != 1) + return res ? res : -ENOTSUP; + spa_pod_fixate(param); + if ((res = spa_pod_parse_object(param, SPA_TYPE_OBJECT_ParamBuffers, NULL, + SPA_PARAM_BUFFERS_size, SPA_POD_Int(&buffer_size))) < 0) + return res; + /* use buffers on the source and sink */ init_buffer(data, data->source_buffers, data->source_buffer, 1, buffer_size); if ((res = spa_node_port_use_buffers(data->source_node, @@ -540,6 +679,12 @@ SPA_DIRECTION_INPUT, 0, 0, data->source_buffers, 1)) < 0) return res; + /* Set the control buffers */ + init_buffer(data, data->control_buffers, data->control_buffer, 1, CONTROL_BUFFER_SIZE); + if ((res = spa_node_port_use_buffers(data->sink_node, + SPA_DIRECTION_INPUT, 1, 0, data->control_buffers, 1)) < 0) + return res; + return 0; }
View file
pipewire-0.3.52.tar.gz/spa/include/spa/buffer/buffer.h -> pipewire-0.3.53.tar.gz/spa/include/spa/buffer/buffer.h
Changed
@@ -63,6 +63,9 @@ int32_t stride; /**< stride of valid data */ #define SPA_CHUNK_FLAG_NONE 0 #define SPA_CHUNK_FLAG_CORRUPTED (1u<<0) /**< chunk data is corrupted in some way */ +#define SPA_CHUNK_FLAG_EMPTY (1u<<1) /**< chunk data is empty with media specific + * neutral data such as silence or black. This + * could be used to optimize processing. */ int32_t flags; /**< chunk flags */ };
View file
pipewire-0.3.52.tar.gz/spa/include/spa/param/audio/layout.h -> pipewire-0.3.53.tar.gz/spa/include/spa/param/audio/layout.h
Changed
@@ -29,7 +29,7 @@ extern "C" { #endif -#ifndef __FreeBSD__ +#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) #include <endian.h> #endif
View file
pipewire-0.3.52.tar.gz/spa/include/spa/param/audio/raw.h -> pipewire-0.3.53.tar.gz/spa/include/spa/param/audio/raw.h
Changed
@@ -31,7 +31,7 @@ #include <stdint.h> -#ifndef __FreeBSD__ +#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) #include <endian.h> #endif
View file
pipewire-0.3.52.tar.gz/spa/plugins/alsa/90-pipewire-alsa.rules -> pipewire-0.3.53.tar.gz/spa/plugins/alsa/90-pipewire-alsa.rules
Changed
@@ -177,6 +177,10 @@ # Sennheiser GSP 670 USB headset ATTRS{idVendor}=="1395", ATTRS{idProduct}=="008a", ENV{ACP_PROFILE_SET}="usb-gaming-headset.conf" +# Audioengine HD3 powered speakers support IEC958 but don't actually +# have any digital outputs. +ATTRS{idVendor}=="0a12", ATTRS{idProduct}=="4007", ENV{ACP_PROFILE_SET}="analog-only.conf" + GOTO="pipewire_end" LABEL="pipewire_check_pci"
View file
pipewire-0.3.52.tar.gz/spa/plugins/alsa/acp/alsa-util.c -> pipewire-0.3.53.tar.gz/spa/plugins/alsa/acp/alsa-util.c
Changed
@@ -1626,7 +1626,12 @@ { int err; const char *name = snd_hctl_elem_get_name(helem); - if (mask & SND_CTL_EVENT_MASK_ADD) { + // NOTE: The remove event defined as '~0U`. + if (mask == SND_CTL_EVENT_MASK_REMOVE) { + // NOTE: unless remove pointer to melem from link-list at private_data of helem, hits + // assersion in alsa-lib since the list is not empty. + snd_mixer_elem_detach(melem, helem); + } else if (mask & SND_CTL_EVENT_MASK_ADD) { snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem); if (iface == SND_CTL_ELEM_IFACE_CARD || iface == SND_CTL_ELEM_IFACE_PCM) { snd_mixer_elem_t *new_melem;
View file
pipewire-0.3.52.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.53.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
@@ -616,7 +616,7 @@ const struct spa_pod *format) { struct state *this = object; - int err; + int err = 0; if (format == NULL) { if (!this->have_format) @@ -673,7 +673,7 @@ } emit_port_info(this, false); - return 0; + return err; } static int
View file
pipewire-0.3.52.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.53.tar.gz/spa/plugins/alsa/alsa-pcm-source.c
Changed
@@ -566,7 +566,7 @@ uint32_t flags, const struct spa_pod *format) { struct state *this = object; - int err; + int err = 0; if (format == NULL) { if (!this->have_format) @@ -610,7 +610,7 @@ } emit_port_info(this, false); - return 0; + return err; } static int
View file
pipewire-0.3.52.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.53.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -1409,7 +1409,10 @@ state->props.device, rchannels, val); if (!SPA_FLAG_IS_SET(flags, SPA_NODE_PARAM_FLAG_NEAREST)) return -EINVAL; + if (fmt->media_subtype != SPA_MEDIA_SUBTYPE_raw) + return -EINVAL; rchannels = val; + fmt->info.raw.channels = rchannels; match = false; } @@ -1429,7 +1432,10 @@ state->props.device, rrate, val); if (!SPA_FLAG_IS_SET(flags, SPA_NODE_PARAM_FLAG_NEAREST)) return -EINVAL; + if (fmt->media_subtype != SPA_MEDIA_SUBTYPE_raw) + return -EINVAL; rrate = val; + fmt->info.raw.rate = rrate; match = false; } @@ -1895,6 +1901,7 @@ snd_pcm_uframes_t written, frames, offset, off, to_write, total_written, max_write; snd_pcm_sframes_t commitres; int res = 0; + size_t frame_size = state->frame_size; check_position_config(state); @@ -1951,56 +1958,37 @@ written = 0; while (!spa_list_is_empty(&state->ready) && to_write > 0) { - uint8_t *dst, *src; size_t n_bytes, n_frames; struct buffer *b; struct spa_data *d; - uint32_t i, index, offs, avail, size, maxsize, l0, l1; + uint32_t i, offs, size; b = spa_list_first(&state->ready, struct buffer, link); d = b->buf->datas; - size = d0.chunk->size; - maxsize = d0.maxsize; - - index = d0.chunk->offset + state->ready_offset; - avail = size - state->ready_offset; - avail /= state->frame_size; + offs = d0.chunk->offset + state->ready_offset; + size = d0.chunk->size - state->ready_offset; - n_frames = SPA_MIN(avail, to_write); - n_bytes = n_frames * state->frame_size; + offs = SPA_MIN(offs, d0.maxsize); + size = SPA_MIN(d0.maxsize - offs, size); - offs = index % maxsize; - l0 = SPA_MIN(n_bytes, maxsize - offs); - l1 = n_bytes - l0; + n_frames = SPA_MIN(size / frame_size, to_write); + n_bytes = n_frames * frame_size; if (SPA_LIKELY(state->use_mmap)) { for (i = 0; i < b->buf->n_datas; i++) { - dst = SPA_PTROFF(my_areasi.addr, off * state->frame_size, uint8_t); - src = di.data; - - spa_memcpy(dst, src + offs, l0); - if (SPA_UNLIKELY(l1 > 0)) - spa_memcpy(dst + l0, src, l1); + spa_memcpy(SPA_PTROFF(my_areasi.addr, off * frame_size, void), + SPA_PTROFF(di.data, offs, void), n_bytes); } } else { - if (state->planar) { - void *bufsb->buf->n_datas; - - for (i = 0; i < b->buf->n_datas; i++) - bufsi = SPA_PTROFF(di.data, offs, void); - snd_pcm_writen(hndl, bufs, l0 / state->frame_size); - if (SPA_UNLIKELY(l1 > 0)) { - for (i = 0; i < b->buf->n_datas; i++) - bufsi = di.data; - snd_pcm_writen(hndl, bufs, l1 / state->frame_size); - } - } else { - src = d0.data; - snd_pcm_writei(hndl, src + offs, l0 / state->frame_size); - if (SPA_UNLIKELY(l1 > 0)) - snd_pcm_writei(hndl, src, l1 / state->frame_size); - } + void *bufsb->buf->n_datas; + for (i = 0; i < b->buf->n_datas; i++) + bufsi = SPA_PTROFF(di.data, offs, void); + + if (state->planar) + snd_pcm_writen(hndl, bufs, n_frames); + else + snd_pcm_writei(hndl, bufs0, n_frames); } state->ready_offset += n_bytes; @@ -2071,8 +2059,7 @@ spa_log_warn(state->log, "%s: no more buffers", state->props.device); total_frames = frames; } else { - uint8_t *src; - size_t n_bytes, left; + size_t n_bytes, left, frame_size = state->frame_size; struct buffer *b; struct spa_data *d; uint32_t i, avail, l0, l1; @@ -2088,23 +2075,26 @@ d = b->buf->datas; - avail = d0.maxsize / state->frame_size; + avail = d0.maxsize / frame_size; total_frames = SPA_MIN(avail, frames); - n_bytes = total_frames * state->frame_size; + n_bytes = total_frames * frame_size; if (my_areas) { left = state->buffer_frames - offset; - l0 = SPA_MIN(n_bytes, left * state->frame_size); + l0 = SPA_MIN(n_bytes, left * frame_size); l1 = n_bytes - l0; for (i = 0; i < b->buf->n_datas; i++) { - src = SPA_PTROFF(my_areasi.addr, offset * state->frame_size, uint8_t); - spa_memcpy(di.data, src, l0); - if (l1 > 0) - spa_memcpy(SPA_PTROFF(di.data, l0, void), my_areasi.addr, l1); + spa_memcpy(di.data, + SPA_PTROFF(my_areasi.addr, offset * frame_size, void), + l0); + if (SPA_UNLIKELY(l1 > 0)) + spa_memcpy(SPA_PTROFF(di.data, l0, void), + my_areasi.addr, + l1); di.chunk->offset = 0; di.chunk->size = n_bytes; - di.chunk->stride = state->frame_size; + di.chunk->stride = frame_size; } } else { void *bufsb->buf->n_datas; @@ -2112,7 +2102,7 @@ bufsi = di.data; di.chunk->offset = 0; di.chunk->size = n_bytes; - di.chunk->stride = state->frame_size; + di.chunk->stride = frame_size; } if (state->planar) { snd_pcm_readn(state->hndl, bufs, total_frames);
View file
pipewire-0.3.52.tar.gz/spa/plugins/alsa/alsa-seq.c -> pipewire-0.3.53.tar.gz/spa/plugins/alsa/alsa-seq.c
Changed
@@ -131,13 +131,19 @@ static int init_stream(struct seq_state *state, enum spa_direction direction) { struct seq_stream *stream = &state->streamsdirection; + int res; stream->direction = direction; if (direction == SPA_DIRECTION_INPUT) { stream->caps = SND_SEQ_PORT_CAP_SUBS_WRITE; } else { stream->caps = SND_SEQ_PORT_CAP_SUBS_READ; } - snd_midi_event_new(MAX_EVENT_SIZE, &stream->codec); + if ((res = snd_midi_event_new(MAX_EVENT_SIZE, &stream->codec)) < 0) { + spa_log_error(state->log, "can make event decoder: %s", + snd_strerror(res)); + return res; + } + snd_midi_event_no_status(stream->codec, 1); memset(stream->ports, 0, sizeof(stream->ports)); return 0; } @@ -145,7 +151,9 @@ static int uninit_stream(struct seq_state *state, enum spa_direction direction) { struct seq_stream *stream = &state->streamsdirection; - snd_midi_event_free(stream->codec); + if (stream->codec) + snd_midi_event_free(stream->codec); + stream->codec = NULL; return 0; } @@ -543,12 +551,6 @@ continue; } - /* fixup NoteOn with vel 0 */ - if ((data0 & 0xF0) == 0x90 && data2 == 0x00) { - data0 = 0x80 + (data0 & 0x0F); - data2 = 0x40; - } - /* queue_time is the estimated current time of the queue as calculated by * the DLL. Calculate the age of the event. */ ev_time = SPA_TIMESPEC_TO_NSEC(&ev->time.time);
View file
pipewire-0.3.52.tar.gz/spa/plugins/alsa/alsa-udev.c -> pipewire-0.3.53.tar.gz/spa/plugins/alsa/alsa-udev.c
Changed
@@ -477,15 +477,9 @@ if ((str = udev_device_get_property_value(dev, "SUBSYSTEM")) && *str) { itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SUBSYSTEM, str); } - if ((str = udev_device_get_property_value(dev, "ID_VENDOR_ID")) && *str) { - char *dec = alloca(6); /* 65535 is max */ - int32_t val; + if ((str = udev_device_get_property_value(dev, "ID_VENDOR_ID")) && *str) + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, str); - if (spa_atoi32(str, &val, 16)) { - snprintf(dec, 6, "%d", val); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, dec); - } - } str = udev_device_get_property_value(dev, "ID_VENDOR_FROM_DATABASE"); if (!(str && *str)) { str = udev_device_get_property_value(dev, "ID_VENDOR_ENC"); @@ -500,15 +494,9 @@ if (str && *str) { itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_NAME, str); } - if ((str = udev_device_get_property_value(dev, "ID_MODEL_ID")) && *str) { - char *dec = alloca(6); /* 65535 is max */ - int32_t val; + if ((str = udev_device_get_property_value(dev, "ID_MODEL_ID")) && *str) + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, str); - if (spa_atoi32(str, &val, 16)) { - snprintf(dec, 6, "%d", val); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, dec); - } - } str = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE"); if (!(str && *str)) { str = udev_device_get_property_value(dev, "ID_MODEL_ENC");
View file
pipewire-0.3.53.tar.gz/spa/plugins/alsa/mixer/profile-sets/analog-only.conf
Added
@@ -0,0 +1,102 @@ +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. + +; Some USB DACs appear to support IEC958, but don't physically have any +; digital outputs. + +General +auto-profiles = yes + +Mapping analog-stereo +device-strings = front:%f +channel-map = left,right +paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 +paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic +priority = 15 + +# If everything else fails, try to use hw:0 as a stereo device... +Mapping stereo-fallback +device-strings = hw:%f +fallback = yes +channel-map = front-left,front-right +paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 +paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic +priority = 1 + +# ...and if even that fails, try to use hw:0 as a mono device. +Mapping mono-fallback +device-strings = hw:%f +fallback = yes +channel-map = mono +paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono +paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headset-mic +priority = 1 + +Mapping analog-surround-21 +device-strings = surround21:%f +channel-map = front-left,front-right,lfe +paths-input = analog-input analog-input-linein analog-input-mic +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 13 + +Mapping analog-surround-40 +device-strings = surround40:%f +channel-map = front-left,front-right,rear-left,rear-right +paths-input = analog-input analog-input-linein analog-input-mic +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 12 + +Mapping analog-surround-41 +device-strings = surround41:%f +channel-map = front-left,front-right,rear-left,rear-right,lfe +paths-input = analog-input analog-input-linein analog-input-mic +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 13 + +Mapping analog-surround-50 +device-strings = surround50:%f +channel-map = front-left,front-right,rear-left,rear-right,front-center +paths-input = analog-input analog-input-linein analog-input-mic +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 12 + +Mapping analog-surround-51 +device-strings = surround51:%f +channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe +paths-input = analog-input analog-input-linein analog-input-mic +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 13 + +Mapping analog-surround-71 +device-strings = surround71:%f +channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right +description = Analog Surround 7.1 +paths-input = analog-input analog-input-linein analog-input-mic +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 12 + +Mapping multichannel-output +device-strings = hw:%f +channel-map = left,right,rear-left,rear-right +exact-channels = false +fallback = yes +priority = 1 +direction = output + +Mapping multichannel-input +device-strings = hw:%f +channel-map = left,right,rear-left,rear-right +exact-channels = false +fallback = yes +priority = 1 +direction = input
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/audioadapter.c
Changed
@@ -49,7 +49,7 @@ #define DEFAULT_ALIGN 16 -#define MAX_PORTS SPA_AUDIO_MAX_CHANNELS +#define MAX_PORTS (SPA_AUDIO_MAX_CHANNELS+1) /** \cond */ @@ -442,6 +442,29 @@ if (format && spa_log_level_enabled(this->log, SPA_LOG_LEVEL_DEBUG)) spa_debug_format(0, NULL, format); + if ((res = spa_node_port_set_param(this->follower, + this->direction, 0, + SPA_PARAM_Format, flags, + format)) < 0) + return res; + if (res > 0) { + uint8_t buffer4096; + struct spa_pod_builder b = { 0 }; + uint32_t state = 0; + struct spa_pod *fmt; + + /* format was changed to nearest compatible format */ + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + + if ((res = spa_node_port_enum_params_sync(this->follower, + this->direction, 0, + SPA_PARAM_Format, &state, + NULL, &fmt, &b)) != 1) + return -EIO; + + format = fmt; + } + if (this->target != this->follower && this->convert) { if ((res = spa_node_port_set_param(this->convert, SPA_DIRECTION_REVERSE(this->direction), 0, @@ -450,12 +473,6 @@ return res; } - if ((res = spa_node_port_set_param(this->follower, - this->direction, 0, - SPA_PARAM_Format, flags, - format)) < 0) - return res; - this->have_format = format != NULL; if (format == NULL) { this->n_buffers = 0; @@ -494,7 +511,7 @@ int res = 0; struct spa_hook l; - spa_log_debug(this->log, "%p: passthrough mode %d", this, passthrough); + spa_log_info(this->log, "%p: passthrough mode %d", this, passthrough); if (this->passthrough != passthrough) { if (passthrough) { @@ -513,7 +530,7 @@ /* set new target */ this->target = passthrough ? this->follower : this->convert; - if ((res = configure_format(this, 0, format)) < 0) + if ((res = configure_format(this, SPA_NODE_PARAM_FLAG_NEAREST, format)) < 0) return res; if (this->passthrough != passthrough) { @@ -595,7 +612,6 @@ enum spa_direction dir; enum spa_param_port_config_mode mode; struct spa_pod *format = NULL; - int monitor = false; if (this->started) { spa_log_error(this->log, "was started"); @@ -606,7 +622,6 @@ SPA_TYPE_OBJECT_ParamPortConfig, NULL, SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(&dir), SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(&mode), - SPA_PARAM_PORT_CONFIG_monitor, SPA_POD_OPT_Bool(&monitor), SPA_PARAM_PORT_CONFIG_format, SPA_POD_OPT_Pod(&format)) < 0) return -EINVAL; @@ -777,7 +792,7 @@ spa_pod_fixate(format); - res = configure_format(this, 0, format); + res = configure_format(this, SPA_NODE_PARAM_FLAG_NEAREST, format); done: spa_node_send_command(this->follower, @@ -852,6 +867,12 @@ uint32_t idx; switch (info->paramsi.id) { + case SPA_PARAM_EnumPortConfig: + idx = IDX_EnumPortConfig; + break; + case SPA_PARAM_PortConfig: + idx = IDX_PortConfig; + break; case SPA_PARAM_PropInfo: idx = IDX_PropInfo; break;
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/audioconvert.c
Changed
@@ -1,6 +1,6 @@ /* Spa * - * Copyright © 2018 Wim Taymans + * Copyright © 2022 Wim Taymans * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -25,52 +25,153 @@ #include <errno.h> #include <string.h> #include <stdio.h> +#include <limits.h> #include <spa/support/plugin.h> -#include <spa/support/log.h> #include <spa/support/cpu.h> +#include <spa/support/log.h> #include <spa/utils/result.h> #include <spa/utils/list.h> #include <spa/utils/names.h> #include <spa/utils/string.h> #include <spa/node/node.h> -#include <spa/buffer/alloc.h> #include <spa/node/io.h> #include <spa/node/utils.h> +#include <spa/node/keys.h> #include <spa/param/audio/format-utils.h> #include <spa/param/param.h> +#include <spa/param/latency-utils.h> #include <spa/pod/filter.h> -#include <spa/debug/pod.h> #include <spa/debug/types.h> +#include <spa/debug/pod.h> + +#include "volume-ops.h" +#include "fmt-ops.h" +#include "channelmix-ops.h" +#include "resample.h" #undef SPA_LOG_TOPIC_DEFAULT #define SPA_LOG_TOPIC_DEFAULT log_topic static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.audioconvert"); -#define DEFAULT_ALIGN 16 +#define DEFAULT_RATE 48000 +#define DEFAULT_CHANNELS 2 + +#define MAX_ALIGN FMT_OPS_MAX_ALIGN +#define MAX_BUFFERS 32 +#define MAX_DATAS SPA_AUDIO_MAX_CHANNELS +#define MAX_PORTS (SPA_AUDIO_MAX_CHANNELS+1) + +#define DEFAULT_MUTE false +#define DEFAULT_VOLUME VOLUME_NORM + +struct volumes { + bool mute; + uint32_t n_volumes; + float volumesSPA_AUDIO_MAX_CHANNELS; +}; + +static void init_volumes(struct volumes *vol) +{ + uint32_t i; + vol->mute = DEFAULT_MUTE; + vol->n_volumes = 0; + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) + vol->volumesi = DEFAULT_VOLUME; +} + +struct props { + float volume; + uint32_t n_channels; + uint32_t channel_mapSPA_AUDIO_MAX_CHANNELS; + struct volumes channel; + struct volumes soft; + struct volumes monitor; + unsigned int have_soft_volume:1; + unsigned int mix_disabled:1; + unsigned int resample_quality; + unsigned int resample_disabled:1; + double rate; +}; -#define MAX_PORTS SPA_AUDIO_MAX_CHANNELS +static void props_reset(struct props *props) +{ + uint32_t i; + props->volume = DEFAULT_VOLUME; + props->n_channels = 0; + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) + props->channel_mapi = SPA_AUDIO_CHANNEL_UNKNOWN; + init_volumes(&props->channel); + init_volumes(&props->soft); + init_volumes(&props->monitor); + props->mix_disabled = false; + props->rate = 1.0; + props->resample_quality = RESAMPLE_DEFAULT_QUALITY; + props->resample_disabled = false; +} struct buffer { - struct spa_list link; -#define BUFFER_FLAG_OUT (1 << 0) + uint32_t id; +#define BUFFER_FLAG_QUEUED (1<<0) uint32_t flags; - struct spa_buffer *outbuf; - struct spa_meta_header *h; + struct spa_list link; + struct spa_buffer *buf; + void *datasMAX_DATAS; }; -struct link { - struct spa_node *out_node; - uint32_t out_port; - uint32_t out_flags; - struct spa_node *in_node; - uint32_t in_port; - uint32_t in_flags; - struct spa_io_buffers io; - uint32_t min_buffers; +struct port { + uint32_t direction; + uint32_t id; + + struct spa_io_buffers *io; + + uint64_t info_all; + struct spa_port_info info; +#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; + char position16; + + struct buffer buffersMAX_BUFFERS; uint32_t n_buffers; - struct spa_buffer **buffers; - unsigned int negotiated:1; + + struct spa_audio_info format; + unsigned int have_format:1; + unsigned int is_dsp:1; + unsigned int is_monitor:1; + unsigned int is_control:1; + + uint32_t blocks; + uint32_t stride; + + const struct spa_pod_sequence *ctrl; + uint32_t ctrl_offset; + + struct spa_list queue; +}; + +struct dir { + struct port *portsMAX_PORTS; + uint32_t n_ports; + + enum spa_param_port_config_mode mode; + + struct spa_audio_info format; + unsigned int have_format:1; + unsigned int have_profile:1; + struct spa_latency_info latency; + + uint32_t src_remapMAX_PORTS; + uint32_t dst_remapMAX_PORTS; + + struct convert conv; + unsigned int is_passthrough:1; + unsigned int control:1; }; struct impl { @@ -80,9 +181,15 @@ struct spa_log *log; struct spa_cpu *cpu; + uint32_t cpu_flags; uint32_t max_align; + uint32_t quantum_limit; + enum spa_direction direction; - struct spa_hook_list hooks; + struct props props; + + struct spa_io_position *io_position; + struct spa_io_rate_match *io_rate_match; uint64_t info_all; struct spa_node_info info; @@ -90,52 +197,50 @@ #define IDX_PortConfig 1 #define IDX_PropInfo 2 #define IDX_Props 3 - struct spa_param_info params4; - uint32_t param_flags4; - - int n_links; - struct link links8; - int n_nodes; - struct spa_node *nodes8; +#define N_NODE_PARAMS 4 + struct spa_param_info paramsN_NODE_PARAMS; - enum spa_param_port_config_mode mode2; - bool fmt_removing2; + struct spa_hook_list hooks; - struct spa_handle *hnd_merger; - struct spa_handle *hnd_convert_in; - struct spa_handle *hnd_channelmix; - struct spa_handle *hnd_resample; - struct spa_handle *hnd_convert_out; - struct spa_handle *hnd_splitter; + unsigned int monitor:1; + unsigned int monitor_channel_volumes:1; - struct spa_node *merger; - struct spa_node *convert_in; - struct spa_node *channelmix; - struct spa_node *resample; - struct spa_node *convert_out; - struct spa_node *splitter; + struct dir dir2; + struct channelmix mix; + struct resample resample; + struct volume volume; + double rate_scale; - struct spa_node *fmt2; - struct spa_hook fmt_listener2; - bool have_fmt_listener2; + uint32_t in_offset; + uint32_t out_offset; + unsigned int started:1; + unsigned int peaks:1; + unsigned int is_passthrough:1; + unsigned int drained:1; - struct spa_hook listener2; + uint32_t empty_size; + float *empty; + float *scratch; + float *tmp; + float *tmp2; - unsigned int started:1; - unsigned int add_listener:1; + float *tmp_datas2MAX_PORTS; }; -#define IS_MONITOR_PORT(this,dir,port_id) (dir == SPA_DIRECTION_OUTPUT && port_id > 0 && \ - this->modeSPA_DIRECTION_INPUT == SPA_PARAM_PORT_CONFIG_MODE_dsp && \ - this->modeSPA_DIRECTION_OUTPUT != SPA_PARAM_PORT_CONFIG_MODE_dsp) +#define CHECK_PORT(this,d,p) ((p) < this->dird.n_ports) +#define GET_PORT(this,d,p) (this->dird.portsp) +#define GET_IN_PORT(this,p) GET_PORT(this,SPA_DIRECTION_INPUT,p) +#define GET_OUT_PORT(this,p) GET_PORT(this,SPA_DIRECTION_OUTPUT,p) + +#define PORT_IS_DSP(this,d,p) (GET_PORT(this,d,p)->is_dsp) +#define PORT_IS_CONTROL(this,d,p) (GET_PORT(this,d,p)->is_control) + +static void set_volume(struct impl *this); static void emit_node_info(struct impl *this, bool full) { - uint32_t i; uint64_t old = full ? this->info.change_mask : 0; - - if (this->add_listener) - return; + uint32_t i; if (full) this->info.change_mask = this->info_all; @@ -153,344 +258,103 @@ } } -static int make_link(struct impl *this, - struct spa_node *out_node, uint32_t out_port, - struct spa_node *in_node, uint32_t in_port, uint32_t min_buffers) -{ - struct link *l = &this->linksthis->n_links++; - - l->out_node = out_node; - l->out_port = out_port; - l->out_flags = 0; - l->in_node = in_node; - l->in_port = in_port; - l->in_flags = 0; - l->negotiated = false; - l->io = SPA_IO_BUFFERS_INIT; - l->n_buffers = 0; - l->min_buffers = min_buffers; - - spa_node_port_set_io(out_node, - SPA_DIRECTION_OUTPUT, out_port, - SPA_IO_Buffers, - &l->io, sizeof(l->io)); - spa_node_port_set_io(in_node, - SPA_DIRECTION_INPUT, in_port, - SPA_IO_Buffers, - &l->io, sizeof(l->io)); - return 0; -} - -static void clean_link(struct impl *this, struct link *link) -{ - spa_node_port_set_param(link->in_node, - SPA_DIRECTION_INPUT, link->in_port, - SPA_PARAM_Format, 0, NULL); - spa_node_port_set_param(link->out_node, - SPA_DIRECTION_OUTPUT, link->out_port, - SPA_PARAM_Format, 0, NULL); - if (link->buffers) - free(link->buffers); - link->buffers = NULL; -} - -static int debug_params(struct impl *this, struct spa_node *node, - enum spa_direction direction, uint32_t port_id, uint32_t id, struct spa_pod *filter) -{ - struct spa_pod_builder b = { 0 }; - uint8_t buffer4096; - uint32_t state; - struct spa_pod *param; - int res; - - spa_log_error(this->log, "params:"); - - state = 0; - while (true) { - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - res = spa_node_port_enum_params_sync(node, - direction, port_id, - id, &state, - NULL, ¶m, &b); - if (res != 1) - break; - - spa_debug_pod(2, NULL, param); - } - - spa_log_error(this->log, "failed filter:"); - if (filter) - spa_debug_pod(2, NULL, filter); - - return 0; -} - -static int negotiate_link_format(struct impl *this, struct link *link) -{ - struct spa_pod_builder b = { 0 }; - uint8_t buffer4096; - uint32_t state; - struct spa_pod *format, *filter; - int res; - - if (link->negotiated) - return 0; - - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - - state = 0; - filter = NULL; - if ((res = spa_node_port_enum_params_sync(link->out_node, - SPA_DIRECTION_OUTPUT, link->out_port, - SPA_PARAM_EnumFormat, &state, - filter, &format, &b)) != 1) { - debug_params(this, link->out_node, SPA_DIRECTION_OUTPUT, link->out_port, - SPA_PARAM_EnumFormat, filter); - return -ENOTSUP; - } - filter = format; - state = 0; - if ((res = spa_node_port_enum_params_sync(link->in_node, - SPA_DIRECTION_INPUT, link->in_port, - SPA_PARAM_EnumFormat, &state, - filter, &format, &b)) != 1) { - debug_params(this, link->in_node, SPA_DIRECTION_INPUT, link->in_port, - SPA_PARAM_EnumFormat, filter); - return -ENOTSUP; - } - filter = format; - - spa_pod_fixate(filter); - - if ((res = spa_node_port_set_param(link->out_node, - SPA_DIRECTION_OUTPUT, link->out_port, - SPA_PARAM_Format, 0, - filter)) < 0) - return res; - - if ((res = spa_node_port_set_param(link->in_node, - SPA_DIRECTION_INPUT, link->in_port, - SPA_PARAM_Format, 0, - filter)) < 0) - return res; - - link->negotiated = true; - - return 0; -} - -static int setup_convert(struct impl *this) +static void emit_port_info(struct impl *this, struct port *port, bool full) { - int i, j, res; - - spa_log_debug(this->log, "setup convert n_links:%d", this->n_links); + uint64_t old = full ? port->info.change_mask : 0; + uint32_t i; - if (this->n_links > 0) - return 0; + if (full) + port->info.change_mask = port->info_all; + if (port->info.change_mask) { + struct spa_dict_item items3; + uint32_t n_items = 0; + + if (PORT_IS_DSP(this, port->direction, port->id)) { + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "32 bit float mono audio"); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_AUDIO_CHANNEL, port->position); + if (port->is_monitor) + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_MONITOR, "true"); + } else if (PORT_IS_CONTROL(this, port->direction, port->id)) { + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, "control"); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi"); + } + port->info.props = &SPA_DICT_INIT(items, n_items); - this->n_nodes = 0; - /* unpack */ - this->nodesthis->n_nodes++ = this->fmtSPA_DIRECTION_INPUT; - /* down mix */ - this->nodesthis->n_nodes++ = this->channelmix; - /* resample */ - this->nodesthis->n_nodes++ = this->resample; - /* pack */ - this->nodesthis->n_nodes++ = this->fmtSPA_DIRECTION_OUTPUT; - - make_link(this, this->nodes0, 0, this->nodes1, 0, 2); - make_link(this, this->nodes1, 0, this->nodes2, 0, 2); - make_link(this, this->nodes2, 0, this->nodes3, 0, 1); - - for (i = 0, j = this->n_links - 1; j >= i; i++, j--) { - spa_log_debug(this->log, "negotiate %d", i); - if ((res = negotiate_link_format(this, &this->linksi)) < 0) - return res; - spa_log_debug(this->log, "negotiate %d", j); - if ((res = negotiate_link_format(this, &this->linksj)) < 0) - return res; + if (port->info.change_mask & SPA_PORT_CHANGE_MASK_PARAMS) { + for (i = 0; i < SPA_N_ELEMENTS(port->params); i++) { + if (port->paramsi.user > 0) { + port->paramsi.flags ^= SPA_PARAM_INFO_SERIAL; + port->paramsi.user = 0; + } + } + } + spa_node_emit_port_info(&this->hooks, port->direction, port->id, &port->info); + port->info.change_mask = old; } - return 0; } -static int negotiate_link_buffers(struct impl *this, struct link *link) +static int init_port(struct impl *this, enum spa_direction direction, uint32_t port_id, + uint32_t position, bool is_dsp, bool is_monitor, bool is_control) { - uint8_t buffer4096; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - uint32_t state; - struct spa_pod *param = NULL, *filter; - int res; - bool in_alloc, out_alloc; - uint32_t i, size, buffers, blocks, align, flags; - uint32_t *aligns; - struct spa_data *datas; + struct port *port = GET_PORT(this, direction, port_id); + const char *name; - if (link->n_buffers > 0) - return 0; + spa_assert(port_id < MAX_PORTS); - state = 0; - filter = NULL; - if ((res = spa_node_port_enum_params_sync(link->in_node, - SPA_DIRECTION_INPUT, link->in_port, - SPA_PARAM_Buffers, &state, - filter, ¶m, &b)) != 1) { - debug_params(this, link->in_node, SPA_DIRECTION_INPUT, link->in_port, - SPA_PARAM_Buffers, filter); - return -ENOTSUP; - } - state = 0; - filter = param; - if ((res = spa_node_port_enum_params_sync(link->out_node, - SPA_DIRECTION_OUTPUT, link->out_port, - SPA_PARAM_Buffers, &state, - filter, ¶m, &b)) != 1) { - debug_params(this, link->out_node, SPA_DIRECTION_OUTPUT, link->out_port, - SPA_PARAM_Buffers, filter); - return -ENOTSUP; + if (port == NULL) { + port = calloc(1, sizeof(struct port)); + if (port == NULL) + return -errno; + this->dirdirection.portsport_id = port; } - - spa_pod_fixate(param); - - in_alloc = SPA_FLAG_IS_SET(link->in_flags, - SPA_PORT_FLAG_CAN_ALLOC_BUFFERS); - out_alloc = SPA_FLAG_IS_SET(link->out_flags, - SPA_PORT_FLAG_CAN_ALLOC_BUFFERS); - - flags = 0; - if (out_alloc || in_alloc) { - flags |= SPA_BUFFER_ALLOC_FLAG_NO_DATA; - if (out_alloc) - in_alloc = false; + port->direction = direction; + port->id = port_id; + + name = spa_debug_type_find_short_name(spa_type_audio_channel, position); + snprintf(port->position, sizeof(port->position), "%s", name ? name : "UNK"); + + 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.flags = SPA_PORT_FLAG_NO_REF | + SPA_PORT_FLAG_DYNAMIC_DATA; + 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->n_buffers = 0; + port->have_format = false; + port->is_monitor = is_monitor; + port->is_dsp = is_dsp; + if (port->is_dsp) { + port->format.media_type = SPA_MEDIA_TYPE_audio; + port->format.media_subtype = SPA_MEDIA_SUBTYPE_dsp; + port->format.info.dsp.format = SPA_AUDIO_FORMAT_DSP_F32; + port->blocks = 1; + port->stride = 4; } - - align = DEFAULT_ALIGN; - - if (spa_pod_parse_object(param, - SPA_TYPE_OBJECT_ParamBuffers, NULL, - SPA_PARAM_BUFFERS_buffers, SPA_POD_Int(&buffers), - SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(&blocks), - SPA_PARAM_BUFFERS_size, SPA_POD_Int(&size), - SPA_PARAM_BUFFERS_align, SPA_POD_OPT_Int(&align)) < 0) - return -EINVAL; - - spa_log_debug(this->log, "%p: buffers %d, blocks %d, size %d, align %d %d:%d", - this, buffers, blocks, size, align, out_alloc, in_alloc); - - align = SPA_MAX(align, this->max_align); - - datas = alloca(sizeof(struct spa_data) * blocks); - memset(datas, 0, sizeof(struct spa_data) * blocks); - aligns = alloca(sizeof(uint32_t) * blocks); - for (i = 0; i < blocks; i++) { - datasi.type = SPA_DATA_MemPtr; - datasi.flags = SPA_DATA_FLAG_DYNAMIC; - datasi.maxsize = size; - alignsi = align; + port->is_control = is_control; + if (port->is_control) { + port->format.media_type = SPA_MEDIA_TYPE_application; + port->format.media_subtype = SPA_MEDIA_SUBTYPE_control; + port->blocks = 1; + port->stride = 1; } + spa_list_init(&port->queue); - buffers = SPA_MAX(link->min_buffers, buffers); - - if (link->buffers) - free(link->buffers); - link->buffers = spa_buffer_alloc_array(buffers, flags, 0, NULL, blocks, datas, aligns); - if (link->buffers == NULL) - return -errno; - - link->n_buffers = buffers; - - if ((res = spa_node_port_use_buffers(link->out_node, - SPA_DIRECTION_OUTPUT, link->out_port, - out_alloc ? SPA_NODE_BUFFERS_FLAG_ALLOC : 0, - link->buffers, link->n_buffers)) < 0) - return res; - - if ((res = spa_node_port_use_buffers(link->in_node, - SPA_DIRECTION_INPUT, link->in_port, - in_alloc ? SPA_NODE_BUFFERS_FLAG_ALLOC : 0, - link->buffers, link->n_buffers)) < 0) - return res; - - return 0; -} - -static void flush_convert(struct impl *this) -{ - int i; - spa_log_debug(this->log, "%p: %d", this, this->n_links); - for (i = 0; i < this->n_links; i++) - this->linksi.io.status = SPA_STATUS_OK; -} - -static void clean_convert(struct impl *this) -{ - int i; - - spa_log_debug(this->log, "%p: %d", this, this->n_links); - - for (i = 0; i < this->n_links; i++) - clean_link(this, &this->linksi); - this->n_links = 0; -} - -static int setup_buffers(struct impl *this, enum spa_direction direction) -{ - int i, res; - - spa_log_debug(this->log, "%p: %d %d", this, direction, this->n_links); - - if (direction == SPA_DIRECTION_INPUT) { - for (i = 0; i < this->n_links; i++) { - if ((res = negotiate_link_buffers(this, &this->linksi)) < 0) - spa_log_error(this->log, "%p: buffers %d failed %s", - this, i, spa_strerror(res)); - } - } else { - for (i = this->n_links-1; i >= 0 ; i--) { - if ((res = negotiate_link_buffers(this, &this->linksi)) < 0) - spa_log_error(this->log, "%p: buffers %d failed %s", - this, i, spa_strerror(res)); - } - } + spa_log_info(this->log, "%p: add port %d:%d position:%s %d %d %d", + this, direction, port_id, port->position, is_dsp, is_monitor, is_control); + emit_port_info(this, port, true); return 0; } -static int enum_params(struct impl *this, - uint32_t id, - struct spa_result_node_params *result, - const struct spa_pod *filter, - struct spa_pod_builder *builder) -{ - int res; - result->param = NULL; - result->next = result->index; - if (result->next < 0x1000) { - if (this->fmtSPA_DIRECTION_INPUT == this->merger && - (res = spa_node_enum_params_sync(this->merger, - id, &result->next, filter, &result->param, builder)) == 1) { - return res; - } - result->next = 0x1000; - } - if (result->next < 0x2000) { - result->next &= 0xfff; - if ((res = spa_node_enum_params_sync(this->channelmix, - id, &result->next, filter, &result->param, builder)) == 1) { - result->next |= 0x1000; - return res; - } - result->next = 0x2000; - } - if (result->next >= 0x2000) { - result->next &= 0xfff; - if ((res = spa_node_enum_params_sync(this->resample, - id, &result->next, filter, &result->param, builder)) == 1) { - result->next |= 0x2000; - return res; - } - } - return 0; -} static int impl_node_enum_params(void *object, int seq, uint32_t id, uint32_t start, uint32_t num, const struct spa_pod *filter) @@ -501,7 +365,6 @@ uint8_t buffer4096; 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); @@ -509,7 +372,6 @@ result.id = id; result.next = start; next: - res = 0; result.index = result.next++; spa_pod_builder_init(&b, buffer, sizeof(buffer)); @@ -552,13 +414,13 @@ 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(this->modeSPA_DIRECTION_INPUT)); + SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(this->dirSPA_DIRECTION_INPUT.mode)); break; case 1: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_ParamPortConfig, id, SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(SPA_DIRECTION_OUTPUT), - SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(this->modeSPA_DIRECTION_OUTPUT)); + SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(this->dirSPA_DIRECTION_OUTPUT.mode)); break; default: return 0; @@ -566,23 +428,317 @@ break; case SPA_PARAM_PropInfo: - if ((res = enum_params(this, id, &result, filter, &b)) != 1) - return res; + { + struct props *p = &this->props; + struct spa_pod_frame f2; + uint32_t i; + + 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_volume), + SPA_PROP_INFO_name, SPA_POD_String("Volume"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0)); + break; + case 1: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_mute), + SPA_PROP_INFO_name, SPA_POD_String("Mute"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->channel.mute)); + break; + case 2: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_channelVolumes), + SPA_PROP_INFO_name, SPA_POD_String("Channel Volumes"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), + SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); + break; + case 3: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_channelMap), + SPA_PROP_INFO_name, SPA_POD_String("Channel Map"), + SPA_PROP_INFO_type, SPA_POD_Id(SPA_AUDIO_CHANNEL_UNKNOWN), + SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); + break; + case 4: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_monitorMute), + SPA_PROP_INFO_name, SPA_POD_String("Monitor Mute"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->monitor.mute)); + break; + case 5: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_monitorVolumes), + SPA_PROP_INFO_name, SPA_POD_String("Monitor Volumes"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), + SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); + break; + case 6: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_softMute), + SPA_PROP_INFO_name, SPA_POD_String("Soft Mute"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->soft.mute)); + break; + case 7: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_softVolumes), + SPA_PROP_INFO_name, SPA_POD_String("Soft Volumes"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), + SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); + break; + case 8: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("monitor.channel-volumes"), + SPA_PROP_INFO_description, SPA_POD_String("Monitor channel volume"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool( + this->monitor_channel_volumes), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 9: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.disable"), + SPA_PROP_INFO_description, SPA_POD_String("Disable Channel mixing"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->mix_disabled), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 10: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.normalize"), + SPA_PROP_INFO_description, SPA_POD_String("Normalize Volumes"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool( + SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_NORMALIZE)), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 11: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.mix-lfe"), + SPA_PROP_INFO_description, SPA_POD_String("Mix LFE into channels"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool( + SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_MIX_LFE)), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 12: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.upmix"), + SPA_PROP_INFO_description, SPA_POD_String("Enable upmixing"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool( + SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_UPMIX)), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 13: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.lfe-cutoff"), + SPA_PROP_INFO_description, SPA_POD_String("LFE cutoff frequency"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float( + this->mix.lfe_cutoff, 0.0, 1000.0), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 14: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.fc-cutoff"), + SPA_PROP_INFO_description, SPA_POD_String("FC cutoff frequency (Hz)"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float( + this->mix.fc_cutoff, 0.0, 48000.0), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 15: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.rear-delay"), + SPA_PROP_INFO_description, SPA_POD_String("Rear channels delay (ms)"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float( + this->mix.rear_delay, 0.0, 1000.0), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 16: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.stereo-widen"), + SPA_PROP_INFO_description, SPA_POD_String("Stereo widen"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float( + this->mix.widen, 0.0, 1.0), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 17: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.hilbert-taps"), + SPA_PROP_INFO_description, SPA_POD_String("Taps for phase shift of rear"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int( + this->mix.hilbert_taps, 0, MAX_TAPS), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 18: + spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_PropInfo, id); + spa_pod_builder_add(&b, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.upmix-method"), + SPA_PROP_INFO_description, SPA_POD_String("Upmix method to use"), + SPA_PROP_INFO_type, SPA_POD_String( + channelmix_upmix_infothis->mix.upmix.label), + SPA_PROP_INFO_params, SPA_POD_Bool(true), + 0); + + spa_pod_builder_prop(&b, SPA_PROP_INFO_labels, 0); + spa_pod_builder_push_struct(&b, &f1); + for (i = 0; i < SPA_N_ELEMENTS(channelmix_upmix_info); i++) { + spa_pod_builder_string(&b, channelmix_upmix_infoi.label); + spa_pod_builder_string(&b, channelmix_upmix_infoi.description); + } + spa_pod_builder_pop(&b, &f1); + param = spa_pod_builder_pop(&b, &f0); + break; + case 19: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_rate), + SPA_PROP_INFO_description, SPA_POD_String("Rate scaler"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Double(p->rate, 0.0, 10.0)); + break; + case 20: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_quality), + SPA_PROP_INFO_name, SPA_POD_String("resample.quality"), + SPA_PROP_INFO_description, SPA_POD_String("Resample Quality"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->resample_quality, 0, 14), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 21: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("resample.disable"), + SPA_PROP_INFO_description, SPA_POD_String("Disable Resampling"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->resample_disabled), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 22: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("dither.noise"), + SPA_PROP_INFO_description, SPA_POD_String("Add dithering noise"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(this->dir1.conv.noise, 0, 16), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 23: + spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_PropInfo, id); + spa_pod_builder_add(&b, + SPA_PROP_INFO_name, SPA_POD_String("dither.method"), + SPA_PROP_INFO_description, SPA_POD_String("The dithering method"), + SPA_PROP_INFO_type, SPA_POD_String( + dither_method_infothis->dir1.conv.method.label), + SPA_PROP_INFO_params, SPA_POD_Bool(true), + 0); + spa_pod_builder_prop(&b, SPA_PROP_INFO_labels, 0); + spa_pod_builder_push_struct(&b, &f1); + for (i = 0; i < SPA_N_ELEMENTS(channelmix_upmix_info); i++) { + spa_pod_builder_string(&b, dither_method_infoi.label); + spa_pod_builder_string(&b, dither_method_infoi.description); + } + spa_pod_builder_pop(&b, &f1); + param = spa_pod_builder_pop(&b, &f0); + break; + default: + return 0; + } break; + } case SPA_PARAM_Props: - if ((res = enum_params(this, id, &result, filter, &b)) != 1) - return res; - break; + { + struct props *p = &this->props; + struct spa_pod_frame f2; + switch (result.index) { + case 0: + spa_pod_builder_push_object(&b, &f0, + SPA_TYPE_OBJECT_Props, id); + spa_pod_builder_add(&b, + SPA_PROP_volume, SPA_POD_Float(p->volume), + SPA_PROP_mute, SPA_POD_Bool(p->channel.mute), + SPA_PROP_channelVolumes, SPA_POD_Array(sizeof(float), + SPA_TYPE_Float, + p->channel.n_volumes, + p->channel.volumes), + SPA_PROP_channelMap, SPA_POD_Array(sizeof(uint32_t), + SPA_TYPE_Id, + p->n_channels, + p->channel_map), + SPA_PROP_softMute, SPA_POD_Bool(p->soft.mute), + SPA_PROP_softVolumes, SPA_POD_Array(sizeof(float), + SPA_TYPE_Float, + p->soft.n_volumes, + p->soft.volumes), + SPA_PROP_monitorMute, SPA_POD_Bool(p->monitor.mute), + SPA_PROP_monitorVolumes, SPA_POD_Array(sizeof(float), + SPA_TYPE_Float, + p->monitor.n_volumes, + p->monitor.volumes), + 0); + spa_pod_builder_prop(&b, SPA_PROP_params, 0); + spa_pod_builder_push_struct(&b, &f1); + spa_pod_builder_string(&b, "monitor.channel-volumes"); + spa_pod_builder_bool(&b, this->monitor_channel_volumes); + spa_pod_builder_string(&b, "channelmix.disable"); + spa_pod_builder_bool(&b, this->props.mix_disabled); + spa_pod_builder_string(&b, "channelmix.normalize"); + spa_pod_builder_bool(&b, SPA_FLAG_IS_SET(this->mix.options, + CHANNELMIX_OPTION_NORMALIZE)); + spa_pod_builder_string(&b, "channelmix.mix-lfe"); + spa_pod_builder_bool(&b, SPA_FLAG_IS_SET(this->mix.options, + CHANNELMIX_OPTION_MIX_LFE)); + spa_pod_builder_string(&b, "channelmix.upmix"); + spa_pod_builder_bool(&b, SPA_FLAG_IS_SET(this->mix.options, + CHANNELMIX_OPTION_UPMIX)); + spa_pod_builder_string(&b, "channelmix.lfe-cutoff"); + spa_pod_builder_float(&b, this->mix.lfe_cutoff); + spa_pod_builder_string(&b, "channelmix.fc-cutoff"); + spa_pod_builder_float(&b, this->mix.fc_cutoff); + spa_pod_builder_string(&b, "channelmix.rear-delay"); + spa_pod_builder_float(&b, this->mix.rear_delay); + spa_pod_builder_string(&b, "channelmix.stereo-widen"); + spa_pod_builder_float(&b, this->mix.widen); + spa_pod_builder_string(&b, "channelmix.hilbert-taps"); + spa_pod_builder_int(&b, this->mix.hilbert_taps); + spa_pod_builder_string(&b, "channelmix.upmix-method"); + spa_pod_builder_string(&b, channelmix_upmix_infothis->mix.upmix.label); + spa_pod_builder_string(&b, "resample.quality"); + spa_pod_builder_int(&b, p->resample_quality); + spa_pod_builder_string(&b, "resample.disable"); + spa_pod_builder_bool(&b, p->resample_disabled); + spa_pod_builder_string(&b, "dither.noise"); + spa_pod_builder_int(&b, this->dir1.conv.noise); + spa_pod_builder_string(&b, "dither.method"); + spa_pod_builder_string(&b, dither_method_infothis->dir1.conv.method.label); + spa_pod_builder_pop(&b, &f1); + param = spa_pod_builder_pop(&b, &f0); + break; + default: + return 0; + } + break; + } default: - return -ENOENT; + return 0; } - if (res == 0) { - if (spa_pod_filter(&b, &result.param, param, filter) < 0) - goto next; - } + 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) @@ -594,7 +750,6 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size) { struct impl *this = object; - int res; spa_return_val_if_fail(this != NULL, -EINVAL); @@ -602,230 +757,297 @@ switch (id) { case SPA_IO_Position: - res = spa_node_set_io(this->resample, id, data, size); - res = spa_node_set_io(this->channelmix, id, data, size); - res = spa_node_set_io(this->fmt0, id, data, size); - res = spa_node_set_io(this->fmt1, id, data, size); + this->io_position = data; break; default: - res = -ENOENT; - break; + return -ENOENT; } - return res; + return 0; } -static void fmt_input_port_info(void *data, - enum spa_direction direction, uint32_t port, - const struct spa_port_info *info) +static int audioconvert_set_param(struct impl *this, const char *k, const char *s) { - struct impl *this = data; - bool is_monitor = IS_MONITOR_PORT(this, direction, port); - - if (this->fmt_removingdirection) - info = NULL; - if (is_monitor && this->fmt_removingSPA_DIRECTION_INPUT) - info = NULL; - - spa_log_debug(this->log, "%p: %d.%d info", this, direction, port); - - if (direction == SPA_DIRECTION_INPUT || is_monitor) - spa_node_emit_port_info(&this->hooks, direction, port, info); + if (spa_streq(k, "monitor.channel-volumes")) + this->monitor_channel_volumes = spa_atob(s); + else if (spa_streq(k, "channelmix.disable")) + this->props.mix_disabled = spa_atob(s); + else if (spa_streq(k, "channelmix.normalize")) + SPA_FLAG_UPDATE(this->mix.options, CHANNELMIX_OPTION_NORMALIZE, spa_atob(s)); + else if (spa_streq(k, "channelmix.mix-lfe")) + SPA_FLAG_UPDATE(this->mix.options, CHANNELMIX_OPTION_MIX_LFE, spa_atob(s)); + else if (spa_streq(k, "channelmix.upmix")) + SPA_FLAG_UPDATE(this->mix.options, CHANNELMIX_OPTION_UPMIX, spa_atob(s)); + else if (spa_streq(k, "channelmix.lfe-cutoff")) + spa_atof(s, &this->mix.lfe_cutoff); + else if (spa_streq(k, "channelmix.fc-cutoff")) + spa_atof(s, &this->mix.fc_cutoff); + else if (spa_streq(k, "channelmix.rear-delay")) + spa_atof(s, &this->mix.rear_delay); + else if (spa_streq(k, "channelmix.stereo-widen")) + spa_atof(s, &this->mix.widen); + else if (spa_streq(k, "channelmix.hilbert-taps")) + spa_atou32(s, &this->mix.hilbert_taps, 0); + else if (spa_streq(k, "channelmix.upmix-method")) + this->mix.upmix = channelmix_upmix_from_label(s); + else if (spa_streq(k, "resample.quality")) + this->props.resample_quality = atoi(s); + else if (spa_streq(k, "resample.disable")) + this->props.resample_disabled = spa_atob(s); + else if (spa_streq(k, "dither.noise")) + spa_atou32(s, &this->dir1.conv.noise, 0); + else if (spa_streq(k, "dither.method")) + this->dir1.conv.method = dither_method_from_label(s); + else + return 0; + return 1; } -static const struct spa_node_events fmt_input_events = { - SPA_VERSION_NODE_EVENTS, - .port_info = fmt_input_port_info, -}; - -static void fmt_output_port_info(void *data, - enum spa_direction direction, uint32_t port, - const struct spa_port_info *info) +static int parse_prop_params(struct impl *this, struct spa_pod *params) { - struct impl *this = data; + struct spa_pod_parser prs; + struct spa_pod_frame f; + int changed = 0; - if (this->fmt_removingdirection) - info = NULL; + spa_pod_parser_pod(&prs, params); + if (spa_pod_parser_push_struct(&prs, &f) < 0) + return 0; - spa_log_debug(this->log, "%p: %d.%d info", this, direction, port); + while (true) { + const char *name; + struct spa_pod *pod; + char value512; - if (direction == SPA_DIRECTION_OUTPUT) - spa_node_emit_port_info(&this->hooks, direction, port, info); -} + if (spa_pod_parser_get_string(&prs, &name) < 0) + break; -static const struct spa_node_events fmt_output_events = { - SPA_VERSION_NODE_EVENTS, - .port_info = fmt_output_port_info, -}; + if (spa_pod_parser_get_pod(&prs, &pod) < 0) + break; -static void on_channelmix_info(void *data, const struct spa_node_info *info) -{ - struct impl *this = data; - uint32_t i; + if (spa_pod_is_string(pod)) { + spa_pod_copy_string(pod, sizeof(value), value); + } else if (spa_pod_is_float(pod)) { + snprintf(value, sizeof(value), "%f", + SPA_POD_VALUE(struct spa_pod_float, pod)); + } else if (spa_pod_is_int(pod)) { + snprintf(value, sizeof(value), "%d", + SPA_POD_VALUE(struct spa_pod_int, pod)); + } else if (spa_pod_is_bool(pod)) { + snprintf(value, sizeof(value), "%s", + SPA_POD_VALUE(struct spa_pod_bool, pod) ? + "true" : "false"); + } else + continue; - if ((info->change_mask & SPA_NODE_CHANGE_MASK_PARAMS) == 0) - return; - - for (i = 0; i < info->n_params; i++) { - uint32_t idx; + spa_log_info(this->log, "key:'%s' val:'%s'", name, value); + changed += audioconvert_set_param(this, name, value); + } + if (changed) { + channelmix_init(&this->mix); + set_volume(this); + } + return changed; +} - switch (info->paramsi.id) { - case SPA_PARAM_PropInfo: - idx = IDX_PropInfo; +static int apply_props(struct impl *this, const struct spa_pod *param) +{ + struct spa_pod_prop *prop; + struct spa_pod_object *obj = (struct spa_pod_object *) param; + struct props *p = &this->props; + bool have_channel_volume = false; + bool have_soft_volume = false; + int changed = 0; + uint32_t n; + + SPA_POD_OBJECT_FOREACH(obj, prop) { + switch (prop->key) { + case SPA_PROP_volume: + if (spa_pod_get_float(&prop->value, &p->volume) == 0) + changed++; + break; + case SPA_PROP_mute: + if (spa_pod_get_bool(&prop->value, &p->channel.mute) == 0) { + have_channel_volume = true; + changed++; + } break; - case SPA_PARAM_Props: - idx = IDX_Props; + case SPA_PROP_channelVolumes: + if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, + p->channel.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) { + have_channel_volume = true; + p->channel.n_volumes = n; + changed++; + } + break; + case SPA_PROP_channelMap: + if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Id, + p->channel_map, SPA_AUDIO_MAX_CHANNELS)) > 0) { + p->n_channels = n; + changed++; + } + break; + case SPA_PROP_softMute: + if (spa_pod_get_bool(&prop->value, &p->soft.mute) == 0) { + have_soft_volume = true; + changed++; + } + break; + case SPA_PROP_softVolumes: + if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, + p->soft.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) { + have_soft_volume = true; + p->soft.n_volumes = n; + changed++; + } + break; + case SPA_PROP_monitorMute: + if (spa_pod_get_bool(&prop->value, &p->monitor.mute) == 0) + changed++; + break; + case SPA_PROP_monitorVolumes: + if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, + p->monitor.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) { + p->monitor.n_volumes = n; + changed++; + } + break; + case SPA_PROP_rate: + if (spa_pod_get_double(&prop->value, &p->rate) == 0) + changed++; + break; + case SPA_PROP_params: + changed += parse_prop_params(this, &prop->value); break; default: - continue; + break; } - if (!this->add_listener && - this->param_flagsidx == info->paramsi.flags) - continue; - - this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; - this->param_flagsidx = info->paramsi.flags; - this->paramsidx.flags = - (this->paramsidx.flags & SPA_PARAM_INFO_SERIAL) | - (info->paramsi.flags & SPA_PARAM_INFO_READWRITE); + } + if (changed) { + if (have_soft_volume) + p->have_soft_volume = true; + else if (have_channel_volume) + p->have_soft_volume = false; - if (!this->add_listener) - this->paramsidx.user++; + set_volume(this); } - emit_node_info(this, false); + return changed; } -static const struct spa_node_events channelmix_events = { - SPA_VERSION_NODE_EVENTS, - .info = on_channelmix_info, -}; - -static int reconfigure_mode(struct impl *this, enum spa_param_port_config_mode mode, - enum spa_direction direction, bool monitor, struct spa_audio_info *info) +static int apply_midi(struct impl *this, const struct spa_pod *value) { - int res = 0; - struct spa_node *old, *new; - bool do_signal; + const uint8_t *val = SPA_POD_BODY(value); + uint32_t size = SPA_POD_BODY_SIZE(value); + struct props *p = &this->props; - spa_log_debug(this->log, "%p: mode %d", this, mode); - - /* old node on input/output */ - old = this->fmtdirection; - - /* decide on new node based on mode and direction */ - switch (mode) { - case SPA_PARAM_PORT_CONFIG_MODE_convert: - new = direction == SPA_DIRECTION_INPUT ? this->convert_in : this->convert_out; - break; + if (size < 3) + return -EINVAL; - case SPA_PARAM_PORT_CONFIG_MODE_dsp: - new = direction == SPA_DIRECTION_INPUT ? this->merger : this->splitter; - break; - case SPA_PARAM_PORT_CONFIG_MODE_none: - new = NULL; - break; - default: - return -EIO; - } + if ((val0 & 0xf0) != 0xb0 || val1 != 7) + return 0; - clean_convert(this); + p->volume = val2 / 127.0f; + set_volume(this); + return 1; +} - this->fmtdirection = new; +static int reconfigure_mode(struct impl *this, enum spa_param_port_config_mode mode, + enum spa_direction direction, bool monitor, bool control, struct spa_audio_info *info) +{ + struct dir *dir; + uint32_t i; - /* signal if we change nodes or when DSP config changes */ - do_signal = this->fmtdirection != old || - mode == SPA_PARAM_PORT_CONFIG_MODE_dsp; + dir = &this->dirdirection; - if (do_signal && old != NULL) { - /* change, remove old ports. We trigger a new port_info event - * on the old node with info set to NULL to mark delete */ - if (this->have_fmt_listenerdirection) { - spa_hook_remove(&this->fmt_listenerdirection); + if (dir->have_profile && this->monitor == monitor && dir->mode == mode && + dir->control == control && + (info == NULL || memcmp(&dir->format, info, sizeof(*info)) == 0)) + return 0; - this->fmt_removingdirection = true; - spa_node_add_listener(old, - &this->fmt_listenerdirection, - direction == SPA_DIRECTION_INPUT ? - &fmt_input_events : &fmt_output_events, - this); - this->fmt_removingdirection = false; + spa_log_info(this->log, "%p: port config direction:%d monitor:%d control:%d mode:%d %d", this, + direction, monitor, control, mode, dir->n_ports); - spa_hook_remove(&this->fmt_listenerdirection); - this->have_fmt_listenerdirection = false; - } + for (i = 0; i < dir->n_ports; i++) { + spa_node_emit_port_info(&this->hooks, direction, i, NULL); + if (this->monitor && direction == SPA_DIRECTION_INPUT) + spa_node_emit_port_info(&this->hooks, SPA_DIRECTION_OUTPUT, i+1, NULL); } - this->modedirection = mode; - - if (new != NULL) { - struct spa_pod_builder b = { 0 }; - uint8_t buffer4096; - struct spa_pod *param = NULL; - - spa_pod_builder_init(&b, buffer, sizeof(buffer)); + this->monitor = monitor; + dir->control = control; + dir->have_profile = true; + dir->mode = mode; + switch (mode) { + case SPA_PARAM_PORT_CONFIG_MODE_dsp: + { if (info) { - spa_log_debug(this->log, "%p: port config %d", this, info->info.raw.channels); - param = spa_format_audio_raw_build(&b, SPA_PARAM_Format, &info->info.raw); - } - if (mode == SPA_PARAM_PORT_CONFIG_MODE_dsp) { - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, - SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction), - SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp), - SPA_PARAM_PORT_CONFIG_monitor, SPA_POD_Bool(monitor), - SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param)); - res = spa_node_set_param(this->fmtdirection, SPA_PARAM_PortConfig, 0, param); + dir->n_ports = info->info.raw.channels; + dir->format = *info; + dir->format.info.raw.format = SPA_AUDIO_FORMAT_DSP_F32; + dir->format.info.raw.rate = 0; + dir->have_format = true; } else { - res = spa_node_port_set_param(this->fmtdirection, direction, 0, - SPA_PARAM_Format, 0, param); + dir->n_ports = 0; } - if (res < 0) - return res; - this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS | SPA_NODE_CHANGE_MASK_PARAMS; - this->info.flags &= ~SPA_NODE_FLAG_NEED_CONFIGURE; - this->paramsIDX_Props.user++; - } + if (this->monitor && direction == SPA_DIRECTION_INPUT) + this->dirSPA_DIRECTION_OUTPUT.n_ports = dir->n_ports + 1; - /* notify ports of new node */ - if (do_signal && new != NULL) { - if (this->have_fmt_listenerdirection) - spa_hook_remove(&this->fmt_listenerdirection); - - spa_node_add_listener(this->fmtdirection, - &this->fmt_listenerdirection, - direction == SPA_DIRECTION_INPUT ? - &fmt_input_events : &fmt_output_events, - this); - this->have_fmt_listenerdirection = true; + for (i = 0; i < dir->n_ports; i++) { + init_port(this, direction, i, info->info.raw.positioni, true, false, false); + if (this->monitor && direction == SPA_DIRECTION_INPUT) + init_port(this, SPA_DIRECTION_OUTPUT, i+1, + info->info.raw.positioni, true, true, false); + } + break; + } + case SPA_PARAM_PORT_CONFIG_MODE_convert: + { + dir->n_ports = 1; + dir->have_format = false; + init_port(this, direction, 0, 0, false, false, false); + break; + } + default: + return -ENOTSUP; + } + if (direction == SPA_DIRECTION_INPUT && dir->control) { + i = dir->n_ports++; + init_port(this, direction, i, 0, false, false, true); } - emit_node_info(this, false); + this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS | SPA_NODE_CHANGE_MASK_PARAMS; + this->info.flags &= ~SPA_NODE_FLAG_NEED_CONFIGURE; + this->paramsIDX_Props.user++; + this->paramsIDX_PortConfig.user++; return 0; } static int impl_node_set_param(void *object, uint32_t id, uint32_t flags, const struct spa_pod *param) { - int res = 0; struct impl *this = object; spa_return_val_if_fail(this != NULL, -EINVAL); + if (param == NULL) + return 0; + switch (id) { case SPA_PARAM_PortConfig: { - enum spa_direction dir; - enum spa_param_port_config_mode mode; - struct spa_pod *format = NULL; struct spa_audio_info info = { 0, }, *infop = NULL; - int monitor = false; + struct spa_pod *format = NULL; + enum spa_direction direction; + enum spa_param_port_config_mode mode; + bool monitor = false, control = false; + int res; if (spa_pod_parse_object(param, SPA_TYPE_OBJECT_ParamPortConfig, NULL, - SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(&dir), + SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(&direction), SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(&mode), SPA_PARAM_PORT_CONFIG_monitor, SPA_POD_OPT_Bool(&monitor), + SPA_PARAM_PORT_CONFIG_control, SPA_POD_OPT_Bool(&control), SPA_PARAM_PORT_CONFIG_format, SPA_POD_OPT_Pod(&format)) < 0) return -EINVAL; @@ -838,95 +1060,483 @@ if (info.media_type != SPA_MEDIA_TYPE_audio || info.media_subtype != SPA_MEDIA_SUBTYPE_raw) - return -ENOTSUP; + return -EINVAL; if (spa_format_audio_raw_parse(format, &info.info.raw) < 0) return -EINVAL; - if (info.info.raw.channels == 0 || info.info.raw.rate == 0) + if (info.info.raw.channels > SPA_AUDIO_MAX_CHANNELS) return -EINVAL; infop = &info; } - spa_log_debug(this->log, "mode:%d direction:%d %d", mode, dir, monitor); + if ((res = reconfigure_mode(this, mode, direction, monitor, control, infop)) < 0) + return res; - switch (mode) { - case SPA_PARAM_PORT_CONFIG_MODE_passthrough: - return -ENOTSUP; + emit_node_info(this, false); + break; + } + case SPA_PARAM_Props: + if (apply_props(this, param) > 0) + emit_node_info(this, false); + break; + default: + return -ENOENT; + } + return 0; +} - case SPA_PARAM_PORT_CONFIG_MODE_none: - case SPA_PARAM_PORT_CONFIG_MODE_convert: - break; +static int int32_cmp(const void *v1, const void *v2) +{ + int32_t a1 = *(int32_t*)v1; + int32_t a2 = *(int32_t*)v2; + if (a1 == 0 && a2 != 0) + return 1; + if (a2 == 0 && a1 != 0) + return -1; + return a1 - a2; +} + +static int setup_in_convert(struct impl *this) +{ + uint32_t i, j; + struct dir *in = &this->dirSPA_DIRECTION_INPUT; + struct spa_audio_info src_info, dst_info; + int res; - case SPA_PARAM_PORT_CONFIG_MODE_dsp: - info.info.raw.format = SPA_AUDIO_FORMAT_F32P; + src_info = in->format; + dst_info = src_info; + dst_info.info.raw.format = SPA_AUDIO_FORMAT_DSP_F32; + + spa_log_info(this->log, "%p: %s/%d@%d->%s/%d@%d", this, + spa_debug_type_find_name(spa_type_audio_format, src_info.info.raw.format), + src_info.info.raw.channels, + src_info.info.raw.rate, + spa_debug_type_find_name(spa_type_audio_format, dst_info.info.raw.format), + dst_info.info.raw.channels, + dst_info.info.raw.rate); + + qsort(dst_info.info.raw.position, dst_info.info.raw.channels, + sizeof(uint32_t), int32_cmp); + + for (i = 0; i < src_info.info.raw.channels; i++) { + for (j = 0; j < dst_info.info.raw.channels; j++) { + if (src_info.info.raw.positioni != + dst_info.info.raw.positionj) + continue; + in->src_remapi = j; + in->dst_remapj = i; + spa_log_debug(this->log, "%p: channel %d -> %d (%s -> %s)", this, + i, j, + spa_debug_type_find_short_name(spa_type_audio_channel, + src_info.info.raw.positioni), + spa_debug_type_find_short_name(spa_type_audio_channel, + dst_info.info.raw.positionj)); + dst_info.info.raw.positionj = -1; break; - default: - return -EINVAL; } + } + in->conv.src_fmt = src_info.info.raw.format; + in->conv.dst_fmt = dst_info.info.raw.format; + in->conv.n_channels = dst_info.info.raw.channels; + in->conv.cpu_flags = this->cpu_flags; + + if ((res = convert_init(&in->conv)) < 0) + return res; + + spa_log_debug(this->log, "%p: got converter features %08x:%08x passthrough:%d %s", this, + this->cpu_flags, in->conv.cpu_flags, in->conv.is_passthrough, + in->conv.func_name); + + return 0; +} - res = reconfigure_mode(this, mode, dir, monitor, infop); +#define _MASK(ch) (1ULL << SPA_AUDIO_CHANNEL_ ## ch) +#define STEREO (_MASK(FL)|_MASK(FR)) +static uint64_t default_mask(uint32_t channels) +{ + uint64_t mask = 0; + switch (channels) { + case 7: + case 8: + mask |= _MASK(RL); + mask |= _MASK(RR); + SPA_FALLTHROUGH + case 5: + case 6: + mask |= _MASK(SL); + mask |= _MASK(SR); + if ((channels & 1) == 0) + mask |= _MASK(LFE); + SPA_FALLTHROUGH + case 3: + mask |= _MASK(FC); + SPA_FALLTHROUGH + case 2: + mask |= _MASK(FL); + mask |= _MASK(FR); break; - } - case SPA_PARAM_Props: - { - if (this->fmtSPA_DIRECTION_INPUT == this->merger) - res = spa_node_set_param(this->merger, id, flags, param); - res = spa_node_set_param(this->channelmix, id, flags, param); - res = spa_node_set_param(this->resample, id, flags, param); + case 1: + mask |= _MASK(MONO); break; - } - default: - res = -ENOTSUP; + case 4: + mask |= _MASK(FL); + mask |= _MASK(FR); + mask |= _MASK(RL); + mask |= _MASK(RR); break; } + return mask; +} + +static void fix_volumes(struct impl *this, struct volumes *vols, uint32_t channels) +{ + float s; + uint32_t i; + spa_log_debug(this->log, "%p %d -> %d", this, vols->n_volumes, channels); + if (vols->n_volumes > 0) { + s = 0.0f; + for (i = 0; i < vols->n_volumes; i++) + s += vols->volumesi; + s /= vols->n_volumes; + } else { + s = 1.0f; + } + vols->n_volumes = channels; + for (i = 0; i < vols->n_volumes; i++) + vols->volumesi = s; +} + +static int remap_volumes(struct impl *this, const struct spa_audio_info *info) +{ + struct props *p = &this->props; + uint32_t i, j, target = info->info.raw.channels; + + for (i = 0; i < p->n_channels; i++) { + for (j = i; j < target; j++) { + spa_log_debug(this->log, "%d %d: %d <-> %d", i, j, + p->channel_mapi, info->info.raw.positionj); + if (p->channel_mapi != info->info.raw.positionj) + continue; + if (i != j) { + SPA_SWAP(p->channel_mapi, p->channel_mapj); + SPA_SWAP(p->channel.volumesi, p->channel.volumesj); + SPA_SWAP(p->soft.volumesi, p->soft.volumesj); + SPA_SWAP(p->monitor.volumesi, p->monitor.volumesj); + } + break; + } + } + p->n_channels = target; + for (i = 0; i < p->n_channels; i++) + p->channel_mapi = info->info.raw.positioni; + + if (target == 0) + return 0; + if (p->channel.n_volumes != target) + fix_volumes(this, &p->channel, target); + if (p->soft.n_volumes != target) + fix_volumes(this, &p->soft, target); + if (p->monitor.n_volumes != target) + fix_volumes(this, &p->monitor, target); + + return 1; +} + +static void set_volume(struct impl *this) +{ + struct volumes *vol; + uint32_t i; + float volumesSPA_AUDIO_MAX_CHANNELS; + struct dir *dir = &this->dirthis->direction; + + spa_log_debug(this->log, "%p", this); + + if (dir->have_format) + remap_volumes(this, &dir->format); + + if (this->mix.set_volume == NULL) + return; + + if (this->props.have_soft_volume) + vol = &this->props.soft; + else + vol = &this->props.channel; + + for (i = 0; i < vol->n_volumes; i++) + volumesi = vol->volumesdir->src_remapi; + + channelmix_set_volume(&this->mix, this->props.volume, vol->mute, + vol->n_volumes, volumes); + + this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + this->paramsIDX_Props.user++; +} + +static int setup_channelmix(struct impl *this) +{ + struct dir *in = &this->dirSPA_DIRECTION_INPUT; + struct dir *out = &this->dirSPA_DIRECTION_OUTPUT; + uint32_t i, src_chan, dst_chan, p; + uint64_t src_mask, dst_mask; + int res; + + src_chan = in->format.info.raw.channels; + dst_chan = out->format.info.raw.channels; + + for (i = 0, src_mask = 0; i < src_chan; i++) { + p = in->format.info.raw.positioni; + src_mask |= 1ULL << (p < 64 ? p : 0); + } + for (i = 0, dst_mask = 0; i < dst_chan; i++) { + p = out->format.info.raw.positioni; + dst_mask |= 1ULL << (p < 64 ? p : 0); + } + + if (src_mask & 1) + src_mask = default_mask(src_chan); + if (dst_mask & 1) + dst_mask = default_mask(dst_chan); + + spa_log_info(this->log, "%p: %s/%d@%d->%s/%d@%d %08"PRIx64":%08"PRIx64, this, + spa_debug_type_find_name(spa_type_audio_format, SPA_AUDIO_FORMAT_DSP_F32), + src_chan, + in->format.info.raw.rate, + spa_debug_type_find_name(spa_type_audio_format, SPA_AUDIO_FORMAT_DSP_F32), + dst_chan, + in->format.info.raw.rate, + src_mask, dst_mask); + + this->mix.src_chan = src_chan; + this->mix.src_mask = src_mask; + this->mix.dst_chan = dst_chan; + this->mix.dst_mask = dst_mask; + this->mix.cpu_flags = this->cpu_flags; + this->mix.log = this->log; + this->mix.freq = in->format.info.raw.rate; + + if ((res = channelmix_init(&this->mix)) < 0) + return res; + + set_volume(this); + + spa_log_debug(this->log, "%p: got channelmix features %08x:%08x flags:%08x %s", + this, this->cpu_flags, this->mix.cpu_flags, + this->mix.flags, this->mix.func_name); + return 0; +} + +static int setup_resample(struct impl *this) +{ + struct dir *in = &this->dirSPA_DIRECTION_INPUT; + struct dir *out = &this->dirSPA_DIRECTION_OUTPUT; + int res; + + spa_log_info(this->log, "%p: %s/%d@%d->%s/%d@%d", this, + spa_debug_type_find_name(spa_type_audio_format, SPA_AUDIO_FORMAT_DSP_F32), + out->format.info.raw.channels, + in->format.info.raw.rate, + spa_debug_type_find_name(spa_type_audio_format, SPA_AUDIO_FORMAT_DSP_F32), + out->format.info.raw.channels, + out->format.info.raw.rate); + + if (this->resample.free) + resample_free(&this->resample); + + this->resample.channels = out->format.info.raw.channels; + this->resample.i_rate = in->format.info.raw.rate; + this->resample.o_rate = out->format.info.raw.rate; + this->resample.log = this->log; + this->resample.quality = this->props.resample_quality; + this->resample.cpu_flags = this->cpu_flags; + + if (this->peaks) + res = resample_peaks_init(&this->resample); + else + res = resample_native_init(&this->resample); + + spa_log_debug(this->log, "%p: got resample features %08x:%08x %s", + this, this->cpu_flags, this->resample.cpu_flags, + this->resample.func_name); return res; } +static int calc_width(struct spa_audio_info *info) +{ + switch (info->info.raw.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 1; + case SPA_AUDIO_FORMAT_S16P: + case SPA_AUDIO_FORMAT_S16: + case SPA_AUDIO_FORMAT_S16_OE: + return 2; + case SPA_AUDIO_FORMAT_S24P: + case SPA_AUDIO_FORMAT_S24: + case SPA_AUDIO_FORMAT_S24_OE: + return 3; + case SPA_AUDIO_FORMAT_F64P: + case SPA_AUDIO_FORMAT_F64: + case SPA_AUDIO_FORMAT_F64_OE: + return 8; + default: + return 4; + } +} + +static int setup_out_convert(struct impl *this) +{ + uint32_t i, j; + struct dir *out = &this->dirSPA_DIRECTION_OUTPUT; + struct spa_audio_info src_info, dst_info; + int res; + + dst_info = out->format; + src_info = dst_info; + src_info.info.raw.format = SPA_AUDIO_FORMAT_DSP_F32; + + spa_log_info(this->log, "%p: %s/%d@%d->%s/%d@%d", this, + spa_debug_type_find_name(spa_type_audio_format, src_info.info.raw.format), + src_info.info.raw.channels, + src_info.info.raw.rate, + spa_debug_type_find_name(spa_type_audio_format, dst_info.info.raw.format), + dst_info.info.raw.channels, + dst_info.info.raw.rate); + + qsort(src_info.info.raw.position, src_info.info.raw.channels, + sizeof(uint32_t), int32_cmp); + + for (i = 0; i < src_info.info.raw.channels; i++) { + for (j = 0; j < dst_info.info.raw.channels; j++) { + if (src_info.info.raw.positioni != + dst_info.info.raw.positionj) + continue; + out->src_remapi = j; + out->dst_remapj = i; + spa_log_debug(this->log, "%p: channel %d -> %d (%s -> %s)", this, + i, j, + spa_debug_type_find_short_name(spa_type_audio_channel, + src_info.info.raw.positioni), + spa_debug_type_find_short_name(spa_type_audio_channel, + dst_info.info.raw.positionj)); + dst_info.info.raw.positionj = -1; + break; + } + } + out->conv.quantize = calc_width(&dst_info) * 8; + out->conv.src_fmt = src_info.info.raw.format; + out->conv.dst_fmt = dst_info.info.raw.format; + out->conv.rate = dst_info.info.raw.rate; + out->conv.n_channels = dst_info.info.raw.channels; + out->conv.cpu_flags = this->cpu_flags; + + if ((res = convert_init(&out->conv)) < 0) + return res; + + spa_log_debug(this->log, "%p: got converter features %08x:%08x quant:%d:%d:%d passthrough:%d %s", this, + this->cpu_flags, out->conv.cpu_flags, out->conv.method, + out->conv.quantize, out->conv.noise, + out->conv.is_passthrough, out->conv.func_name); + + return 0; +} + +static int setup_convert(struct impl *this) +{ + struct dir *in, *out; + uint32_t i, rate; + int res; + + in = &this->dirSPA_DIRECTION_INPUT; + out = &this->dirSPA_DIRECTION_OUTPUT; + + if (!in->have_format || !out->have_format) + return -EINVAL; + + rate = this->io_position ? this->io_position->clock.rate.denom : DEFAULT_RATE; + + if (in->format.info.raw.rate == 0 && in->mode == SPA_PARAM_PORT_CONFIG_MODE_dsp) + in->format.info.raw.rate = rate; + if (out->format.info.raw.rate == 0 && out->mode == SPA_PARAM_PORT_CONFIG_MODE_dsp) + out->format.info.raw.rate = rate; + + if (in->format.info.raw.rate == 0) + in->format.info.raw.rate = out->format.info.raw.rate; + else if (out->format.info.raw.rate == 0) + out->format.info.raw.rate = in->format.info.raw.rate; + + if (in->format.info.raw.rate == 0 && out->format.info.raw.rate == 0) + return -EINVAL; + if (in->format.info.raw.channels == 0 && out->format.info.raw.channels == 0) + return -EINVAL; + + if (in->format.info.raw.channels == 0) + in->format.info.raw.channels = out->format.info.raw.channels; + else if (out->format.info.raw.channels == 0) + out->format.info.raw.channels = in->format.info.raw.channels; + + if ((res = setup_in_convert(this)) < 0) + return res; + if ((res = setup_channelmix(this)) < 0) + return res; + if ((res = setup_resample(this)) < 0) + return res; + if ((res = setup_out_convert(this)) < 0) + return res; + + for (i = 0; i < MAX_PORTS; i++) { + this->tmp_datas0i = SPA_PTROFF(this->tmp, this->empty_size * i, void); + this->tmp_datas0i = SPA_PTR_ALIGN(this->tmp_datas0i, MAX_ALIGN, void); + this->tmp_datas1i = SPA_PTROFF(this->tmp2, this->empty_size * i, void); + this->tmp_datas1i = SPA_PTR_ALIGN(this->tmp_datas1i, MAX_ALIGN, void); + } + + emit_node_info(this, false); + + return 0; +} + +static void reset_node(struct impl *this) +{ + if (this->resample.reset) + resample_reset(&this->resample); + this->in_offset = 0; + this->out_offset = 0; +} + static int impl_node_send_command(void *object, const struct spa_command *command) { struct impl *this = object; - int res, i; + int res; 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 (this->started) + return 0; if ((res = setup_convert(this)) < 0) return res; - if ((res = setup_buffers(this, SPA_DIRECTION_INPUT)) < 0) - return res; + this->started = true; break; - case SPA_NODE_COMMAND_Suspend: - clean_convert(this); - SPA_FALLTHROUGH + SPA_FALLTHROUGH; case SPA_NODE_COMMAND_Flush: - flush_convert(this); - SPA_FALLTHROUGH + reset_node(this); + SPA_FALLTHROUGH; case SPA_NODE_COMMAND_Pause: this->started = false; break; default: return -ENOTSUP; } - - for (i = 0; i < this->n_nodes; i++) { - if ((res = spa_node_send_command(this->nodesi, command)) < 0) { - spa_log_error(this->log, "%p: can't send command to node %d: %s", - this, i, spa_strerror(res)); - } - } - - switch (SPA_NODE_COMMAND_ID(command)) { - case SPA_NODE_COMMAND_Start: - this->started = true; - break; - } - return 0; } @@ -937,37 +1547,21 @@ void *data) { struct impl *this = object; + uint32_t i; struct spa_hook_list save; - struct spa_hook l3; spa_return_val_if_fail(this != NULL, -EINVAL); - spa_hook_list_isolate(&this->hooks, &save, listener, events, data); - spa_log_trace(this->log, "%p: add listener %p", this, listener); - - this->add_listener = true; - - spa_zero(l); - if (this->fmtSPA_DIRECTION_INPUT) - spa_node_add_listener(this->fmtSPA_DIRECTION_INPUT, - &l0, &fmt_input_events, this); - spa_node_add_listener(this->channelmix, - &l1, &channelmix_events, this); - if (this->fmtSPA_DIRECTION_OUTPUT) - spa_node_add_listener(this->fmtSPA_DIRECTION_OUTPUT, - &l2, &fmt_output_events, this); - - if (this->fmtSPA_DIRECTION_INPUT) - spa_hook_remove(&l0); - spa_hook_remove(&l1); - if (this->fmtSPA_DIRECTION_OUTPUT) - spa_hook_remove(&l2); - - this->add_listener = false; + spa_hook_list_isolate(&this->hooks, &save, listener, events, data); emit_node_info(this, true); - + for (i = 0; i < this->dirSPA_DIRECTION_INPUT.n_ports; i++) { + emit_port_info(this, GET_IN_PORT(this, i), true); + } + for (i = 0; i < this->dirSPA_DIRECTION_OUTPUT.n_ports; i++) { + emit_port_info(this, GET_OUT_PORT(this, i), true); + } spa_hook_list_join(&this->hooks, &save); return 0; @@ -978,7 +1572,7 @@ const struct spa_node_callbacks *callbacks, void *user_data) { - return -ENOTSUP; + return 0; } static int impl_node_add_port(void *object, enum spa_direction direction, uint32_t port_id, @@ -993,6 +1587,77 @@ return -ENOTSUP; } +static int port_enum_formats(void *object, + enum spa_direction direction, uint32_t port_id, + uint32_t index, + struct spa_pod **param, + struct spa_pod_builder *builder) +{ + struct impl *this = object; + struct port *port = GET_PORT(this, direction, port_id); + + switch (index) { + case 0: + if (PORT_IS_DSP(this, direction, port_id)) { + struct spa_audio_info_dsp info; + info.format = SPA_AUDIO_FORMAT_DSP_F32; + *param = spa_format_audio_dsp_build(builder, + SPA_PARAM_EnumFormat, &info); + } else if (PORT_IS_CONTROL(this, direction, port_id)) { + *param = spa_pod_builder_add_object(builder, + 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)); + } else if (port->have_format) { + *param = spa_format_audio_raw_build(builder, + SPA_PARAM_EnumFormat, &this->dirdirection.format.info.raw); + } + else { + uint32_t rate = this->io_position ? + this->io_position->clock.rate.denom : DEFAULT_RATE; + + *param = spa_pod_builder_add_object(builder, + SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), + SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(25, + SPA_AUDIO_FORMAT_F32P, + SPA_AUDIO_FORMAT_F32P, + SPA_AUDIO_FORMAT_F32, + SPA_AUDIO_FORMAT_F32_OE, + SPA_AUDIO_FORMAT_F64P, + SPA_AUDIO_FORMAT_F64, + SPA_AUDIO_FORMAT_F64_OE, + SPA_AUDIO_FORMAT_S32P, + SPA_AUDIO_FORMAT_S32, + SPA_AUDIO_FORMAT_S32_OE, + SPA_AUDIO_FORMAT_S24_32P, + SPA_AUDIO_FORMAT_S24_32, + SPA_AUDIO_FORMAT_S24_32_OE, + SPA_AUDIO_FORMAT_S24P, + SPA_AUDIO_FORMAT_S24, + SPA_AUDIO_FORMAT_S24_OE, + SPA_AUDIO_FORMAT_S16P, + SPA_AUDIO_FORMAT_S16, + SPA_AUDIO_FORMAT_S16_OE, + SPA_AUDIO_FORMAT_S8P, + SPA_AUDIO_FORMAT_S8, + SPA_AUDIO_FORMAT_U8P, + SPA_AUDIO_FORMAT_U8, + SPA_AUDIO_FORMAT_ULAW, + SPA_AUDIO_FORMAT_ALAW), + SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int( + rate, 1, INT32_MAX), + SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int( + DEFAULT_CHANNELS, 1, SPA_AUDIO_MAX_CHANNELS)); + } + break; + default: + return 0; + } + return 1; +} + static int impl_node_port_enum_params(void *object, int seq, enum spa_direction direction, uint32_t port_id, @@ -1000,9 +1665,10 @@ const struct spa_pod *filter) { struct impl *this = object; + struct port *port; struct spa_pod *param; struct spa_pod_builder b = { 0 }; - uint8_t buffer4096; + uint8_t buffer2048; struct spa_result_node_params result; uint32_t count = 0; int res; @@ -1010,51 +1676,92 @@ spa_return_val_if_fail(this != NULL, -EINVAL); spa_return_val_if_fail(num != 0, -EINVAL); - spa_log_debug(this->log, "%p: port %d.%d %d %u", this, direction, port_id, seq, id); + spa_log_debug(this->log, "%p: enum params port %d.%d %d %u", + this, direction, port_id, seq, id); + + 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; + result.index = result.next++; spa_pod_builder_init(&b, buffer, sizeof(buffer)); switch (id) { + case SPA_PARAM_EnumFormat: + if ((res = port_enum_formats(object, 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; + + if (PORT_IS_DSP(this, direction, port_id)) + param = spa_format_audio_dsp_build(&b, id, &port->format.info.dsp); + else if (PORT_IS_CONTROL(this, direction, port_id)) + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_Format, id, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control)); + else + param = spa_format_audio_raw_build(&b, id, &port->format.info.raw); + 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(port->blocks), + SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( + this->quantum_limit * port->stride, + 16 * port->stride, + INT32_MAX), + SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); + 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))); + SPA_PARAM_IO_id, SPA_POD_Id(SPA_IO_Buffers), + SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_buffers))); break; - case 1: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_ParamIO, id, - SPA_PARAM_IO_id, SPA_POD_Id(SPA_IO_RateMatch), - SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_rate_match))); + default: + return 0; + } + break; + case SPA_PARAM_Latency: + switch (result.index) { + case 0: case 1: + param = spa_latency_build(&b, id, &this->dirresult.index.latency); break; default: return 0; } - result.next++; break; default: - { - struct spa_node *target; - - if (IS_MONITOR_PORT(this, direction, port_id)) - target = this->fmtSPA_DIRECTION_INPUT; - else - target = this->fmtdirection; - - res = spa_node_port_enum_params_sync(target, - direction, port_id, - id, &result.next, - NULL, ¶m, &b); - if (res != 1) - return res; - } + return -ENOENT; } if (spa_pod_filter(&b, &result.param, param, filter) < 0) @@ -1068,6 +1775,156 @@ return 0; } +static int clear_buffers(struct impl *this, struct port *port) +{ + if (port->n_buffers > 0) { + spa_log_debug(this->log, "%p: clear buffers %p", this, port); + port->n_buffers = 0; + spa_list_init(&port->queue); + } + return 0; +} + +static int port_set_latency(void *object, + enum spa_direction direction, + uint32_t port_id, + uint32_t flags, + const struct spa_pod *latency) +{ + struct impl *this = object; + struct port *port; + enum spa_direction other = SPA_DIRECTION_REVERSE(direction); + uint32_t i; + + spa_log_debug(this->log, "%p: set latency direction:%d id:%d", + this, direction, port_id); + + port = GET_PORT(this, direction, port_id); + if (port->is_monitor) + return 0; + + if (latency == NULL) { + this->dirother.latency = SPA_LATENCY_INFO(other); + } else { + struct spa_latency_info info; + if (spa_latency_parse(latency, &info) < 0 || + info.direction != other) + return -EINVAL; + this->dirother.latency = info; + } + + for (i = 0; i < this->dirother.n_ports; i++) { + port = GET_PORT(this, other, i); + port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + port->paramsIDX_Latency.user++; + emit_port_info(this, port, false); + } + port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + port->paramsIDX_Latency.user++; + emit_port_info(this, port, false); + return 0; +} + +static int port_set_format(void *object, + enum spa_direction direction, + uint32_t port_id, + uint32_t flags, + const struct spa_pod *format) +{ + struct impl *this = object; + struct port *port; + int res; + + port = GET_PORT(this, direction, port_id); + + spa_log_debug(this->log, "%p: set format", this); + + if (format == NULL) { + port->have_format = false; + clear_buffers(this, port); + } else { + struct spa_audio_info info = { 0 }; + + if ((res = spa_format_parse(format, &info.media_type, &info.media_subtype)) < 0) { + spa_log_error(this->log, "can't parse format %s", spa_strerror(res)); + return res; + } + if (PORT_IS_DSP(this, direction, port_id)) { + if (info.media_type != SPA_MEDIA_TYPE_audio || + info.media_subtype != SPA_MEDIA_SUBTYPE_dsp) { + spa_log_error(this->log, "unexpected types %d/%d", + info.media_type, info.media_subtype); + return -EINVAL; + } + if ((res = spa_format_audio_dsp_parse(format, &info.info.dsp)) < 0) { + spa_log_error(this->log, "can't parse format %s", spa_strerror(res)); + return res; + } + if (info.info.dsp.format != SPA_AUDIO_FORMAT_DSP_F32) { + spa_log_error(this->log, "unexpected format %d<->%d", + info.info.dsp.format, SPA_AUDIO_FORMAT_DSP_F32); + return -EINVAL; + } + port->blocks = 1; + port->stride = 4; + } + else if (PORT_IS_CONTROL(this, direction, port_id)) { + if (info.media_type != SPA_MEDIA_TYPE_application || + info.media_subtype != SPA_MEDIA_SUBTYPE_control) { + spa_log_error(this->log, "unexpected types %d/%d", + info.media_type, info.media_subtype); + return -EINVAL; + } + port->blocks = 1; + port->stride = 1; + } + else { + if (info.media_type != SPA_MEDIA_TYPE_audio || + info.media_subtype != SPA_MEDIA_SUBTYPE_raw) { + spa_log_error(this->log, "unexpected types %d/%d", + info.media_type, info.media_subtype); + return -EINVAL; + } + if ((res = spa_format_audio_raw_parse(format, &info.info.raw)) < 0) { + spa_log_error(this->log, "can't parse format %s", spa_strerror(res)); + return res; + } + if (info.info.raw.channels > SPA_AUDIO_MAX_CHANNELS) { + spa_log_error(this->log, "too many channels %d > %d", + info.info.raw.channels, SPA_AUDIO_MAX_CHANNELS); + return -EINVAL; + } + port->stride = calc_width(&info); + if (SPA_AUDIO_FORMAT_IS_PLANAR(info.info.raw.format)) { + port->blocks = info.info.raw.channels; + } else { + port->stride *= info.info.raw.channels; + port->blocks = 1; + } + this->dirdirection.format = info; + this->dirdirection.have_format = true; + } + port->format = info; + port->have_format = true; + + spa_log_debug(this->log, "%p: %d %d %d", this, + port_id, port->stride, port->blocks); + } + + 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, @@ -1075,41 +1932,56 @@ const struct spa_pod *param) { struct impl *this = object; - int res; - struct spa_node *target; - bool is_monitor; spa_return_val_if_fail(this != NULL, -EINVAL); - spa_log_debug(this->log, "%p: set param %u on port %d:%d %p", - this, id, direction, port_id, param); + spa_log_debug(this->log, "%p: set param port %d.%d %u", + this, direction, port_id, id); + + spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); switch (id) { + case SPA_PARAM_Latency: + return port_set_latency(this, direction, port_id, flags, param); + case SPA_PARAM_Format: + return port_set_format(this, direction, port_id, flags, param); default: - is_monitor = IS_MONITOR_PORT(this, direction, port_id); - if (is_monitor) - target = this->fmtSPA_DIRECTION_INPUT; - else - target = this->fmtdirection; - break; + return -ENOENT; } +} - if ((res = spa_node_port_set_param(target, - direction, port_id, id, flags, param)) < 0) - return res; +static void queue_buffer(struct impl *this, struct port *port, uint32_t id) +{ + struct buffer *b = &port->buffersid; - switch (id) { - case SPA_PARAM_Latency: - if (port_id == 0) { - target = this->fmtSPA_DIRECTION_REVERSE(direction); - if ((res = spa_node_port_set_param(target, - direction, port_id, id, flags, param)) < 0) - return res; - } - break; - } + spa_log_trace_fp(this->log, "%p: queue buffer %d on port %d %d", + this, id, port->id, b->flags); + if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_QUEUED)) + return; - return res; + spa_list_append(&port->queue, &b->link); + SPA_FLAG_SET(b->flags, BUFFER_FLAG_QUEUED); +} + +static struct buffer *peek_buffer(struct impl *this, struct port *port) +{ + struct buffer *b; + + if (spa_list_is_empty(&port->queue)) + return NULL; + + b = spa_list_first(&port->queue, struct buffer, link); + spa_log_trace_fp(this->log, "%p: peek buffer %d on port %d %u", + this, b->id, port->id, b->flags); + return b; +} + +static void dequeue_buffer(struct impl *this, struct port *port, struct buffer *b) +{ + spa_list_remove(&b->link); + SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_QUEUED); + spa_log_trace_fp(this->log, "%p: dequeue buffer %d on port %d %u", + this, b->id, port->id, b->flags); } static int @@ -1121,21 +1993,74 @@ uint32_t n_buffers) { struct impl *this = object; - int res; - struct spa_node *target; + struct port *port; + uint32_t i, j, maxsize; spa_return_val_if_fail(this != NULL, -EINVAL); - if (IS_MONITOR_PORT(this, direction, port_id)) - target = this->fmtSPA_DIRECTION_INPUT; - else - target = this->fmtdirection; + spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); - if ((res = spa_node_port_use_buffers(target, - direction, port_id, flags, buffers, n_buffers)) < 0) - return res; + port = GET_PORT(this, direction, port_id); - return res; + spa_return_val_if_fail(port->have_format, -EIO); + + spa_log_debug(this->log, "%p: use buffers %d on port %d:%d", + this, n_buffers, direction, port_id); + + clear_buffers(this, port); + + maxsize = 0; + for (i = 0; i < n_buffers; i++) { + struct buffer *b; + uint32_t n_datas = buffersi->n_datas; + struct spa_data *d = buffersi->datas; + + b = &port->buffersi; + b->id = i; + b->flags = 0; + b->buf = buffersi; + + if (n_datas != port->blocks) { + spa_log_error(this->log, "%p: invalid blocks %d on buffer %d", + this, n_datas, i); + return -EINVAL; + } + + for (j = 0; j < n_datas; j++) { + if (dj.data == NULL) { + spa_log_error(this->log, "%p: invalid memory %d on buffer %d %d %p", + this, j, i, dj.type, dj.data); + return -EINVAL; + } + if (!SPA_IS_ALIGNED(dj.data, this->max_align)) { + spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned", + this, j, i); + } + if (direction == SPA_DIRECTION_OUTPUT && + !SPA_FLAG_IS_SET(dj.flags, SPA_DATA_FLAG_DYNAMIC)) + this->is_passthrough = false; + + b->datasj = dj.data; + + maxsize = SPA_MAX(maxsize, dj.maxsize); + } + if (direction == SPA_DIRECTION_OUTPUT) + queue_buffer(this, port, i); + } + if (maxsize > this->empty_size) { + this->empty = realloc(this->empty, maxsize + MAX_ALIGN); + this->scratch = realloc(this->scratch, maxsize + MAX_ALIGN); + this->tmp = realloc(this->tmp, (4 * maxsize + MAX_ALIGN) * MAX_PORTS); + this->tmp2 = realloc(this->tmp2, (4 * maxsize + MAX_ALIGN) * MAX_PORTS); + if (this->empty == NULL || this->scratch == NULL || + this->tmp == NULL || this->tmp2 == NULL) + return -errno; + memset(this->empty, 0, maxsize + MAX_ALIGN); + this->empty_size = maxsize; + } + port->n_buffers = n_buffers; + + return 0; } static int @@ -1144,81 +2069,524 @@ uint32_t id, void *data, size_t size) { struct impl *this = object; - struct spa_node *target; - int res; + struct port *port; spa_return_val_if_fail(this != NULL, -EINVAL); - spa_log_debug(this->log, "set io %d %d %d", id, direction, port_id); + spa_log_debug(this->log, "%p: set io %d on port %d:%d %p", + this, id, direction, port_id, data); + + 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; case SPA_IO_RateMatch: - res = spa_node_port_set_io(this->resample, direction, 0, id, data, size); + this->io_rate_match = data; break; default: - if (IS_MONITOR_PORT(this, direction, port_id)) - target = this->fmtSPA_DIRECTION_INPUT; - else - target = this->fmtdirection; - - res = spa_node_port_set_io(target, direction, port_id, id, data, size); - break; + return -ENOENT; } - return res; + return 0; } static int impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id) { struct impl *this = object; - struct spa_node *target; + 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); - if (IS_MONITOR_PORT(this, SPA_DIRECTION_OUTPUT, port_id)) - target = this->fmtSPA_DIRECTION_INPUT; - else - target = this->fmtSPA_DIRECTION_OUTPUT; + port = GET_OUT_PORT(this, port_id); + queue_buffer(this, port, buffer_id); + + return 0; +} + +static int channelmix_process_control(struct impl *this, struct port *ctrlport, + void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + struct spa_pod_control *c, *prev = NULL; + uint32_t avail_samples = n_samples; + uint32_t i; + const float *sMAX_PORTS, **ss = (const float**) src; + float *dMAX_PORTS, **sd = (float **) dst; + const struct spa_pod_sequence_body *body = &(ctrlport->ctrl)->body; + uint32_t size = SPA_POD_BODY_SIZE(ctrlport->ctrl); + bool end = false; + + c = spa_pod_control_first(body); + while (true) { + uint32_t chunk; + + if (c == NULL || !spa_pod_control_is_inside(body, size, c)) { + c = NULL; + end = true; + } + if (avail_samples == 0) + break; + + /* ignore old control offsets */ + if (c != NULL) { + if (c->offset <= ctrlport->ctrl_offset) { + prev = c; + if (c != NULL) + c = spa_pod_control_next(c); + continue; + } + chunk = SPA_MIN(avail_samples, c->offset - ctrlport->ctrl_offset); + spa_log_trace_fp(this->log, "%p: process %d-%d %d/%d", this, + ctrlport->ctrl_offset, c->offset, chunk, avail_samples); + } else { + chunk = avail_samples; + spa_log_trace_fp(this->log, "%p: process remain %d", this, chunk); + } + + if (prev) { + switch (prev->type) { + case SPA_CONTROL_Midi: + apply_midi(this, &prev->value); + break; + case SPA_CONTROL_Properties: + apply_props(this, &prev->value); + break; + default: + continue; + } + } + if (ss == (const float**)src && chunk != avail_samples) { + for (i = 0; i < this->mix.src_chan; i++) + si = ssi; + for (i = 0; i < this->mix.dst_chan; i++) + di = sdi; + ss = s; + sd = d; + } + + channelmix_process(&this->mix, (void**)sd, (const void**)ss, chunk); + + if (chunk != avail_samples) { + for (i = 0; i < this->mix.src_chan; i++) + ssi += chunk; + for (i = 0; i < this->mix.dst_chan; i++) + sdi += chunk; + } + avail_samples -= chunk; + ctrlport->ctrl_offset += chunk; + } + return end ? 1 : 0; +} + +static uint32_t resample_update_rate_match(struct impl *this, bool passthrough, uint32_t out_size, uint32_t in_queued) +{ + double rate = this->rate_scale / this->props.rate; + uint32_t delay, match_size; + + if (passthrough) { + delay = 0; + match_size = out_size; + } else { + if (this->io_rate_match && + SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)) + rate *= this->io_rate_match->rate; + resample_update_rate(&this->resample, rate); + delay = resample_delay(&this->resample); + match_size = resample_in_len(&this->resample, out_size); + } + match_size -= SPA_MIN(match_size, in_queued); + + spa_log_trace_fp(this->log, "%p: next match %u", this, match_size); - return spa_node_port_reuse_buffer(target, port_id, buffer_id); + if (this->io_rate_match) { + this->io_rate_match->delay = delay; + this->io_rate_match->size = match_size; + } + return match_size; +} + +static inline bool resample_is_passthrough(struct impl *this) +{ + return this->resample.i_rate == this->resample.o_rate && this->rate_scale == 1.0 && + this->props.rate == 1.0 && + (this->io_rate_match == NULL || + !SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)); } static int impl_node_process(void *object) { struct impl *this = object; - int r, i, res = SPA_STATUS_OK; - int ready; + const void *src_datasMAX_PORTS, **in_datas; + void *dst_datasMAX_PORTS, **out_datas; + uint32_t i, j, n_src_datas = 0, n_dst_datas = 0, n_mon_datas = 0, remap; + uint32_t n_samples, max_in, n_out, max_out, quant_samples; + struct port *port, *ctrlport = NULL; + struct buffer *buf, *out_bufsMAX_PORTS; + struct spa_data *bd; + struct dir *dir; + int tmp = 0, res = 0; + bool in_passthrough, mix_passthrough, resample_passthrough, out_passthrough, end_passthrough; + bool in_avail = false, flush_in = false, flush_out = false, draining = false, in_empty = true; + struct spa_io_buffers *io, *ctrlio = NULL; + const struct spa_pod_sequence *ctrl = NULL; + + dir = &this->dirSPA_DIRECTION_INPUT; + in_passthrough = dir->conv.is_passthrough; + + max_in = UINT32_MAX; + + /* collect input port data */ + for (i = 0; i < dir->n_ports; i++) { + port = GET_IN_PORT(this, i); + + if (SPA_UNLIKELY((io = port->io) == NULL)) { + spa_log_trace_fp(this->log, "%p: no io on input port %d", + this, port->id); + buf = NULL; + } else if (SPA_UNLIKELY(io->status != SPA_STATUS_HAVE_DATA)) { + if (io->status & SPA_STATUS_DRAINED) { + spa_log_debug(this->log, "%p: port %d drained", this, port->id); + in_avail = flush_in = draining = true; + } else { + spa_log_trace_fp(this->log, "%p: empty input port %d %p %d %d %d", + this, port->id, io, io->status, io->buffer_id, + port->n_buffers); + } + buf = NULL; + } else if (SPA_UNLIKELY(io->buffer_id >= port->n_buffers)) { + spa_log_trace_fp(this->log, "%p: invalid input buffer port %d %p %d %d %d", + this, port->id, io, io->status, io->buffer_id, + port->n_buffers); + io->status = -EINVAL; + buf = NULL; + } else { + buf = &port->buffersio->buffer_id; + } - spa_return_val_if_fail(this != NULL, -EINVAL); + if (SPA_UNLIKELY(buf == NULL)) { + for (j = 0; j < port->blocks; j++) { + if (port->is_control) { + spa_log_trace_fp(this->log, "%p: empty control %d", this, + i * port->blocks + j); + } else { + remap = dir->src_remapn_src_datas++; + src_datasremap = SPA_PTR_ALIGN(this->empty, MAX_ALIGN, void); + spa_log_trace_fp(this->log, "%p: empty input %d->%d", this, + i * port->blocks + j, remap); + max_in = SPA_MIN(max_in, this->empty_size / port->stride); + } + } + } else { + in_avail = true; + for (j = 0; j < port->blocks; j++) { + uint32_t offs, size; + + bd = &buf->buf->datasj; + + offs = SPA_MIN(bd->chunk->offset, bd->maxsize); + size = SPA_MIN(bd->maxsize - offs, bd->chunk->size); + if (!SPA_FLAG_IS_SET(bd->chunk->flags, SPA_CHUNK_FLAG_EMPTY)) + in_empty = false; + + if (SPA_UNLIKELY(port->is_control)) { + spa_log_trace_fp(this->log, "%p: control %d", this, + i * port->blocks + j); + ctrlport = port; + ctrlio = io; + ctrl = spa_pod_from_data(bd->data, bd->maxsize, + bd->chunk->offset, bd->chunk->size); + if (ctrl && !spa_pod_is_sequence(&ctrl->pod)) + ctrl = NULL; + if (ctrl != ctrlport->ctrl) { + ctrlport->ctrl = ctrl; + ctrlport->ctrl_offset = 0; + } + } else { + max_in = SPA_MIN(max_in, size / port->stride); + + remap = dir->src_remapn_src_datas++; + offs += this->in_offset * port->stride; + src_datasremap = SPA_PTROFF(bd->data, offs, void); + + spa_log_trace_fp(this->log, "%p: input %d:%d:%d %d %d %d->%d", this, + offs, size, port->stride, this->in_offset, max_in, + i * port->blocks + j, remap); + } + } + } + } + + /* calculate quantum scale */ + if (SPA_LIKELY(this->io_position)) { + double r = this->rate_scale; - spa_log_trace_fp(this->log, "%p: process %d %d", this, this->n_links, this->n_nodes); + quant_samples = this->io_position->clock.duration; + if (this->direction == SPA_DIRECTION_INPUT) { + if (this->io_position->clock.rate.denom != this->resample.o_rate) + r = (double) this->io_position->clock.rate.denom / this->resample.o_rate; + else + r = 1.0; + } else { + if (this->io_position->clock.rate.denom != this->resample.i_rate) + r = (double) this->resample.i_rate / this->io_position->clock.rate.denom; + else + r = 1.0; + } + if (this->rate_scale != r) { + spa_log_info(this->log, "scale %f->%f", this->rate_scale, r); + this->rate_scale = r; + } + } + else + quant_samples = this->quantum_limit; + + if (SPA_UNLIKELY(draining)) + n_samples = SPA_MIN(max_in, this->quantum_limit); + else { + n_samples = max_in - SPA_MIN(max_in, this->in_offset); + } + + resample_passthrough = resample_is_passthrough(this); - while (1) { - res = SPA_STATUS_OK; - ready = 0; - for (i = 0; i < this->n_nodes; i++) { - r = spa_node_process(this->nodesi); + if (this->direction == SPA_DIRECTION_INPUT) { + uint32_t out = resample_update_rate_match(this, resample_passthrough, quant_samples, 0); + if (!in_avail || this->drained) { + spa_log_trace_fp(this->log, "%p: no input drained:%d", this, this->drained); + /* no input, ask for more */ + res |= this->drained ? SPA_STATUS_DRAINED : SPA_STATUS_NEED_DATA; + return res; + } + /* in split mode we need to output exactly the size of the + * duration so we don't try to flush early */ + n_samples = SPA_MIN(n_samples, out); + max_out = quant_samples; + flush_out = false; + } else { + /* in merge mode we consume one duration of samples and + * always output the resulting data */ + n_samples = SPA_MIN(n_samples, quant_samples); + max_out = this->quantum_limit; + flush_out = flush_in = true; + } - spa_log_trace_fp(this->log, "%p: process %d %d: %s", - this, i, r, r < 0 ? spa_strerror(r) : "ok"); + dir = &this->dirSPA_DIRECTION_OUTPUT; + out_passthrough = dir->conv.is_passthrough; - if (SPA_UNLIKELY(r < 0)) - return r; + /* collect output ports and monitor ports data */ + for (i = 0; i < dir->n_ports; i++) { + port = GET_OUT_PORT(this, i); - if (r & SPA_STATUS_HAVE_DATA) - ready++; + if (SPA_UNLIKELY((io = port->io) == NULL || + io->status == SPA_STATUS_HAVE_DATA)) { + buf = NULL; + } + else { + if (SPA_LIKELY(io->buffer_id < port->n_buffers)) + queue_buffer(this, port, io->buffer_id); - if (SPA_UNLIKELY(i == 0)) - res |= r & SPA_STATUS_NEED_DATA; - if (SPA_UNLIKELY(i == this->n_nodes-1)) - res |= r & (SPA_STATUS_HAVE_DATA | SPA_STATUS_DRAINED); + buf = peek_buffer(this, port); } - if (res & SPA_STATUS_HAVE_DATA) - break; - if (ready == 0) - break; + out_bufsi = buf; + + if (SPA_UNLIKELY(buf == NULL)) { + for (j = 0; j < port->blocks; j++) { + if (port->is_monitor) { + remap = n_mon_datas++; + spa_log_trace_fp(this->log, "%p: empty monitor %d", this, + remap); + } else if (port->is_control) { + spa_log_trace_fp(this->log, "%p: empty control %d", this, j); + } else { + remap = dir->dst_remapn_dst_datas++; + dst_datasremap = SPA_PTR_ALIGN(this->scratch, MAX_ALIGN, void); + spa_log_trace_fp(this->log, "%p: empty output %d->%d", this, + i * port->blocks + j, remap); + } + } + } else { + for (j = 0; j < port->blocks; j++) { + bd = &buf->buf->datasj; + + bd->chunk->offset = 0; + bd->chunk->size = 0; + if (port->is_monitor) { + float volume; + uint32_t mon_max; + + remap = n_mon_datas++; + volume = this->props.monitor.mute ? 0.0f : this->props.monitor.volumesremap; + if (this->monitor_channel_volumes) + volume *= this->props.channel.mute ? 0.0f : + this->props.channel.volumesremap; + + mon_max = SPA_MIN(bd->maxsize / port->stride, n_samples); + + volume_process(&this->volume, bd->data, src_datasremap, + volume, mon_max); + + bd->chunk->size = mon_max * port->stride; + + spa_log_trace_fp(this->log, "%p: monitor %d %d", this, + remap, mon_max); + + dequeue_buffer(this, port, buf); + io->status = SPA_STATUS_HAVE_DATA; + io->buffer_id = buf->id; + res |= SPA_STATUS_HAVE_DATA; + } else if (SPA_UNLIKELY(port->is_control)) { + spa_log_trace_fp(this->log, "%p: control %d", this, j); + } else { + remap = dir->dst_remapn_dst_datas++; + dst_datasremap = SPA_PTROFF(bd->data, + this->out_offset * port->stride, void); + max_out = SPA_MIN(max_out, bd->maxsize / port->stride); + + spa_log_trace_fp(this->log, "%p: output %d offs:%d %d->%d", this, + max_out, this->out_offset, + i * port->blocks + j, remap); + } + } + } + } + + n_out = max_out - SPA_MIN(max_out, this->out_offset); + + mix_passthrough = SPA_FLAG_IS_SET(this->mix.flags, CHANNELMIX_FLAG_IDENTITY) && + (ctrlport == NULL || ctrlport->ctrl == NULL); + end_passthrough = mix_passthrough && resample_passthrough && out_passthrough; + + if (!in_passthrough || end_passthrough) { + if (end_passthrough) { + out_datas = (void **)dst_datas; + n_samples = SPA_MIN(n_samples, n_out); + } + else + out_datas = (void **)this->tmp_datas(tmp++) & 1; + spa_log_trace_fp(this->log, "%p: convert %d %d", this, n_samples, end_passthrough); + convert_process(&this->dirSPA_DIRECTION_INPUT.conv, out_datas, src_datas, n_samples); + } else { + out_datas = (void **)src_datas; + } + + if (!mix_passthrough) { + in_datas = (const void**)out_datas; + if (resample_passthrough && out_passthrough) { + out_datas = (void **)dst_datas; + n_samples = SPA_MIN(n_samples, n_out); + } + else + out_datas = (void **)this->tmp_datas(tmp++) & 1; + spa_log_trace_fp(this->log, "%p: channelmix %d %d %d", this, n_samples, + resample_passthrough, out_passthrough); + if (ctrlport != NULL && ctrlport->ctrl != NULL) { + if (channelmix_process_control(this, ctrlport, out_datas, + in_datas, n_samples) == 1) { + ctrlio->status = SPA_STATUS_OK; + ctrlport->ctrl = NULL; + } + } else { + channelmix_process(&this->mix, out_datas, in_datas, n_samples); + } + } + + if (!resample_passthrough) { + uint32_t in_len, out_len; + + in_datas = (const void**)out_datas; + if (out_passthrough) + out_datas = (void **)dst_datas; + else + out_datas = (void **)this->tmp_datas(tmp++) & 1; + + in_len = n_samples; + out_len = n_out; + resample_process(&this->resample, in_datas, &in_len, out_datas, &out_len); + spa_log_trace_fp(this->log, "%p: resample %d/%d -> %d/%d %d", this, + n_samples, in_len, n_out, out_len, out_passthrough); + this->in_offset += in_len; + n_samples = out_len; + } else { + this->in_offset += n_samples; + n_samples = SPA_MIN(n_samples, n_out); } + this->out_offset += n_samples; - spa_log_trace_fp(this->log, "%p: process result: %d", this, res); + if (!out_passthrough) { + in_datas = (const void**)out_datas; + spa_log_trace_fp(this->log, "%p: convert %d", this, n_samples); + convert_process(&this->dirSPA_DIRECTION_OUTPUT.conv, dst_datas, in_datas, n_samples); + } + + spa_log_trace_fp(this->log, "%d/%d %d/%d %d->%d", this->in_offset, max_in, + this->out_offset, max_out, n_samples, n_out); + + dir = &this->dirSPA_DIRECTION_INPUT; + if (SPA_LIKELY(this->in_offset >= max_in || flush_in)) { + /* return input buffers */ + for (i = 0; i < dir->n_ports; i++) { + port = GET_IN_PORT(this, i); + if (port->is_control) + continue; + if (SPA_UNLIKELY((io = port->io) == NULL)) + continue; + spa_log_trace_fp(this->log, "return: input %d %d", port->id, io->buffer_id); + io->status = SPA_STATUS_NEED_DATA; + } + this->in_offset = 0; + max_in = 0; + res |= SPA_STATUS_NEED_DATA; + } + + dir = &this->dirSPA_DIRECTION_OUTPUT; + if (SPA_LIKELY(n_samples > 0 && (this->out_offset >= max_out || flush_out))) { + /* queue output buffers */ + for (i = 0; i < dir->n_ports; i++) { + port = GET_OUT_PORT(this, i); + if (SPA_UNLIKELY(port->is_monitor || port->is_control)) + continue; + if (SPA_UNLIKELY((io = port->io) == NULL)) + continue; + + if (SPA_UNLIKELY((buf = out_bufsi) == NULL)) + continue; + + dequeue_buffer(this, port, buf); + + for (j = 0; j < port->blocks; j++) { + bd = &buf->buf->datasj; + bd->chunk->size = this->out_offset * port->stride; + SPA_FLAG_UPDATE(bd->chunk->flags, SPA_CHUNK_FLAG_EMPTY, in_empty); + spa_log_trace_fp(this->log, "out: %d %d %d", this->out_offset, + port->stride, bd->chunk->size); + } + io->status = SPA_STATUS_HAVE_DATA; + io->buffer_id = buf->id; + } + res |= SPA_STATUS_HAVE_DATA; + this->drained = draining; + this->out_offset = 0; + } + else if (n_samples == 0 && this->peaks) { + for (i = 0; i < dir->n_ports; i++) { + port = GET_OUT_PORT(this, i); + if (port->is_monitor || port->is_control) + continue; + if (SPA_UNLIKELY((io = port->io) == NULL)) + continue; + + io->status = SPA_STATUS_HAVE_DATA; + io->buffer_id = SPA_ID_INVALID; + res |= SPA_STATUS_HAVE_DATA; + spa_log_trace_fp(this->log, "%p: no output buffer", this); + } + } + resample_update_rate_match(this, resample_passthrough, + max_out - this->out_offset, + max_in - this->in_offset); return res; } @@ -1261,44 +2629,32 @@ static int impl_clear(struct spa_handle *handle) { struct impl *this; + uint32_t i; spa_return_val_if_fail(handle != NULL, -EINVAL); this = (struct impl *) handle; - clean_convert(this); + for (i = 0; i < MAX_PORTS; i++) + free(this->dirSPA_DIRECTION_INPUT.portsi); + for (i = 0; i < MAX_PORTS; i++) + free(this->dirSPA_DIRECTION_OUTPUT.portsi); + free(this->empty); + free(this->scratch); + free(this->tmp); + free(this->tmp2); - spa_handle_clear(this->hnd_merger); - spa_handle_clear(this->hnd_convert_in); - spa_handle_clear(this->hnd_channelmix); - spa_handle_clear(this->hnd_resample); - spa_handle_clear(this->hnd_convert_out); - spa_handle_clear(this->hnd_splitter); + if (this->resample.free) + resample_free(&this->resample); return 0; } -extern const struct spa_handle_factory spa_fmtconvert_factory; -extern const struct spa_handle_factory spa_channelmix_factory; -extern const struct spa_handle_factory spa_resample_factory; -extern const struct spa_handle_factory spa_splitter_factory; -extern const struct spa_handle_factory spa_merger_factory; - static size_t impl_get_size(const struct spa_handle_factory *factory, const struct spa_dict *params) { - size_t size; - - size = sizeof(struct impl); - size += spa_handle_factory_get_size(&spa_merger_factory, params); - size += spa_handle_factory_get_size(&spa_fmtconvert_factory, params); - size += spa_handle_factory_get_size(&spa_channelmix_factory, params); - size += spa_handle_factory_get_size(&spa_resample_factory, params); - size += spa_handle_factory_get_size(&spa_fmtconvert_factory, params); - size += spa_handle_factory_get_size(&spa_splitter_factory, params); - - return size; + return sizeof(struct impl); } static int @@ -1309,8 +2665,7 @@ uint32_t n_support) { struct impl *this; - size_t size; - void *iface; + uint32_t i; spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); @@ -1324,8 +2679,40 @@ spa_log_topic_init(this->log, log_topic); this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU); - if (this->cpu) - this->max_align = spa_cpu_get_max_align(this->cpu); + if (this->cpu) { + this->cpu_flags = spa_cpu_get_flags(this->cpu); + this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu)); + } + + props_reset(&this->props); + + this->mix.options = CHANNELMIX_OPTION_UPMIX; + this->mix.upmix = CHANNELMIX_UPMIX_PSD; + this->mix.log = this->log; + this->mix.lfe_cutoff = 150.0f; + this->mix.fc_cutoff = 12000.0f; + this->mix.rear_delay = 12.0f; + this->mix.widen = 0.0f; + + 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, "resample.peaks")) + this->peaks = spa_atob(s); + else if (spa_streq(k, "factory.mode")) { + if (spa_streq(s, "merge")) + this->direction = SPA_DIRECTION_OUTPUT; + else + this->direction = SPA_DIRECTION_INPUT; + } + else + audioconvert_set_param(this, k, s); + } + + this->dirSPA_DIRECTION_INPUT.latency = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); + this->dirSPA_DIRECTION_OUTPUT.latency = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); this->node.iface = SPA_INTERFACE_INIT( SPA_TYPE_INTERFACE_Node, @@ -1347,67 +2734,21 @@ 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->info.params = this->params; - this->info.n_params = 4; - - this->hnd_merger = SPA_PTROFF(this, sizeof(struct impl), struct spa_handle); - spa_handle_factory_init(&spa_merger_factory, - this->hnd_merger, - info, support, n_support); - size = spa_handle_factory_get_size(&spa_merger_factory, info); - - this->hnd_convert_in = SPA_PTROFF(this->hnd_merger, size, struct spa_handle); - spa_handle_factory_init(&spa_fmtconvert_factory, - this->hnd_convert_in, - info, support, n_support); - size = spa_handle_factory_get_size(&spa_fmtconvert_factory, info); - - this->hnd_channelmix = SPA_PTROFF(this->hnd_convert_in, size, struct spa_handle); - spa_handle_factory_init(&spa_channelmix_factory, - this->hnd_channelmix, - info, support, n_support); - size = spa_handle_factory_get_size(&spa_channelmix_factory, info); - - this->hnd_resample = SPA_PTROFF(this->hnd_channelmix, size, struct spa_handle); - spa_handle_factory_init(&spa_resample_factory, - this->hnd_resample, - info, support, n_support); - size = spa_handle_factory_get_size(&spa_resample_factory, info); - - this->hnd_convert_out = SPA_PTROFF(this->hnd_resample, size, struct spa_handle); - spa_handle_factory_init(&spa_fmtconvert_factory, - this->hnd_convert_out, - info, support, n_support); - size = spa_handle_factory_get_size(&spa_fmtconvert_factory, info); - - this->hnd_splitter = SPA_PTROFF(this->hnd_convert_out, size, struct spa_handle); - spa_handle_factory_init(&spa_splitter_factory, - this->hnd_splitter, - info, support, n_support); - - spa_handle_get_interface(this->hnd_merger, SPA_TYPE_INTERFACE_Node, &iface); - this->merger = iface; - spa_handle_get_interface(this->hnd_convert_in, SPA_TYPE_INTERFACE_Node, &iface); - this->convert_in = iface; - spa_handle_get_interface(this->hnd_channelmix, SPA_TYPE_INTERFACE_Node, &iface); - this->channelmix = iface; - spa_handle_get_interface(this->hnd_resample, SPA_TYPE_INTERFACE_Node, &iface); - this->resample = iface; - spa_handle_get_interface(this->hnd_convert_out, SPA_TYPE_INTERFACE_Node, &iface); - this->convert_out = iface; - spa_handle_get_interface(this->hnd_splitter, SPA_TYPE_INTERFACE_Node, &iface); - this->splitter = iface; - - reconfigure_mode(this, SPA_PARAM_PORT_CONFIG_MODE_convert, SPA_DIRECTION_OUTPUT, false, NULL); - reconfigure_mode(this, SPA_PARAM_PORT_CONFIG_MODE_convert, SPA_DIRECTION_INPUT, false, NULL); - - spa_node_add_listener(this->channelmix, - &this->listener0, &channelmix_events, this); + this->info.n_params = N_NODE_PARAMS; + + this->volume.cpu_flags = this->cpu_flags; + volume_init(&this->volume); + + this->rate_scale = 1.0; + + reconfigure_mode(this, SPA_PARAM_PORT_CONFIG_MODE_convert, SPA_DIRECTION_INPUT, false, false, NULL); + reconfigure_mode(this, SPA_PARAM_PORT_CONFIG_MODE_convert, SPA_DIRECTION_OUTPUT, false, false, NULL); return 0; } static const struct spa_interface_info impl_interfaces = { - { SPA_TYPE_INTERFACE_Node, }, + {SPA_TYPE_INTERFACE_Node,}, }; static int
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/channelmix-ops-c.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/channelmix-ops-c.c
Changed
@@ -177,6 +177,7 @@ channelmix_f32_2_4_c(struct channelmix *mix, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { + uint32_t i, n_dst = mix->dst_chan; float **d = (float **)dst; const float **s = (const float **)src; const float v0 = mix->matrix00; @@ -184,10 +185,25 @@ const float v2 = mix->matrix20; const float v3 = mix->matrix31; - vol_c(d0, s0, v0, n_samples); - vol_c(d1, s1, v1, n_samples); - vol_c(d2, s0, v2, n_samples); - vol_c(d3, s1, v3, n_samples); + if (SPA_FLAG_IS_SET(mix->flags, CHANNELMIX_FLAG_ZERO)) { + for (i = 0; i < n_dst; i++) + clear_c(di, n_samples); + } + else { + vol_c(d0, s0, v0, n_samples); + vol_c(d1, s1, v1, n_samples); + if (mix->upmix != CHANNELMIX_UPMIX_PSD) { + vol_c(d2, s0, v2, n_samples); + vol_c(d3, s1, v3, n_samples); + } else { + sub_c(d2, s0, s1, n_samples); + + delay_convolve_run(mix->buffer1, &mix->pos1, BUFFER_SIZE, mix->delay, + mix->taps, mix->n_taps, d3, d2, -v3, n_samples); + delay_convolve_run(mix->buffer0, &mix->pos0, BUFFER_SIZE, mix->delay, + mix->taps, mix->n_taps, d2, d2, v2, n_samples); + } + } } #define MASK_3_1 _M(FL)|_M(FR)|_M(FC)|_M(LFE) @@ -294,6 +310,32 @@ } } +/* FL+FR+FC+LFE -> FL+FR */ +void +channelmix_f32_3p1_2_c(struct channelmix *mix, void * SPA_RESTRICT dst, + const void * SPA_RESTRICT src, uint32_t n_samples) +{ + uint32_t n; + float **d = (float **) dst; + const float **s = (const float **) src; + const float v0 = mix->matrix00; + const float v1 = mix->matrix11; + const float clev = (mix->matrix02 + mix->matrix12) * 0.5f; + const float llev = (mix->matrix03 + mix->matrix13) * 0.5f; + + if (SPA_FLAG_IS_SET(mix->flags, CHANNELMIX_FLAG_ZERO)) { + clear_c(d0, n_samples); + clear_c(d1, n_samples); + } + else { + for (n = 0; n < n_samples; n++) { + const float ctr = clev * s2n + llev * s3n; + d0n = s0n * v0 + ctr; + d1n = s1n * v1 + ctr; + } + } +} + /* FL+FR+FC+LFE+SL+SR -> FL+FR */ void channelmix_f32_5p1_2_c(struct channelmix *mix, void * SPA_RESTRICT dst, @@ -356,13 +398,9 @@ channelmix_f32_5p1_4_c(struct channelmix *mix, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { - uint32_t i, n, n_dst = mix->dst_chan; + uint32_t i, n_dst = mix->dst_chan; float **d = (float **) dst; const float **s = (const float **) src; - const float clev = mix->matrix02; - const float llev = mix->matrix03; - const float v0 = mix->matrix00; - const float v1 = mix->matrix11; const float v4 = mix->matrix24; const float v5 = mix->matrix35; @@ -371,11 +409,8 @@ clear_c(di, n_samples); } else { - for (n = 0; n < n_samples; n++) { - const float ctr = s2n * clev + s3n * llev; - d0n = s0n * v0 + ctr; - d1n = s1n * v1 + ctr; - } + channelmix_f32_3p1_2_c(mix, dst, src, n_samples); + vol_c(d2, s4, v4, n_samples); vol_c(d3, s5, v5, n_samples); }
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/channelmix-ops-sse.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/channelmix-ops-sse.c
Changed
@@ -26,113 +26,104 @@ #include <xmmintrin.h> -void channelmix_copy_sse(struct channelmix *mix, void * SPA_RESTRICT dst, - const void * SPA_RESTRICT src, uint32_t n_samples) +static inline void clear_sse(float *d, uint32_t n_samples) { - uint32_t i, n, unrolled, n_dst = mix->dst_chan; - float **d = (float **)dst; - const float **s = (const float **)src; + memset(d, 0, n_samples * sizeof(float)); +} - if (SPA_FLAG_IS_SET(mix->flags, CHANNELMIX_FLAG_ZERO)) { - for (i = 0; i < n_dst; i++) - memset(di, 0, n_samples * sizeof(float)); - } - else if (SPA_FLAG_IS_SET(mix->flags, CHANNELMIX_FLAG_IDENTITY)) { - for (i = 0; i < n_dst; i++) - spa_memcpy(di, si, n_samples * sizeof(float)); - } - else { - for (i = 0; i < n_dst; i++) { - float *di = di; - const float *si = si; - __m128 t4; - const __m128 vol = _mm_set1_ps(mix->matrixii); +static inline void copy_sse(float *d, const float *s, uint32_t n_samples) +{ + spa_memcpy(d, s, n_samples * sizeof(float)); +} - if (SPA_IS_ALIGNED(di, 16) && - SPA_IS_ALIGNED(si, 16)) - unrolled = n_samples & ~15; - else - unrolled = 0; +static inline void vol_sse(float *d, const float *s, float vol, uint32_t n_samples) +{ + uint32_t n, unrolled; + if (vol == 0.0f) { + clear_sse(d, n_samples); + } else if (vol == 1.0f) { + copy_sse(d, s, n_samples); + } else { + __m128 t4; + const __m128 v = _mm_set1_ps(vol); + + if (SPA_IS_ALIGNED(d, 16) && + SPA_IS_ALIGNED(s, 16)) + unrolled = n_samples & ~15; + else + unrolled = 0; - for(n = 0; n < unrolled; n += 16) { - t0 = _mm_load_ps(&sin); - t1 = _mm_load_ps(&sin+4); - t2 = _mm_load_ps(&sin+8); - t3 = _mm_load_ps(&sin+12); - _mm_store_ps(&din, _mm_mul_ps(t0, vol)); - _mm_store_ps(&din+4, _mm_mul_ps(t1, vol)); - _mm_store_ps(&din+8, _mm_mul_ps(t2, vol)); - _mm_store_ps(&din+12, _mm_mul_ps(t3, vol)); - } - for(; n < n_samples; n++) - _mm_store_ss(&din, _mm_mul_ss(_mm_load_ss(&sin), vol)); + for(n = 0; n < unrolled; n += 16) { + t0 = _mm_load_ps(&sn); + t1 = _mm_load_ps(&sn+4); + t2 = _mm_load_ps(&sn+8); + t3 = _mm_load_ps(&sn+12); + _mm_store_ps(&dn, _mm_mul_ps(t0, v)); + _mm_store_ps(&dn+4, _mm_mul_ps(t1, v)); + _mm_store_ps(&dn+8, _mm_mul_ps(t2, v)); + _mm_store_ps(&dn+12, _mm_mul_ps(t3, v)); } + for(; n < n_samples; n++) + _mm_store_ss(&dn, _mm_mul_ss(_mm_load_ss(&sn), v)); } } -void -channelmix_f32_2_4_sse(struct channelmix *mix, void * SPA_RESTRICT dst, +void channelmix_copy_sse(struct channelmix *mix, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { - uint32_t i, n, unrolled, n_dst = mix->dst_chan; + uint32_t i, n_dst = mix->dst_chan; float **d = (float **)dst; const float **s = (const float **)src; - const float m00 = mix->matrix00; - const float m11 = mix->matrix11; - __m128 in; - const float *sFL = s0, *sFR = s1; - float *dFL = d0, *dFR = d1, *dRL = d2, *dRR = d3; + for (i = 0; i < n_dst; i++) + vol_sse(di, si, mix->matrixii, n_samples); +} - if (SPA_IS_ALIGNED(sFL, 16) && - SPA_IS_ALIGNED(sFR, 16) && - SPA_IS_ALIGNED(dFL, 16) && - SPA_IS_ALIGNED(dFR, 16) && - SPA_IS_ALIGNED(dRL, 16) && - SPA_IS_ALIGNED(dRR, 16)) - unrolled = n_samples & ~3; - else - unrolled = 0; +/* FL+FR+FC+LFE -> FL+FR */ +void +channelmix_f32_3p1_2_sse(struct channelmix *mix, void * SPA_RESTRICT dst, + const void * SPA_RESTRICT src, uint32_t n_samples) +{ + float **d = (float **) dst; + const float **s = (const float **) src; + const float m0 = mix->matrix00; + const float m1 = mix->matrix11; + const float m2 = (mix->matrix02 + mix->matrix12) * 0.5f; + const float m3 = (mix->matrix03 + mix->matrix13) * 0.5f; - if (SPA_FLAG_IS_SET(mix->flags, CHANNELMIX_FLAG_ZERO)) { - for (i = 0; i < n_dst; i++) - memset(di, 0, n_samples * sizeof(float)); - } - else if (m00 == 1.0f && m11 == 1.0f) { - for(n = 0; n < unrolled; n += 4) { - in = _mm_load_ps(&sFLn); - _mm_store_ps(&dFLn, in); - _mm_store_ps(&dRLn, in); - in = _mm_load_ps(&sFRn); - _mm_store_ps(&dFRn, in); - _mm_store_ps(&dRRn, in); - } - for(; n < n_samples; n++) { - in = _mm_load_ss(&sFLn); - _mm_store_ss(&dFLn, in); - _mm_store_ss(&dRLn, in); - in = _mm_load_ss(&sFRn); - _mm_store_ss(&dFRn, in); - _mm_store_ss(&dRRn, in); - } + if (m0 == 0.0f && m1 == 0.0f && m2 == 0.0f && m3 == 0.0f) { + clear_sse(d0, n_samples); + clear_sse(d1, n_samples); } else { - const __m128 v0 = _mm_set1_ps(m00); - const __m128 v1 = _mm_set1_ps(m11); + uint32_t n, unrolled; + const __m128 v0 = _mm_set1_ps(m0); + const __m128 v1 = _mm_set1_ps(m1); + const __m128 clev = _mm_set1_ps(m2); + const __m128 llev = _mm_set1_ps(m3); + __m128 ctr; + + if (SPA_IS_ALIGNED(s0, 16) && + SPA_IS_ALIGNED(s1, 16) && + SPA_IS_ALIGNED(s2, 16) && + SPA_IS_ALIGNED(s3, 16) && + SPA_IS_ALIGNED(d0, 16) && + SPA_IS_ALIGNED(d1, 16)) + unrolled = n_samples & ~3; + else + unrolled = 0; + for(n = 0; n < unrolled; n += 4) { - in = _mm_mul_ps(_mm_load_ps(&sFLn), v0); - _mm_store_ps(&dFLn, in); - _mm_store_ps(&dRLn, in); - in = _mm_mul_ps(_mm_load_ps(&sFRn), v1); - _mm_store_ps(&dFRn, in); - _mm_store_ps(&dRRn, in); + ctr = _mm_add_ps( + _mm_mul_ps(_mm_load_ps(&s2n), clev), + _mm_mul_ps(_mm_load_ps(&s3n), llev)); + _mm_store_ps(&d0n, _mm_add_ps(_mm_mul_ps(_mm_load_ps(&s0n), v0), ctr)); + _mm_store_ps(&d1n, _mm_add_ps(_mm_mul_ps(_mm_load_ps(&s1n), v1), ctr)); } for(; n < n_samples; n++) { - in = _mm_mul_ss(_mm_load_ss(&sFLn), v0); - _mm_store_ss(&dFLn, in); - _mm_store_ss(&dRLn, in); - in = _mm_mul_ss(_mm_load_ss(&sFRn), v1); - _mm_store_ss(&dFRn, in); - _mm_store_ss(&dRRn, in); + ctr = _mm_add_ss(_mm_mul_ss(_mm_load_ss(&s2n), clev), + _mm_mul_ss(_mm_load_ss(&s3n), llev)); + _mm_store_ss(&d0n, _mm_add_ss(_mm_mul_ss(_mm_load_ss(&s0n), v0), ctr)); + _mm_store_ss(&d1n, _mm_add_ss(_mm_mul_ss(_mm_load_ss(&s1n), v1), ctr)); } } } @@ -152,77 +143,49 @@ const __m128 slev0 = _mm_set1_ps(mix->matrix04); const __m128 slev1 = _mm_set1_ps(mix->matrix15); __m128 in, ctr; - const float *sFL = s0, *sFR = s1, *sFC = s2, *sLFE = s3, *sSL = s4, *sSR = s5; - float *dFL = d0, *dFR = d1; - if (SPA_IS_ALIGNED(sFL, 16) && - SPA_IS_ALIGNED(sFR, 16) && - SPA_IS_ALIGNED(sFC, 16) && - SPA_IS_ALIGNED(sLFE, 16) && - SPA_IS_ALIGNED(sSL, 16) && - SPA_IS_ALIGNED(sSR, 16) && - SPA_IS_ALIGNED(dFL, 16) && - SPA_IS_ALIGNED(dFR, 16)) + if (SPA_IS_ALIGNED(s0, 16) && + SPA_IS_ALIGNED(s1, 16) && + SPA_IS_ALIGNED(s2, 16) && + SPA_IS_ALIGNED(s3, 16) && + SPA_IS_ALIGNED(s4, 16) && + SPA_IS_ALIGNED(s5, 16) && + SPA_IS_ALIGNED(d0, 16) && + SPA_IS_ALIGNED(d1, 16)) unrolled = n_samples & ~3; else unrolled = 0; if (SPA_FLAG_IS_SET(mix->flags, CHANNELMIX_FLAG_ZERO)) { - memset(dFL, 0, n_samples * sizeof(float)); - memset(dFR, 0, n_samples * sizeof(float)); - } - else if (m00 == 1.0f && m11 == 1.0f) { - for(n = 0; n < unrolled; n += 4) { - ctr = _mm_mul_ps(_mm_load_ps(&sFCn), clev); - ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFEn), llev)); - in = _mm_mul_ps(_mm_load_ps(&sSLn), slev0); - in = _mm_add_ps(in, ctr); - in = _mm_add_ps(in, _mm_load_ps(&sFLn)); - _mm_store_ps(&dFLn, in); - in = _mm_mul_ps(_mm_load_ps(&sSRn), slev1); - in = _mm_add_ps(in, ctr); - in = _mm_add_ps(in, _mm_load_ps(&sFRn)); - _mm_store_ps(&dFRn, in); - } - for(; n < n_samples; n++) { - ctr = _mm_mul_ss(_mm_load_ss(&sFCn), clev); - ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&sLFEn), llev)); - in = _mm_mul_ss(_mm_load_ss(&sSLn), slev0); - in = _mm_add_ss(in, ctr); - in = _mm_add_ss(in, _mm_load_ss(&sFLn)); - _mm_store_ss(&dFLn, in); - in = _mm_mul_ss(_mm_load_ss(&sSRn), slev1); - in = _mm_add_ss(in, ctr); - in = _mm_add_ss(in, _mm_load_ss(&sFRn)); - _mm_store_ss(&dFRn, in); - } + clear_sse(d0, n_samples); + clear_sse(d1, n_samples); } else { const __m128 v0 = _mm_set1_ps(m00); const __m128 v1 = _mm_set1_ps(m11); for(n = 0; n < unrolled; n += 4) { - ctr = _mm_mul_ps(_mm_load_ps(&sFCn), clev); - ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFEn), llev)); - in = _mm_mul_ps(_mm_load_ps(&sSLn), slev0); + ctr = _mm_add_ps(_mm_mul_ps(_mm_load_ps(&s2n), clev), + _mm_mul_ps(_mm_load_ps(&s3n), llev)); + in = _mm_mul_ps(_mm_load_ps(&s4n), slev0); in = _mm_add_ps(in, ctr); - in = _mm_add_ps(in, _mm_mul_ps(_mm_load_ps(&sFLn), v0)); - _mm_store_ps(&dFLn, in); - in = _mm_mul_ps(_mm_load_ps(&sSRn), slev1); + in = _mm_add_ps(in, _mm_mul_ps(_mm_load_ps(&s0n), v0)); + _mm_store_ps(&d0n, in); + in = _mm_mul_ps(_mm_load_ps(&s5n), slev1); in = _mm_add_ps(in, ctr); - in = _mm_add_ps(in, _mm_mul_ps(_mm_load_ps(&sFRn), v1)); - _mm_store_ps(&dFRn, in); + in = _mm_add_ps(in, _mm_mul_ps(_mm_load_ps(&s1n), v1)); + _mm_store_ps(&d1n, in); } for(; n < n_samples; n++) { - ctr = _mm_mul_ss(_mm_load_ss(&sFCn), clev); - ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&sLFEn), llev)); - in = _mm_mul_ss(_mm_load_ss(&sSLn), slev0); + ctr = _mm_mul_ss(_mm_load_ss(&s2n), clev); + ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&s3n), llev)); + in = _mm_mul_ss(_mm_load_ss(&s4n), slev0); in = _mm_add_ss(in, ctr); - in = _mm_add_ss(in, _mm_mul_ss(_mm_load_ss(&sFLn), v0)); - _mm_store_ss(&dFLn, in); - in = _mm_mul_ss(_mm_load_ss(&sSRn), slev1); + in = _mm_add_ss(in, _mm_mul_ss(_mm_load_ss(&s0n), v0)); + _mm_store_ss(&d0n, in); + in = _mm_mul_ss(_mm_load_ss(&s5n), slev1); in = _mm_add_ss(in, ctr); - in = _mm_add_ss(in, _mm_mul_ss(_mm_load_ss(&sFRn), v1)); - _mm_store_ss(&dFRn, in); + in = _mm_add_ss(in, _mm_mul_ss(_mm_load_ss(&s1n), v1)); + _mm_store_ss(&d1n, in); } } } @@ -235,73 +198,51 @@ uint32_t i, n, unrolled, n_dst = mix->dst_chan; float **d = (float **) dst; const float **s = (const float **) src; - const __m128 v0 = _mm_set1_ps(mix->matrix00); - const __m128 v1 = _mm_set1_ps(mix->matrix11); - const __m128 slev0 = _mm_set1_ps(mix->matrix04); - const __m128 slev1 = _mm_set1_ps(mix->matrix15); - const __m128 v2 = _mm_set1_ps(mix->matrix22); - const __m128 v3 = _mm_set1_ps(mix->matrix33); - __m128 avg2; - const float *sFL = s0, *sFR = s1, *sFC = s2, *sLFE = s3, *sSL = s4, *sSR = s5; - float *dFL = d0, *dFR = d1, *dFC = d2, *dLFE = d3; - if (SPA_IS_ALIGNED(sFL, 16) && - SPA_IS_ALIGNED(sFR, 16) && - SPA_IS_ALIGNED(sFC, 16) && - SPA_IS_ALIGNED(sLFE, 16) && - SPA_IS_ALIGNED(sSL, 16) && - SPA_IS_ALIGNED(sSR, 16) && - SPA_IS_ALIGNED(dFL, 16) && - SPA_IS_ALIGNED(dFR, 16) && - SPA_IS_ALIGNED(dFC, 16) && - SPA_IS_ALIGNED(dLFE, 16)) - unrolled = n_samples & ~7; + if (SPA_IS_ALIGNED(s0, 16) && + SPA_IS_ALIGNED(s1, 16) && + SPA_IS_ALIGNED(s2, 16) && + SPA_IS_ALIGNED(s3, 16) && + SPA_IS_ALIGNED(s4, 16) && + SPA_IS_ALIGNED(s5, 16) && + SPA_IS_ALIGNED(d0, 16) && + SPA_IS_ALIGNED(d1, 16) && + SPA_IS_ALIGNED(d2, 16) && + SPA_IS_ALIGNED(d3, 16)) + unrolled = n_samples & ~3; else unrolled = 0; if (SPA_FLAG_IS_SET(mix->flags, CHANNELMIX_FLAG_ZERO)) { for (i = 0; i < n_dst; i++) - memset(di, 0, n_samples * sizeof(float)); + clear_sse(di, n_samples); } else { - for(n = 0; n < unrolled; n += 8) { - avg0 = _mm_add_ps( - _mm_mul_ps(_mm_load_ps(&sFLn), v0), - _mm_mul_ps(_mm_load_ps(&sSLn), slev0)); - avg1 = _mm_add_ps( - _mm_mul_ps(_mm_load_ps(&sFLn+4), v0), - _mm_mul_ps(_mm_load_ps(&sSLn+4), slev0)); - _mm_store_ps(&dFLn, avg0); - _mm_store_ps(&dFLn+4, avg1); + const __m128 v0 = _mm_set1_ps(mix->matrix00); + const __m128 v1 = _mm_set1_ps(mix->matrix11); + const __m128 slev0 = _mm_set1_ps(mix->matrix04); + const __m128 slev1 = _mm_set1_ps(mix->matrix15); - avg0 = _mm_add_ps( - _mm_mul_ps(_mm_load_ps(&sFRn), v1), - _mm_mul_ps(_mm_load_ps(&sSRn), slev1)); - avg1 = _mm_add_ps( - _mm_mul_ps(_mm_load_ps(&sFRn+4), v1), - _mm_mul_ps(_mm_load_ps(&sSRn+4), slev1)); - _mm_store_ps(&dFRn, avg0); - _mm_store_ps(&dFRn+4, avg1); + for(n = 0; n < unrolled; n += 4) { + _mm_store_ps(&d0n, _mm_add_ps( + _mm_mul_ps(_mm_load_ps(&s0n), v0), + _mm_mul_ps(_mm_load_ps(&s4n), slev0))); - _mm_store_ps(&dFCn, _mm_mul_ps(_mm_load_ps(&sFCn), v2)); - _mm_store_ps(&dFCn+4, _mm_mul_ps(_mm_load_ps(&sFCn+4), v2)); - _mm_store_ps(&dLFEn, _mm_mul_ps(_mm_load_ps(&sLFEn), v3)); - _mm_store_ps(&dLFEn+4, _mm_mul_ps(_mm_load_ps(&sLFEn+4), v3)); + _mm_store_ps(&d1n, _mm_add_ps( + _mm_mul_ps(_mm_load_ps(&s1n), v1), + _mm_mul_ps(_mm_load_ps(&s5n), slev1))); } for(; n < n_samples; n++) { - avg0 = _mm_add_ss( - _mm_mul_ss(_mm_load_ss(&sFLn), v0), - _mm_mul_ss(_mm_load_ss(&sSLn), slev0)); - _mm_store_ss(&dFLn, avg0); - - avg0 = _mm_add_ss( - _mm_mul_ss(_mm_load_ss(&sFRn), v1), - _mm_mul_ss(_mm_load_ss(&sSRn), slev1)); - _mm_store_ss(&dFRn, avg0); + _mm_store_ss(&d0n, _mm_add_ss( + _mm_mul_ss(_mm_load_ss(&s0n), v0), + _mm_mul_ss(_mm_load_ss(&s4n), slev0))); - _mm_store_ss(&dFCn, _mm_mul_ss(_mm_load_ss(&sFCn), v2)); - _mm_store_ss(&dLFEn, _mm_mul_ss(_mm_load_ss(&sLFEn), v3)); + _mm_store_ss(&d1n, _mm_add_ss( + _mm_mul_ss(_mm_load_ss(&s1n), v1), + _mm_mul_ss(_mm_load_ss(&s5n), slev1))); } + vol_sse(d2, s2, mix->matrix22, n_samples); + vol_sse(d3, s3, mix->matrix33, n_samples); } } @@ -310,76 +251,20 @@ channelmix_f32_5p1_4_sse(struct channelmix *mix, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { - uint32_t i, n, unrolled, n_dst = mix->dst_chan; + uint32_t i, n_dst = mix->dst_chan; float **d = (float **) dst; const float **s = (const float **) src; - const __m128 clev = _mm_set1_ps(mix->matrix02); - const __m128 llev = _mm_set1_ps(mix->matrix03); - const float m00 = mix->matrix00; - const float m11 = mix->matrix11; - const float m24 = mix->matrix24; - const float m35 = mix->matrix35; - __m128 ctr; - const float *sFL = s0, *sFR = s1, *sFC = s2, *sLFE = s3, *sSL = s4, *sSR = s5; - float *dFL = d0, *dFR = d1, *dRL = d2, *dRR = d3; - - if (SPA_IS_ALIGNED(sFL, 16) && - SPA_IS_ALIGNED(sFR, 16) && - SPA_IS_ALIGNED(sFC, 16) && - SPA_IS_ALIGNED(sLFE, 16) && - SPA_IS_ALIGNED(sSL, 16) && - SPA_IS_ALIGNED(sSR, 16) && - SPA_IS_ALIGNED(dFL, 16) && - SPA_IS_ALIGNED(dFR, 16) && - SPA_IS_ALIGNED(dRL, 16) && - SPA_IS_ALIGNED(dRR, 16)) - unrolled = n_samples & ~3; - else - unrolled = 0; + const float v4 = mix->matrix24; + const float v5 = mix->matrix35; if (SPA_FLAG_IS_SET(mix->flags, CHANNELMIX_FLAG_ZERO)) { for (i = 0; i < n_dst; i++) - memset(di, 0, n_samples * sizeof(float)); - } - else if (m00 == 1.0f && m11 == 1.0f && m24 == 1.0f && m35 == 1.0f) { - for(n = 0; n < unrolled; n += 4) { - ctr = _mm_mul_ps(_mm_load_ps(&sFCn), clev); - ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFEn), llev)); - _mm_store_ps(&dFLn, _mm_add_ps(_mm_load_ps(&sFLn), ctr)); - _mm_store_ps(&dFRn, _mm_add_ps(_mm_load_ps(&sFRn), ctr)); - _mm_store_ps(&dRLn, _mm_load_ps(&sSLn)); - _mm_store_ps(&dRRn, _mm_load_ps(&sSRn)); - } - for(; n < n_samples; n++) { - ctr = _mm_mul_ss(_mm_load_ss(&sFCn), clev); - ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&sLFEn), llev)); - _mm_store_ss(&dFLn, _mm_add_ss(_mm_load_ss(&sFLn), ctr)); - _mm_store_ss(&dFRn, _mm_add_ss(_mm_load_ss(&sFRn), ctr)); - _mm_store_ss(&dRLn, _mm_load_ss(&sSLn)); - _mm_store_ss(&dRRn, _mm_load_ss(&sSRn)); - } + clear_sse(di, n_samples); } else { - const __m128 v0 = _mm_set1_ps(m00); - const __m128 v1 = _mm_set1_ps(m11); - const __m128 v4 = _mm_set1_ps(m24); - const __m128 v5 = _mm_set1_ps(m35); + channelmix_f32_3p1_2_sse(mix, dst, src, n_samples); - for(n = 0; n < unrolled; n += 4) { - ctr = _mm_mul_ps(_mm_load_ps(&sFCn), clev); - ctr = _mm_add_ps(ctr, _mm_mul_ps(_mm_load_ps(&sLFEn), llev)); - _mm_store_ps(&dFLn, _mm_mul_ps(_mm_add_ps(_mm_load_ps(&sFLn), ctr), v0)); - _mm_store_ps(&dFRn, _mm_mul_ps(_mm_add_ps(_mm_load_ps(&sFRn), ctr), v1)); - _mm_store_ps(&dRLn, _mm_mul_ps(_mm_load_ps(&sSLn), v4)); - _mm_store_ps(&dRRn, _mm_mul_ps(_mm_load_ps(&sSRn), v5)); - } - for(; n < n_samples; n++) { - ctr = _mm_mul_ss(_mm_load_ss(&sFCn), clev); - ctr = _mm_add_ss(ctr, _mm_mul_ss(_mm_load_ss(&sLFEn), llev)); - _mm_store_ss(&dFLn, _mm_mul_ss(_mm_add_ss(_mm_load_ss(&sFLn), ctr), v0)); - _mm_store_ss(&dFRn, _mm_mul_ss(_mm_add_ss(_mm_load_ss(&sFRn), ctr), v1)); - _mm_store_ss(&dRLn, _mm_mul_ss(_mm_load_ss(&sSLn), v4)); - _mm_store_ss(&dRRn, _mm_mul_ss(_mm_load_ss(&sSRn), v5)); - } + vol_sse(d2, s4, v4, n_samples); + vol_sse(d3, s5, v5, n_samples); } }
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/channelmix-ops.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/channelmix-ops.c
Changed
@@ -37,9 +37,6 @@ #include "channelmix-ops.h" #include "hilbert.h" -#undef SPA_LOG_TOPIC_DEFAULT -#define SPA_LOG_TOPIC_DEFAULT log_topic -struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.channelmix"); #define _M(ch) (1UL << SPA_AUDIO_CHANNEL_ ## ch) #define MASK_MONO _M(FC)|_M(MONO)|_M(UNKNOWN) @@ -55,6 +52,9 @@ typedef void (*channelmix_func_t) (struct channelmix *mix, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples); +#define MAKE(sc,sm,dc,dm,func,...) \ + { sc, sm, dc, dm, func, #func, __VA_ARGS__ } + static const struct channelmix_info { uint32_t src_chan; uint64_t src_mask; @@ -62,50 +62,53 @@ uint64_t dst_mask; channelmix_func_t process; - uint32_t cpu_flags; const char *name; + + uint32_t cpu_flags; } channelmix_table = { #if defined (HAVE_SSE) - { 2, MASK_MONO, 2, MASK_MONO, channelmix_copy_sse, SPA_CPU_FLAG_SSE, "copy_sse" }, - { 2, MASK_STEREO, 2, MASK_STEREO, channelmix_copy_sse, SPA_CPU_FLAG_SSE, "copy_sse" }, - { EQ, 0, EQ, 0, channelmix_copy_sse, SPA_CPU_FLAG_SSE, "copy_sse" }, + MAKE(2, MASK_MONO, 2, MASK_MONO, channelmix_copy_sse, SPA_CPU_FLAG_SSE), + MAKE(2, MASK_STEREO, 2, MASK_STEREO, channelmix_copy_sse, SPA_CPU_FLAG_SSE), + MAKE(EQ, 0, EQ, 0, channelmix_copy_sse, SPA_CPU_FLAG_SSE), #endif - { 2, MASK_MONO, 2, MASK_MONO, channelmix_copy_c, 0, "copy_c" }, - { 2, MASK_STEREO, 2, MASK_STEREO, channelmix_copy_c, 0, "copy_c" }, - { EQ, 0, EQ, 0, channelmix_copy_c, 0 }, - - { 1, MASK_MONO, 2, MASK_STEREO, channelmix_f32_1_2_c, 0, "f32_1_2_c" }, - { 2, MASK_STEREO, 1, MASK_MONO, channelmix_f32_2_1_c, 0, "f32_2_1_c" }, - { 4, MASK_QUAD, 1, MASK_MONO, channelmix_f32_4_1_c, 0, "f32_4_1_c" }, - { 4, MASK_3_1, 1, MASK_MONO, channelmix_f32_4_1_c, 0, "f32_4_1_c" }, + MAKE(2, MASK_MONO, 2, MASK_MONO, channelmix_copy_c), + MAKE(2, MASK_STEREO, 2, MASK_STEREO, channelmix_copy_c), + MAKE(EQ, 0, EQ, 0, channelmix_copy_c), + + MAKE(1, MASK_MONO, 2, MASK_STEREO, channelmix_f32_1_2_c), + MAKE(2, MASK_STEREO, 1, MASK_MONO, channelmix_f32_2_1_c), + MAKE(4, MASK_QUAD, 1, MASK_MONO, channelmix_f32_4_1_c), + MAKE(4, MASK_3_1, 1, MASK_MONO, channelmix_f32_4_1_c), + MAKE(2, MASK_STEREO, 4, MASK_QUAD, channelmix_f32_2_4_c), + MAKE(2, MASK_STEREO, 4, MASK_3_1, channelmix_f32_2_3p1_c), + MAKE(2, MASK_STEREO, 6, MASK_5_1, channelmix_f32_2_5p1_c), + MAKE(2, MASK_STEREO, 8, MASK_7_1, channelmix_f32_2_7p1_c), #if defined (HAVE_SSE) - { 2, MASK_STEREO, 4, MASK_QUAD, channelmix_f32_2_4_sse, SPA_CPU_FLAG_SSE, "f32_2_4_sse" }, + MAKE(4, MASK_3_1, 2, MASK_STEREO, channelmix_f32_3p1_2_sse, SPA_CPU_FLAG_SSE), #endif - { 2, MASK_STEREO, 4, MASK_QUAD, channelmix_f32_2_4_c, 0, "f32_2_4_c" }, - { 2, MASK_STEREO, 4, MASK_3_1, channelmix_f32_2_3p1_c, 0, "f32_2_3p1_c" }, - { 2, MASK_STEREO, 6, MASK_5_1, channelmix_f32_2_5p1_c, 0, "f32_2_5p1_c" }, - { 2, MASK_STEREO, 8, MASK_7_1, channelmix_f32_2_7p1_c, 0, "f32_2_7p1_c" }, + MAKE(4, MASK_3_1, 2, MASK_STEREO, channelmix_f32_3p1_2_c), #if defined (HAVE_SSE) - { 6, MASK_5_1, 2, MASK_STEREO, channelmix_f32_5p1_2_sse, SPA_CPU_FLAG_SSE, "f32_5p1_2_sse" }, + MAKE(6, MASK_5_1, 2, MASK_STEREO, channelmix_f32_5p1_2_sse, SPA_CPU_FLAG_SSE), #endif - { 6, MASK_5_1, 2, MASK_STEREO, channelmix_f32_5p1_2_c, 0, "f32_5p1_2_c" }, + MAKE(6, MASK_5_1, 2, MASK_STEREO, channelmix_f32_5p1_2_c), #if defined (HAVE_SSE) - { 6, MASK_5_1, 4, MASK_QUAD, channelmix_f32_5p1_4_sse, SPA_CPU_FLAG_SSE, "f32_5p1_4_sse" }, + MAKE(6, MASK_5_1, 4, MASK_QUAD, channelmix_f32_5p1_4_sse, SPA_CPU_FLAG_SSE), #endif - { 6, MASK_5_1, 4, MASK_QUAD, channelmix_f32_5p1_4_c, 0, "f32_5p1_4_c" }, + MAKE(6, MASK_5_1, 4, MASK_QUAD, channelmix_f32_5p1_4_c), #if defined (HAVE_SSE) - { 6, MASK_5_1, 4, MASK_3_1, channelmix_f32_5p1_3p1_sse, SPA_CPU_FLAG_SSE, "f32_5p1_3p1_sse" }, + MAKE(6, MASK_5_1, 4, MASK_3_1, channelmix_f32_5p1_3p1_sse, SPA_CPU_FLAG_SSE), #endif - { 6, MASK_5_1, 4, MASK_3_1, channelmix_f32_5p1_3p1_c, 0, "f32_5p1_3p1_c" }, + MAKE(6, MASK_5_1, 4, MASK_3_1, channelmix_f32_5p1_3p1_c), - { 8, MASK_7_1, 2, MASK_STEREO, channelmix_f32_7p1_2_c, 0, "f32_7p1_2_c" }, - { 8, MASK_7_1, 4, MASK_QUAD, channelmix_f32_7p1_4_c, 0, "f32_7p1_4_c" }, - { 8, MASK_7_1, 4, MASK_3_1, channelmix_f32_7p1_3p1_c, 0, "f32_7p1_3p1_c" }, + MAKE(8, MASK_7_1, 2, MASK_STEREO, channelmix_f32_7p1_2_c), + MAKE(8, MASK_7_1, 4, MASK_QUAD, channelmix_f32_7p1_4_c), + MAKE(8, MASK_7_1, 4, MASK_3_1, channelmix_f32_7p1_3p1_c), - { ANY, 0, ANY, 0, channelmix_f32_n_m_c, 0, "f32_n_m_c" }, + MAKE(ANY, 0, ANY, 0, channelmix_f32_n_m_c), }; +#undef MAKE #define MATCH_CHAN(a,b) ((a) == ANY || (a) == (b)) #define MATCH_CPU_FLAGS(a,b) ((a) == 0 || ((a) & (b)) == a) @@ -426,8 +429,8 @@ _MATRIX(SR,RR) += 1.0f; } else if ((src_mask & STEREO) == STEREO) { spa_log_debug(mix->log, "produce SIDE from STEREO"); - _MATRIX(SL,FL) += 1.0f; - _MATRIX(SR,FR) += 1.0f; + _MATRIX(SL,FL) += slev; + _MATRIX(SR,FR) += slev; } else if ((src_mask & FRONT) == FRONT) { spa_log_debug(mix->log, "produce SIDE from FC"); _MATRIX(SL,FC) += clev; @@ -441,8 +444,8 @@ _MATRIX(RR,SR) += 1.0f; } else if ((src_mask & STEREO) == STEREO) { spa_log_debug(mix->log, "produce REAR from STEREO"); - _MATRIX(RL,FL) += 1.0f; - _MATRIX(RR,FR) += 1.0f; + _MATRIX(RL,FL) += slev; + _MATRIX(RR,FR) += slev; } else if ((src_mask & FRONT) == FRONT) { spa_log_debug(mix->log, "produce REAR from FC"); _MATRIX(RL,FC) += clev; @@ -551,6 +554,10 @@ { const struct channelmix_info *info; + if (mix->src_chan > SPA_AUDIO_MAX_CHANNELS || + mix->dst_chan > SPA_AUDIO_MAX_CHANNELS) + return -EINVAL; + info = find_channelmix_info(mix->src_chan, mix->src_mask, mix->dst_chan, mix->dst_mask, mix->cpu_flags); if (info == NULL) @@ -561,6 +568,7 @@ mix->set_volume = impl_channelmix_set_volume; mix->cpu_flags = info->cpu_flags; mix->delay = mix->rear_delay * mix->freq / 1000.0f; + mix->func_name = info->name; spa_log_debug(mix->log, "selected %s delay:%d options:%08x", info->name, mix->delay, mix->options);
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/channelmix-ops.h -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/channelmix-ops.h
Changed
@@ -29,10 +29,6 @@ #include <spa/utils/string.h> #include <spa/param/audio/raw.h> -#undef SPA_LOG_TOPIC_DEFAULT -#define SPA_LOG_TOPIC_DEFAULT log_topic -extern struct spa_log_topic *log_topic; - #include "crossover.h" #include "delay.h" @@ -48,8 +44,6 @@ #define MASK_7_1 _M(FL)|_M(FR)|_M(FC)|_M(LFE)|_M(SL)|_M(SR)|_M(RL)|_M(RR) #define BUFFER_SIZE 4096 - -#define BUFFER_SIZE 4096 #define MAX_TAPS 255 struct channelmix { @@ -62,12 +56,13 @@ #define CHANNELMIX_OPTION_NORMALIZE (1<<1) /**< normalize volumes */ #define CHANNELMIX_OPTION_UPMIX (1<<2) /**< do simple upmixing */ uint32_t options; -#define CHANNELMIX_UPMIX_NONE (0) /**< disable upmixing */ -#define CHANNELMIX_UPMIX_SIMPLE (1) /**< simple upmixing */ -#define CHANNELMIX_UPMIX_PSD (2) /**< Passive Surround Decoding upmixing */ +#define CHANNELMIX_UPMIX_NONE 0 /**< disable upmixing */ +#define CHANNELMIX_UPMIX_SIMPLE 1 /**< simple upmixing */ +#define CHANNELMIX_UPMIX_PSD 2 /**< Passive Surround Decoding upmixing */ uint32_t upmix; struct spa_log *log; + const char *func_name; #define CHANNELMIX_FLAG_ZERO (1<<0) /**< all zero components */ #define CHANNELMIX_FLAG_IDENTITY (1<<1) /**< identity matrix */ @@ -142,6 +137,7 @@ DEFINE_FUNCTION(f32_2_3p1, c); DEFINE_FUNCTION(f32_2_5p1, c); DEFINE_FUNCTION(f32_2_7p1, c); +DEFINE_FUNCTION(f32_3p1_2, c); DEFINE_FUNCTION(f32_5p1_2, c); DEFINE_FUNCTION(f32_5p1_3p1, c); DEFINE_FUNCTION(f32_5p1_4, c); @@ -151,9 +147,11 @@ #if defined (HAVE_SSE) DEFINE_FUNCTION(copy, sse); -DEFINE_FUNCTION(f32_2_4, sse); +DEFINE_FUNCTION(f32_3p1_2, sse); DEFINE_FUNCTION(f32_5p1_2, sse); DEFINE_FUNCTION(f32_5p1_3p1, sse); DEFINE_FUNCTION(f32_5p1_4, sse); DEFINE_FUNCTION(f32_7p1_4, sse); #endif + +#undef DEFINE_FUNCTION
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/fmt-ops-avx2.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/fmt-ops-avx2.c
Changed
@@ -41,7 +41,7 @@ const int16_t *s = src; float *d0 = dst0; uint32_t n, unrolled; - __m256i in; + __m256i in = _mm256_setzero_si256(); __m256 out, factor = _mm256_set1_ps(1.0f / S16_SCALE); if (SPA_LIKELY(SPA_IS_ALIGNED(d0, 32))) @@ -67,7 +67,7 @@ } for(; n < n_samples; n++) { __m128 out, factor = _mm_set1_ps(1.0f / S16_SCALE); - out = _mm_cvtsi32_ss(out, s0); + out = _mm_cvtsi32_ss(factor, s0); out = _mm_mul_ss(out, factor); _mm_store_ss(&d0n, out); s += n_channels; @@ -133,9 +133,9 @@ } for(; n < n_samples; n++) { __m128 out4, factor = _mm_set1_ps(1.0f / S16_SCALE); - out0 = _mm_cvtsi32_ss(out0, s0); + out0 = _mm_cvtsi32_ss(factor, s0); out0 = _mm_mul_ss(out0, factor); - out1 = _mm_cvtsi32_ss(out1, s1); + out1 = _mm_cvtsi32_ss(factor, s1); out1 = _mm_mul_ss(out1, factor); _mm_store_ss(&d0n, out0); _mm_store_ss(&d1n, out1); @@ -175,7 +175,7 @@ s += 12 * n_channels; } for(; n < n_samples; n++) { - out = _mm_cvtsi32_ss(out, read_s24(s)); + out = _mm_cvtsi32_ss(factor, read_s24(s)); out = _mm_mul_ss(out, factor); _mm_store_ss(&d0n, out); s += 3 * n_channels; @@ -232,8 +232,8 @@ s += 12 * n_channels; } for(; n < n_samples; n++) { - out0 = _mm_cvtsi32_ss(out0, read_s24(s)); - out1 = _mm_cvtsi32_ss(out1, read_s24(s+3)); + out0 = _mm_cvtsi32_ss(factor, read_s24(s)); + out1 = _mm_cvtsi32_ss(factor, read_s24(s+3)); out0 = _mm_mul_ss(out0, factor); out1 = _mm_mul_ss(out1, factor); _mm_store_ss(&d0n, out0); @@ -313,10 +313,10 @@ s += 12 * n_channels; } for(; n < n_samples; n++) { - out0 = _mm_cvtsi32_ss(out0, read_s24(s)); - out1 = _mm_cvtsi32_ss(out1, read_s24(s+3)); - out2 = _mm_cvtsi32_ss(out2, read_s24(s+6)); - out3 = _mm_cvtsi32_ss(out3, read_s24(s+9)); + out0 = _mm_cvtsi32_ss(factor, read_s24(s)); + out1 = _mm_cvtsi32_ss(factor, read_s24(s+3)); + out2 = _mm_cvtsi32_ss(factor, read_s24(s+6)); + out3 = _mm_cvtsi32_ss(factor, read_s24(s+9)); out0 = _mm_mul_ss(out0, factor); out1 = _mm_mul_ss(out1, factor); out2 = _mm_mul_ss(out2, factor); @@ -406,10 +406,10 @@ } for(; n < n_samples; n++) { __m128 out4, factor = _mm_set1_ps(1.0f / S24_SCALE); - out0 = _mm_cvtsi32_ss(out0, s0>>8); - out1 = _mm_cvtsi32_ss(out1, s1>>8); - out2 = _mm_cvtsi32_ss(out2, s2>>8); - out3 = _mm_cvtsi32_ss(out3, s3>>8); + out0 = _mm_cvtsi32_ss(factor, s0>>8); + out1 = _mm_cvtsi32_ss(factor, s1>>8); + out2 = _mm_cvtsi32_ss(factor, s2>>8); + out3 = _mm_cvtsi32_ss(factor, s3>>8); out0 = _mm_mul_ss(out0, factor); out1 = _mm_mul_ss(out1, factor); out2 = _mm_mul_ss(out2, factor); @@ -467,8 +467,8 @@ } for(; n < n_samples; n++) { __m128 out2, factor = _mm_set1_ps(1.0f / S24_SCALE); - out0 = _mm_cvtsi32_ss(out0, s0>>8); - out1 = _mm_cvtsi32_ss(out1, s1>>8); + out0 = _mm_cvtsi32_ss(factor, s0>>8); + out1 = _mm_cvtsi32_ss(factor, s1>>8); out0 = _mm_mul_ss(out0, factor); out1 = _mm_mul_ss(out1, factor); _mm_store_ss(&d0n, out0); @@ -518,7 +518,7 @@ } for(; n < n_samples; n++) { __m128 out, factor = _mm_set1_ps(1.0f / S24_SCALE); - out = _mm_cvtsi32_ss(out, s0>>8); + out = _mm_cvtsi32_ss(factor, s0>>8); out = _mm_mul_ss(out, factor); _mm_store_ss(&d0n, out); s += n_channels; @@ -550,7 +550,7 @@ __m128 in1; __m128i out4; __m128 scale = _mm_set1_ps(S32_SCALE); - __m128 int_min = _mm_set1_ps(S32_MIN); + __m128 int_max = _mm_set1_ps(S32_MAX); if (SPA_IS_ALIGNED(s0, 16)) unrolled = n_samples & ~3; @@ -559,7 +559,7 @@ for(n = 0; n < unrolled; n += 4) { in0 = _mm_mul_ps(_mm_load_ps(&s0n), scale); - in0 = _mm_min_ps(in0, int_min); + in0 = _mm_min_ps(in0, int_max); out0 = _mm_cvtps_epi32(in0); out1 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(0, 3, 2, 1)); out2 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(1, 0, 3, 2)); @@ -574,7 +574,7 @@ for(; n < n_samples; n++) { in0 = _mm_load_ss(&s0n); in0 = _mm_mul_ss(in0, scale); - in0 = _mm_min_ss(in0, int_min); + in0 = _mm_min_ss(in0, int_max); *d = _mm_cvtss_si32(in0); d += n_channels; } @@ -590,7 +590,7 @@ __m256 in2; __m256i out2, t2; __m256 scale = _mm256_set1_ps(S32_SCALE); - __m256 int_min = _mm256_set1_ps(S32_MIN); + __m256 int_max = _mm256_set1_ps(S32_MAX); if (SPA_IS_ALIGNED(s0, 32) && SPA_IS_ALIGNED(s1, 32)) @@ -602,8 +602,8 @@ in0 = _mm256_mul_ps(_mm256_load_ps(&s0n), scale); in1 = _mm256_mul_ps(_mm256_load_ps(&s1n), scale); - in0 = _mm256_min_ps(in0, int_min); - in1 = _mm256_min_ps(in1, int_min); + in0 = _mm256_min_ps(in0, int_max); + in1 = _mm256_min_ps(in1, int_max); out0 = _mm256_cvtps_epi32(in0); /* a0 a1 a2 a3 a4 a5 a6 a7 */ out1 = _mm256_cvtps_epi32(in1); /* b0 b1 b2 b3 b4 b5 b6 b7 */ @@ -636,7 +636,7 @@ __m128 in2; __m128i out2; __m128 scale = _mm_set1_ps(S32_SCALE); - __m128 int_min = _mm_set1_ps(S32_MIN); + __m128 int_max = _mm_set1_ps(S32_MAX); in0 = _mm_load_ss(&s0n); in1 = _mm_load_ss(&s1n); @@ -644,7 +644,7 @@ in0 = _mm_unpacklo_ps(in0, in1); in0 = _mm_mul_ps(in0, scale); - in0 = _mm_min_ps(in0, int_min); + in0 = _mm_min_ps(in0, int_max); out0 = _mm_cvtps_epi32(in0); _mm_storel_epi64((__m128i*)d, out0); d += n_channels; @@ -661,7 +661,7 @@ __m256 in4; __m256i out4, t4; __m256 scale = _mm256_set1_ps(S32_SCALE); - __m256 int_min = _mm256_set1_ps(S32_MIN); + __m256 int_max = _mm256_set1_ps(S32_MAX); if (SPA_IS_ALIGNED(s0, 32) && SPA_IS_ALIGNED(s1, 32) && @@ -677,10 +677,10 @@ in2 = _mm256_mul_ps(_mm256_load_ps(&s2n), scale); in3 = _mm256_mul_ps(_mm256_load_ps(&s3n), scale); - in0 = _mm256_min_ps(in0, int_min); - in1 = _mm256_min_ps(in1, int_min); - in2 = _mm256_min_ps(in2, int_min); - in3 = _mm256_min_ps(in3, int_min); + in0 = _mm256_min_ps(in0, int_max); + in1 = _mm256_min_ps(in1, int_max); + in2 = _mm256_min_ps(in2, int_max); + in3 = _mm256_min_ps(in3, int_max); out0 = _mm256_cvtps_epi32(in0); /* a0 a1 a2 a3 a4 a5 a6 a7 */ out1 = _mm256_cvtps_epi32(in1); /* b0 b1 b2 b3 b4 b5 b6 b7 */ @@ -711,7 +711,7 @@ __m128 in4; __m128i out4; __m128 scale = _mm_set1_ps(S32_SCALE); - __m128 int_min = _mm_set1_ps(S32_MIN); + __m128 int_max = _mm_set1_ps(S32_MAX); in0 = _mm_load_ss(&s0n); in1 = _mm_load_ss(&s1n); @@ -723,7 +723,7 @@ in0 = _mm_unpacklo_ps(in0, in1); in0 = _mm_mul_ps(in0, scale); - in0 = _mm_min_ps(in0, int_min); + in0 = _mm_min_ps(in0, int_max); out0 = _mm_cvtps_epi32(in0); _mm_storeu_si128((__m128i*)d, out0); d += n_channels;
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/fmt-ops-c.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/fmt-ops-c.c
Changed
@@ -736,6 +736,43 @@ } } +static inline int32_t +lcnoise(uint32_t *state) +{ + *state = (*state * 96314165) + 907633515; + return (int32_t)(*state); +} + +static inline void update_dither_c(struct convert *conv, uint32_t n_samples) +{ + uint32_t n; + float *dither = conv->dither, scale = conv->scale; + uint32_t *state = &conv->random0; + + for (n = 0; n < n_samples; n++) + dithern = lcnoise(state) * scale; +} + +#define SHAPER5(type,s,scale,offs,sh,min,max,d) \ +({ \ + type t; \ + float v = s * scale + offs + \ + - sh->eidx * 2.033f \ + + sh->e(idx - 1) & NS_MASK * 2.165f \ + - sh->e(idx - 2) & NS_MASK * 1.959f \ + + sh->e(idx - 3) & NS_MASK * 1.590f \ + - sh->e(idx - 4) & NS_MASK * 0.6149f; \ + t = (type)SPA_CLAMP(v + d, min, max); \ + idx = (idx + 1) & NS_MASK; \ + sh->eidx = t - v; \ + t; \ +}) + +#define F32_TO_U8_SH(s,sh,d) SHAPER5(uint8_t, s, U8_SCALE, U8_OFFS, sh, U8_MIN, U8_MAX, d) +#define F32_TO_S8_SH(s,sh,d) SHAPER5(int8_t, s, S8_SCALE, 0, sh, S8_MIN, S8_MAX, d) +#define F32_TO_S16_SH(s,sh,d) SHAPER5(int16_t, s, S16_SCALE, 0, sh, S16_MIN, S16_MAX, d) +#define F32_TO_S16S_SH(s,sh,d) bswap_16(F32_TO_S16_SH(s,sh,d)) + void conv_f32d_to_u8d_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) @@ -752,6 +789,51 @@ } void +conv_f32d_to_u8d_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + uint8_t *d = dsti; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj = F32_TO_U8_D(sj, ditherk); + } + } +} + +void +conv_f32d_to_u8d_shaped_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + uint8_t *d = dsti; + struct shaper *sh = &conv->shaperi; + uint32_t idx = sh->idx; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj = F32_TO_U8_SH(sj, sh, ditherk); + } + sh->idx = idx; + } +} + +void conv_f32_to_u8_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -794,6 +876,51 @@ } void +conv_f32d_to_u8_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + const float **s = (const float **) src; + uint8_t *d = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) { + for (i = 0; i < n_channels; i++) + *d++ = F32_TO_U8_D(sij, ditherk); + } + } +} + +void +conv_f32d_to_u8_shaped_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + uint8_t *d0 = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + uint8_t *d = &d0i; + struct shaper *sh = &conv->shaperi; + uint32_t idx = sh->idx; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj * n_channels = F32_TO_U8_SH(sj, sh, ditherk); + } + sh->idx = idx; + } +} + +void conv_f32d_to_s8d_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -809,6 +936,51 @@ } void +conv_f32d_to_s8d_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + int8_t *d = dsti; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj = F32_TO_S8_D(sj, ditherk); + } + } +} + +void +conv_f32d_to_s8d_shaped_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + int8_t *d = dsti; + struct shaper *sh = &conv->shaperi; + uint32_t idx = sh->idx; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj = F32_TO_S8_SH(sj, sh, ditherk); + } + sh->idx = idx; + } +} + +void conv_f32_to_s8_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -851,6 +1023,51 @@ } void +conv_f32d_to_s8_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + const float **s = (const float **) src; + int8_t *d = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) { + for (i = 0; i < n_channels; i++) + *d++ = F32_TO_S8_D(sij, ditherk); + } + } +} + +void +conv_f32d_to_s8_shaped_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + int8_t *d0 = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + int8_t *d = &d0i; + struct shaper *sh = &conv->shaperi; + uint32_t idx = sh->idx; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj * n_channels = F32_TO_S8_SH(sj, sh, ditherk); + } + sh->idx = idx; + } +} + +void conv_f32d_to_alaw_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -921,6 +1138,52 @@ } void +conv_f32d_to_s16d_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + int16_t *d = dsti; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj = F32_TO_S16_D(sj, ditherk); + } + } +} + + +void +conv_f32d_to_s16d_shaped_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + int16_t *d = dsti; + struct shaper *sh = &conv->shaperi; + uint32_t idx = sh->idx; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj = F32_TO_S16_SH(sj, sh, ditherk); + } + sh->idx = idx; + } +} + +void conv_f32_to_s16_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -963,6 +1226,51 @@ } void +conv_f32d_to_s16_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + const float **s = (const float **) src; + int16_t *d = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) { + for (i = 0; i < n_channels; i++) + *d++ = F32_TO_S16_D(sij, ditherk); + } + } +} + +void +conv_f32d_to_s16_shaped_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + int16_t *d0 = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + int16_t *d = &d0i; + struct shaper *sh = &conv->shaperi; + uint32_t idx = sh->idx; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj * n_channels = F32_TO_S16_SH(sj, sh, ditherk); + } + sh->idx = idx; + } +} + +void conv_f32d_to_s16s_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -977,6 +1285,50 @@ } void +conv_f32d_to_s16s_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + const float **s = (const float **) src; + uint16_t *d = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) { + for (i = 0; i < n_channels; i++) + *d++ = F32_TO_S16S_D(sij, ditherk); + } + } +} + +void +conv_f32d_to_s16s_shaped_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + int16_t *d0 = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + int16_t *d = &d0i; + struct shaper *sh = &conv->shaperi; + uint32_t idx = sh->idx; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj * n_channels = F32_TO_S16S_SH(sj, sh, ditherk); + } + sh->idx = idx; + } +} +void conv_f32_to_u32_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -1020,6 +1372,27 @@ } void +conv_f32d_to_s32d_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + int32_t *d = dsti; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj = F32_TO_S32_D(sj, ditherk); + } + } +} + +void conv_f32_to_s32_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -1062,11 +1435,31 @@ } void -conv_f32d_to_s32s_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, +conv_f32d_to_s32_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { const float **s = (const float **) src; int32_t *d = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) { + for (i = 0; i < n_channels; i++) + *d++ = F32_TO_S32_D(sij, ditherk); + } + } +} + +void +conv_f32d_to_s32s_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + const float **s = (const float **) src; + uint32_t *d = dst0; uint32_t i, j, n_channels = conv->n_channels; for (j = 0; j < n_samples; j++) { @@ -1076,6 +1469,26 @@ } void +conv_f32d_to_s32s_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + const float **s = (const float **) src; + uint32_t *d = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) { + for (i = 0; i < n_channels; i++) + *d++ = F32_TO_S32S_D(sij, ditherk); + } + } +} + +void conv_f32d_to_f64d_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -1196,6 +1609,29 @@ } void +conv_f32d_to_s24d_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + uint8_t *d = dsti; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) { + write_s24(d, F32_TO_S24_D(sj, ditherk)); + d += 3; + } + } + } +} + +void conv_f32_to_s24_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -1243,6 +1679,28 @@ } void +conv_f32d_to_s24_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + const float **s = (const float **) src; + uint8_t *d = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) { + for (i = 0; i < n_channels; i++) { + write_s24(d, F32_TO_S24_D(sij, ditherk)); + d += 3; + } + } + } +} + +void conv_f32d_to_s24s_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -1258,6 +1716,27 @@ } } +void +conv_f32d_to_s24s_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + const float **s = (const float **) src; + uint8_t *d = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) { + for (i = 0; i < n_channels; i++) { + write_s24s(d, F32_TO_S24_D(sij, ditherk)); + d += 3; + } + } + } +} void conv_f32d_to_s24_32d_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, @@ -1275,6 +1754,27 @@ } void +conv_f32d_to_s24_32d_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (i = 0; i < n_channels; i++) { + const float *s = srci; + int32_t *d = dsti; + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) + dj = F32_TO_S24_32_D(sj, ditherk); + } + } +} + +void conv_f32_to_u24_32_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -1345,6 +1845,26 @@ } void +conv_f32d_to_s24_32_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + const float **s = (const float **) src; + int32_t *d = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) { + for (i = 0; i < n_channels; i++) + *d++ = F32_TO_S24_32_D(sij, ditherk); + } + } +} + +void conv_f32d_to_s24_32s_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) { @@ -1359,6 +1879,26 @@ } void +conv_f32d_to_s24_32s_dither_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + const float **s = (const float **) src; + int32_t *d = dst0; + uint32_t i, j, k, chunk, n_channels = conv->n_channels, dither_size = conv->dither_size; + float *dither = conv->dither; + + update_dither_c(conv, SPA_MIN(n_samples, dither_size)); + + for (j = 0; j < n_samples;) { + chunk = SPA_MIN(n_samples - j, dither_size); + for (k = 0; k < chunk; k++, j++) { + for (i = 0; i < n_channels; i++) + *d++ = F32_TO_S24_32S_D(sij, ditherk); + } + } +} + +void conv_deinterleave_8_c(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples) {
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/fmt-ops-sse2.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/fmt-ops-sse2.c
Changed
@@ -33,7 +33,7 @@ const int16_t *s = src; float *d0 = dst0; uint32_t n, unrolled; - __m128i in; + __m128i in = _mm_setzero_si128(); __m128 out, factor = _mm_set1_ps(1.0f / S16_SCALE); if (SPA_LIKELY(SPA_IS_ALIGNED(d0, 16))) @@ -53,7 +53,7 @@ s += 4*n_channels; } for(; n < n_samples; n++) { - out = _mm_cvtsi32_ss(out, s0); + out = _mm_cvtsi32_ss(factor, s0); out = _mm_mul_ss(out, factor); _mm_store_ss(&d0n, out); s += n_channels; @@ -118,9 +118,9 @@ s += 16; } for(; n < n_samples; n++) { - out0 = _mm_cvtsi32_ss(out0, s0); + out0 = _mm_cvtsi32_ss(factor, s0); out0 = _mm_mul_ss(out0, factor); - out1 = _mm_cvtsi32_ss(out1, s1); + out1 = _mm_cvtsi32_ss(factor, s1); out1 = _mm_mul_ss(out1, factor); _mm_store_ss(&d0n, out0); _mm_store_ss(&d1n, out1); @@ -160,7 +160,7 @@ s += 12 * n_channels; } for(; n < n_samples; n++) { - out = _mm_cvtsi32_ss(out, read_s24(s)); + out = _mm_cvtsi32_ss(factor, read_s24(s)); out = _mm_mul_ss(out, factor); _mm_store_ss(&d0n, out); s += 3 * n_channels; @@ -217,8 +217,8 @@ s += 12 * n_channels; } for(; n < n_samples; n++) { - out0 = _mm_cvtsi32_ss(out0, read_s24(s)); - out1 = _mm_cvtsi32_ss(out1, read_s24(s+3)); + out0 = _mm_cvtsi32_ss(factor, read_s24(s)); + out1 = _mm_cvtsi32_ss(factor, read_s24(s+3)); out0 = _mm_mul_ss(out0, factor); out1 = _mm_mul_ss(out1, factor); _mm_store_ss(&d0n, out0); @@ -298,10 +298,10 @@ s += 12 * n_channels; } for(; n < n_samples; n++) { - out0 = _mm_cvtsi32_ss(out0, read_s24(s)); - out1 = _mm_cvtsi32_ss(out1, read_s24(s+3)); - out2 = _mm_cvtsi32_ss(out2, read_s24(s+6)); - out3 = _mm_cvtsi32_ss(out3, read_s24(s+9)); + out0 = _mm_cvtsi32_ss(factor, read_s24(s)); + out1 = _mm_cvtsi32_ss(factor, read_s24(s+3)); + out2 = _mm_cvtsi32_ss(factor, read_s24(s+6)); + out3 = _mm_cvtsi32_ss(factor, read_s24(s+9)); out0 = _mm_mul_ss(out0, factor); out1 = _mm_mul_ss(out1, factor); out2 = _mm_mul_ss(out2, factor); @@ -357,7 +357,7 @@ s += 4*n_channels; } for(; n < n_samples; n++) { - out = _mm_cvtsi32_ss(out, s0>>8); + out = _mm_cvtsi32_ss(factor, s0>>8); out = _mm_mul_ss(out, factor); _mm_store_ss(&d0n, out); s += n_channels; @@ -385,7 +385,7 @@ __m128 in1; __m128i out4; __m128 scale = _mm_set1_ps(S32_SCALE); - __m128 int_min = _mm_set1_ps(S32_MIN); + __m128 int_max = _mm_set1_ps(S32_MAX); if (SPA_IS_ALIGNED(s0, 16)) unrolled = n_samples & ~3; @@ -394,7 +394,7 @@ for(n = 0; n < unrolled; n += 4) { in0 = _mm_mul_ps(_mm_load_ps(&s0n), scale); - in0 = _mm_min_ps(in0, int_min); + in0 = _mm_min_ps(in0, int_max); out0 = _mm_cvtps_epi32(in0); out1 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(0, 3, 2, 1)); out2 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(1, 0, 3, 2)); @@ -409,7 +409,7 @@ for(; n < n_samples; n++) { in0 = _mm_load_ss(&s0n); in0 = _mm_mul_ss(in0, scale); - in0 = _mm_min_ss(in0, int_min); + in0 = _mm_min_ss(in0, int_max); *d = _mm_cvtss_si32(in0); d += n_channels; } @@ -425,7 +425,7 @@ __m128 in2; __m128i out2, t2; __m128 scale = _mm_set1_ps(S32_SCALE); - __m128 int_min = _mm_set1_ps(S32_MIN); + __m128 int_max = _mm_set1_ps(S32_MAX); if (SPA_IS_ALIGNED(s0, 16) && SPA_IS_ALIGNED(s1, 16)) @@ -437,8 +437,8 @@ in0 = _mm_mul_ps(_mm_load_ps(&s0n), scale); in1 = _mm_mul_ps(_mm_load_ps(&s1n), scale); - in0 = _mm_min_ps(in0, int_min); - in1 = _mm_min_ps(in1, int_min); + in0 = _mm_min_ps(in0, int_max); + in1 = _mm_min_ps(in1, int_max); out0 = _mm_cvtps_epi32(in0); out1 = _mm_cvtps_epi32(in1); @@ -459,7 +459,7 @@ in0 = _mm_unpacklo_ps(in0, in1); in0 = _mm_mul_ps(in0, scale); - in0 = _mm_min_ps(in0, int_min); + in0 = _mm_min_ps(in0, int_max); out0 = _mm_cvtps_epi32(in0); _mm_storel_epi64((__m128i*)d, out0); d += n_channels; @@ -476,7 +476,7 @@ __m128 in4; __m128i out4; __m128 scale = _mm_set1_ps(S32_SCALE); - __m128 int_min = _mm_set1_ps(S32_MIN); + __m128 int_max = _mm_set1_ps(S32_MAX); if (SPA_IS_ALIGNED(s0, 16) && SPA_IS_ALIGNED(s1, 16) && @@ -492,10 +492,10 @@ in2 = _mm_mul_ps(_mm_load_ps(&s2n), scale); in3 = _mm_mul_ps(_mm_load_ps(&s3n), scale); - in0 = _mm_min_ps(in0, int_min); - in1 = _mm_min_ps(in1, int_min); - in2 = _mm_min_ps(in2, int_min); - in3 = _mm_min_ps(in3, int_min); + in0 = _mm_min_ps(in0, int_max); + in1 = _mm_min_ps(in1, int_max); + in2 = _mm_min_ps(in2, int_max); + in3 = _mm_min_ps(in3, int_max); _MM_TRANSPOSE4_PS(in0, in1, in2, in3); @@ -521,7 +521,7 @@ in0 = _mm_unpacklo_ps(in0, in1); in0 = _mm_mul_ps(in0, scale); - in0 = _mm_min_ps(in0, int_min); + in0 = _mm_min_ps(in0, int_max); out0 = _mm_cvtps_epi32(in0); _mm_storeu_si128((__m128i*)d, out0); d += n_channels; @@ -543,6 +543,92 @@ conv_f32d_to_s32_1s_sse2(conv, &di, &srci, n_channels, n_samples); } +static inline void update_dither_sse2(struct convert *conv, uint32_t n_samples) +{ + uint32_t n; + const uint32_t *r = SPA_PTR_ALIGN(conv->random, 16, uint32_t); + float *dither = SPA_PTR_ALIGN(conv->dither, 16, float); + __m128 scale = _mm_set1_ps(conv->scale), out1; + __m128i in1, t1; + + for (n = 0; n < n_samples; n += 4) { + /* 32 bit xorshift PRNG, see https://en.wikipedia.org/wiki/Xorshift */ + in0 = _mm_load_si128((__m128i*)r); + t0 = _mm_slli_epi32(in0, 13); + in0 = _mm_xor_si128(in0, t0); + t0 = _mm_srli_epi32(in0, 17); + in0 = _mm_xor_si128(in0, t0); + t0 = _mm_slli_epi32(in0, 5); + in0 = _mm_xor_si128(in0, t0); + _mm_store_si128((__m128i*)r, in0); + + out0 = _mm_cvtepi32_ps(in0); + out0 = _mm_mul_ps(out0, scale); + _mm_store_ps(&dithern, out0); + } +} + +static void +conv_f32d_to_s32_1s_dither_sse2(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_channels, uint32_t n_samples) +{ + const float *s = src; + float *dither = SPA_PTR_ALIGN(conv->dither, 16, float); + int32_t *d = dst; + uint32_t n, unrolled; + __m128 in1; + __m128i out4; + __m128 scale = _mm_set1_ps(S32_SCALE); + __m128 int_max = _mm_set1_ps(S32_MAX); + + if (SPA_IS_ALIGNED(s, 16)) + unrolled = n_samples & ~3; + else + unrolled = 0; + + for(n = 0; n < unrolled; n += 4) { + in0 = _mm_mul_ps(_mm_load_ps(&sn), scale); + in0 = _mm_add_ps(in0, _mm_load_ps(&dithern)); + in0 = _mm_min_ps(in0, int_max); + out0 = _mm_cvtps_epi32(in0); + out1 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(0, 3, 2, 1)); + out2 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(1, 0, 3, 2)); + out3 = _mm_shuffle_epi32(out0, _MM_SHUFFLE(2, 1, 0, 3)); + + d0*n_channels = _mm_cvtsi128_si32(out0); + d1*n_channels = _mm_cvtsi128_si32(out1); + d2*n_channels = _mm_cvtsi128_si32(out2); + d3*n_channels = _mm_cvtsi128_si32(out3); + d += 4*n_channels; + } + for(; n < n_samples; n++) { + in0 = _mm_load_ss(&sn); + in0 = _mm_mul_ss(in0, scale); + in0 = _mm_add_ss(in0, _mm_load_ss(&dithern)); + in0 = _mm_min_ss(in0, int_max); + *d = _mm_cvtss_si32(in0); + d += n_channels; + } +} + +void +conv_f32d_to_s32_dither_sse2(struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, + uint32_t n_samples) +{ + int32_t *d = dst0; + uint32_t i, k, chunk, n_channels = conv->n_channels; + + update_dither_sse2(conv, SPA_MIN(n_samples, conv->dither_size)); + + for(i = 0; i < n_channels; i++) { + const float *s = srci; + for(k = 0; k < n_samples; k += chunk) { + chunk = SPA_MIN(n_samples - k, conv->dither_size); + conv_f32d_to_s32_1s_dither_sse2(conv, &di + k*n_channels, &sk, n_channels, chunk); + } + } +} + static void conv_interleave_32_1s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_channels, uint32_t n_samples)
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/fmt-ops-sse41.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/fmt-ops-sse41.c
Changed
@@ -33,7 +33,7 @@ const uint8_t *s = src; float *d0 = dst0; uint32_t n, unrolled; - __m128i in; + __m128i in = _mm_setzero_si128(); __m128 out, factor = _mm_set1_ps(1.0f / S24_SCALE); if (SPA_IS_ALIGNED(d0, 16)) @@ -54,7 +54,7 @@ s += 12 * n_channels; } for(; n < n_samples; n++) { - out = _mm_cvtsi32_ss(out, read_s24(s)); + out = _mm_cvtsi32_ss(factor, read_s24(s)); out = _mm_mul_ss(out, factor); _mm_store_ss(&d0n, out); s += 3 * n_channels;
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/fmt-ops-ssse3.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/fmt-ops-ssse3.c
Changed
@@ -77,10 +77,10 @@ s += 12 * n_channels; } for(; n < n_samples; n++) { - out0 = _mm_cvtsi32_ss(out0, read_s24(s)); - out1 = _mm_cvtsi32_ss(out1, read_s24(s+3)); - out2 = _mm_cvtsi32_ss(out2, read_s24(s+6)); - out3 = _mm_cvtsi32_ss(out3, read_s24(s+9)); + out0 = _mm_cvtsi32_ss(factor, read_s24(s)); + out1 = _mm_cvtsi32_ss(factor, read_s24(s+3)); + out2 = _mm_cvtsi32_ss(factor, read_s24(s+6)); + out3 = _mm_cvtsi32_ss(factor, read_s24(s+9)); out0 = _mm_mul_ss(out0, factor); out1 = _mm_mul_ss(out1, factor); out2 = _mm_mul_ss(out2, factor);
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/fmt-ops.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/fmt-ops.c
Changed
@@ -32,6 +32,8 @@ #include "fmt-ops.h" +#define DITHER_SIZE (1<<10) + typedef void (*convert_func_t) (struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples); @@ -39,277 +41,316 @@ uint32_t src_fmt; uint32_t dst_fmt; uint32_t n_channels; - uint32_t cpu_flags; convert_func_t process; + const char *name; + + uint32_t cpu_flags; +#define CONV_DITHER (1<<0) +#define CONV_SHAPE (1<<1) + uint32_t dither_flags; }; +#define MAKE(fmt1,fmt2,chan,func,...) \ + { SPA_AUDIO_FORMAT_ ##fmt1, SPA_AUDIO_FORMAT_ ##fmt2, chan, func, #func , __VA_ARGS__ } + static struct conv_info conv_table = { /* to f32 */ - { SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_F32, 0, 0, conv_u8_to_f32_c }, - { SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_u8d_to_f32d_c }, - { SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_u8_to_f32d_c }, - { SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_u8d_to_f32_c }, + MAKE(U8, F32, 0, conv_u8_to_f32_c), + MAKE(U8, F32, 0, conv_u8_to_f32_c), + MAKE(U8P, F32P, 0, conv_u8d_to_f32d_c), + MAKE(U8, F32P, 0, conv_u8_to_f32d_c), + MAKE(U8P, F32, 0, conv_u8d_to_f32_c), - { SPA_AUDIO_FORMAT_S8, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s8_to_f32_c }, - { SPA_AUDIO_FORMAT_S8P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s8d_to_f32d_c }, - { SPA_AUDIO_FORMAT_S8, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s8_to_f32d_c }, - { SPA_AUDIO_FORMAT_S8P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s8d_to_f32_c }, + MAKE(S8, F32, 0, conv_s8_to_f32_c), + MAKE(S8P, F32P, 0, conv_s8d_to_f32d_c), + MAKE(S8, F32P, 0, conv_s8_to_f32d_c), + MAKE(S8P, F32, 0, conv_s8d_to_f32_c), - { SPA_AUDIO_FORMAT_ALAW, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_alaw_to_f32d_c }, - { SPA_AUDIO_FORMAT_ULAW, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_ulaw_to_f32d_c }, + MAKE(ALAW, F32P, 0, conv_alaw_to_f32d_c), + MAKE(ULAW, F32P, 0, conv_ulaw_to_f32d_c), - { SPA_AUDIO_FORMAT_U16, SPA_AUDIO_FORMAT_F32, 0, 0, conv_u16_to_f32_c }, - { SPA_AUDIO_FORMAT_U16, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_u16_to_f32d_c }, + MAKE(U16, F32, 0, conv_u16_to_f32_c), + MAKE(U16, F32P, 0, conv_u16_to_f32d_c), - { SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s16_to_f32_c }, - { SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s16d_to_f32d_c }, + MAKE(S16, F32, 0, conv_s16_to_f32_c), + MAKE(S16P, F32P, 0, conv_s16d_to_f32d_c), #if defined (HAVE_NEON) - { SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, 2, SPA_CPU_FLAG_NEON, conv_s16_to_f32d_2_neon }, - { SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_NEON, conv_s16_to_f32d_neon }, + MAKE(S16, F32P, 2, conv_s16_to_f32d_2_neon, SPA_CPU_FLAG_NEON), + MAKE(S16, F32P, 0, conv_s16_to_f32d_neon, SPA_CPU_FLAG_NEON), #endif #if defined (HAVE_AVX2) - { SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, 2, SPA_CPU_FLAG_AVX2, conv_s16_to_f32d_2_avx2 }, - { SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_AVX2, conv_s16_to_f32d_avx2 }, + MAKE(S16, F32P, 2, conv_s16_to_f32d_2_avx2, SPA_CPU_FLAG_AVX2), + MAKE(S16, F32P, 0, conv_s16_to_f32d_avx2, SPA_CPU_FLAG_AVX2), #endif #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, 2, SPA_CPU_FLAG_SSE2, conv_s16_to_f32d_2_sse2 }, - { SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_SSE2, conv_s16_to_f32d_sse2 }, + MAKE(S16, F32P, 2, conv_s16_to_f32d_2_sse2, SPA_CPU_FLAG_SSE2), + MAKE(S16, F32P, 0, conv_s16_to_f32d_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s16_to_f32d_c }, - { SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s16d_to_f32_c }, + MAKE(S16, F32P, 0, conv_s16_to_f32d_c), + MAKE(S16P, F32, 0, conv_s16d_to_f32_c), - { SPA_AUDIO_FORMAT_S16_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s16s_to_f32d_c }, + MAKE(S16_OE, F32P, 0, conv_s16s_to_f32d_c), - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_copy32_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_copy32d_c }, + MAKE(F32, F32, 0, conv_copy32_c), + MAKE(F32P, F32P, 0, conv_copy32d_c), #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32_sse2 }, + MAKE(F32, F32P, 0, conv_deinterleave_32_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32_c }, + MAKE(F32, F32P, 0, conv_deinterleave_32_c), #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_interleave_32_sse2 }, + MAKE(F32P, F32, 0, conv_interleave_32_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_interleave_32_c }, + MAKE(F32P, F32, 0, conv_interleave_32_c), #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_F32_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32s_sse2 }, + MAKE(F32_OE, F32P, 0, conv_deinterleave_32s_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_F32_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32s_c }, + MAKE(F32_OE, F32P, 0, conv_deinterleave_32s_c), #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32_OE, 0, 0, conv_interleave_32s_sse2 }, + MAKE(F32P, F32_OE, 0, conv_interleave_32s_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32_OE, 0, 0, conv_interleave_32s_c }, + MAKE(F32P, F32_OE, 0, conv_interleave_32s_c), - { SPA_AUDIO_FORMAT_U32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_u32_to_f32_c }, - { SPA_AUDIO_FORMAT_U32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_u32_to_f32d_c }, + MAKE(U32, F32, 0, conv_u32_to_f32_c), + MAKE(U32, F32P, 0, conv_u32_to_f32d_c), #if defined (HAVE_AVX2) - { SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_AVX2, conv_s32_to_f32d_avx2 }, + MAKE(S32, F32P, 0, conv_s32_to_f32d_avx2, SPA_CPU_FLAG_AVX2), #endif #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_SSE2, conv_s32_to_f32d_sse2 }, + MAKE(S32, F32P, 0, conv_s32_to_f32d_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s32_to_f32_c }, - { SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s32d_to_f32d_c }, - { SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s32_to_f32d_c }, - { SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s32d_to_f32_c }, + MAKE(S32, F32, 0, conv_s32_to_f32_c), + MAKE(S32P, F32P, 0, conv_s32d_to_f32d_c), + MAKE(S32, F32P, 0, conv_s32_to_f32d_c), + MAKE(S32P, F32, 0, conv_s32d_to_f32_c), - { SPA_AUDIO_FORMAT_S32_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s32s_to_f32d_c }, + MAKE(S32_OE, F32P, 0, conv_s32s_to_f32d_c), - { SPA_AUDIO_FORMAT_U24, SPA_AUDIO_FORMAT_F32, 0, 0, conv_u24_to_f32_c }, - { SPA_AUDIO_FORMAT_U24, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_u24_to_f32d_c }, + MAKE(U24, F32, 0, conv_u24_to_f32_c), + MAKE(U24, F32P, 0, conv_u24_to_f32d_c), - { SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s24_to_f32_c }, - { SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24d_to_f32d_c }, + MAKE(S24, F32, 0, conv_s24_to_f32_c), + MAKE(S24P, F32P, 0, conv_s24d_to_f32d_c), #if defined (HAVE_AVX2) - { SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_AVX2, conv_s24_to_f32d_avx2 }, + MAKE(S24, F32P, 0, conv_s24_to_f32d_avx2, SPA_CPU_FLAG_AVX2), #endif #if defined (HAVE_SSSE3) -// { SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_SSSE3, conv_s24_to_f32d_ssse3 }, +// MAKE(S24, F32P, 0, conv_s24_to_f32d_ssse3, SPA_CPU_FLAG_SSSE3), #endif #if defined (HAVE_SSE41) - { SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_SSE41, conv_s24_to_f32d_sse41 }, + MAKE(S24, F32P, 0, conv_s24_to_f32d_sse41, SPA_CPU_FLAG_SSE41), #endif #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_SSE2, conv_s24_to_f32d_sse2 }, + MAKE(S24, F32P, 0, conv_s24_to_f32d_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24_to_f32d_c }, - { SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s24d_to_f32_c }, + MAKE(S24, F32P, 0, conv_s24_to_f32d_c), + MAKE(S24P, F32, 0, conv_s24d_to_f32_c), - { SPA_AUDIO_FORMAT_S24_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24s_to_f32d_c }, + MAKE(S24_OE, F32P, 0, conv_s24s_to_f32d_c), - { SPA_AUDIO_FORMAT_U24_32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_u24_32_to_f32_c }, - { SPA_AUDIO_FORMAT_U24_32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_u24_32_to_f32d_c }, + MAKE(U24_32, F32, 0, conv_u24_32_to_f32_c), + MAKE(U24_32, F32P, 0, conv_u24_32_to_f32d_c), - { SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s24_32_to_f32_c }, - { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24_32d_to_f32d_c }, - { SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24_32_to_f32d_c }, - { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s24_32d_to_f32_c }, + MAKE(S24_32, F32, 0, conv_s24_32_to_f32_c), + MAKE(S24_32P, F32P, 0, conv_s24_32d_to_f32d_c), + MAKE(S24_32, F32P, 0, conv_s24_32_to_f32d_c), + MAKE(S24_32P, F32, 0, conv_s24_32d_to_f32_c), - { SPA_AUDIO_FORMAT_S24_32_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24_32s_to_f32d_c }, + MAKE(S24_32_OE, F32P, 0, conv_s24_32s_to_f32d_c), - { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F32, 0, 0, conv_f64_to_f32_c }, - { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_f64d_to_f32d_c }, - { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_f64_to_f32d_c }, - { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_f64d_to_f32_c }, + MAKE(F64, F32, 0, conv_f64_to_f32_c), + MAKE(F64P, F32P, 0, conv_f64d_to_f32d_c), + MAKE(F64, F32P, 0, conv_f64_to_f32d_c), + MAKE(F64P, F32, 0, conv_f64d_to_f32_c), - { SPA_AUDIO_FORMAT_F64_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_f64s_to_f32d_c }, + MAKE(F64_OE, F32P, 0, conv_f64s_to_f32d_c), /* from f32 */ - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U8, 0, 0, conv_f32_to_u8_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_f32d_to_u8d_c }, - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_f32_to_u8d_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U8, 0, 0, conv_f32d_to_u8_c }, - - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S8, 0, 0, conv_f32_to_s8_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S8P, 0, 0, conv_f32d_to_s8d_c }, - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S8P, 0, 0, conv_f32_to_s8d_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S8, 0, 0, conv_f32d_to_s8_c }, - - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_ALAW, 0, 0, conv_f32d_to_alaw_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_ULAW, 0, 0, conv_f32d_to_ulaw_c }, - - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U16, 0, 0, conv_f32_to_u16_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U16, 0, 0, conv_f32d_to_u16_c }, + MAKE(F32, U8, 0, conv_f32_to_u8_c), + MAKE(F32P, U8P, 0, conv_f32d_to_u8d_shaped_c, 0, CONV_SHAPE), + MAKE(F32P, U8P, 0, conv_f32d_to_u8d_dither_c, 0, CONV_DITHER), + MAKE(F32P, U8P, 0, conv_f32d_to_u8d_c), + MAKE(F32, U8P, 0, conv_f32_to_u8d_c), + MAKE(F32P, U8, 0, conv_f32d_to_u8_shaped_c, 0, CONV_SHAPE), + MAKE(F32P, U8, 0, conv_f32d_to_u8_dither_c, 0, CONV_DITHER), + MAKE(F32P, U8, 0, conv_f32d_to_u8_c), + + MAKE(F32, S8, 0, conv_f32_to_s8_c), + MAKE(F32P, S8P, 0, conv_f32d_to_s8d_shaped_c, 0, CONV_SHAPE), + MAKE(F32P, S8P, 0, conv_f32d_to_s8d_dither_c, 0, CONV_DITHER), + MAKE(F32P, S8P, 0, conv_f32d_to_s8d_c), + MAKE(F32, S8P, 0, conv_f32_to_s8d_c), + MAKE(F32P, S8, 0, conv_f32d_to_s8_shaped_c, 0, CONV_SHAPE), + MAKE(F32P, S8, 0, conv_f32d_to_s8_dither_c, 0, CONV_DITHER), + MAKE(F32P, S8, 0, conv_f32d_to_s8_c), + + MAKE(F32P, ALAW, 0, conv_f32d_to_alaw_c), + MAKE(F32P, ULAW, 0, conv_f32d_to_ulaw_c), + + MAKE(F32, U16, 0, conv_f32_to_u16_c), + MAKE(F32P, U16, 0, conv_f32d_to_u16_c), #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S16, 0, SPA_CPU_FLAG_SSE2, conv_f32_to_s16_sse2 }, + MAKE(F32, S16, 0, conv_f32_to_s16_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S16, 0, 0, conv_f32_to_s16_c }, + MAKE(F32, S16, 0, conv_f32_to_s16_c), + MAKE(F32P, S16P, 0, conv_f32d_to_s16d_shaped_c, 0, CONV_SHAPE), + MAKE(F32P, S16P, 0, conv_f32d_to_s16d_dither_c, 0, CONV_DITHER), #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16P, 0, SPA_CPU_FLAG_SSE2, conv_f32d_to_s16d_sse2 }, + MAKE(F32P, S16P, 0, conv_f32d_to_s16d_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16P, 0, 0, conv_f32d_to_s16d_c }, + MAKE(F32P, S16P, 0, conv_f32d_to_s16d_c), - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S16P, 0, 0, conv_f32_to_s16d_c }, + MAKE(F32, S16P, 0, conv_f32_to_s16d_c), + MAKE(F32P, S16, 0, conv_f32d_to_s16_shaped_c, 0, CONV_SHAPE), + MAKE(F32P, S16, 0, conv_f32d_to_s16_dither_c, 0, CONV_DITHER), #if defined (HAVE_NEON) - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16, 0, SPA_CPU_FLAG_NEON, conv_f32d_to_s16_neon }, + MAKE(F32P, S16, 0, conv_f32d_to_s16_neon, SPA_CPU_FLAG_NEON), #endif #if defined (HAVE_AVX2) - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16, 4, SPA_CPU_FLAG_AVX2, conv_f32d_to_s16_4_avx2 }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16, 2, SPA_CPU_FLAG_AVX2, conv_f32d_to_s16_2_avx2 }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16, 0, SPA_CPU_FLAG_AVX2, conv_f32d_to_s16_avx2 }, + MAKE(F32P, S16, 4, conv_f32d_to_s16_4_avx2, SPA_CPU_FLAG_AVX2), + MAKE(F32P, S16, 2, conv_f32d_to_s16_2_avx2, SPA_CPU_FLAG_AVX2), + MAKE(F32P, S16, 0, conv_f32d_to_s16_avx2, SPA_CPU_FLAG_AVX2), #endif #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16, 2, SPA_CPU_FLAG_SSE2, conv_f32d_to_s16_2_sse2 }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16, 0, SPA_CPU_FLAG_SSE2, conv_f32d_to_s16_sse2 }, + MAKE(F32P, S16, 2, conv_f32d_to_s16_2_sse2, SPA_CPU_FLAG_SSE2), + MAKE(F32P, S16, 0, conv_f32d_to_s16_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16, 0, 0, conv_f32d_to_s16_c }, + MAKE(F32P, S16, 0, conv_f32d_to_s16_c), + + MAKE(F32P, S16_OE, 0, conv_f32d_to_s16s_shaped_c, 0, CONV_SHAPE), + MAKE(F32P, S16_OE, 0, conv_f32d_to_s16s_dither_c, 0, CONV_DITHER), + MAKE(F32P, S16_OE, 0, conv_f32d_to_s16s_c), - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16_OE, 0, 0, conv_f32d_to_s16s_c }, + MAKE(F32, U32, 0, conv_f32_to_u32_c), + MAKE(F32P, U32, 0, conv_f32d_to_u32_c), - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U32, 0, 0, conv_f32_to_u32_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U32, 0, 0, conv_f32d_to_u32_c }, + MAKE(F32, S32, 0, conv_f32_to_s32_c), + MAKE(F32P, S32P, 0, conv_f32d_to_s32d_dither_c, 0, CONV_DITHER), + MAKE(F32P, S32P, 0, conv_f32d_to_s32d_c), + MAKE(F32, S32P, 0, conv_f32_to_s32d_c), + +#if defined (HAVE_SSE2) + MAKE(F32P, S32, 0, conv_f32d_to_s32_dither_sse2, SPA_CPU_FLAG_SSE2, CONV_DITHER), +#endif + MAKE(F32P, S32, 0, conv_f32d_to_s32_dither_c, 0, CONV_DITHER), - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S32, 0, 0, conv_f32_to_s32_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_f32d_to_s32d_c }, - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_f32_to_s32d_c }, #if defined (HAVE_AVX2) - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S32, 0, SPA_CPU_FLAG_AVX2, conv_f32d_to_s32_avx2 }, + MAKE(F32P, S32, 0, conv_f32d_to_s32_avx2, SPA_CPU_FLAG_AVX2), #endif #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S32, 0, SPA_CPU_FLAG_SSE2, conv_f32d_to_s32_sse2 }, + MAKE(F32P, S32, 0, conv_f32d_to_s32_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S32, 0, 0, conv_f32d_to_s32_c }, + MAKE(F32P, S32, 0, conv_f32d_to_s32_c), - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S32_OE, 0, 0, conv_f32d_to_s32s_c }, + MAKE(F32P, S32_OE, 0, conv_f32d_to_s32s_dither_c, 0, CONV_DITHER), + MAKE(F32P, S32_OE, 0, conv_f32d_to_s32s_c), - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U24, 0, 0, conv_f32_to_u24_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U24, 0, 0, conv_f32d_to_u24_c }, + MAKE(F32, U24, 0, conv_f32_to_u24_c), + MAKE(F32P, U24, 0, conv_f32d_to_u24_c), - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24, 0, 0, conv_f32_to_s24_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24P, 0, 0, conv_f32d_to_s24d_c }, - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24P, 0, 0, conv_f32_to_s24d_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24, 0, 0, conv_f32d_to_s24_c }, + MAKE(F32, S24, 0, conv_f32_to_s24_c), + MAKE(F32P, S24P, 0, conv_f32d_to_s24d_dither_c, 0, CONV_DITHER), + MAKE(F32P, S24P, 0, conv_f32d_to_s24d_c), + MAKE(F32, S24P, 0, conv_f32_to_s24d_c), + MAKE(F32P, S24, 0, conv_f32d_to_s24_dither_c, 0, CONV_DITHER), + MAKE(F32P, S24, 0, conv_f32d_to_s24_c), - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24_OE, 0, 0, conv_f32d_to_s24s_c }, + MAKE(F32P, S24_OE, 0, conv_f32d_to_s24s_dither_c, 0, CONV_DITHER), + MAKE(F32P, S24_OE, 0, conv_f32d_to_s24s_c), - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U24_32, 0, 0, conv_f32_to_u24_32_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U24_32, 0, 0, conv_f32d_to_u24_32_c }, + MAKE(F32, U24_32, 0, conv_f32_to_u24_32_c), + MAKE(F32P, U24_32, 0, conv_f32d_to_u24_32_c), - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_f32_to_s24_32_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_f32d_to_s24_32d_c }, - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_f32_to_s24_32d_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_f32d_to_s24_32_c }, + MAKE(F32, S24_32, 0, conv_f32_to_s24_32_c), + MAKE(F32P, S24_32P, 0, conv_f32d_to_s24_32d_dither_c, 0, CONV_DITHER), + MAKE(F32P, S24_32P, 0, conv_f32d_to_s24_32d_c), + MAKE(F32, S24_32P, 0, conv_f32_to_s24_32d_c), + MAKE(F32P, S24_32, 0, conv_f32d_to_s24_32_dither_c, 0, CONV_DITHER), + MAKE(F32P, S24_32, 0, conv_f32d_to_s24_32_c), - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24_32_OE, 0, 0, conv_f32d_to_s24_32s_c }, + MAKE(F32P, S24_32_OE, 0, conv_f32d_to_s24_32s_dither_c, 0, CONV_DITHER), + MAKE(F32P, S24_32_OE, 0, conv_f32d_to_s24_32s_c), - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F64, 0, 0, conv_f32_to_f64_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_f32d_to_f64d_c }, - { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_f32_to_f64d_c }, - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F64, 0, 0, conv_f32d_to_f64_c }, + MAKE(F32, F64, 0, conv_f32_to_f64_c), + MAKE(F32P, F64P, 0, conv_f32d_to_f64d_c), + MAKE(F32, F64P, 0, conv_f32_to_f64d_c), + MAKE(F32P, F64, 0, conv_f32d_to_f64_c), - { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F64_OE, 0, 0, conv_f32d_to_f64s_c }, + MAKE(F32P, F64_OE, 0, conv_f32d_to_f64s_c), /* u8 */ - { SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_U8, 0, 0, conv_copy8_c }, - { SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_copy8d_c }, - { SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_deinterleave_8_c }, - { SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_U8, 0, 0, conv_interleave_8_c }, + MAKE(U8, U8, 0, conv_copy8_c), + MAKE(U8P, U8P, 0, conv_copy8d_c), + MAKE(U8, U8P, 0, conv_deinterleave_8_c), + MAKE(U8P, U8, 0, conv_interleave_8_c), /* s8 */ - { SPA_AUDIO_FORMAT_S8, SPA_AUDIO_FORMAT_S8, 0, 0, conv_copy8_c }, - { SPA_AUDIO_FORMAT_S8P, SPA_AUDIO_FORMAT_S8P, 0, 0, conv_copy8d_c }, - { SPA_AUDIO_FORMAT_S8, SPA_AUDIO_FORMAT_S8P, 0, 0, conv_deinterleave_8_c }, - { SPA_AUDIO_FORMAT_S8P, SPA_AUDIO_FORMAT_S8, 0, 0, conv_interleave_8_c }, + MAKE(S8, S8, 0, conv_copy8_c), + MAKE(S8P, S8P, 0, conv_copy8d_c), + MAKE(S8, S8P, 0, conv_deinterleave_8_c), + MAKE(S8P, S8, 0, conv_interleave_8_c), /* alaw */ - { SPA_AUDIO_FORMAT_ALAW, SPA_AUDIO_FORMAT_ALAW, 0, 0, conv_copy8_c }, + MAKE(ALAW, ALAW, 0, conv_copy8_c), /* ulaw */ - { SPA_AUDIO_FORMAT_ULAW, SPA_AUDIO_FORMAT_ULAW, 0, 0, conv_copy8_c }, + MAKE(ULAW, ULAW, 0, conv_copy8_c), /* s16 */ - { SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_S16, 0, 0, conv_copy16_c }, - { SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_S16P, 0, 0, conv_copy16d_c }, - { SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_S16P, 0, 0, conv_deinterleave_16_c }, - { SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_S16, 0, 0, conv_interleave_16_c }, + MAKE(S16, S16, 0, conv_copy16_c), + MAKE(S16P, S16P, 0, conv_copy16d_c), + MAKE(S16, S16P, 0, conv_deinterleave_16_c), + MAKE(S16P, S16, 0, conv_interleave_16_c), /* s32 */ - { SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32, 0, 0, conv_copy32_c }, - { SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_copy32d_c }, + MAKE(S32, S32, 0, conv_copy32_c), + MAKE(S32P, S32P, 0, conv_copy32d_c), #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_deinterleave_32_sse2 }, + MAKE(S32, S32P, 0, conv_deinterleave_32_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_deinterleave_32_c }, + MAKE(S32, S32P, 0, conv_deinterleave_32_c), #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32, 0, 0, conv_interleave_32_sse2 }, + MAKE(S32P, S32, 0, conv_interleave_32_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32, 0, 0, conv_interleave_32_c }, + MAKE(S32P, S32, 0, conv_interleave_32_c), /* s24 */ - { SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_S24, 0, 0, conv_copy24_c }, - { SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_S24P, 0, 0, conv_copy24d_c }, - { SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_S24P, 0, 0, conv_deinterleave_24_c }, - { SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_S24, 0, 0, conv_interleave_24_c }, + MAKE(S24, S24, 0, conv_copy24_c), + MAKE(S24P, S24P, 0, conv_copy24d_c), + MAKE(S24, S24P, 0, conv_deinterleave_24_c), + MAKE(S24P, S24, 0, conv_interleave_24_c), /* s24_32 */ - { SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_copy32_c }, - { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_copy32d_c }, + MAKE(S24_32, S24_32, 0, conv_copy32_c), + MAKE(S24_32P, S24_32P, 0, conv_copy32d_c), #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_deinterleave_32_sse2 }, + MAKE(S24_32, S24_32P, 0, conv_deinterleave_32_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_deinterleave_32_c }, + MAKE(S24_32, S24_32P, 0, conv_deinterleave_32_c), #if defined (HAVE_SSE2) - { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_interleave_32_sse2 }, + MAKE(S24_32P, S24_32, 0, conv_interleave_32_sse2, SPA_CPU_FLAG_SSE2), #endif - { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_interleave_32_c }, + MAKE(S24_32P, S24_32, 0, conv_interleave_32_c), /* F64 */ - { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F64, 0, 0, conv_copy64_c }, - { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_copy64d_c }, - { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_deinterleave_64_c }, - { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F64, 0, 0, conv_interleave_64_c }, + MAKE(F64, F64, 0, conv_copy64_c), + MAKE(F64P, F64P, 0, conv_copy64d_c), + MAKE(F64, F64P, 0, conv_deinterleave_64_c), + MAKE(F64P, F64, 0, conv_interleave_64_c), }; +#undef MAKE #define MATCH_CHAN(a,b) ((a) == 0 || (a) == (b)) #define MATCH_CPU_FLAGS(a,b) ((a) == 0 || ((a) & (b)) == a) +#define MATCH_DITHER(a,b) ((a) == 0 || ((a) & (b)) == a) static const struct conv_info *find_conv_info(uint32_t src_fmt, uint32_t dst_fmt, - uint32_t n_channels, uint32_t cpu_flags) + uint32_t n_channels, uint32_t cpu_flags, uint32_t dither_flags) { size_t i; @@ -317,7 +358,8 @@ if (conv_tablei.src_fmt == src_fmt && conv_tablei.dst_fmt == dst_fmt && MATCH_CHAN(conv_tablei.n_channels, n_channels) && - MATCH_CPU_FLAGS(conv_tablei.cpu_flags, cpu_flags)) + MATCH_CPU_FLAGS(conv_tablei.cpu_flags, cpu_flags) && + MATCH_DITHER(conv_tablei.dither_flags, dither_flags)) return &conv_tablei; } return NULL; @@ -326,20 +368,68 @@ static void impl_convert_free(struct convert *conv) { conv->process = NULL; + free(conv->dither); + conv->dither = NULL; +} + +static bool need_dither(uint32_t format) +{ + switch (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: + case SPA_AUDIO_FORMAT_S16P: + case SPA_AUDIO_FORMAT_S16: + case SPA_AUDIO_FORMAT_S16_OE: + return true; + } + return false; } int convert_init(struct convert *conv) { const struct conv_info *info; + uint32_t i, dither_flags; + + conv->scale = 1.0f / (float)(INT32_MAX >> conv->noise); - info = find_conv_info(conv->src_fmt, conv->dst_fmt, conv->n_channels, conv->cpu_flags); + /* disable dither if not needed */ + if (!need_dither(conv->dst_fmt)) + conv->method = DITHER_METHOD_NONE; + + /* don't use shaped for too low rates, it moves the noise to + * audible ranges */ + if (conv->method == DITHER_METHOD_SHAPED_5 && conv->rate < 32000) + conv->method = DITHER_METHOD_TRIANGULAR; + + dither_flags = 0; + if (conv->method != DITHER_METHOD_NONE || conv->noise) + dither_flags |= CONV_DITHER; + if (conv->method == DITHER_METHOD_SHAPED_5) + dither_flags |= CONV_SHAPE; + + info = find_conv_info(conv->src_fmt, conv->dst_fmt, conv->n_channels, + conv->cpu_flags, dither_flags); if (info == NULL) return -ENOTSUP; + conv->dither_size = DITHER_SIZE; + conv->dither = calloc(conv->dither_size + 16 + + FMT_OPS_MAX_ALIGN / sizeof(float), sizeof(float)); + if (conv->dither == NULL) + return -errno; + + for (i = 0; i < SPA_N_ELEMENTS(conv->random); i++) + conv->randomi = random(); + conv->is_passthrough = conv->src_fmt == conv->dst_fmt; conv->cpu_flags = info->cpu_flags; conv->process = info->process; conv->free = impl_convert_free; + conv->func_name = info->name; return 0; }
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/fmt-ops.h -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/fmt-ops.h
Changed
@@ -23,7 +23,7 @@ */ #include <math.h> -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__MidnightBSD__) #include <sys/endian.h> #define bswap_16 bswap16 #define bswap_32 bswap32 @@ -33,73 +33,96 @@ #endif #include <spa/utils/defs.h> +#include <spa/utils/string.h> -#define U8_MIN 0 -#define U8_MAX 255 -#define U8_SCALE 127.5f -#define U8_OFFS 128 -#define U8_TO_F32(v) ((((uint8_t)(v)) * (1.0f / U8_OFFS)) - 1.0) -#define F32_TO_U8(v) (uint8_t)((SPA_CLAMP(v, -1.0f, 1.0f) * U8_SCALE) + U8_OFFS) - -#define S8_MIN -127 -#define S8_MAX 127 -#define S8_MAX_F 127.0f -#define S8_SCALE 127.0f -#define S8_TO_F32(v) (((int8_t)(v)) * (1.0f / S8_SCALE)) -#define F32_TO_S8(v) (int8_t)(SPA_CLAMP(v, -1.0f, 1.0f) * S8_SCALE) - -#define U16_MIN 0 -#define U16_MAX 65535 -#define U16_SCALE 32767.5f -#define U16_OFFS 32768 -#define U16_TO_F32(v) ((((uint16_t)(v)) * (1.0f / U16_OFFS)) - 1.0) -#define U16S_TO_F32(v) (((uint16_t)bswap_16((uint16_t)(v)) * (1.0f / U16_OFFS)) - 1.0) -#define F32_TO_U16(v) (uint16_t)((SPA_CLAMP(v, -1.0f, 1.0f) * U16_SCALE) + U16_OFFS) -#define F32_TO_U16S(v) ((uint16_t)bswap_16((uint16_t)((SPA_CLAMP(v, -1.0f, 1.0f) * U16_SCALE) + U16_OFFS))) - -#define S16_MIN -32767 -#define S16_MAX 32767 -#define S16_MAX_F 32767.0f -#define S16_SCALE 32767.0f -#define S16_TO_F32(v) (((int16_t)(v)) * (1.0f / S16_SCALE)) -#define S16S_TO_F32(v) (((int16_t)bswap_16((uint16_t)v)) * (1.0f / S16_SCALE)) -#define F32_TO_S16(v) (int16_t)(SPA_CLAMP(v, -1.0f, 1.0f) * S16_SCALE) -#define F32_TO_S16S(v) ((int16_t)bswap_16((uint16_t)(SPA_CLAMP(v, -1.0f, 1.0f) * S16_SCALE))) - -#define U24_MIN 0 -#define U24_MAX 16777215 -#define U24_SCALE 8388607.5f -#define U24_OFFS 8388608 -#define U24_TO_F32(v) ((((uint32_t)(v)) * (1.0f / U24_OFFS)) - 1.0) -#define F32_TO_U24(v) (uint32_t)((SPA_CLAMP(v, -1.0f, 1.0f) * U24_SCALE) + U24_OFFS) - -#define S24_MIN -8388607 -#define S24_MAX 8388607 -#define S24_MAX_F 8388607.0f -#define S24_SCALE 8388607.0f -#define S24_TO_F32(v) (((int32_t)(v)) * (1.0f / S24_SCALE)) -#define F32_TO_S24(v) (int32_t)(SPA_CLAMP(v, -1.0f, 1.0f) * S24_SCALE) - -#define U32_TO_F32(v) U24_TO_F32(((uint32_t)(v)) >> 8) -#define F32_TO_U32(v) (F32_TO_U24(v) << 8) - -#define S32_SCALE 2147483648.0f -#define S32_MIN 2147483520.0f - -#define S32_TO_F32(v) S24_TO_F32(((int32_t)(v)) >> 8) -#define S32S_TO_F32(v) S24_TO_F32(((int32_t)bswap_32(v)) >> 8) -#define F32_TO_S32(v) (F32_TO_S24(v) << 8) -#define F32_TO_S32S(v) bswap_32((F32_TO_S24(v) << 8)) +#define FMT_OPS_MAX_ALIGN 32 + +#define U8_MIN 0u +#define U8_MAX 255u +#define U8_SCALE 127.5f +#define U8_OFFS 128.f +#define U8_TO_F32(v) ((((uint8_t)(v)) * (1.0f / U8_OFFS)) - 1.0f) +#define F32_TO_U8(v) (uint8_t)SPA_CLAMP((v) * U8_SCALE + U8_OFFS, U8_MIN, U8_MAX) +#define F32_TO_U8_D(v,d) (uint8_t)SPA_CLAMP((v) * U8_SCALE + U8_OFFS + (d), U8_MIN, U8_MAX) + +#define S8_MIN -127 +#define S8_MAX 127 +#define S8_MAX_F 127.0f +#define S8_SCALE 127.0f +#define S8_TO_F32(v) (((int8_t)(v)) * (1.0f / S8_SCALE)) +#define F32_TO_S8(v) (int8_t)SPA_CLAMP((v) * S8_SCALE, S8_MIN, S8_MAX) +#define F32_TO_S8_D(v,d) (int8_t)SPA_CLAMP((v) * S8_SCALE + (d), S8_MIN, S8_MAX) + +#define U16_MIN 0u +#define U16_MAX 65535u +#define U16_SCALE 32767.5f +#define U16_OFFS 32768.f +#define U16_TO_F32(v) ((((uint16_t)(v)) * (1.0f / U16_OFFS)) - 1.0) +#define U16S_TO_F32(v) (((uint16_t)bswap_16((uint16_t)(v)) * (1.0f / U16_OFFS)) - 1.0) +#define F32_TO_U16(v) (uint16_t)SPA_CLAMP((v) * U16_SCALE + U16_OFFS, U16_MIN, U16_MAX) +#define F32_TO_U16_D(v,d) (uint16_t)SPA_CLAMP((v) * U16_SCALE + U16_OFFS + (d), U16_MIN, U16_MAX) +#define F32_TO_U16S(v) bswap_16(F32_TO_U16(v)) +#define F32_TO_U16S_D(v,d) bswap_16(F32_TO_U16_D(v,d)) + +#define S16_MIN -32767 +#define S16_MAX 32767 +#define S16_MAX_F 32767.0f +#define S16_SCALE 32767.0f +#define S16_TO_F32(v) (((int16_t)(v)) * (1.0f / S16_SCALE)) +#define S16S_TO_F32(v) (((int16_t)bswap_16(v)) * (1.0f / S16_SCALE)) +#define F32_TO_S16(v) (int16_t)SPA_CLAMP((v) * S16_SCALE, S16_MIN, S16_MAX) +#define F32_TO_S16_D(v,d) (int16_t)SPA_CLAMP((v) * S16_SCALE + (d), S16_MIN, S16_MAX) +#define F32_TO_S16S(v) bswap_16(F32_TO_S16(v)) +#define F32_TO_S16S_D(v,d) bswap_16(F32_TO_S16_D(v,d)) + +#define U24_MIN 0u +#define U24_MAX 16777215u +#define U24_SCALE 8388607.5f +#define U24_OFFS 8388608.f +#define U24_TO_F32(v) ((((uint32_t)(v)) * (1.0f / U24_OFFS)) - 1.0) +#define F32_TO_U24(v) (uint32_t)SPA_CLAMP((v) * U24_SCALE + U24_OFFS, U24_MIN, U24_MAX) +#define F32_TO_U24_D(v,d) (uint32_t)SPA_CLAMP((v) * U24_SCALE + U24_OFFS + (d), U24_MIN, U24_MAX) + +#define S24_MIN -8388607 +#define S24_MAX 8388607 +#define S24_MAX_F 8388607.0f +#define S24_SCALE 8388607.0f +#define S24_TO_F32(v) (((int32_t)(v)) * (1.0f / S24_SCALE)) +#define F32_TO_S24(v) (int32_t)SPA_CLAMP((v) * S24_SCALE, S24_MIN, S24_MAX) +#define F32_TO_S24_D(v,d) (int32_t)SPA_CLAMP((v) * S24_SCALE + (d), S24_MIN, S24_MAX) + +#define U32_MIN 0u +#define U32_MAX 4294967040u +#define U32_SCALE 2147483520.f +#define U32_OFFS 2147483520.f +#define U32_TO_F32(v) ((((uint32_t)(v)) * (1.0f / U32_OFFS)) - 1.0) +#define F32_TO_U32(v) (uint32_t)SPA_CLAMP((v) * U32_SCALE + U32_OFFS, U32_MIN, U32_MAX) +#define F32_TO_U32_D(v,d) (uint32_t)SPA_CLAMP((v) * U32_SCALE + U32_OFFS + (d), U32_MIN, U32_MAX) + +#define S32_MIN -2147483520 +#define S32_MAX 2147483520 +#define S32_MAX_F 2147483520.f +#define S32_SCALE 2147483648.f +#define S32_TO_F32(v) (((int32_t)(v)) * (1.0f / S32_SCALE)) +#define S32S_TO_F32(v) (((int32_t)bswap_32(v)) * (1.0f / S32_SCALE)) +#define F32_TO_S32(v) (int32_t)SPA_CLAMP((v) * S32_SCALE, S32_MIN, S32_MAX) +#define F32_TO_S32_D(v,d) (int32_t)SPA_CLAMP((v) * S32_SCALE + (d), S32_MIN, S32_MAX) +#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)) #define U24_32_TO_F32(v) U32_TO_F32((v)<<8) #define U24_32S_TO_F32(v) U32_TO_F32(((int32_t)bswap_32(v))<<8) #define F32_TO_U24_32(v) F32_TO_U24(v) #define F32_TO_U24_32S(v) bswap_32(F32_TO_U24(v)) +#define F32_TO_U24_32_D(v,d) F32_TO_U24_D(v,d) +#define F32_TO_U24_32S_D(v,d) bswap_32(F32_TO_U24_D(v,d)) #define S24_32_TO_F32(v) S32_TO_F32((v)<<8) #define S24_32S_TO_F32(v) S32_TO_F32(((int32_t)bswap_32(v))<<8) #define F32_TO_S24_32(v) F32_TO_S24(v) #define F32_TO_S24_32S(v) bswap_32(F32_TO_S24(v)) +#define F32_TO_S24_32_D(v,d) F32_TO_S24_D(v,d) +#define F32_TO_S24_32S_D(v,d) bswap_32(F32_TO_S24_D(v,d)) static inline uint32_t read_u24(const void *src) { @@ -173,18 +196,38 @@ #endif } -#define MAX_NS 64 +#define NS_MAX 8 +#define NS_MASK (NS_MAX-1) + +struct shaper { + float eNS_MAX; + uint32_t idx; + float r; +}; struct convert { + uint32_t quantize; + uint32_t noise; +#define DITHER_METHOD_NONE 0 +#define DITHER_METHOD_RECTANGULAR 1 +#define DITHER_METHOD_TRIANGULAR 2 +#define DITHER_METHOD_SHAPED_5 3 + uint32_t method; + uint32_t src_fmt; uint32_t dst_fmt; uint32_t n_channels; + uint32_t rate; uint32_t cpu_flags; + const char *func_name; unsigned int is_passthrough:1; - float ns_dataMAX_NS; - uint32_t ns_idx; - uint32_t ns_size; + + float scale; + uint32_t random16 + FMT_OPS_MAX_ALIGN/4; + float *dither; + uint32_t dither_size; + struct shaper shaper64; void (*process) (struct convert *conv, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, uint32_t n_samples); @@ -193,6 +236,27 @@ int convert_init(struct convert *conv); +static const struct dither_method_info { + const char *label; + const char *description; + uint32_t method; +} dither_method_info = { + DITHER_METHOD_NONE = { "none", "Disabled", DITHER_METHOD_NONE }, + DITHER_METHOD_RECTANGULAR = { "rectangular", "Rectangular dithering", DITHER_METHOD_RECTANGULAR }, + DITHER_METHOD_TRIANGULAR = { "triangular", "Triangular dithering", DITHER_METHOD_TRIANGULAR }, + DITHER_METHOD_SHAPED_5 = { "shaped5", "Shaped 5 dithering", DITHER_METHOD_SHAPED_5 } +}; + +static inline uint32_t dither_method_from_label(const char *label) +{ + uint32_t i; + for (i = 0; i < SPA_N_ELEMENTS(dither_method_info); i++) { + if (spa_streq(dither_method_infoi.label, label)) + return dither_method_infoi.method; + } + return DITHER_METHOD_NONE; +} + #define convert_process(conv,...) (conv)->process(conv, __VA_ARGS__) #define convert_free(conv) (conv)->free(conv) @@ -200,8 +264,6 @@ void conv_##name##_##arch(struct convert *conv, void * SPA_RESTRICT dst, \ const void * SPA_RESTRICT src, uint32_t n_samples) \ -#define FMT_OPS_MAX_ALIGN 32 - DEFINE_FUNCTION(copy8d, c); DEFINE_FUNCTION(copy8, c); DEFINE_FUNCTION(copy16d, c); @@ -256,43 +318,66 @@ DEFINE_FUNCTION(f64s_to_f32d, c); DEFINE_FUNCTION(f64d_to_f32, c); DEFINE_FUNCTION(f32d_to_u8d, c); +DEFINE_FUNCTION(f32d_to_u8d_dither, c); +DEFINE_FUNCTION(f32d_to_u8d_shaped, c); DEFINE_FUNCTION(f32_to_u8, c); DEFINE_FUNCTION(f32_to_u8d, c); DEFINE_FUNCTION(f32d_to_u8, c); +DEFINE_FUNCTION(f32d_to_u8_dither, c); +DEFINE_FUNCTION(f32d_to_u8_shaped, c); DEFINE_FUNCTION(f32d_to_s8d, c); +DEFINE_FUNCTION(f32d_to_s8d_dither, c); +DEFINE_FUNCTION(f32d_to_s8d_shaped, c); DEFINE_FUNCTION(f32_to_s8, c); DEFINE_FUNCTION(f32_to_s8d, c); DEFINE_FUNCTION(f32d_to_s8, c); +DEFINE_FUNCTION(f32d_to_s8_dither, c); +DEFINE_FUNCTION(f32d_to_s8_shaped, c); DEFINE_FUNCTION(f32d_to_alaw, c); DEFINE_FUNCTION(f32d_to_ulaw, c); DEFINE_FUNCTION(f32_to_u16, c); DEFINE_FUNCTION(f32d_to_u16, c); DEFINE_FUNCTION(f32d_to_s16d, c); +DEFINE_FUNCTION(f32d_to_s16d_dither, c); +DEFINE_FUNCTION(f32d_to_s16d_shaped, c); DEFINE_FUNCTION(f32_to_s16, c); DEFINE_FUNCTION(f32_to_s16d, c); DEFINE_FUNCTION(f32d_to_s16, c); +DEFINE_FUNCTION(f32d_to_s16_dither, c); +DEFINE_FUNCTION(f32d_to_s16_shaped, c); DEFINE_FUNCTION(f32d_to_s16s, c); +DEFINE_FUNCTION(f32d_to_s16s_dither, c); +DEFINE_FUNCTION(f32d_to_s16s_shaped, c); DEFINE_FUNCTION(f32_to_u32, c); DEFINE_FUNCTION(f32d_to_u32, c); DEFINE_FUNCTION(f32d_to_s32d, c); +DEFINE_FUNCTION(f32d_to_s32d_dither, c); DEFINE_FUNCTION(f32_to_s32, c); DEFINE_FUNCTION(f32_to_s32d, c); DEFINE_FUNCTION(f32d_to_s32, c); +DEFINE_FUNCTION(f32d_to_s32_dither, c); DEFINE_FUNCTION(f32d_to_s32s, c); +DEFINE_FUNCTION(f32d_to_s32s_dither, c); DEFINE_FUNCTION(f32_to_u24, c); DEFINE_FUNCTION(f32d_to_u24, c); DEFINE_FUNCTION(f32d_to_s24d, c); +DEFINE_FUNCTION(f32d_to_s24d_dither, c); DEFINE_FUNCTION(f32_to_s24, c); DEFINE_FUNCTION(f32_to_s24d, c); DEFINE_FUNCTION(f32d_to_s24, c); +DEFINE_FUNCTION(f32d_to_s24_dither, c); DEFINE_FUNCTION(f32d_to_s24s, c); +DEFINE_FUNCTION(f32d_to_s24s_dither, c); DEFINE_FUNCTION(f32_to_u24_32, c); DEFINE_FUNCTION(f32d_to_u24_32, c); DEFINE_FUNCTION(f32d_to_s24_32d, c); +DEFINE_FUNCTION(f32d_to_s24_32d_dither, c); DEFINE_FUNCTION(f32_to_s24_32, c); DEFINE_FUNCTION(f32_to_s24_32d, c); DEFINE_FUNCTION(f32d_to_s24_32, c); +DEFINE_FUNCTION(f32d_to_s24_32_dither, c); DEFINE_FUNCTION(f32d_to_s24_32s, c); +DEFINE_FUNCTION(f32d_to_s24_32s_dither, c); DEFINE_FUNCTION(f32d_to_f64d, c); DEFINE_FUNCTION(f32_to_f64, c); DEFINE_FUNCTION(f32_to_f64d, c); @@ -324,6 +409,7 @@ DEFINE_FUNCTION(s24_to_f32d, sse2); DEFINE_FUNCTION(s32_to_f32d, sse2); DEFINE_FUNCTION(f32d_to_s32, sse2); +DEFINE_FUNCTION(f32d_to_s32_dither, sse2); DEFINE_FUNCTION(f32_to_s16, sse2); DEFINE_FUNCTION(f32d_to_s16_2, sse2); DEFINE_FUNCTION(f32d_to_s16, sse2);
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/meson.build -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/meson.build
Changed
@@ -1,11 +1,8 @@ -audioconvert_sources = 'audioadapter.c', +audioconvert_sources = + 'audioadapter.c', 'audioconvert.c', - 'fmtconvert.c', - 'channelmix.c', - 'merger.c', - 'plugin.c', - 'resample.c', - 'splitter.c' + 'plugin.c' + simd_cargs = simd_dependencies =
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/plugin.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/plugin.c
Changed
@@ -27,11 +27,6 @@ #include <spa/support/plugin.h> extern const struct spa_handle_factory spa_audioconvert_factory; -extern const struct spa_handle_factory spa_fmtconvert_factory; -extern const struct spa_handle_factory spa_channelmix_factory; -extern const struct spa_handle_factory spa_resample_factory; -extern const struct spa_handle_factory spa_splitter_factory; -extern const struct spa_handle_factory spa_merger_factory; extern const struct spa_handle_factory spa_audioadapter_factory; SPA_EXPORT @@ -45,21 +40,6 @@ *factory = &spa_audioconvert_factory; break; case 1: - *factory = &spa_fmtconvert_factory; - break; - case 2: - *factory = &spa_channelmix_factory; - break; - case 3: - *factory = &spa_resample_factory; - break; - case 4: - *factory = &spa_splitter_factory; - break; - case 5: - *factory = &spa_merger_factory; - break; - case 6: *factory = &spa_audioadapter_factory; break; default:
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/resample-native-impl.h -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/resample-native-impl.h
Changed
@@ -34,10 +34,13 @@ struct resample_info { uint32_t format; - uint32_t cpu_flags; resample_func_t process_copy; + const char *copy_name; resample_func_t process_full; + const char *full_name; resample_func_t process_inter; + const char *inter_name; + uint32_t cpu_flags; }; struct native_data {
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/resample-native.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/resample-native.c
Changed
@@ -58,14 +58,23 @@ return sin(x) / x; } -static inline double blackman(double x, double n_taps) +#if 0 +static inline double window_blackman(double x, double n_taps) { double alpha = 0.232; x = 2.0 * M_PI * x / n_taps; return (1.0 - alpha) / 2.0 + (1.0 / 2.0) * cos(x) + (alpha / 2.0) * cos(2 * x); } - +#else +static inline double window_cosh(double x, double n_taps) +{ + double R = 95.0; + double A = -325.1E-6 * (R * R) + 0.1677 * R - 3.149; + x = 2.0 * M_PI * x / n_taps; + return cosh(A * sqrt(1 - pow(x / M_PI, 2))) / cosh(A); +} +#endif static int build_filter(float *taps, uint32_t stride, uint32_t n_taps, uint32_t n_phases, double cutoff) { @@ -77,7 +86,7 @@ /* exploit symmetry in filter taps */ taps(n_phases - i) * stride + n_taps12 + j = tapsi * stride + (n_taps12 - j - 1) = - cutoff * sinc(t * cutoff) * blackman(t, n_taps); + cutoff * sinc(t * cutoff) * window_cosh(t, n_taps); } } return 0; @@ -124,27 +133,27 @@ MAKE_RESAMPLER_FULL(c); MAKE_RESAMPLER_INTER(c); +#define MAKE(fmt,copy,full,inter,...) \ + { SPA_AUDIO_FORMAT_ ##fmt, do_resample_ ##copy, #copy, \ + do_resample_ ##full, #full, do_resample_ ##inter, #inter, __VA_ARGS__ } + static struct resample_info resample_table = { #if defined (HAVE_NEON) - { SPA_AUDIO_FORMAT_F32, SPA_CPU_FLAG_NEON, - do_resample_copy_c, do_resample_full_neon, do_resample_inter_neon }, + MAKE(F32, copy_c, full_neon, inter_neon, SPA_CPU_FLAG_NEON), #endif #if defined(HAVE_AVX) && defined(HAVE_FMA) - { SPA_AUDIO_FORMAT_F32, SPA_CPU_FLAG_AVX | SPA_CPU_FLAG_FMA3, - do_resample_copy_c, do_resample_full_avx, do_resample_inter_avx }, + MAKE(F32, copy_c, full_avx, inter_avx, SPA_CPU_FLAG_AVX | SPA_CPU_FLAG_FMA3), #endif #if defined (HAVE_SSSE3) - { SPA_AUDIO_FORMAT_F32, SPA_CPU_FLAG_SSSE3 | SPA_CPU_FLAG_SLOW_UNALIGNED, - do_resample_copy_c, do_resample_full_ssse3, do_resample_inter_ssse3 }, + MAKE(F32, copy_c, full_ssse3, inter_ssse3, SPA_CPU_FLAG_SSSE3 | SPA_CPU_FLAG_SLOW_UNALIGNED), #endif #if defined (HAVE_SSE) - { SPA_AUDIO_FORMAT_F32, SPA_CPU_FLAG_SSE, - do_resample_copy_c, do_resample_full_sse, do_resample_inter_sse }, + MAKE(F32, copy_c, full_sse, inter_sse, SPA_CPU_FLAG_SSE), #endif - { SPA_AUDIO_FORMAT_F32, 0, - do_resample_copy_c, do_resample_full_c, do_resample_inter_c }, + MAKE(F32, copy_c, full_c, inter_c), }; +#undef MAKE #define MATCH_CPU_FLAGS(a,b) ((a) == 0 || ((a) & (b)) == a) static const struct resample_info *find_resample_info(uint32_t format, uint32_t cpu_flags) @@ -200,12 +209,18 @@ data->inc = data->in_rate / data->out_rate; data->frac = data->in_rate % data->out_rate; - if (data->in_rate == data->out_rate) + if (data->in_rate == data->out_rate) { data->func = data->info->process_copy; - else if (rate == 1.0) + r->func_name = data->info->copy_name; + } + else if (rate == 1.0) { data->func = data->info->process_full; - else + r->func_name = data->info->full_name; + } + else { data->func = data->info->process_inter; + r->func_name = data->info->inter_name; + } spa_log_trace_fp(r->log, "native %p: rate:%f in:%d out:%d phase:%d inc:%d frac:%d", r, rate, data->in_rate, data->out_rate, data->phase, data->inc, data->frac); @@ -396,10 +411,9 @@ build_filter(d->filter, d->filter_stride, n_taps, n_phases, scale); d->info = find_resample_info(SPA_AUDIO_FORMAT_F32, r->cpu_flags); - if (SPA_UNLIKELY(!d->info)) - { + if (SPA_UNLIKELY(d->info == NULL)) { spa_log_error(r->log, "failed to find suitable resample format!"); - return -1; + return -ENOTSUP; } spa_log_debug(r->log, "native %p: q:%d in:%d out:%d n_taps:%d n_phases:%d features:%08x:%08x",
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/resample.h -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/resample.h
Changed
@@ -31,11 +31,13 @@ #define RESAMPLE_DEFAULT_QUALITY 4 struct resample { + struct spa_log *log; uint32_t cpu_flags; + const char *func_name; + uint32_t channels; uint32_t i_rate; uint32_t o_rate; - struct spa_log *log; double rate; int quality;
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/test-audioconvert.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/test-audioconvert.c
Changed
@@ -43,7 +43,7 @@ extern const struct spa_handle_factory test_source_factory; -#define MAX_PORTS SPA_AUDIO_MAX_CHANNELS +#define MAX_PORTS (SPA_AUDIO_MAX_CHANNELS+1) struct context { struct spa_handle *convert_handle;
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/volume-ops.c -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/volume-ops.c
Changed
@@ -36,16 +36,21 @@ typedef void (*volume_func_t) (struct volume *vol, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src, float volume, uint32_t n_samples); +#define MAKE(func,...) \ + { func, #func , __VA_ARGS__ } + static const struct volume_info { volume_func_t process; + const char *name; uint32_t cpu_flags; } volume_table = { #if defined (HAVE_SSE) - { volume_f32_sse, SPA_CPU_FLAG_SSE }, + MAKE(volume_f32_sse, SPA_CPU_FLAG_SSE), #endif - { volume_f32_c, 0 }, + MAKE(volume_f32_c), }; +#undef MAKE #define MATCH_CPU_FLAGS(a,b) ((a) == 0 || ((a) & (b)) == a) @@ -73,6 +78,8 @@ if (info == NULL) return -ENOTSUP; + vol->cpu_flags = info->cpu_flags; + vol->func_name = info->name; vol->free = impl_volume_free; vol->process = info->process; return 0;
View file
pipewire-0.3.52.tar.gz/spa/plugins/audioconvert/volume-ops.h -> pipewire-0.3.53.tar.gz/spa/plugins/audioconvert/volume-ops.h
Changed
@@ -33,6 +33,7 @@ struct volume { uint32_t cpu_flags; + const char *func_name; struct spa_log *log;
View file
pipewire-0.3.52.tar.gz/spa/plugins/audiomixer/audiomixer.c -> pipewire-0.3.53.tar.gz/spa/plugins/audiomixer/audiomixer.c
Changed
@@ -755,6 +755,8 @@ struct port *inport = GET_IN_PORT(this, i); struct spa_io_buffers *inio = NULL; struct buffer *inb; + struct spa_data *bd; + uint32_t size, offs; if (SPA_UNLIKELY(!PORT_VALID(inport) || (inio = inport->io) == NULL || @@ -770,13 +772,20 @@ } inb = &inport->buffersinio->buffer_id; - maxsize = SPA_MIN(inb->buffer->datas0.chunk->size, maxsize); + bd = &inb->buffer->datas0; - spa_log_trace_fp(this->log, "%p: mix input %d %p->%p %d %d %d", this, - i, inio, outio, inio->status, inio->buffer_id, maxsize); + offs = SPA_MIN(bd->chunk->offset, bd->maxsize); + size = SPA_MIN(bd->maxsize - offs, bd->chunk->size); + maxsize = SPA_MIN(size, maxsize); - datasn_buffers = inb->buffer->datas0.data; - buffersn_buffers++ = inb; + spa_log_trace_fp(this->log, "%p: mix input %d %p->%p %d %d %d:%d", this, + i, inio, outio, inio->status, inio->buffer_id, + offs, size); + + if (!SPA_FLAG_IS_SET(bd->chunk->flags, SPA_CHUNK_FLAG_EMPTY)) { + datasn_buffers = SPA_PTROFF(bd->data, offs, void); + buffersn_buffers++ = inb; + } inio->status = SPA_STATUS_NEED_DATA; } @@ -788,8 +797,7 @@ if (n_buffers == 1) { *outb->buffer = *buffers0->buffer; - } - else { + } else { struct spa_data *d = outb->buf.datas; *outb->buffer = outb->buf; @@ -799,6 +807,7 @@ d0.chunk->offset = 0; d0.chunk->size = maxsize; d0.chunk->stride = this->stride; + SPA_FLAG_UPDATE(d0.chunk->flags, SPA_CHUNK_FLAG_EMPTY, n_buffers == 0); mix_ops_process(&this->ops, d0.data, datas, n_buffers, maxsize / this->stride);
View file
pipewire-0.3.52.tar.gz/spa/plugins/audiomixer/mixer-dsp.c -> pipewire-0.3.53.tar.gz/spa/plugins/audiomixer/mixer-dsp.c
Changed
@@ -105,6 +105,7 @@ uint32_t cpu_flags; uint32_t max_align; + struct spa_io_position *io_position; uint32_t quantum_limit; struct mix_ops ops; @@ -152,7 +153,20 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size) { - return -ENOTSUP; + struct impl *this = object; + + spa_return_val_if_fail(this != NULL, -EINVAL); + + spa_log_debug(this->log, "%p: io %d %p/%zd", this, id, data, size); + + switch (id) { + case SPA_IO_Position: + this->io_position = data; + break; + default: + return -ENOENT; + } + return 0; } static int impl_node_send_command(void *object, const struct spa_command *command) @@ -694,7 +708,10 @@ datas = alloca(MAX_PORTS * sizeof(void *)); n_buffers = 0; - maxsize = UINT32_MAX; + if (SPA_LIKELY(this->io_position)) + maxsize = this->io_position->clock.duration * sizeof(float); + else + maxsize = this->quantum_limit; for (i = 0; i < this->last_port; i++) { struct port *inport = GET_IN_PORT(this, i); @@ -727,8 +744,10 @@ i, inio, outio, inio->status, inio->buffer_id, offs, size); - datasn_buffers = SPA_PTROFF(bd->data, offs, void); - buffersn_buffers++ = inb; + if (!SPA_FLAG_IS_SET(bd->chunk->flags, SPA_CHUNK_FLAG_EMPTY)) { + datasn_buffers = SPA_PTROFF(bd->data, offs, void); + buffersn_buffers++ = inb; + } inio->status = SPA_STATUS_NEED_DATA; } @@ -742,6 +761,7 @@ *outb->buffer = *buffers0->buffer; } else { struct spa_data *d = outb->buf.datas; + *outb->buffer = outb->buf; maxsize = SPA_MIN(maxsize, d0.maxsize); @@ -749,6 +769,7 @@ d0.chunk->offset = 0; d0.chunk->size = maxsize; d0.chunk->stride = sizeof(float); + SPA_FLAG_UPDATE(d0.chunk->flags, SPA_CHUNK_FLAG_EMPTY, n_buffers == 0); spa_log_trace_fp(this->log, "%p: %d mix %d", this, n_buffers, maxsize); @@ -846,6 +867,7 @@ this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu)); } + this->quantum_limit = 8192; for (i = 0; info && i < info->n_items; i++) { const char *k = info->itemsi.key; const char *s = info->itemsi.value;
View file
pipewire-0.3.52.tar.gz/spa/plugins/bluez5/meson.build -> pipewire-0.3.53.tar.gz/spa/plugins/bluez5/meson.build
Changed
@@ -116,7 +116,7 @@ bluez_codec_lc3plus = shared_library('spa-codec-bluez5-lc3plus', 'a2dp-codec-lc3plus.c', 'a2dp-codecs.c' , include_directories : configinc , - c_args : ldac_args, + c_args : codec_args, dependencies : spa_dep, lc3plus_dep, mathlib , install : true, install_dir : spa_plugindir / 'bluez5')
View file
pipewire-0.3.52.tar.gz/spa/plugins/ffmpeg/ffmpeg-dec.c -> pipewire-0.3.53.tar.gz/spa/plugins/ffmpeg/ffmpeg-dec.c
Changed
@@ -38,6 +38,8 @@ #include <spa/param/video/format.h> #include <spa/pod/filter.h> +#include "ffmpeg.h" + #define IS_VALID_PORT(this,d,id) ((id) == 0) #define GET_IN_PORT(this,p) (&this->in_portsp) #define GET_OUT_PORT(this,p) (&this->out_portsp) @@ -456,6 +458,20 @@ return 0; } +static int +impl_clear(struct spa_handle *handle) +{ + spa_return_val_if_fail(handle != NULL, -EINVAL); + + return 0; +} + +size_t +spa_ffmpeg_dec_get_size(const struct spa_handle_factory *factory, const struct spa_dict *params) +{ + return sizeof(struct impl); +} + int spa_ffmpeg_dec_init(struct spa_handle *handle, const struct spa_dict *info, @@ -466,6 +482,7 @@ struct port *port; handle->get_interface = impl_get_interface; + handle->clear = impl_clear; this = (struct impl *) handle;
View file
pipewire-0.3.52.tar.gz/spa/plugins/ffmpeg/ffmpeg-enc.c -> pipewire-0.3.53.tar.gz/spa/plugins/ffmpeg/ffmpeg-enc.c
Changed
@@ -37,6 +37,8 @@ #include <spa/param/video/format-utils.h> #include <spa/pod/filter.h> +#include "ffmpeg.h" + #define IS_VALID_PORT(this,d,id) ((id) == 0) #define GET_IN_PORT(this,p) (&this->in_portsp) #define GET_OUT_PORT(this,p) (&this->out_portsp) @@ -435,6 +437,20 @@ return 0; } +static int +impl_clear(struct spa_handle *handle) +{ + spa_return_val_if_fail(handle != NULL, -EINVAL); + + return 0; +} + +size_t +spa_ffmpeg_enc_get_size(const struct spa_handle_factory *factory, const struct spa_dict *params) +{ + return sizeof(struct impl); +} + int spa_ffmpeg_enc_init(struct spa_handle *handle, const struct spa_dict *info, @@ -444,6 +460,7 @@ struct port *port; handle->get_interface = impl_get_interface; + handle->clear = impl_clear; this = (struct impl *) handle;
View file
pipewire-0.3.52.tar.gz/spa/plugins/ffmpeg/ffmpeg.c -> pipewire-0.3.53.tar.gz/spa/plugins/ffmpeg/ffmpeg.c
Changed
@@ -30,10 +30,7 @@ #include <libavcodec/avcodec.h> -int spa_ffmpeg_dec_init(struct spa_handle *handle, const struct spa_dict *info, - const struct spa_support *support, uint32_t n_support); -int spa_ffmpeg_enc_init(struct spa_handle *handle, const struct spa_dict *info, - const struct spa_support *support, uint32_t n_support); +#include "ffmpeg.h" static int ffmpeg_dec_init(const struct spa_handle_factory *factory, @@ -130,8 +127,12 @@ SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { - static struct spa_handle_factory f; static char name128; + static struct spa_handle_factory f = { + SPA_VERSION_HANDLE_FACTORY, + .name = name, + .enum_interface_info = ffmpeg_enum_interface_info, + }; #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100) avcodec_register_all(); @@ -144,16 +145,14 @@ if (av_codec_is_encoder(c)) { snprintf(name, sizeof(name), "encoder.%s", c->name); + f.get_size = spa_ffmpeg_enc_get_size; f.init = ffmpeg_enc_init; } else { snprintf(name, sizeof(name), "decoder.%s", c->name); + f.get_size = spa_ffmpeg_dec_get_size; f.init = ffmpeg_dec_init; } - f.name = name; - f.info = NULL; - f.enum_interface_info = ffmpeg_enum_interface_info; - *factory = &f; (*index)++;
View file
pipewire-0.3.53.tar.gz/spa/plugins/ffmpeg/ffmpeg.h
Added
@@ -0,0 +1,20 @@ +#ifndef SPA_FFMPEG_H +#define SPA_FFMPEG_H + +#include <stdint.h> +#include <stddef.h> + +struct spa_dict; +struct spa_handle; +struct spa_support; +struct spa_handle_factory; + +int spa_ffmpeg_dec_init(struct spa_handle *handle, const struct spa_dict *info, + const struct spa_support *support, uint32_t n_support); +int spa_ffmpeg_enc_init(struct spa_handle *handle, const struct spa_dict *info, + const struct spa_support *support, uint32_t n_support); + +size_t spa_ffmpeg_dec_get_size(const struct spa_handle_factory *factory, const struct spa_dict *params); +size_t spa_ffmpeg_enc_get_size(const struct spa_handle_factory *factory, const struct spa_dict *params); + +#endif
View file
pipewire-0.3.52.tar.gz/spa/plugins/support/cpu.c -> pipewire-0.3.53.tar.gz/spa/plugins/support/cpu.c
Changed
@@ -30,7 +30,7 @@ #include <sched.h> #include <fcntl.h> -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__MidnightBSD__) #include <sys/sysctl.h> #endif
View file
pipewire-0.3.52.tar.gz/spa/plugins/support/logger.c -> pipewire-0.3.53.tar.gz/spa/plugins/support/logger.c
Changed
@@ -42,7 +42,7 @@ #include "log-patterns.h" -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__MidnightBSD__) #define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC #endif
View file
pipewire-0.3.52.tar.gz/spa/plugins/v4l2/v4l2-udev.c -> pipewire-0.3.53.tar.gz/spa/plugins/v4l2/v4l2-udev.c
Changed
@@ -278,15 +278,9 @@ if ((str = udev_device_get_property_value(dev, "SUBSYSTEM")) && *str) { itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_SUBSYSTEM, str); } - if ((str = udev_device_get_property_value(dev, "ID_VENDOR_ID")) && *str) { - char *dec = alloca(6); /* 65535 is max */ - int32_t val; + if ((str = udev_device_get_property_value(dev, "ID_VENDOR_ID")) && *str) + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, str); - if (spa_atoi32(str, &val, 16)) { - snprintf(dec, 6, "%d", val); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_ID, dec); - } - } str = udev_device_get_property_value(dev, "ID_VENDOR_FROM_DATABASE"); if (!(str && *str)) { str = udev_device_get_property_value(dev, "ID_VENDOR_ENC"); @@ -301,15 +295,8 @@ if (str && *str) { itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_VENDOR_NAME, str); } - if ((str = udev_device_get_property_value(dev, "ID_MODEL_ID")) && *str) { - char *dec = alloca(6); /* 65535 is max */ - int32_t val; - - if (spa_atoi32(str, &val, 16)) { - snprintf(dec, 6, "%d", val); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, dec); - } - } + if ((str = udev_device_get_property_value(dev, "ID_MODEL_ID")) && *str) + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PRODUCT_ID, str); str = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE"); if (!(str && *str)) {
View file
pipewire-0.3.52.tar.gz/spa/plugins/v4l2/v4l2-utils.c -> pipewire-0.3.53.tar.gz/spa/plugins/v4l2/v4l2-utils.c
Changed
@@ -1107,6 +1107,8 @@ spa_log_debug(this->log, "test control %08x", queryctrl.id); if (query_ext_ctrl_ioctl(port, &queryctrl) != 0) { + if (errno == ENOTTY) + goto enum_end; if (errno == EINVAL) { if (queryctrl.id != next_fl) goto enum_end; @@ -1123,6 +1125,7 @@ } res = -errno; spa_log_error(this->log, "'%s' VIDIOC_QUERYCTRL: %m", this->props.device); + spa_v4l2_close(dev); return res; } if (result.next & next_fl)
View file
pipewire-0.3.52.tar.gz/spa/plugins/vulkan/vulkan-utils.c -> pipewire-0.3.53.tar.gz/spa/plugins/vulkan/vulkan-utils.c
Changed
@@ -6,7 +6,7 @@ #include <sys/mman.h> #include <fcntl.h> #include <string.h> -#ifndef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__MidnightBSD__) #include <alloca.h> #endif #include <errno.h>
View file
pipewire-0.3.52.tar.gz/spa/tests/stress-ringbuffer.c -> pipewire-0.3.53.tar.gz/spa/tests/stress-ringbuffer.c
Changed
@@ -11,10 +11,10 @@ #define ARRAY_SIZE 63 #define MAX_VALUE 0x10000 -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__MidnightBSD__) #include <sys/param.h> #if (__FreeBSD_version >= 1400000 && __FreeBSD_version < 1400043) \ - || (__FreeBSD_version < 1300523) + || (__FreeBSD_version < 1300523) || defined(__MidnightBSD__) static int sched_getcpu(void) { return -1; }; #endif #endif
View file
pipewire-0.3.52.tar.gz/spa/tools/spa-inspect.c -> pipewire-0.3.53.tar.gz/spa/tools/spa-inspect.c
Changed
@@ -232,7 +232,7 @@ if ((res = spa_handle_factory_init(factory, handle, NULL, data->support, data->n_support)) < 0) { printf("can't make factory instance: %d\n", res); - return; + goto out; } printf("factory instance:\n"); @@ -256,6 +256,12 @@ else printf("skipping unknown interface\n"); } + + if ((res = spa_handle_clear(handle)) < 0) + printf("failed to clear handle: %s\n", spa_strerror(res)); + +out: + free(handle); } static const struct spa_loop_methods impl_loop = {
View file
pipewire-0.3.52.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.53.tar.gz/src/daemon/client-rt.conf.in
Changed
@@ -82,7 +82,7 @@ #node.autoconnect = true #resample.quality = 4 #channelmix.normalize = false - #channelmix.mix-lfe = true + #channelmix.mix-lfe = false #channelmix.upmix = true #channelmix.upmix-method = psd # none, simple #channelmix.lfe-cutoff = 150 @@ -90,4 +90,5 @@ #channelmix.rear-delay = 12.0 #channelmix.stereo-widen = 0.0 #channelmix.hilbert-taps = 0 + #dither.noise = 0 }
View file
pipewire-0.3.52.tar.gz/src/daemon/client.conf.in -> pipewire-0.3.53.tar.gz/src/daemon/client.conf.in
Changed
@@ -80,4 +80,5 @@ #channelmix.rear-delay = 12.0 #channelmix.stereo-widen = 0.0 #channelmix.hilbert-taps = 0 + #dither.noise = 0 }
View file
pipewire-0.3.52.tar.gz/src/daemon/jack.conf.in -> pipewire-0.3.53.tar.gz/src/daemon/jack.conf.in
Changed
@@ -81,7 +81,8 @@ # ignore-all: Ignore all self connect requests #jack.self-connect-mode = allow #jack.locked-process = true - #jack.default-as-system = false + #jack.default-as-system = false + #jack.fix-midi-events = true } # client specific properties
View file
pipewire-0.3.52.tar.gz/src/daemon/minimal.conf.in -> pipewire-0.3.53.tar.gz/src/daemon/minimal.conf.in
Changed
@@ -27,7 +27,7 @@ ## Properties for the DSP configuration. #default.clock.rate = 48000 - #default.clock.allowed-rates = 44100 48000 + #default.clock.allowed-rates = 48000 #default.clock.quantum = 1024 #default.clock.min-quantum = 32 #default.clock.max-quantum = 2048 @@ -212,6 +212,7 @@ #channelmix.stereo-widen = 0.0 #channelmix.hilbert-taps = 0 channelmix.disable = true + #dither.noise = 0 #node.param.Props = { # params = # audio.channels 6 @@ -220,6 +221,7 @@ adapter.auto-port-config = { mode = dsp monitor = false + control = false position = unknown # aux, preserve } #node.param.PortConfig = { @@ -272,6 +274,7 @@ #channelmix.stereo-widen = 0.0 #channelmix.hilbert-taps = 0 channelmix.disable = true + #dither.noise = 0 #node.param.Props = { # params = # audio.format S16 @@ -280,6 +283,7 @@ adapter.auto-port-config = { mode = dsp monitor = false + control = false position = unknown # aux, preserve } #node.param.PortConfig = {
View file
pipewire-0.3.52.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.53.tar.gz/src/daemon/pipewire-pulse.conf.in
Changed
@@ -66,6 +66,7 @@ #channelmix.rear-delay = 12.0 #channelmix.stereo-widen = 0.0 #channelmix.hilbert-taps = 0 + #dither.noise = 0 } pulse.properties = {
View file
pipewire-0.3.52.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.53.tar.gz/src/daemon/pipewire.conf.in
Changed
@@ -27,7 +27,7 @@ ## Properties for the DSP configuration. #default.clock.rate = 48000 - #default.clock.allowed-rates = 44100 48000 + #default.clock.allowed-rates = 48000 #default.clock.quantum = 1024 default.clock.min-quantum = 16 #default.clock.max-quantum = 2048
View file
pipewire-0.3.52.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-0.3.53.tar.gz/src/gst/gstpipewiresrc.c
Changed
@@ -44,6 +44,7 @@ #include <unistd.h> #include <spa/pod/builder.h> +#include <spa/utils/result.h> #include <gst/net/gstnetclientclock.h> #include <gst/allocators/gstfdmemory.h> @@ -443,6 +444,7 @@ { GstPipeWireSrc *src; GstPipeWirePoolData *data; + int res; data = gst_pipewire_pool_get_data (GST_BUFFER_CAST(obj)); @@ -466,8 +468,11 @@ data->queued = TRUE; - GST_LOG_OBJECT (src, "recycle buffer %p", obj); - pw_stream_queue_buffer (src->stream, data->b); + if ((res = pw_stream_queue_buffer (src->stream, data->b)) < 0) + GST_WARNING_OBJECT (src, "can't queue recycled buffer %p, %s", obj, spa_strerror(res)); + else + GST_LOG_OBJECT (src, "recycle buffer %p", obj); + pw_thread_loop_unlock (src->core->loop); GST_OBJECT_UNLOCK (data->pool); @@ -481,9 +486,9 @@ GstPipeWireSrc *pwsrc = _data; GstPipeWirePoolData *data; - GST_DEBUG_OBJECT (pwsrc, "add buffer"); gst_pipewire_pool_wrap_buffer (pwsrc->pool, b); data = b->user_data; + GST_DEBUG_OBJECT (pwsrc, "add buffer %p", data->buf); data->owner = pwsrc; data->queued = TRUE; GST_MINI_OBJECT_CAST (data->buf)->dispose = buffer_recycle; @@ -495,15 +500,18 @@ GstPipeWireSrc *pwsrc = _data; GstPipeWirePoolData *data = b->user_data; GstBuffer *buf = data->buf; + int res; GST_DEBUG_OBJECT (pwsrc, "remove buffer %p", buf); GST_MINI_OBJECT_CAST (buf)->dispose = NULL; - if (data->queued) + if (data->queued) { gst_buffer_unref (buf); - else - pw_stream_queue_buffer (pwsrc->stream, b); + } else { + if ((res = pw_stream_queue_buffer (pwsrc->stream, b)) < 0) + GST_WARNING_OBJECT (pwsrc, "can't queue removed buffer %p, %s", buf, spa_strerror(res)); + } } static GstBuffer *dequeue_buffer(GstPipeWireSrc *pwsrc) @@ -1026,10 +1034,10 @@ pwsrc = GST_PIPEWIRE_SRC (psrc); + pw_thread_loop_lock (pwsrc->core->loop); if (!pwsrc->negotiated) goto not_negotiated; - pw_thread_loop_lock (pwsrc->core->loop); while (TRUE) { enum pw_stream_state state; @@ -1126,6 +1134,7 @@ not_negotiated: { + pw_thread_loop_unlock (pwsrc->core->loop); return GST_FLOW_NOT_NEGOTIATED; } streaming_eos: @@ -1348,7 +1357,9 @@ case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: + pw_thread_loop_lock (this->core->loop); this->negotiated = FALSE; + pw_thread_loop_unlock (this->core->loop); break; case GST_STATE_CHANGE_READY_TO_NULL: gst_pipewire_src_close (this);
View file
pipewire-0.3.52.tar.gz/src/modules/module-adapter/adapter.c -> pipewire-0.3.53.tar.gz/src/modules/module-adapter/adapter.c
Changed
@@ -95,7 +95,7 @@ struct pw_properties *new; const char *str, *path, *desc, *nick, *name, *node_name, *media_class; char position8, *prefix; - bool is_monitor, is_device, is_duplex, is_virtual; + bool is_monitor, is_device, is_duplex, is_virtual, is_control = false; direction = pw_impl_port_get_direction(port); @@ -105,6 +105,9 @@ if (!is_monitor && direction != n->direction) return; + if ((str = pw_properties_get(old, PW_KEY_FORMAT_DSP)) != NULL) + is_control = spa_streq(str, "8 bit raw midi"); + path = pw_properties_get(n->props, PW_KEY_OBJECT_PATH); media_class = pw_properties_get(n->props, PW_KEY_MEDIA_CLASS); @@ -120,7 +123,10 @@ new = pw_properties_new(NULL, NULL); - if (is_duplex) + if (is_control) + prefix = direction == PW_DIRECTION_INPUT ? + "control" : "notify"; + else if (is_duplex) prefix = direction == PW_DIRECTION_INPUT ? "playback" : "capture"; else if (is_virtual) @@ -156,13 +162,20 @@ pw_properties_setf(new, PW_KEY_OBJECT_PATH, "%s:%s_%d", path ? path : node_name, prefix, pw_impl_port_get_id(port)); - pw_properties_setf(new, PW_KEY_PORT_NAME, "%s_%s", prefix, str); + if (is_control) + pw_properties_setf(new, PW_KEY_PORT_NAME, "%s", prefix); + else + pw_properties_setf(new, PW_KEY_PORT_NAME, "%s_%s", prefix, str); if ((node_name = nick) == NULL && (node_name = desc) == NULL && (node_name = name) == NULL) node_name = "node"; - pw_properties_setf(new, PW_KEY_PORT_ALIAS, "%s:%s_%s", + if (is_control) + pw_properties_setf(new, PW_KEY_PORT_ALIAS, "%s:%s", + node_name, prefix); + else + pw_properties_setf(new, PW_KEY_PORT_ALIAS, "%s:%s_%s", node_name, prefix, str); pw_impl_port_update_properties(port, &new->dict); @@ -240,7 +253,7 @@ int res, position = POSITION_PRESERVE; struct spa_pod *param; uint32_t media_type, media_subtype; - bool have_format = false, monitor = false; + bool have_format = false, monitor = false, control = false; struct spa_audio_info format = { 0, }; enum spa_param_port_config_mode mode = SPA_PARAM_PORT_CONFIG_MODE_none; struct spa_json it2; @@ -260,6 +273,8 @@ mode = SPA_PARAM_PORT_CONFIG_MODE_none; } else if (spa_streq(key, "monitor")) { monitor = spa_atob(val); + } else if (spa_streq(key, "control")) { + control = spa_atob(val); } else if (spa_streq(key, "position")) { if (spa_streq(val, "unknown")) position = POSITION_UNKNOWN; @@ -331,6 +346,7 @@ SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(n->direction), SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(mode), SPA_PARAM_PORT_CONFIG_monitor, SPA_POD_Bool(monitor), + SPA_PARAM_PORT_CONFIG_control, SPA_POD_Bool(control), SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param)); pw_impl_node_set_param(n->node, SPA_PARAM_PortConfig, 0, param);
View file
pipewire-0.3.52.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.53.tar.gz/src/modules/module-echo-cancel.c
Changed
@@ -80,6 +80,7 @@ * * - \ref PW_KEY_AUDIO_RATE * - \ref PW_KEY_AUDIO_CHANNELS + * - \ref SPA_KEY_AUDIO_POSITION * - \ref PW_KEY_MEDIA_CLASS * - \ref PW_KEY_NODE_LATENCY * - \ref PW_KEY_NODE_NAME @@ -89,7 +90,6 @@ * - \ref PW_KEY_NODE_VIRTUAL * - \ref PW_KEY_NODE_LATENCY * - \ref PW_KEY_REMOTE_NAME - * - \ref SPA_KEY_AUDIO_POSITION * * ## Example configuration *\code{.unparsed} @@ -125,6 +125,10 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); #define PW_LOG_TOPIC_DEFAULT mod_topic +#define DEFAULT_RATE 48000 +#define DEFAULT_CHANNELS 2 +#define DEFAULT_POSITION " FL FR " + /* Hopefully this is enough for any combination of AEC engine and resampler * input requirement for rate matching */ #define MAX_BUFSIZE_MS 100 @@ -859,9 +863,15 @@ *info = SPA_AUDIO_INFO_RAW_INIT( .format = SPA_AUDIO_FORMAT_F32P); info->rate = pw_properties_get_uint32(props, PW_KEY_AUDIO_RATE, info->rate); + if (info->rate == 0) + info->rate = DEFAULT_RATE; + info->channels = pw_properties_get_uint32(props, PW_KEY_AUDIO_CHANNELS, info->channels); + 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 void copy_props(struct impl *impl, struct pw_properties *props, const char *key) @@ -927,14 +937,6 @@ parse_audio_info(props, &impl->info); - if (impl->info.channels == 0) { - impl->info.channels = 2; - impl->info.position0 = SPA_AUDIO_CHANNEL_FL; - impl->info.position1 = SPA_AUDIO_CHANNEL_FR; - } - if (impl->info.rate == 0) - impl->info.rate = 48000; - if ((str = pw_properties_get(props, "source.props")) != NULL) pw_properties_update_string(impl->source_props, str, strlen(str)); if ((str = pw_properties_get(props, "sink.props")) != NULL)
View file
pipewire-0.3.52.tar.gz/src/modules/module-example-sink.c -> pipewire-0.3.53.tar.gz/src/modules/module-example-sink.c
Changed
@@ -64,6 +64,7 @@ * Options with well-known behavior. * * - \ref PW_KEY_REMOTE_NAME + * - \ref PW_KEY_AUDIO_FORMAT * - \ref PW_KEY_AUDIO_RATE * - \ref PW_KEY_AUDIO_CHANNELS * - \ref SPA_KEY_AUDIO_POSITION @@ -107,7 +108,7 @@ " node.description=<description of the nodes> " \ " audio.format=<format, default:"DEFAULT_FORMAT"> " \ " audio.rate=<sample rate, default: "SPA_STRINGIFY(DEFAULT_RATE)"> " \ - " audio.channels=<number of channels, default:"SPA_STRINGIFY(EFAULT_CHANNELS) "> " \ + " audio.channels=<number of channels, default:"SPA_STRINGIFY(DEFAULT_CHANNELS) "> " \ " audio.position=<channel map, default:"DEFAULT_POSITION"> " \ " stream.props=<properties> " @@ -340,56 +341,59 @@ } } -static int parse_audio_info(struct impl *impl) +static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info) { - struct pw_properties *props = impl->stream_props; - struct spa_audio_info_raw *info = &impl->info; const char *str; spa_zero(*info); - if ((str = pw_properties_get(props, PW_KEY_AUDIO_FORMAT)) == NULL) str = DEFAULT_FORMAT; info->format = format_from_name(str, strlen(str)); + + info->rate = pw_properties_get_uint32(props, PW_KEY_AUDIO_RATE, info->rate); + if (info->rate == 0) + info->rate = DEFAULT_RATE; + + info->channels = pw_properties_get_uint32(props, PW_KEY_AUDIO_CHANNELS, info->channels); + 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 int calc_frame_size(const struct spa_audio_info_raw *info) +{ + int res = info->channels; switch (info->format) { - case SPA_AUDIO_FORMAT_S8: case SPA_AUDIO_FORMAT_U8: - impl->frame_size = 1; - break; + case SPA_AUDIO_FORMAT_S8: + case SPA_AUDIO_FORMAT_ALAW: + case SPA_AUDIO_FORMAT_ULAW: + return res; case SPA_AUDIO_FORMAT_S16: - impl->frame_size = 2; - break; + case SPA_AUDIO_FORMAT_S16_OE: + case SPA_AUDIO_FORMAT_U16: + return res * 2; case SPA_AUDIO_FORMAT_S24: - impl->frame_size = 3; - break; + case SPA_AUDIO_FORMAT_S24_OE: + case SPA_AUDIO_FORMAT_U24: + return res * 3; case SPA_AUDIO_FORMAT_S24_32: + case SPA_AUDIO_FORMAT_S24_32_OE: case SPA_AUDIO_FORMAT_S32: + case SPA_AUDIO_FORMAT_S32_OE: + case SPA_AUDIO_FORMAT_U32: + case SPA_AUDIO_FORMAT_U32_OE: case SPA_AUDIO_FORMAT_F32: - impl->frame_size = 4; - break; + case SPA_AUDIO_FORMAT_F32_OE: + return res * 4; case SPA_AUDIO_FORMAT_F64: - impl->frame_size = 8; - break; + case SPA_AUDIO_FORMAT_F64_OE: + return res * 8; default: - pw_log_error("unsupported format '%s'", str); - return -EINVAL; - } - info->rate = pw_properties_get_uint32(props, PW_KEY_AUDIO_RATE, DEFAULT_RATE); - if (info->rate == 0) { - pw_log_error("invalid rate '%s'", str); - return -EINVAL; + return 0; } - info->channels = pw_properties_get_uint32(props, PW_KEY_AUDIO_CHANNELS, DEFAULT_CHANNELS); - if ((str = pw_properties_get(props, SPA_KEY_AUDIO_POSITION)) == NULL) - str = DEFAULT_POSITION; - parse_position(info, str, strlen(str)); - if (info->channels == 0) { - pw_log_error("invalid channels '%s'", str); - return -EINVAL; - } - impl->frame_size *= info->channels; - - return 0; } static void copy_props(struct impl *impl, struct pw_properties *props, const char *key) @@ -467,7 +471,11 @@ copy_props(impl, props, PW_KEY_NODE_VIRTUAL); copy_props(impl, props, PW_KEY_MEDIA_CLASS); - if ((res = parse_audio_info(impl)) < 0) { + parse_audio_info(impl->stream_props, &impl->info); + + impl->frame_size = calc_frame_size(&impl->info); + if (impl->frame_size == 0) { + res = -EINVAL; pw_log_error( "can't parse audio format"); goto error; }
View file
pipewire-0.3.52.tar.gz/src/modules/module-example-source.c -> pipewire-0.3.53.tar.gz/src/modules/module-example-source.c
Changed
@@ -64,6 +64,7 @@ * Options with well-known behavior. * * - \ref PW_KEY_REMOTE_NAME + * - \ref PW_KEY_AUDIO_FORMAT * - \ref PW_KEY_AUDIO_RATE * - \ref PW_KEY_AUDIO_CHANNELS * - \ref SPA_KEY_AUDIO_POSITION @@ -107,7 +108,7 @@ " node.description=<description of the nodes> " \ " audio.format=<format, default:"DEFAULT_FORMAT"> " \ " audio.rate=<sample rate, default: "SPA_STRINGIFY(DEFAULT_RATE)"> " \ - " audio.channels=<number of channels, default:"SPA_STRINGIFY(EFAULT_CHANNELS) "> " \ + " audio.channels=<number of channels, default:"SPA_STRINGIFY(DEFAULT_CHANNELS) "> " \ " audio.position=<channel map, default:"DEFAULT_POSITION"> " \ " stream.props=<properties> " @@ -344,56 +345,59 @@ } } -static int parse_audio_info(struct impl *impl) +static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info) { - struct pw_properties *props = impl->stream_props; - struct spa_audio_info_raw *info = &impl->info; const char *str; spa_zero(*info); - if ((str = pw_properties_get(props, PW_KEY_AUDIO_FORMAT)) == NULL) str = DEFAULT_FORMAT; info->format = format_from_name(str, strlen(str)); + + info->rate = pw_properties_get_uint32(props, PW_KEY_AUDIO_RATE, info->rate); + if (info->rate == 0) + info->rate = DEFAULT_RATE; + + info->channels = pw_properties_get_uint32(props, PW_KEY_AUDIO_CHANNELS, info->channels); + 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 int calc_frame_size(const struct spa_audio_info_raw *info) +{ + int res = info->channels; switch (info->format) { - case SPA_AUDIO_FORMAT_S8: case SPA_AUDIO_FORMAT_U8: - impl->frame_size = 1; - break; + case SPA_AUDIO_FORMAT_S8: + case SPA_AUDIO_FORMAT_ALAW: + case SPA_AUDIO_FORMAT_ULAW: + return res; case SPA_AUDIO_FORMAT_S16: - impl->frame_size = 2; - break; + case SPA_AUDIO_FORMAT_S16_OE: + case SPA_AUDIO_FORMAT_U16: + return res * 2; case SPA_AUDIO_FORMAT_S24: - impl->frame_size = 3; - break; + case SPA_AUDIO_FORMAT_S24_OE: + case SPA_AUDIO_FORMAT_U24: + return res * 3; case SPA_AUDIO_FORMAT_S24_32: + case SPA_AUDIO_FORMAT_S24_32_OE: case SPA_AUDIO_FORMAT_S32: + case SPA_AUDIO_FORMAT_S32_OE: + case SPA_AUDIO_FORMAT_U32: + case SPA_AUDIO_FORMAT_U32_OE: case SPA_AUDIO_FORMAT_F32: - impl->frame_size = 4; - break; + case SPA_AUDIO_FORMAT_F32_OE: + return res * 4; case SPA_AUDIO_FORMAT_F64: - impl->frame_size = 8; - break; + case SPA_AUDIO_FORMAT_F64_OE: + return res * 8; default: - pw_log_error("unsupported format '%s'", str); - return -EINVAL; - } - info->rate = pw_properties_get_uint32(props, PW_KEY_AUDIO_RATE, DEFAULT_RATE); - if (info->rate == 0) { - pw_log_error("invalid rate '%s'", str); - return -EINVAL; + return 0; } - info->channels = pw_properties_get_uint32(props, PW_KEY_AUDIO_CHANNELS, DEFAULT_CHANNELS); - if ((str = pw_properties_get(props, SPA_KEY_AUDIO_POSITION)) == NULL) - str = DEFAULT_POSITION; - parse_position(info, str, strlen(str)); - if (info->channels == 0) { - pw_log_error("invalid channels '%s'", str); - return -EINVAL; - } - impl->frame_size *= info->channels; - - return 0; } static void copy_props(struct impl *impl, struct pw_properties *props, const char *key) @@ -471,7 +475,11 @@ copy_props(impl, props, PW_KEY_NODE_VIRTUAL); copy_props(impl, props, PW_KEY_MEDIA_CLASS); - if ((res = parse_audio_info(impl)) < 0) { + parse_audio_info(impl->stream_props, &impl->info); + + impl->frame_size = calc_frame_size(&impl->info); + if (impl->frame_size == 0) { + res = -EINVAL; pw_log_error( "can't parse audio format"); goto error; }
View file
pipewire-0.3.52.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.53.tar.gz/src/modules/module-filter-chain.c
Changed
@@ -1690,15 +1690,29 @@ * graph n_hndl times when needed. */ n_hndl = impl->capture_info.channels / n_input; if (n_hndl != impl->playback_info.channels / n_output) { - pw_log_error("invalid channels"); + pw_log_error("invalid channels. The capture stream has %1$d channels and " + "the filter has %2$d inputs. The playback stream has %3$d channels " + "and the filter has %4$d outputs. capture:%1$d / input:%2$d != " + "playback:%3$d / output:%4$d. Check inputs and outputs objects.", + impl->capture_info.channels, n_input, + impl->playback_info.channels, n_output); res = -EINVAL; goto error; } if (n_hndl > MAX_HNDL) { - pw_log_error("too many channels"); + pw_log_error("too many channels. %d > %d", n_hndl, MAX_HNDL); res = -EINVAL; goto error; } + if (n_hndl == 0) { + n_hndl = 1; + pw_log_warn("The capture stream has %1$d channels and " + "the filter has %2$d inputs. The playback stream has %3$d channels " + "and the filter has %4$d outputs. Some filter ports will be " + "unconnected..", + impl->capture_info.channels, n_input, + impl->playback_info.channels, n_output); + } pw_log_info("using %d instances %d %d", n_hndl, n_input, n_output); /* now go over all nodes and create instances. */ @@ -2083,8 +2097,9 @@ *info = SPA_AUDIO_INFO_RAW_INIT( .format = SPA_AUDIO_FORMAT_F32P); - info->rate = pw_properties_get_int32(props, PW_KEY_AUDIO_RATE, 0); - info->channels = pw_properties_get_int32(props, PW_KEY_AUDIO_CHANNELS, 0); + info->rate = pw_properties_get_int32(props, PW_KEY_AUDIO_RATE, info->rate); + info->channels = pw_properties_get_int32(props, PW_KEY_AUDIO_CHANNELS, info->channels); + 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)); }
View file
pipewire-0.3.52.tar.gz/src/modules/module-filter-chain/ladspa_plugin.c -> pipewire-0.3.53.tar.gz/src/modules/module-filter-chain/ladspa_plugin.c
Changed
@@ -167,7 +167,7 @@ desc->desc.free = ladspa_free; desc->desc.name = d->Label; - desc->desc.flags = d->Properties; + desc->desc.flags = 0; desc->desc.n_ports = d->PortCount; desc->desc.ports = calloc(desc->desc.n_ports, sizeof(struct fc_port));
View file
pipewire-0.3.52.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.53.tar.gz/src/modules/module-loopback.c
Changed
@@ -453,6 +453,7 @@ .format = SPA_AUDIO_FORMAT_F32P); info->rate = pw_properties_get_int32(props, PW_KEY_AUDIO_RATE, 0); 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)); }
View file
pipewire-0.3.52.tar.gz/src/modules/module-pipe-tunnel.c -> pipewire-0.3.53.tar.gz/src/modules/module-pipe-tunnel.c
Changed
@@ -84,6 +84,7 @@ * Options with well-known behavior. * * - \ref PW_KEY_REMOTE_NAME + * - \ref PW_KEY_AUDIO_FORMAT * - \ref PW_KEY_AUDIO_RATE * - \ref PW_KEY_AUDIO_CHANNELS * - \ref SPA_KEY_AUDIO_POSITION @@ -107,6 +108,7 @@ * tunnel.mode = playback * # Set the pipe name to tunnel to * pipe.filename = "/tmp/fifo_output" + * #audio.format=<sample format> * #audio.rate=<sample rate> * #audio.channels=<number of channels> * #audio.position=<channel map> @@ -125,6 +127,11 @@ #define DEFAULT_CAPTURE_FILENAME "/tmp/fifo_input" #define DEFAULT_PLAYBACK_FILENAME "/tmp/fifo_output" +#define DEFAULT_FORMAT "S16" +#define DEFAULT_RATE 48000 +#define DEFAULT_CHANNELS 2 +#define DEFAULT_POSITION " FL FR " + PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); #define PW_LOG_TOPIC_DEFAULT mod_topic @@ -133,6 +140,7 @@ " node.name=<name of the nodes> " \ " node.description=<description of the nodes> " \ " node.target=<remote node target name> " \ + " audio.format=<sample format> " \ " audio.rate=<sample rate> " \ " audio.channels=<number of channels> " \ " audio.position=<channel map> " \ @@ -377,7 +385,7 @@ do_unlink_fifo = true; } - if ((fd = open(filename, O_RDWR | O_CLOEXEC | O_NONBLOCK, 0)) <= 0) { + if ((fd = open(filename, O_RDWR | O_CLOEXEC | O_NONBLOCK, 0)) < 0) { res = -errno; pw_log_error("open('%s'): %s", filename, spa_strerror(res)); goto error; @@ -408,7 +416,7 @@ error: if (do_unlink_fifo) unlink(filename); - if (fd > 0) + if (fd >= 0) close(fd); return res; } @@ -453,7 +461,7 @@ unlink(impl->filename); free(impl->filename); } - if (impl->fd > 0) + if (impl->fd >= 0) close(impl->fd); pw_properties_free(impl->stream_props); @@ -511,31 +519,28 @@ return SPA_AUDIO_FORMAT_UNKNOWN; } -static void parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info) +static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info) { const char *str; - *info = SPA_AUDIO_INFO_RAW_INIT( - .rate = 48000, - .channels = 2, - .format = SPA_AUDIO_FORMAT_S16); - - if ((str = pw_properties_get(props, PW_KEY_AUDIO_FORMAT)) != NULL) { - uint32_t id; - - id = format_from_name(str, strlen(str)); - if (id != SPA_AUDIO_FORMAT_UNKNOWN) - info->format = id; - } + spa_zero(*info); + if ((str = pw_properties_get(props, PW_KEY_AUDIO_FORMAT)) == NULL) + str = DEFAULT_FORMAT; + info->format = format_from_name(str, strlen(str)); info->rate = pw_properties_get_uint32(props, PW_KEY_AUDIO_RATE, info->rate); + if (info->rate == 0) + info->rate = DEFAULT_RATE; + info->channels = pw_properties_get_uint32(props, PW_KEY_AUDIO_CHANNELS, info->channels); + 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 int calc_frame_size(struct spa_audio_info_raw *info) +static int calc_frame_size(const struct spa_audio_info_raw *info) { int res = info->channels; switch (info->format) { @@ -662,13 +667,6 @@ parse_audio_info(impl->stream_props, &impl->info); - if (impl->info.rate != 0 && - pw_properties_get(props, PW_KEY_NODE_RATE) == NULL) - pw_properties_setf(props, PW_KEY_NODE_RATE, - "1/%u", impl->info.rate), - - copy_props(impl, props, PW_KEY_NODE_RATE); - impl->frame_size = calc_frame_size(&impl->info); if (impl->frame_size == 0) { pw_log_error("unsupported audio format:%d channels:%d", @@ -676,6 +674,13 @@ res = -EINVAL; goto error; } + if (impl->info.rate != 0 && + pw_properties_get(props, PW_KEY_NODE_RATE) == NULL) + pw_properties_setf(props, PW_KEY_NODE_RATE, + "1/%u", impl->info.rate), + + copy_props(impl, props, PW_KEY_NODE_RATE); + impl->leftover = calloc(1, impl->frame_size); if (impl->leftover == NULL) { res = -errno;
View file
pipewire-0.3.52.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.53.tar.gz/src/modules/module-protocol-native.c
Changed
@@ -38,7 +38,7 @@ #ifdef HAVE_PWD_H #include <pwd.h> #endif -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__MidnightBSD__) #include <sys/ucred.h> #endif @@ -534,7 +534,7 @@ struct pw_impl_client *client; struct pw_protocol *protocol = s->this.protocol; socklen_t len; -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__MidnightBSD__) struct xucred xucred; #else struct ucred ucred; @@ -583,7 +583,7 @@ (int)len, buffer); } } -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__MidnightBSD__) len = sizeof(xucred); if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { pw_log_warn("server %p: no peercred: %m", s);
View file
pipewire-0.3.52.tar.gz/src/modules/module-protocol-pulse.c -> pipewire-0.3.53.tar.gz/src/modules/module-protocol-pulse.c
Changed
@@ -214,14 +214,16 @@ * VMs usually can't support the low latency settings that are possible on real * hardware. * - * ## Application settings (Rules) - * - * The pulse protocol module supports generic config rules. It provides a `quirks` - * and an `update-props` action. + * ## Stream settings and rules * * Streams created by module-protocol-pulse will use the stream.properties * section and stream.rules sections as usual. * + * ## Application settings (Rules) + * + * The pulse protocol module supports generic config rules. It supports a pulse.rules + * section with a `quirks` and an `update-props` action. + * *\code{.unparsed} * pulse.rules = * {
View file
pipewire-0.3.52.tar.gz/src/modules/module-protocol-pulse/client.c -> pipewire-0.3.53.tar.gz/src/modules/module-protocol-pulse/client.c
Changed
@@ -159,10 +159,10 @@ pending_sample_free(p); if (client->message) - message_free(impl, client->message, false, false); + message_free(client->message, false, false); spa_list_consume(msg, &client->out_messages, link) - message_free(impl, msg, true, false); + message_free(msg, true, false); spa_list_consume(o, &client->operations, link) operation_free(o); @@ -220,14 +220,12 @@ return 0; error: - message_free(impl, msg, false, false); + message_free(msg, false, false); return res; } static int client_try_flush_messages(struct client *client) { - struct impl *impl = client->impl; - pw_log_trace("client %p: flushing", client); spa_assert(!client->disconnect); @@ -254,7 +252,7 @@ } else { if (debug_messages && m->channel == SPA_ID_INVALID) message_dump(SPA_LOG_LEVEL_INFO, m); - message_free(impl, m, true, false); + message_free(m, true, false); client->out_index = 0; continue; } @@ -307,7 +305,7 @@ if (m == first && client->out_index > 0) return false; - message_free(client->impl, m, true, false); + message_free(m, true, false); return true; }
View file
pipewire-0.3.52.tar.gz/src/modules/module-protocol-pulse/client.h -> pipewire-0.3.53.tar.gz/src/modules/module-protocol-pulse/client.h
Changed
@@ -56,7 +56,7 @@ struct server *server; int ref; - const char *name; + const char *name; /* owned by `client::props` */ struct spa_source *source;
View file
pipewire-0.3.52.tar.gz/src/modules/module-protocol-pulse/message.c -> pipewire-0.3.53.tar.gz/src/modules/module-protocol-pulse/message.c
Changed
@@ -390,6 +390,9 @@ uint32_t alloc, diff; void *data; + if (m->length > m->allocated) + return -ENOMEM; + if (m->length + size <= m->allocated) return size; @@ -397,12 +400,13 @@ diff = alloc - m->allocated; if ((data = realloc(m->data, alloc)) == NULL) { free(m->data); - m->stat->allocated -= m->allocated; + m->data = NULL; + m->impl->stat.allocated -= m->allocated; m->allocated = 0; return -errno; } - m->stat->allocated += diff; - m->stat->accumulated += diff; + m->impl->stat.allocated += diff; + m->impl->stat.accumulated += diff; m->data = data; m->allocated = alloc; return size; @@ -826,18 +830,20 @@ msg = spa_list_first(&impl->free_messages, struct message, link); spa_list_remove(&msg->link); pw_log_trace("using recycled message %p size:%d", msg, size); + + spa_assert(msg->impl == impl); } else { if ((msg = calloc(1, sizeof(*msg))) == NULL) return NULL; pw_log_trace("new message %p size:%d", msg, size); - msg->stat = &impl->stat; - msg->stat->n_allocated++; - msg->stat->n_accumulated++; + msg->impl = impl; + msg->impl->stat.n_allocated++; + msg->impl->stat.n_accumulated++; } if (ensure_size(msg, size) < 0) { - message_free(impl, msg, false, true); + message_free(msg, false, true); return NULL; } @@ -849,23 +855,23 @@ return msg; } -void message_free(struct impl *impl, struct message *msg, bool dequeue, bool destroy) +void message_free(struct message *msg, bool dequeue, bool destroy) { if (dequeue) spa_list_remove(&msg->link); - if (msg->stat->allocated > MAX_ALLOCATED || msg->allocated > MAX_SIZE) + if (msg->impl->stat.allocated > MAX_ALLOCATED || msg->allocated > MAX_SIZE) destroy = true; if (destroy) { pw_log_trace("destroy message %p size:%d", msg, msg->allocated); - msg->stat->n_allocated--; - msg->stat->allocated -= msg->allocated; + msg->impl->stat.n_allocated--; + msg->impl->stat.allocated -= msg->allocated; free(msg->data); free(msg); } else { pw_log_trace("recycle message %p size:%d/%d", msg, msg->length, msg->allocated); - spa_list_append(&impl->free_messages, &msg->link); + spa_list_append(&msg->impl->free_messages, &msg->link); msg->length = 0; } }
View file
pipewire-0.3.52.tar.gz/src/modules/module-protocol-pulse/message.h -> pipewire-0.3.53.tar.gz/src/modules/module-protocol-pulse/message.h
Changed
@@ -32,12 +32,10 @@ #include <spa/support/log.h> struct impl; -struct client; -struct stats; struct message { struct spa_list link; - struct stats *stat; + struct impl *impl; uint32_t extra4; uint32_t channel; uint32_t allocated; @@ -69,7 +67,7 @@ }; struct message *message_alloc(struct impl *impl, uint32_t channel, uint32_t size); -void message_free(struct impl *impl, struct message *msg, bool dequeue, bool destroy); +void message_free(struct message *msg, bool dequeue, bool destroy); int message_get(struct message *m, ...); int message_put(struct message *m, ...); int message_dump(enum spa_log_level level, struct message *m);
View file
pipewire-0.3.52.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.53.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
@@ -87,9 +87,6 @@ #define DEFAULT_POSITION " FL FR " #define MAX_FORMATS 32 -/* The max amount of data we send in one block when capturing. In PulseAudio this - * size is derived from the mempool PA_MEMPOOL_SLOT_SIZE */ -#define MAX_FRAGSIZE (64*1024) #define TEMPORARY_MOVE_TIMEOUT (SPA_NSEC_PER_SEC) @@ -455,6 +452,10 @@ if (frame_size == 0) frame_size = 4; + pw_log_info("%s maxlength:%u tlength:%u minreq:%u prebuf:%u", + s->client->name, attr->maxlength, attr->tlength, + attr->minreq, attr->prebuf); + minreq = frac_to_bytes_round_up(s->min_req, &s->ss); max_latency = defs->quantum_limit * frame_size; @@ -651,6 +652,9 @@ if (frame_size == 0) frame_size = 4; + pw_log_info("%s maxlength:%u fragsize:%u", + s->client->name, attr->maxlength, attr->fragsize); + if (attr->maxlength == (uint32_t) -1 || attr->maxlength > MAXLENGTH) attr->maxlength = MAXLENGTH; attr->maxlength -= attr->maxlength % frame_size; @@ -660,12 +664,9 @@ if (attr->fragsize == (uint32_t) -1 || attr->fragsize == 0) attr->fragsize = frac_to_bytes_round_up(s->default_frag, &s->ss); - attr->fragsize -= attr->fragsize % frame_size; + attr->fragsize = SPA_MIN(attr->fragsize, attr->maxlength); + attr->fragsize = SPA_ROUND_UP(attr->fragsize, frame_size); attr->fragsize = SPA_MAX(attr->fragsize, minfrag); - attr->fragsize = SPA_MAX(attr->fragsize, frame_size); - - if (attr->fragsize > attr->maxlength) - attr->fragsize = attr->maxlength; attr->tlength = attr->minreq = attr->prebuf = 0; @@ -676,6 +677,9 @@ } else { latency = attr->fragsize; } + /* make sure can queue at least to fragsize without overruns */ + if (attr->maxlength < attr->fragsize * 2) + attr->maxlength = attr->fragsize * 2; pw_log_info("%s maxlength:%u fragsize:%u minfrag:%u latency:%u", s->client->name, attr->maxlength, attr->fragsize, minfrag, @@ -748,13 +752,12 @@ peer = find_linked(manager, peer->id, PW_DIRECTION_OUTPUT); if (peer && pw_manager_object_is_source_or_monitor(peer)) { name = pw_properties_get(peer->props, PW_KEY_NODE_NAME); + peer_index = peer->index; if (!pw_manager_object_is_source(peer)) { size_t len = (name ? strlen(name) : 5) + 10; - peer_index = peer->index; peer_name = tmp = alloca(len); snprintf(tmp, len, "%s.monitor", name ? name : "sink"); } else { - peer_index = peer->index; peer_name = name; } } else { @@ -849,6 +852,13 @@ s->peer_index = peer->index; peer_name = pw_properties_get(peer->props, PW_KEY_NODE_NAME); + if (peer_name && s->direction == PW_DIRECTION_INPUT && + pw_manager_object_is_monitor(peer)) { + int len = strlen(peer_name) + 10; + char *tmp = alloca(len); + snprintf(tmp, len, "%s.monitor", peer_name); + peer_name = tmp; + } if (peer_name != NULL) stream_send_moved(s, peer->index, peer_name); } @@ -1024,12 +1034,12 @@ changed++; } + client_update_quirks(client); + client->name = pw_properties_get(client->props, PW_KEY_APP_NAME); pw_log_info("%s %s tag:%d", client->name, commandscommand.name, tag); - client_update_quirks(client); - if (client->core == NULL) { client->core = pw_context_connect(impl->context, pw_properties_copy(client->props), 0); @@ -1320,8 +1330,7 @@ } while ((uint32_t)avail >= stream->attr.fragsize) { - towrite = SPA_MIN(avail, MAX_FRAGSIZE); - towrite = SPA_ROUND_DOWN(towrite, stream->frame_size); + towrite = SPA_MIN((uint32_t)avail, stream->attr.fragsize); msg = message_alloc(impl, stream->channel, towrite); if (msg == NULL) @@ -3236,6 +3245,7 @@ } else { if (pw_properties_update(client->props, &props->dict) > 0) { client_update_quirks(client); + client->name = pw_properties_get(client->props, PW_KEY_APP_NAME); pw_core_update_properties(client->core, &client->props->dict); } } @@ -4313,7 +4323,7 @@ goto error; error: if (reply) - message_free(impl, reply, false, false); + message_free(reply, false, false); return res; } @@ -4389,7 +4399,7 @@ error: if (reply) - message_free(impl, reply, false, false); + message_free(reply, false, false); return res; } @@ -5353,7 +5363,7 @@ client_free(c); spa_list_consume(msg, &impl->free_messages, link) - message_free(impl, msg, true, true); + message_free(msg, true, true); pw_map_for_each(&impl->samples, impl_free_sample, impl); pw_map_clear(&impl->samples);
View file
pipewire-0.3.52.tar.gz/src/modules/module-protocol-pulse/remap.c -> pipewire-0.3.53.tar.gz/src/modules/module-protocol-pulse/remap.c
Changed
@@ -43,6 +43,7 @@ const struct str_map props_key_map = { { PW_KEY_DEVICE_BUS_PATH, "device.bus_path" }, + { PW_KEY_DEVICE_SYSFS_PATH, "sysfs.path" }, { PW_KEY_DEVICE_FORM_FACTOR, "device.form_factor" }, { PW_KEY_DEVICE_ICON_NAME, "device.icon_name" }, { PW_KEY_DEVICE_INTENDED_ROLES, "device.intended_roles" },
View file
pipewire-0.3.52.tar.gz/src/modules/module-protocol-pulse/server.c -> pipewire-0.3.53.tar.gz/src/modules/module-protocol-pulse/server.c
Changed
@@ -66,7 +66,6 @@ static int handle_packet(struct client *client, struct message *msg) { - struct impl * const impl = client->impl; uint32_t command, tag; int res = 0; @@ -110,7 +109,7 @@ res = cmd->run(client, command, tag, msg); finish: - message_free(impl, msg, false, false); + message_free(msg, false, false); if (res < 0) reply_error(client, command, tag, res); @@ -119,7 +118,6 @@ static int handle_memblock(struct client *client, struct message *msg) { - struct impl * const impl = client->impl; struct stream *stream; uint32_t channel, flags, index; int64_t offset, diff; @@ -190,7 +188,7 @@ stream_send_request(stream); finish: - message_free(impl, msg, false, false); + message_free(msg, false, false); return res; } @@ -264,7 +262,7 @@ } if (client->message) - message_free(impl, client->message, false, false); + message_free(client->message, false, false); client->message = message_alloc(impl, channel, length); } else if (client->message && @@ -460,7 +458,7 @@ if (address0 != '/') { char runtime_dirPATH_MAX; - if ((res = get_runtime_dir(runtime_dir, sizeof(runtime_dir), "pulse")) < 0) + if ((res = get_runtime_dir(runtime_dir, sizeof(runtime_dir))) < 0) return res; res = snprintf(addr.sun_path, sizeof(addr.sun_path),
View file
pipewire-0.3.52.tar.gz/src/modules/module-protocol-pulse/utils.c -> pipewire-0.3.53.tar.gz/src/modules/module-protocol-pulse/utils.c
Changed
@@ -50,27 +50,30 @@ #include "log.h" #include "utils.h" -int get_runtime_dir(char *buf, size_t buflen, const char *dir) +int get_runtime_dir(char *buf, size_t buflen) { - const char *runtime_dir; + const char *runtime_dir, *dir = NULL; struct stat stat_buf; int res, size; runtime_dir = getenv("PULSE_RUNTIME_PATH"); - if (runtime_dir == NULL) + if (runtime_dir == NULL) { runtime_dir = getenv("XDG_RUNTIME_DIR"); - + dir = "pulse"; + } if (runtime_dir == NULL) { pw_log_error("could not find a suitable runtime directory in" "$PULSE_RUNTIME_PATH and $XDG_RUNTIME_DIR"); return -ENOENT; } - size = snprintf(buf, buflen, "%s/%s", runtime_dir, dir); + size = snprintf(buf, buflen, "%s%s%s", runtime_dir, + dir ? "/" : "", dir ? dir : ""); if (size < 0) return -errno; if ((size_t) size >= buflen) { - pw_log_error("path %s/%s too long", runtime_dir, dir); + pw_log_error("path %s%s%s too long", runtime_dir, + dir ? "/" : "", dir ? dir : ""); return -ENAMETOOLONG; } @@ -149,7 +152,7 @@ pw_log_warn("client %p: no peercred: %m", client); } else return ucred.pid; -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__MidnightBSD__) struct xucred xucred; len = sizeof(xucred); if (getsockopt(client_fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { @@ -182,7 +185,7 @@ FILE *f; int res; - if ((res = get_runtime_dir(pid_file, sizeof(pid_file), "pulse")) < 0) + if ((res = get_runtime_dir(pid_file, sizeof(pid_file))) < 0) return res; if (strlen(pid_file) > PATH_MAX - sizeof("/pid")) {
View file
pipewire-0.3.52.tar.gz/src/modules/module-protocol-pulse/utils.h -> pipewire-0.3.53.tar.gz/src/modules/module-protocol-pulse/utils.h
Changed
@@ -31,7 +31,7 @@ struct client; struct pw_context; -int get_runtime_dir(char *buf, size_t buflen, const char *dir); +int get_runtime_dir(char *buf, size_t buflen); int check_flatpak(struct client *client, pid_t pid); pid_t get_client_pid(struct client *client, int client_fd); const char *get_server_name(struct pw_context *context);
View file
pipewire-0.3.52.tar.gz/src/modules/module-pulse-tunnel.c -> pipewire-0.3.53.tar.gz/src/modules/module-pulse-tunnel.c
Changed
@@ -80,6 +80,7 @@ * Options with well-known behavior. * * - \ref PW_KEY_REMOTE_NAME + * - \ref PW_KEY_AUDIO_FORMAT * - \ref PW_KEY_AUDIO_RATE * - \ref PW_KEY_AUDIO_CHANNELS * - \ref SPA_KEY_AUDIO_POSITION @@ -118,11 +119,17 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); #define PW_LOG_TOPIC_DEFAULT mod_topic +#define DEFAULT_FORMAT "S16" +#define DEFAULT_RATE 48000 +#define DEFAULT_CHANNELS 2 +#define DEFAULT_POSITION " FL FR " + #define MODULE_USAGE " remote.name=<remote> " \ " node.latency=<latency as fraction> " \ " node.name=<name of the nodes> " \ " node.description=<description of the nodes> " \ " node.target=<remote node target name> " \ + " audio.format=<sample format> " \ " audio.rate=<sample rate> " \ " audio.channels=<number of channels> " \ " audio.position=<channel map> " \ @@ -823,28 +830,25 @@ return SPA_AUDIO_FORMAT_UNKNOWN; } -static void parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info) +static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info) { const char *str; - *info = SPA_AUDIO_INFO_RAW_INIT( - .rate = 48000, - .channels = 2, - .format = SPA_AUDIO_FORMAT_S16); - - if ((str = pw_properties_get(props, PW_KEY_AUDIO_FORMAT)) != NULL) { - uint32_t id; - - id = format_from_name(str, strlen(str)); - if (id != SPA_AUDIO_FORMAT_UNKNOWN) - info->format = id; - } + spa_zero(*info); + if ((str = pw_properties_get(props, PW_KEY_AUDIO_FORMAT)) == NULL) + str = DEFAULT_FORMAT; + info->format = format_from_name(str, strlen(str)); info->rate = pw_properties_get_uint32(props, PW_KEY_AUDIO_RATE, info->rate); + if (info->rate == 0) + info->rate = DEFAULT_RATE; + info->channels = pw_properties_get_uint32(props, PW_KEY_AUDIO_CHANNELS, info->channels); + 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 int calc_frame_size(struct spa_audio_info_raw *info)
View file
pipewire-0.3.52.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.53.tar.gz/src/modules/module-raop-sink.c
Changed
@@ -110,7 +110,7 @@ " node.name=<name of the nodes> " \ " node.description=<description of the nodes> " \ " audio.format=<format, default:"DEFAULT_FORMAT"> " \ - " audio.rate=<sample rate, default: "SPA_STRINGIFY(DEFAuLT_RATE)"> " \ + " audio.rate=<sample rate, default: "SPA_STRINGIFY(DEFAULT_RATE)"> " \ " audio.channels=<number of channels, default:"SPA_STRINGIFY(DEFAULT_CHANNELS)"> " \ " audio.position=<channel map, default:"DEFAULT_POSITION"> " \ " stream.props=<properties> " @@ -1143,7 +1143,7 @@ DEFAULT_USER_NAME, realm, nonce, resp); } else - return -EINVAL; + goto error; pw_properties_setf(impl->headers, "Authorization", "%s %s", tokens0, auth); @@ -1484,56 +1484,59 @@ } } -static int parse_audio_info(struct impl *impl) +static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info) { - struct pw_properties *props = impl->stream_props; - struct spa_audio_info_raw *info = &impl->info; const char *str; spa_zero(*info); - if ((str = pw_properties_get(props, PW_KEY_AUDIO_FORMAT)) == NULL) str = DEFAULT_FORMAT; info->format = format_from_name(str, strlen(str)); + + info->rate = pw_properties_get_uint32(props, PW_KEY_AUDIO_RATE, info->rate); + if (info->rate == 0) + info->rate = DEFAULT_RATE; + + info->channels = pw_properties_get_uint32(props, PW_KEY_AUDIO_CHANNELS, info->channels); + 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 int calc_frame_size(struct spa_audio_info_raw *info) +{ + int res = info->channels; switch (info->format) { - case SPA_AUDIO_FORMAT_S8: case SPA_AUDIO_FORMAT_U8: - impl->frame_size = 1; - break; + case SPA_AUDIO_FORMAT_S8: + case SPA_AUDIO_FORMAT_ALAW: + case SPA_AUDIO_FORMAT_ULAW: + return res; case SPA_AUDIO_FORMAT_S16: - impl->frame_size = 2; - break; + case SPA_AUDIO_FORMAT_S16_OE: + case SPA_AUDIO_FORMAT_U16: + return res * 2; case SPA_AUDIO_FORMAT_S24: - impl->frame_size = 3; - break; + case SPA_AUDIO_FORMAT_S24_OE: + case SPA_AUDIO_FORMAT_U24: + return res * 3; case SPA_AUDIO_FORMAT_S24_32: + case SPA_AUDIO_FORMAT_S24_32_OE: case SPA_AUDIO_FORMAT_S32: + case SPA_AUDIO_FORMAT_S32_OE: + case SPA_AUDIO_FORMAT_U32: + case SPA_AUDIO_FORMAT_U32_OE: case SPA_AUDIO_FORMAT_F32: - impl->frame_size = 4; - break; + case SPA_AUDIO_FORMAT_F32_OE: + return res * 4; case SPA_AUDIO_FORMAT_F64: - impl->frame_size = 8; - break; + case SPA_AUDIO_FORMAT_F64_OE: + return res * 8; default: - pw_log_error("unsupported format '%s'", str); - return -EINVAL; - } - info->rate = pw_properties_get_uint32(props, PW_KEY_AUDIO_RATE, DEFAULT_RATE); - if (info->rate == 0) { - pw_log_error("invalid rate '%s'", str); - return -EINVAL; - } - info->channels = pw_properties_get_uint32(props, PW_KEY_AUDIO_CHANNELS, DEFAULT_CHANNELS); - if ((str = pw_properties_get(props, SPA_KEY_AUDIO_POSITION)) == NULL) - str = DEFAULT_POSITION; - parse_position(info, str, strlen(str)); - if (info->channels == 0) { - pw_log_error("invalid channels '%s'", str); - return -EINVAL; + return 0; } - impl->frame_size *= info->channels; - - return 0; } static void copy_props(struct impl *impl, struct pw_properties *props, const char *key) @@ -1617,8 +1620,13 @@ copy_props(impl, props, PW_KEY_NODE_VIRTUAL); copy_props(impl, props, PW_KEY_MEDIA_CLASS); - if ((res = parse_audio_info(impl)) < 0) { - pw_log_error( "can't parse audio format"); + parse_audio_info(impl->stream_props, &impl->info); + + impl->frame_size = calc_frame_size(&impl->info); + if (impl->frame_size == 0) { + pw_log_error("unsupported audio format:%d channels:%d", + impl->info.format, impl->info.channels); + res = -EINVAL; goto error; } @@ -1630,6 +1638,7 @@ impl->protocol = PROTO_TCP; else { pw_log_error( "can't handle transport %s", str); + res = -EINVAL; goto error; } @@ -1641,6 +1650,7 @@ impl->encryption = CRYPTO_RSA; else { pw_log_error( "can't handle encryption type %s", str); + res = -EINVAL; goto error; } @@ -1650,6 +1660,7 @@ impl->codec = CODEC_PCM; else { pw_log_error( "can't handle codec type %s", str); + res = -EINVAL; goto error; } str = pw_properties_get(props, "raop.password");
View file
pipewire-0.3.52.tar.gz/src/modules/module-roc-sink.c -> pipewire-0.3.53.tar.gz/src/modules/module-roc-sink.c
Changed
@@ -316,7 +316,7 @@ /* Fixed to be the same as ROC sender config above */ info.rate = 44100; info.channels = 2; - info.format = SPA_AUDIO_FORMAT_F32_LE; + info.format = SPA_AUDIO_FORMAT_F32; info.position0 = SPA_AUDIO_CHANNEL_FL; info.position1 = SPA_AUDIO_CHANNEL_FR;
View file
pipewire-0.3.52.tar.gz/src/modules/module-roc-source.c -> pipewire-0.3.53.tar.gz/src/modules/module-roc-source.c
Changed
@@ -337,7 +337,7 @@ /* Fixed to be the same as ROC receiver config above */ info.rate = 44100; info.channels = 2; - info.format = SPA_AUDIO_FORMAT_F32_LE; + info.format = SPA_AUDIO_FORMAT_F32; info.position0 = SPA_AUDIO_CHANNEL_FL; info.position1 = SPA_AUDIO_CHANNEL_FR; data->stride = info.channels * sizeof(float);
View file
pipewire-0.3.52.tar.gz/src/modules/module-rt.c -> pipewire-0.3.53.tar.gz/src/modules/module-rt.c
Changed
@@ -52,7 +52,7 @@ #include <stdio.h> #include <errno.h> #include <sys/stat.h> -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__MidnightBSD__) #include <sys/thr.h> #endif #include <fcntl.h> @@ -205,7 +205,7 @@ return (pid_t) gettid(); #elif defined(__linux__) return syscall(SYS_gettid); -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__MidnightBSD__) long pid; thr_self(&pid); return (pid_t)pid;
View file
pipewire-0.3.52.tar.gz/src/pipewire/conf.c -> pipewire-0.3.53.tar.gz/src/pipewire/conf.c
Changed
@@ -38,7 +38,7 @@ #ifdef HAVE_PWD_H #include <pwd.h> #endif -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__MidnightBSD__) #define O_PATH 0 #endif
View file
pipewire-0.3.52.tar.gz/src/pipewire/data-loop.c -> pipewire-0.3.53.tar.gz/src/pipewire/data-loop.c
Changed
@@ -40,11 +40,11 @@ int res; while (true) { - if (!this->running) { + if (SPA_UNLIKELY(!this->running)) { res = -ECANCELED; break; } - if ((res = pw_loop_iterate(this->loop, timeout)) < 0) { + if (SPA_UNLIKELY((res = pw_loop_iterate(this->loop, timeout)) < 0)) { if (res == -EINTR) continue; } @@ -77,8 +77,8 @@ pthread_cleanup_push(thread_cleanup, this); - while (this->running) { - if ((res = pw_loop_iterate(this->loop, -1)) < 0) { + while (SPA_LIKELY(this->running)) { + if (SPA_UNLIKELY((res = pw_loop_iterate(this->loop, -1)) < 0)) { if (res == -EINTR) continue; pw_log_error("%p: iterate error %d (%s)",
View file
pipewire-0.3.52.tar.gz/src/pipewire/keys.h -> pipewire-0.3.53.tar.gz/src/pipewire/keys.h
Changed
@@ -249,6 +249,7 @@ * "isa", "pci", "usb", "firewire", * "bluetooth" */ #define PW_KEY_DEVICE_SUBSYSTEM "device.subsystem" /**< device subsystem */ +#define PW_KEY_DEVICE_SYSFS_PATH "device.sysfs.path" /**< device sysfs path */ #define PW_KEY_DEVICE_ICON "device.icon" /**< icon for the device. A base64 blob * containing PNG image data */ #define PW_KEY_DEVICE_ICON_NAME "device.icon-name" /**< an XDG icon name for the device.
View file
pipewire-0.3.52.tar.gz/src/pipewire/mem.c -> pipewire-0.3.53.tar.gz/src/pipewire/mem.c
Changed
@@ -44,7 +44,7 @@ PW_LOG_TOPIC_EXTERN(log_mem); #define PW_LOG_TOPIC_DEFAULT log_mem -#if !defined(__FreeBSD__) && !defined(HAVE_MEMFD_CREATE) +#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) && !defined(HAVE_MEMFD_CREATE) /* * No glibc wrappers exist for memfd_create(2), so provide our own. * @@ -61,7 +61,7 @@ #define HAVE_MEMFD_CREATE 1 #endif -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__MidnightBSD__) #define MAP_LOCKED 0 #endif @@ -491,7 +491,7 @@ pw_log_error("%p: Failed to create memfd: %m", pool); goto error_free; } -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__MidnightBSD__) b->this.fd = shm_open(SHM_ANON, O_CREAT | O_RDWR | O_CLOEXEC, 0); if (b->this.fd == -1) { res = -errno;
View file
pipewire-0.3.52.tar.gz/src/pipewire/meson.build -> pipewire-0.3.53.tar.gz/src/pipewire/meson.build
Changed
@@ -94,7 +94,7 @@ '-DOLD_MEDIA_SESSION_WORKAROUND=1' -if build_machine.system() != 'freebsd' +if build_machine.system() != 'freebsd' and build_machine.system() != 'midnightbsd' libpipewire_c_args += '-D_POSIX_C_SOURCE'
View file
pipewire-0.3.52.tar.gz/src/pipewire/pipewire.c -> pipewire-0.3.53.tar.gz/src/pipewire/pipewire.c
Changed
@@ -27,7 +27,7 @@ #include <unistd.h> #include <limits.h> #include <stdio.h> -#ifndef __FreeBSD__ +#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) #include <sys/prctl.h> #endif #include <pwd.h> @@ -746,7 +746,7 @@ static char namePATH_MAX; spa_memzero(name, sizeof(name)); -#if defined(__linux__) || defined(__FreeBSD_kernel__) +#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__MidnightBSD_kernel__) { if (readlink("/proc/self/exe", name, sizeof(name)-1) > 0) { prgname = strrchr(name, '/') + 1; @@ -754,7 +754,7 @@ } } #endif -#if defined __FreeBSD__ +#if defined __FreeBSD__ || defined(__MidnightBSD__) { ssize_t len; @@ -764,7 +764,7 @@ } } #endif -#ifndef __FreeBSD__ +#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) { if (prctl(PR_GET_NAME, (unsigned long) name, 0, 0, 0) == 0) { prgname = name;
View file
pipewire-0.3.52.tar.gz/src/pipewire/private.h -> pipewire-0.3.53.tar.gz/src/pipewire/private.h
Changed
@@ -40,7 +40,7 @@ #include <spa/utils/result.h> #include <spa/utils/type-info.h> -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__MidnightBSD__) struct ucred { }; #endif
View file
pipewire-0.3.52.tar.gz/src/pipewire/settings.c -> pipewire-0.3.53.tar.gz/src/pipewire/settings.c
Changed
@@ -41,7 +41,7 @@ #define NAME "settings" #define DEFAULT_CLOCK_RATE 48000u -#define DEFAULT_CLOCK_RATES " 44100 48000 " +#define DEFAULT_CLOCK_RATES " 48000 " #define DEFAULT_CLOCK_QUANTUM 1024u #define DEFAULT_CLOCK_MIN_QUANTUM 32u #define DEFAULT_CLOCK_MAX_QUANTUM 2048u
View file
pipewire-0.3.52.tar.gz/src/pipewire/stream.c -> pipewire-0.3.53.tar.gz/src/pipewire/stream.c
Changed
@@ -1182,8 +1182,6 @@ return -EINVAL; } - spa_list_append(&stream->controls, &c->link); - pod = spa_pod_get_values(type, &n_vals, &choice); c->type = SPA_POD_TYPE(pod); @@ -1204,22 +1202,28 @@ vals0 = SPA_POD_VALUE(struct spa_pod_bool, pod); n_vals = 3; } - else + else { + free(c); return -ENOTSUP; + } c->container = container != SPA_ID_INVALID ? container : c->type; switch (choice) { case SPA_CHOICE_None: - if (n_vals < 1) + if (n_vals < 1) { + free(c); return -EINVAL; + } c->control.n_values = 1; c->control.max_values = 1; c->control.values0 = c->control.def = c->control.min = c->control.max = vals0; break; case SPA_CHOICE_Range: - if (n_vals < 3) + if (n_vals < 3) { + free(c); return -EINVAL; + } c->control.n_values = 1; c->control.max_values = 1; c->control.values0 = vals0; @@ -1228,10 +1232,12 @@ c->control.max = vals2; break; default: + free(c); return -ENOTSUP; } c->id = iid; + spa_list_append(&stream->controls, &c->link); pw_log_debug("%p: add control %d (%s) container:%d (def:%f min:%f max:%f)", stream, c->id, c->control.name, c->container, c->control.def, c->control.min, c->control.max);
View file
pipewire-0.3.52.tar.gz/src/pipewire/stream.h -> pipewire-0.3.53.tar.gz/src/pipewire/stream.h
Changed
@@ -161,6 +161,15 @@ * \section sec_stream_disconnect Disconnect * * Use \ref pw_stream_disconnect() to disconnect a stream after use. + * + * \section sec_stream_configuration Configuration + * + * \subsection ssec_config_properties Stream Properties + * + * \subsection ssec_config_rules Stream Rules + * + * \section sec_stream_environment Environment Variables + * */ /** \defgroup pw_stream Stream *
View file
pipewire-0.3.52.tar.gz/src/pipewire/thread.c -> pipewire-0.3.53.tar.gz/src/pipewire/thread.c
Changed
@@ -62,9 +62,9 @@ return NULL; } -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__MidnightBSD__) #include <sys/param.h> -#if __FreeBSD_version < 1202000 +#if __FreeBSD_version < 1202000 || defined(__MidnightBSD__) int pthread_setname_np(pthread_t thread, const char *name) { pthread_set_name_np(thread, name);
View file
pipewire-0.3.52.tar.gz/src/tools/meson.build -> pipewire-0.3.53.tar.gz/src/tools/meson.build
Changed
@@ -17,13 +17,11 @@ ) endforeach -if readline_dep.found() - executable('pw-cli', - 'pw-cli.c', - install: true, - dependencies: pipewire_dep, readline_dep - ) -endif +executable('pw-cli', + 'pw-cli.c', + install: true, + dependencies: pipewire_dep, readline_dep +) if ncurses_dep.found() executable('pw-top',
View file
pipewire-0.3.52.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.53.tar.gz/src/tools/pw-cat.c
Changed
@@ -126,7 +126,6 @@ unsigned int rate; int channels; struct channelmap channelmap; - unsigned int samplesize; unsigned int stride; enum unit latency_unit; unsigned int latency_value; @@ -154,125 +153,42 @@ } dsf; }; -static inline int -sf_str_to_fmt(const char *str) -{ - if (!str) - return -1; - - if (spa_streq(str, "s8")) - return SF_FORMAT_PCM_S8; - if (spa_streq(str, "u8")) - return SF_FORMAT_PCM_U8; - if (spa_streq(str, "s16")) - return SF_FORMAT_PCM_16; - if (spa_streq(str, "s24")) - return SF_FORMAT_PCM_24; - if (spa_streq(str, "s32")) - return SF_FORMAT_PCM_32; - if (spa_streq(str, "f32")) - return SF_FORMAT_FLOAT; - if (spa_streq(str, "f64")) - return SF_FORMAT_DOUBLE; - - return -1; -} - -static inline const char * -sf_fmt_to_str(int format) -{ - int sub_type = (format & SF_FORMAT_SUBMASK); - - if (sub_type == SF_FORMAT_PCM_U8) - return "u8"; - if (sub_type == SF_FORMAT_PCM_S8) - return "s8"; - if (sub_type == SF_FORMAT_PCM_16) - return "s16"; - if (sub_type == SF_FORMAT_PCM_24) - return "s24"; - if (sub_type == SF_FORMAT_PCM_32) - return "s32"; - if (sub_type == SF_FORMAT_FLOAT) - return "f32"; - if (sub_type == SF_FORMAT_DOUBLE) - return "f64"; - return "(invalid)"; -} +#define STR_FMTS "(ulaw|alaw|u8|s8|s16|s32|f32|f64)" -#define STR_FMTS "(u8|s8|s16|s32|f32|f64)" - -/* 0 = native, 1 = le, 2 = be */ -static inline int -sf_format_endianess(int format) -{ - return 0; /* native */ -} +static const struct format_info { + const char *name; + int sf_format; + uint32_t spa_format; + uint32_t width; +} format_info = { + { "ulaw", SF_FORMAT_ULAW, SPA_AUDIO_FORMAT_ULAW, 1 }, + { "alaw", SF_FORMAT_ULAW, SPA_AUDIO_FORMAT_ALAW, 1 }, + { "s8", SF_FORMAT_PCM_S8, SPA_AUDIO_FORMAT_S8, 1 }, + { "u8", SF_FORMAT_PCM_U8, SPA_AUDIO_FORMAT_U8, 1 }, + { "s16", SF_FORMAT_PCM_16, SPA_AUDIO_FORMAT_S16, 2 }, + { "s24", SF_FORMAT_PCM_24, SPA_AUDIO_FORMAT_S24, 3 }, + { "s32", SF_FORMAT_PCM_32, SPA_AUDIO_FORMAT_S32, 4 }, + { "f32", SF_FORMAT_FLOAT, SPA_AUDIO_FORMAT_F32, 4 }, + { "f64", SF_FORMAT_DOUBLE, SPA_AUDIO_FORMAT_F32, 8 }, +}; -static inline enum spa_audio_format -sf_format_to_pw(int format) +static const struct format_info *format_info_by_name(const char *str) { - int endianness; - - endianness = sf_format_endianess(format); - if (endianness < 0) - return SPA_AUDIO_FORMAT_UNKNOWN; - - switch (format & SF_FORMAT_SUBMASK) { - case SF_FORMAT_PCM_U8: - return SPA_AUDIO_FORMAT_U8; - case SF_FORMAT_PCM_S8: - return SPA_AUDIO_FORMAT_S8; - case SF_FORMAT_ULAW: - return SPA_AUDIO_FORMAT_ULAW; - case SF_FORMAT_ALAW: - return SPA_AUDIO_FORMAT_ALAW; - case SF_FORMAT_PCM_16: - return endianness == 1 ? SPA_AUDIO_FORMAT_S16_LE : - endianness == 2 ? SPA_AUDIO_FORMAT_S16_BE : - SPA_AUDIO_FORMAT_S16; - case SF_FORMAT_PCM_24: - case SF_FORMAT_PCM_32: - return endianness == 1 ? SPA_AUDIO_FORMAT_S32_LE : - endianness == 2 ? SPA_AUDIO_FORMAT_S32_BE : - SPA_AUDIO_FORMAT_S32; - case SF_FORMAT_DOUBLE: - return endianness == 1 ? SPA_AUDIO_FORMAT_F64_LE : - endianness == 2 ? SPA_AUDIO_FORMAT_F64_BE : - SPA_AUDIO_FORMAT_F64; - case SF_FORMAT_FLOAT: - default: - return endianness == 1 ? SPA_AUDIO_FORMAT_F32_LE : - endianness == 2 ? SPA_AUDIO_FORMAT_F32_BE : - SPA_AUDIO_FORMAT_F32; - break; - } - - return SPA_AUDIO_FORMAT_UNKNOWN; + uint32_t i; + for (i = 0; i < SPA_N_ELEMENTS(format_info); i++) + if (spa_streq(str, format_infoi.name)) + return &format_infoi; + return NULL; } -static inline int -sf_format_samplesize(int format) +static const struct format_info *format_info_by_sf_format(int format) { + uint32_t i; int sub_type = (format & SF_FORMAT_SUBMASK); - - switch (sub_type) { - case SF_FORMAT_PCM_S8: - case SF_FORMAT_PCM_U8: - case SF_FORMAT_ULAW: - case SF_FORMAT_ALAW: - return 1; - case SF_FORMAT_PCM_16: - return 2; - case SF_FORMAT_PCM_32: - return 4; - case SF_FORMAT_DOUBLE: - return 8; - case SF_FORMAT_FLOAT: - default: - return 4; - } - return -1; + for (i = 0; i < SPA_N_ELEMENTS(format_info); i++) + if (format_infoi.sf_format == sub_type) + return &format_infoi; + return NULL; } static int sf_playback_fill_x8(struct data *d, void *dest, unsigned int n_frames) @@ -280,7 +196,7 @@ sf_count_t rn; rn = sf_read_raw(d->file, dest, n_frames * d->stride); - return (int)rn; + return (int)rn / d->stride; } static int sf_playback_fill_s16(struct data *d, void *dest, unsigned int n_frames) @@ -320,10 +236,8 @@ } static inline fill_fn -sf_fmt_playback_fill_fn(int format) +playback_fill_fn(uint32_t fmt) { - enum spa_audio_format fmt = sf_format_to_pw(format); - switch (fmt) { case SPA_AUDIO_FORMAT_S8: case SPA_AUDIO_FORMAT_U8: @@ -364,7 +278,7 @@ sf_count_t rn; rn = sf_write_raw(d->file, src, n_frames * d->stride); - return (int)rn; + return (int)rn / d->stride; } static int sf_record_fill_s16(struct data *d, void *src, unsigned int n_frames) @@ -404,10 +318,8 @@ } static inline fill_fn -sf_fmt_record_fill_fn(int format) +record_fill_fn(uint32_t fmt) { - enum spa_audio_format fmt = sf_format_to_pw(format); - switch (fmt) { case SPA_AUDIO_FORMAT_S8: case SPA_AUDIO_FORMAT_U8: @@ -1076,29 +988,6 @@ return 0; } -struct format_info { - const char *name; - uint32_t spa_format; - uint32_t width; -} format_info = { - { "s8", SPA_AUDIO_FORMAT_S8, 1 }, - { "u8", SPA_AUDIO_FORMAT_U8, 1 }, - { "s16", SPA_AUDIO_FORMAT_S16, 2 }, - { "s24", SPA_AUDIO_FORMAT_S24, 3 }, - { "s32", SPA_AUDIO_FORMAT_S32, 4 }, - { "f32", SPA_AUDIO_FORMAT_F32, 4 }, - { "f64", SPA_AUDIO_FORMAT_F32, 8 }, -}; - -static struct format_info *format_info_by_name(const char *str) -{ - uint32_t i; - for (i = 0; i < SPA_N_ELEMENTS(format_info); i++) - if (spa_streq(str, format_infoi.name)) - return &format_infoi; - return NULL; -} - static int stdout_record(struct data *d, void *src, unsigned int n_frames) { return fwrite(src, d->stride, n_frames, stdout); @@ -1111,7 +1000,7 @@ static int setup_pipe(struct data *data) { - struct format_info *info; + const struct format_info *info; if (data->format == NULL) data->format = DEFAULT_FORMAT; @@ -1129,6 +1018,12 @@ data->spa_format = info->spa_format; data->stride = info->width * data->channels; data->fill = data->mode == mode_playback ? stdin_play : stdout_record; + + if (data->verbose) + printf("PIPE: rate=%u channels=%u fmt=%s samplesize=%u stride=%u\n", + data->rate, data->channels, + info->name, info->width, data->stride); + return 0; } @@ -1221,9 +1116,8 @@ static int setup_sndfile(struct data *data) { + const struct format_info *fi = NULL; SF_INFO info; - const char *s; - unsigned int nom = 0; spa_zero(info); /* for record, you fill in the info first */ @@ -1237,14 +1131,14 @@ if (data->channelmap.n_channels == 0) channelmap_default(&data->channelmap, data->channels); - memset(&info, 0, sizeof(info)); - info.samplerate = data->rate; - info.channels = data->channels; - info.format = sf_str_to_fmt(data->format); - if (info.format == -1) { + if ((fi = format_info_by_name(data->format)) == NULL) { fprintf(stderr, "error: unknown format \"%s\"\n", data->format); return -EINVAL; } + memset(&info, 0, sizeof(info)); + info.samplerate = data->rate; + info.channels = data->channels; + info.format = fi->sf_format; format_from_filename(&info, data->filename); } @@ -1291,13 +1185,46 @@ } } fill_properties(data); + + /* try native format first, else decode to float */ + if ((fi = format_info_by_sf_format(info.format)) == NULL) + fi = format_info_by_sf_format(SF_FORMAT_FLOAT); + } - data->samplesize = sf_format_samplesize(info.format); - data->stride = data->samplesize * data->channels; - data->spa_format = sf_format_to_pw(info.format); + if (fi == NULL) + return -EIO; + + if (data->verbose) + printf("PCM: fmt:%s rate:%u channels:%u width:%u\n", + fi->name, data->rate, data->channels, fi->width); + + /* we read and write S24 as S32 with sndfile */ + if (fi->spa_format == SPA_AUDIO_FORMAT_S24) + fi = format_info_by_sf_format(SF_FORMAT_PCM_32); + + data->spa_format = fi->spa_format; + data->stride = fi->width * data->channels; data->fill = data->mode == mode_playback ? - sf_fmt_playback_fill_fn(info.format) : - sf_fmt_record_fill_fn(info.format); + playback_fill_fn(data->spa_format) : + record_fill_fn(data->spa_format); + + if (data->fill == NULL) { + fprintf(stderr, "PCM: unhandled format %d\n", data->spa_format); + return -EINVAL; + } + return 0; +} + +static int setup_properties(struct data *data) +{ + const char *s; + unsigned int nom = 0; + + if (data->quality >= 0) + pw_properties_setf(data->props, "resample.quality", "%d", data->quality); + + if (data->rate) + pw_properties_setf(data->props, PW_KEY_NODE_RATE, "1/%u", data->rate); data->latency_unit = unit_none; @@ -1348,20 +1275,11 @@ } if (data->verbose) - printf("PCM: rate=%u channels=%u fmt=%s samplesize=%u stride=%u latency=%u (%.3fs)\n", - data->rate, data->channels, - sf_fmt_to_str(info.format), - data->samplesize, - data->stride, nom, (double)nom/data->rate); - + printf("rate:%d latency:%u (%.3fs)\n", + data->rate, nom, data->rate ? (double)nom/data->rate : 0.0f); if (nom) pw_properties_setf(data->props, PW_KEY_NODE_LATENCY, "%u/%u", nom, data->rate); - pw_properties_setf(data->props, PW_KEY_NODE_RATE, "1/%u", data->rate); - - if (data->quality >= 0) - pw_properties_setf(data->props, "resample.quality", "%d", data->quality); - return 0; } @@ -1634,7 +1552,6 @@ break; } } - if (ret < 0) { fprintf(stderr, "error: open failed: %s\n", spa_strerror(ret)); switch (ret) { @@ -1645,6 +1562,8 @@ goto error_usage; } } + ret = setup_properties(&data); + switch (data.data_type) { case TYPE_PCM: {
View file
pipewire-0.3.52.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.53.tar.gz/src/tools/pw-cli.c
Changed
@@ -22,19 +22,23 @@ * DEALINGS IN THE SOFTWARE. */ +#include "config.h" + #include <unistd.h> #include <errno.h> #include <stdio.h> #include <signal.h> #include <string.h> #include <ctype.h> -#ifndef __FreeBSD__ +#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) #include <alloca.h> #endif #include <getopt.h> #include <fnmatch.h> +#ifdef HAVE_READLINE #include <readline/readline.h> #include <readline/history.h> +#endif #include <locale.h> #if !defined(FNM_EXTMATCH) @@ -307,7 +311,12 @@ static void set_prompt(struct remote_data *rd) { snprintf(prompt, sizeof(prompt), "%s>> ", rd->name); +#ifdef HAVE_READLINE rl_set_prompt(prompt); +#else + printf("%s", prompt); + fflush(stdout); +#endif } static void on_core_done(void *_data, uint32_t id, int seq) @@ -3040,18 +3049,20 @@ } /* We need a global variable, readline doesn't have a closure arg */ -static struct data *readline_dataptr; +static struct data *input_dataptr; -static void readline_process_line(char *line) +static void input_process_line(char *line) { - struct data *d = readline_dataptr; + struct data *d = input_dataptr; char *error; if (!line) line = strdup("quit"); if (line0 != '\0') { +#ifdef HAVE_READLINE add_history(line); +#endif if (!parse(d, line, &error)) { fprintf(stderr, "Error: \"%s\"\n", error); free(error); @@ -3065,8 +3076,21 @@ struct data *d = data; if (mask & SPA_IO_IN) { - readline_dataptr = d; + input_dataptr = d; +#ifdef HAVE_READLINE rl_callback_read_char(); +#else + { + char *line = NULL; + size_t s = 0; + + if (getline(&line, &s, stdin) < 0) { + free(line); + line = NULL; + } + input_process_line(line); + } +#endif if (d->current == NULL) pw_main_loop_quit(d->loop); @@ -3078,6 +3102,7 @@ } } +#ifdef HAVE_READLINE static char * readline_match_command(const char *text, int state) { @@ -3119,13 +3144,14 @@ static void readline_init() { rl_attempted_completion_function = readline_command_completion; - rl_callback_handler_install(">> ", readline_process_line); + rl_callback_handler_install(">> ", input_process_line); } static void readline_cleanup() { rl_callback_handler_remove(); } +#endif static void do_quit_on_signal(void *data, int signal_number) { @@ -3152,13 +3178,14 @@ struct pw_loop *l; char *opt_remote = NULL; char *error; - bool daemon = false; + bool daemon = false, monitor = false; struct remote_data *rd; static const struct option long_options = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { "daemon", no_argument, NULL, 'd' }, - { "remote", required_argument, NULL, 'r' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "monitor", no_argument, NULL, 'm' }, + { "daemon", no_argument, NULL, 'd' }, + { "remote", required_argument, NULL, 'r' }, { NULL, 0, NULL, 0} }; int c, i; @@ -3168,7 +3195,7 @@ setlocale(LC_ALL, ""); pw_init(&argc, &argv); - while ((c = getopt_long(argc, argv, "hVdr:", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "hVmdr:", long_options, NULL)) != -1) { switch (c) { case 'h': show_help(&data, argv0, false); @@ -3184,6 +3211,9 @@ case 'd': daemon = true; break; + case 'm': + monitor = true; + break; case 'r': opt_remote = optarg; break; @@ -3228,13 +3258,17 @@ printf("Welcome to PipeWire version %s. Type 'help' for usage.\n", pw_get_library_version()); +#ifdef HAVE_READLINE readline_init(); +#endif pw_loop_add_io(l, STDIN_FILENO, SPA_IO_IN|SPA_IO_HUP, false, do_input, &data); pw_main_loop_run(data.loop); +#ifdef HAVE_READLINE readline_cleanup(); +#endif } else { char buf4096, *p, *error; @@ -3250,9 +3284,11 @@ fprintf(stderr, "Error: \"%s\"\n", error); free(error); } - if (!data.quit && data.current) { + while (!data.quit && data.current) { data.current->prompt_pending = pw_core_sync(data.current->core, 0, 0); pw_main_loop_run(data.loop); + if (!monitor) + break; } } spa_list_consume(rd, &data.remotes, link)
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
.