Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 54
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Wed Jun 11 18:34:44 UTC 2025 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 1.4.4 + +------------------------------------------------------------------- Wed Apr 16 08:10:32 UTC 2025 - Bjørn Lie <zaitor@opensuse.org> - Update to version 1.4.2
View file
pipewire-aptx.spec
Changed
@@ -8,7 +8,7 @@ %define minimum_version 1.4.0 Name: pipewire-aptx -Version: 1.4.2 +Version: 1.4.4 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
_service
Changed
@@ -2,6 +2,6 @@ <service name="download_url"> <param name="host">gitlab.freedesktop.org</param> <param name="protocol">https</param> - <param name="path">/pipewire/pipewire/-/archive/1.4.2/pipewire-1.4.2.tar.bz2</param> + <param name="path">/pipewire/pipewire/-/archive/1.4.4/pipewire-1.4.4.tar.bz2</param> </service> </services> \ No newline at end of file
View file
_service:download_url:pipewire-1.4.2.tar.bz2/NEWS -> _service:download_url:pipewire-1.4.4.tar.bz2/NEWS
Changed
@@ -1,3 +1,68 @@ +# PipeWire 1.4.4 (2025-05-29) + +This is a quick bugfix release that is API and ABI compatible with +previous 1.x releases. + +## Highlights + - Provide better compatibility with 1.2 for MIDI. + - Fix mpv buffer negotiation regression. + - Improve GStreamer compatibility with libcamera. + + +## SPA + - Provide conversions to old style midi in the ALSA sequencer. + - Negotiate only to UMP when using a newer library. + - Fix negotiation direction for buffers, prefer the converter + suggestion instead of the application until we can be sure + applications make good suggestions. + +## GStreamer + - Allow a minimum of 1 buffers again instead of 8. libcamera will + allocate only 4 buffers so we need to support this. + + +Older versions: + +# PipeWire 1.4.3 (2025-05-22) + +This is a bugfix release that is API and ABI compatible with +previous 1.x releases. + +## Highlights + - Many netjack2 improvements. The driver/manager roles were fixed, + MIDI is written correctly and errors are handled better. + - Improvements to UMP sysex handling. + - More small bug fixes and improvements. + + +## PipeWire + - Let all commands go to the node. This makes it possible to send + custom commands. + +## Modules + - Many netjack2 improvements. The driver/manager roles were fixed, + MIDI is written correctly and errors are handled better. + - Improve the filter-graph state management in filter-chain. + +## SPA + - Use default value of filter. (#4619) + - Fix UMP program change conversion to MIDI 1.0. (#4664) + - Skip only the first buffer for raw formats in v4l2 to avoid + dropping important headers when dealing with encoded formats. + - Fix ebur128 port name. (#4667) + - Only convert UMP/MIDI, pass other controls. Fixes OSC and other + control types in the mixer. (#4692) + - Improve UMP sysex handling in alsa seq. + - Improve ALSA audio.channels support. Only use this when the value + is within the valid range. + +## Tools + - debug UMP SysRT messages correctly in pw-mididump. + +## JACK + - Handle sysex in UMP better by appending the converted midi1 + sysex. + # PipeWire 1.4.2 (2025-04-14) This is a bugfix release that is API and ABI compatible with @@ -29,9 +94,6 @@ - Fix a leak in the deviceprovider. (#4616) - Fix negotiation and make renegotiation better. - -Older versions: - # PipeWire 1.4.1 (2025-03-14) This is a quick bugfix release that is API and ABI compatible with
View file
_service:download_url:pipewire-1.4.2.tar.bz2/meson.build -> _service:download_url:pipewire-1.4.4.tar.bz2/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '1.4.2', + version : '1.4.4', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.61.1', default_options : 'warning_level=3',
View file
_service:download_url:pipewire-1.4.2.tar.bz2/pipewire-jack/src/pipewire-jack.c -> _service:download_url:pipewire-1.4.4.tar.bz2/pipewire-jack/src/pipewire-jack.c
Changed
@@ -1538,7 +1538,7 @@ res = ev->inline_data; } else { mb->write_pos += data_size; - ev->byte_offset = mb->buffer_size - 1 - mb->write_pos; + ev->byte_offset = mb->buffer_size - mb->write_pos; res = SPA_PTROFF(mb, ev->byte_offset, uint8_t); } mb->event_count += 1; @@ -1546,14 +1546,37 @@ return res; } +static inline int midi_event_append(void *port_buffer, const jack_midi_data_t *data, size_t data_size) +{ + struct midi_buffer *mb = port_buffer; + struct midi_event *events = SPA_PTROFF(mb, sizeof(*mb), struct midi_event); + struct midi_event *ev; + size_t old_size; + uint8_t *old, *buf; + + ev = &events--mb->event_count; + mb->write_pos -= ev->size; + old_size = ev->size; + if (old_size <= MIDI_INLINE_MAX) + old = ev->inline_data; + else + old = SPA_PTROFF(mb, ev->byte_offset, uint8_t); + buf = midi_event_reserve(port_buffer, ev->time, old_size + data_size); + if (SPA_UNLIKELY(buf == NULL)) + return -ENOBUFS; + memmove(buf, old, old_size); + memcpy(buf+old_size, data, data_size); + return 0; +} + static inline int midi_event_write(void *port_buffer, jack_nframes_t time, const jack_midi_data_t *data, size_t data_size, bool fix) { jack_midi_data_t *retbuf = midi_event_reserve (port_buffer, time, data_size); - if (SPA_UNLIKELY(retbuf == NULL)) - return -ENOBUFS; + if (SPA_UNLIKELY(retbuf == NULL)) + return -ENOBUFS; memcpy (retbuf, data, data_size); if (fix) fix_midi_event(retbuf, data_size); @@ -1566,6 +1589,7 @@ uint64_t state = 0; uint32_t i; int res = 0; + bool in_sysex = false; for (i = 0; i < n_seq; i++) ci = spa_pod_control_first(&seqi->body); @@ -1620,17 +1644,30 @@ void *data = SPA_POD_BODY(&next->value); size_t size = SPA_POD_BODY_SIZE(&next->value); uint8_t ev32; + bool was_sysex = in_sysex; if (type == TYPE_ID_MIDI) { int ev_size = spa_ump_to_midi(data, size, ev, sizeof(ev)); if (ev_size <= 0) break; + size = ev_size; data = ev; + + if (!in_sysex && ev0 == 0xf0) + in_sysex = true; + if (in_sysex && evev_size-1 == 0xf7) + in_sysex = false; + } else if (type != TYPE_ID_UMP) break; - if ((res = midi_event_write(midi, next->offset, data, size, fix)) < 0) + if (was_sysex) + res = midi_event_append(midi, data, size); + else + res = midi_event_write(midi, next->offset, data, size, fix); + + if (res < 0) pw_log_warn("midi %p: can't write event: %s", midi, spa_strerror(res)); } @@ -2512,11 +2549,28 @@ case TYPE_ID_UMP: case TYPE_ID_OSC: case TYPE_ID_MIDI: - *param = spa_pod_builder_add_object(b, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, + { + struct spa_pod_frame f; + int32_t types = 0; + + spa_pod_builder_push_object(b, &f, + SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat); + spa_pod_builder_add(b, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control)); + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control), + 0); + if (p->object->port.type_id == TYPE_ID_UMP) + types |= 1u<<SPA_CONTROL_UMP; + if (p->object->port.type_id == TYPE_ID_OSC) + types |= 1u<<SPA_CONTROL_OSC; + if (types != 0) + spa_pod_builder_add(b, + SPA_FORMAT_CONTROL_types, SPA_POD_CHOICE_FLAGS_Int(types), + 0); + + *param = spa_pod_builder_pop(b, &f); break; + } case TYPE_ID_VIDEO: *param = spa_pod_builder_add_object(b, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, @@ -3429,24 +3483,6 @@ } } -static const char* type_to_format_dsp(jack_port_type_id_t type_id) -{ - switch(type_id) { - case TYPE_ID_AUDIO: - return JACK_DEFAULT_AUDIO_TYPE; - case TYPE_ID_VIDEO: - return JACK_DEFAULT_VIDEO_TYPE; - case TYPE_ID_OSC: - return JACK_DEFAULT_OSC_TYPE; - case TYPE_ID_MIDI: - return JACK_DEFAULT_MIDI_TYPE; - case TYPE_ID_UMP: - return JACK_DEFAULT_UMP_TYPE; - default: - return NULL; - } -} - static bool type_is_dsp(jack_port_type_id_t type_id) { switch(type_id) { @@ -5507,7 +5543,7 @@ spa_list_init(&p->mix); - pw_properties_set(p->props, PW_KEY_FORMAT_DSP, type_to_format_dsp(type_id)); + pw_properties_set(p->props, PW_KEY_FORMAT_DSP, type_to_string(type_id)); pw_properties_set(p->props, PW_KEY_PORT_NAME, port_name); if (flags > 0x1f) { pw_properties_setf(p->props, PW_KEY_PORT_EXTRA, @@ -5754,8 +5790,8 @@ convert_to_event(seq, n_seq, mb, p->client->fix_midi_events, p->object->port.type_id); memcpy(ptr, mb, sizeof(struct midi_buffer) + (mb->event_count * sizeof(struct midi_event))); - if (mb->write_pos) { - size_t offs = mb->buffer_size - 1 - mb->write_pos; + if (mb->write_pos > 0) { + size_t offs = mb->buffer_size - mb->write_pos; memcpy(SPA_PTROFF(ptr, offs, void), SPA_PTROFF(mb, offs, void), mb->write_pos); } return ptr;
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/include/spa/control/ump-utils.h -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/include/spa/control/ump-utils.h
Changed
@@ -96,9 +96,17 @@ if (ump_size < 8) return 0; midisize++ = (ump0 >> 16) | 0x80; - if (midi0 < 0xc0 || midi0 > 0xdf) + switch (midi0 & 0xf0) { + case 0xc0: + midisize++ = (ump1 >> 24); + break; + default: midisize++ = (ump0 >> 8) & 0x7f; - midisize++ = (ump1 >> 25); + SPA_FALLTHROUGH; + case 0xd0: + midisize++ = (ump1 >> 25); + break; + } break; case 0x0: /* Utility Messages */
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/include/spa/pod/builder.h -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/include/spa/pod/builder.h
Changed
@@ -326,6 +326,31 @@ return SPA_POD_BODY(spa_pod_builder_deref(builder, offset)); } +SPA_API_POD_BUILDER uint32_t +spa_pod_builder_bytes_start(struct spa_pod_builder *builder) +{ + uint32_t offset = builder->state.offset; + const struct spa_pod_bytes p = SPA_POD_INIT_Bytes(0); + spa_pod_builder_raw(builder, &p, sizeof(p)); + return offset; +} +SPA_API_POD_BUILDER int +spa_pod_builder_bytes_append(struct spa_pod_builder *builder, uint32_t offset, + const void *data, uint32_t size) +{ + int res = spa_pod_builder_raw(builder, data, size); + struct spa_pod *pod = spa_pod_builder_deref(builder, offset); + if (pod) + pod->size += size; + return res; +} + +SPA_API_POD_BUILDER int +spa_pod_builder_bytes_end(struct spa_pod_builder *builder, uint32_t offset SPA_UNUSED) +{ + return spa_pod_builder_pad(builder, builder->state.offset); +} + #define SPA_POD_INIT_Pointer(type,value) ((struct spa_pod_pointer){ { sizeof(struct spa_pod_pointer_body), SPA_TYPE_Pointer }, { (type), 0, (value) } }) SPA_API_POD_BUILDER int
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/include/spa/pod/filter.h -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/include/spa/pod/filter.h
Changed
@@ -181,7 +181,7 @@ nc = &dummy; /* default value */ - spa_pod_builder_primitive(b, v1); + spa_pod_builder_primitive(b, v2); if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_None) || (p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Enum) || @@ -189,10 +189,10 @@ (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Enum)) { int n_copied = 0; /* copy all equal values but don't copy the default value again */ - for (j = 0, a1 = alt1; j < nalt1; j++, a1 = SPA_PTROFF(a1, size, void)) { - for (k = 0, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) { + for (j = 0, a2 = alt2; j < nalt2; j++, a2 = SPA_PTROFF(a2, size, void)) { + for (k = 0, a1 = alt1; k < nalt1; k++, a1 = SPA_PTROFF(a1,size,void)) { if (spa_pod_compare_value(type, a1, a2, size) == 0) { - if (p1c == SPA_CHOICE_Enum || j > 0) + if (p2c == SPA_CHOICE_Enum || j > 0) spa_pod_builder_raw(b, a1, size); n_copied++; }
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/include/spa/utils/json-core.h -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/include/spa/utils/json-core.h
Changed
@@ -268,6 +268,8 @@ if (--utf8_remain == 0) iter->state = __STRING | flag; continue; + default: + break; } _SPA_ERROR(CHARACTERS_NOT_ALLOWED); case __ESC: @@ -276,12 +278,17 @@ case 'n': case 'r': case 't': case 'u': iter->state = __STRING | flag; continue; + default: + break; } _SPA_ERROR(INVALID_ESCAPE); case __COMMENT: switch (cur) { case '\n': case '\r': iter->state = __STRUCT | flag; + break; + default: + break; } break; default: @@ -299,6 +306,8 @@ case __COMMENT: /* trailing comment */ return 0; + default: + break; } if ((iter->state & __SUB_FLAG) && (iter->state & __KEY_FLAG)) {
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/alsa/alsa-pcm.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -162,6 +162,11 @@ int fmt_change = 0; if (spa_streq(k, SPA_KEY_AUDIO_CHANNELS)) { state->default_channels = atoi(s); + if (state->default_channels > SPA_AUDIO_MAX_CHANNELS) { + spa_log_warn(state->log, "%p: %s: %s > %d, clamping", + state, k, s, SPA_AUDIO_MAX_CHANNELS); + state->default_channels = SPA_AUDIO_MAX_CHANNELS; + } fmt_change++; } else if (spa_streq(k, SPA_KEY_AUDIO_RATE)) { state->default_rate = atoi(s); @@ -1563,15 +1568,18 @@ spa_log_debug(state->log, "channels (%d %d) default:%d all:%d", min, max, state->default_channels, all); - if (state->default_channels != 0 && !all) { - if (min < state->default_channels) - min = state->default_channels; - if (max > state->default_channels) - max = state->default_channels; - } min = SPA_MIN(min, SPA_AUDIO_MAX_CHANNELS); max = SPA_MIN(max, SPA_AUDIO_MAX_CHANNELS); + if (state->default_channels != 0 && !all) { + if (min > state->default_channels || + max < state->default_channels) + spa_log_warn(state->log, "given audio.channels %d out of range:%d-%d", + state->default_channels, min, max); + else + min = max = state->default_channels; + } + spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_channels, 0); if (state->props.use_chmap && (maps = snd_pcm_query_chmaps(hndl)) != NULL) { @@ -1842,10 +1850,12 @@ spa_log_debug(state->log, "rate (%d %d)", rmin, rmax); if (state->default_rate != 0) { - if (rmin < state->default_rate) - rmin = state->default_rate; - if (rmax > state->default_rate) - rmax = state->default_rate; + if (rmin > state->default_rate || + rmax < state->default_rate) + spa_log_warn(state->log, "given audio.rate %d out of range:%d-%d", + state->default_rate, rmin, rmax); + else + rmin = rmax = state->default_rate; } spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_iec958Codec, 0);
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/alsa/alsa-seq-bridge.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/alsa/alsa-seq-bridge.c
Changed
@@ -275,7 +275,7 @@ snprintf(alias, sizeof(alias), "%s:%s", client_name, port_name); clean_name(alias); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "32 bit raw UMP"); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi"); itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_OBJECT_PATH, path); itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, name); itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_ALIAS, alias); @@ -529,8 +529,7 @@ 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), - SPA_FORMAT_CONTROL_types, SPA_POD_CHOICE_FLAGS_Int(1u<<SPA_CONTROL_UMP)); + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control)); break; case SPA_PARAM_Format: @@ -541,8 +540,7 @@ 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), - SPA_FORMAT_CONTROL_types, SPA_POD_Int(1u<<SPA_CONTROL_UMP)); + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control)); break; case SPA_PARAM_Buffers: @@ -635,7 +633,7 @@ port->have_format = false; } else { struct spa_audio_info info = { 0 }; - uint32_t types; + uint32_t types = 0; if ((err = spa_format_parse(format, &info.media_type, &info.media_subtype)) < 0) return err; @@ -646,13 +644,12 @@ if ((err = spa_pod_parse_object(format, SPA_TYPE_OBJECT_Format, NULL, - SPA_FORMAT_CONTROL_types, SPA_POD_Int(&types))) < 0) + SPA_FORMAT_CONTROL_types, SPA_POD_OPT_Int(&types))) < 0) return err; - if (types != 1u << SPA_CONTROL_UMP) - return -EINVAL; port->current_format = info; port->have_format = true; + port->control_types = types; } port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/alsa/alsa-seq.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/alsa/alsa-seq.c
Changed
@@ -78,7 +78,6 @@ spa_log_debug(state->log, "%p: ALSA UMP MIDI enabled", state); state->ump = true; } - return 0; } @@ -404,7 +403,6 @@ state->sys.source.func = alsa_seq_on_sys; state->sys.source.data = state; - spa_loop_add_source(state->main_loop, &state->sys.source); /* increase event queue timer resolution */ snd_seq_queue_timer_alloca(&timer); @@ -449,6 +447,8 @@ state->timerfd = res; + spa_loop_add_source(state->main_loop, &state->sys.source); + state->opened = true; return 0; @@ -586,7 +586,8 @@ spa_pod_builder_init(&port->builder, port->buffer->buf->datas0.data, port->buffer->buf->datas0.maxsize); - spa_pod_builder_push_sequence(&port->builder, &port->frame, 0); + spa_pod_builder_push_sequence(&port->builder, &port->frame, 0); + port->ev_offset = SPA_IDX_INVALID; return 0; } @@ -620,10 +621,8 @@ struct seq_stream *stream = &state->streamsSPA_DIRECTION_OUTPUT; const bool ump = state->ump; uint32_t i; - uint32_t *data; uint8_t midi1_dataMAX_EVENT_SIZE; uint32_t ump_dataMAX_EVENT_SIZE; - long size; int res = -1; /* copy all new midi events into their port buffers */ @@ -631,10 +630,11 @@ const snd_seq_addr_t *addr; struct seq_port *port; uint64_t ev_time, diff; - uint32_t offset; + uint32_t offset, ev_type; void *event; - uint8_t *midi1_ptr; - size_t midi1_size = 0; + uint8_t *data_ptr; + size_t data_size = 0; + long size; uint64_t ump_state = 0; snd_seq_event_type_t SPA_UNUSED type; @@ -679,7 +679,7 @@ continue; if ((res = prepare_buffer(state, port)) < 0) { - spa_log_debug(state->log, "can't prepare buffer port:%p %d.%d: %s", + spa_log_warn(state->log, "can't prepare buffer port:%p %d.%d: %s", port, addr->client, addr->port, spa_strerror(res)); continue; } @@ -702,8 +702,8 @@ #ifdef HAVE_ALSA_UMP snd_seq_ump_event_t *ev = event; - data = (uint32_t*)&ev->ump0; - size = spa_ump_message_size(snd_ump_msg_hdr_type(ev->ump0)) * 4; + data_ptr = (uint8_t*)&ev->ump0; + data_size = spa_ump_message_size(snd_ump_msg_hdr_type(ev->ump0)) * 4; #else spa_assert_not_reached(); #endif @@ -712,40 +712,69 @@ snd_midi_event_reset_decode(stream->codec); if ((size = snd_midi_event_decode(stream->codec, midi1_data, sizeof(midi1_data), ev)) < 0) { - spa_log_warn(state->log, "decode failed: %s", snd_strerror(size)); + spa_log_warn(state->log, "decode failed: %s", snd_strerror(data_size)); continue; } + data_ptr = midi1_data; + data_size = size; + } - midi1_ptr = midi1_data; - midi1_size = size; + ev_type = (port->control_types & (1u << SPA_CONTROL_UMP)) ? + SPA_CONTROL_UMP : SPA_CONTROL_Midi; + + spa_log_trace_fp(state->log, "event %d time:%"PRIu64" offset:%d size:%ld port:%d.%d", + type, ev_time, offset, data_size, addr->client, addr->port); + + if ((ump && ev_type == SPA_CONTROL_UMP) || + (!ump && ev_type == SPA_CONTROL_Midi)) { + /* no conversion needed */ + spa_pod_builder_control(&port->builder, offset, ev_type); + spa_pod_builder_bytes(&port->builder, data_ptr, data_size); } + else if (ump) { + bool continued = port->ev_offset != SPA_IDX_INVALID; + + /* UMP -> MIDI */ + size = spa_ump_to_midi((uint32_t*)data_ptr, data_size, + midi1_data, sizeof(midi1_data)); + if (size < 0) + continue; - do { - if (!ump) { - data = ump_data; - size = spa_ump_from_midi(&midi1_ptr, &midi1_size, + if (!continued) { + spa_pod_builder_control(&port->builder, offset, ev_type); + port->ev_offset = spa_pod_builder_bytes_start(&port->builder); + if (midi1_data0 == 0xf0) + continued = true; + } else { + if (midi1_datasize-1 == 0xf7) + continued = false; + } + spa_pod_builder_bytes_append(&port->builder, port->ev_offset, midi1_data, size); + + if (!continued) { + spa_pod_builder_bytes_end(&port->builder, port->ev_offset); + port->ev_offset = SPA_IDX_INVALID; + } + } else { + /* MIDI -> UMP */ + while (data_size > 0) { + size = spa_ump_from_midi(&data_ptr, &data_size, ump_data, sizeof(ump_data), 0, &ump_state); if (size <= 0) break; - } - - spa_log_trace_fp(state->log, "event %d time:%"PRIu64" offset:%d size:%ld port:%d.%d", - type, ev_time, offset, size, addr->client, addr->port); - - spa_pod_builder_control(&port->builder, offset, SPA_CONTROL_UMP); - spa_pod_builder_bytes(&port->builder, data, size); - /* make sure we can fit at least one control event of max size otherwise - * we keep the event in the queue and try to copy it in the next cycle */ - if (port->builder.state.offset + - sizeof(struct spa_pod_control) + - MAX_EVENT_SIZE > port->buffer->buf->datas0.maxsize) - goto done; + spa_pod_builder_control(&port->builder, offset, ev_type); + spa_pod_builder_bytes(&port->builder, ump_data, size); + } + } - } while (!ump); + /* make sure we can fit at least one control event of max size otherwise + * we keep the event in the queue and try to copy it in the next cycle */ + if (port->builder.state.offset + + sizeof(struct spa_pod_control) + + MAX_EVENT_SIZE > port->buffer->buf->datas0.maxsize) + break; } - -done: if (res < 0 && res != -EAGAIN) spa_log_warn(state->log, "event read failed: %s", snd_strerror(res)); @@ -760,6 +789,8 @@ continue; if (prepare_buffer(state, port) >= 0) { + if (port->ev_offset != SPA_IDX_INVALID) + spa_pod_builder_bytes_end(&port->builder, port->ev_offset); spa_pod_builder_pop(&port->builder, &port->frame); port->buffer->buf->datas0.chunk->offset = 0; @@ -820,6 +851,7 @@ struct spa_pod_control *c; uint64_t out_time; snd_seq_real_time_t out_rt; + bool first = true; if (!port->valid || io == NULL) continue; @@ -845,9 +877,7 @@ SPA_POD_SEQUENCE_FOREACH(pod, c) { size_t body_size; uint8_t *body; - - if (c->type != SPA_CONTROL_UMP) - continue; + int size; body = SPA_POD_BODY(&c->value); body_size = SPA_POD_BODY_SIZE(&c->value); @@ -861,36 +891,77 @@ if (ump) { #ifdef HAVE_ALSA_UMP + uint8_t *ump_data; + uint32_t dataMAX_EVENT_SIZE; snd_seq_ump_event_t ev; - snd_seq_ump_ev_clear(&ev); - snd_seq_ev_set_ump_data(&ev, body, SPA_MIN(sizeof(ev.ump), (size_t)body_size)); - snd_seq_ev_set_source(&ev, state->event.addr.port); - snd_seq_ev_set_dest(&ev, port->addr.client, port->addr.port); - snd_seq_ev_schedule_real(&ev, state->event.queue_id, 0, &out_rt); - - if ((err = snd_seq_ump_event_output(state->event.hndl, &ev)) < 0) { - spa_log_warn(state->log, "failed to output event: %s", - snd_strerror(err)); - } + do { + switch (c->type) { + case SPA_CONTROL_UMP: + ump_data = body; + size = body_size; + body_size = 0; + break; + case SPA_CONTROL_Midi: + size = spa_ump_from_midi(&body, &body_size, + data, sizeof(data), 0, &port->ump_state); + ump_data = (uint8_t*)data; + break; + default: + size = 0; + body_size = 0; + continue; + } + if (size <= 0) + break; + + snd_seq_ump_ev_clear(&ev); + snd_seq_ev_set_ump_data(&ev, ump_data, SPA_MIN(sizeof(ev.ump), (size_t)size)); + snd_seq_ev_set_source(&ev, state->event.addr.port); + snd_seq_ev_set_dest(&ev, port->addr.client, port->addr.port); + snd_seq_ev_schedule_real(&ev, state->event.queue_id, 0, &out_rt); + + if ((err = snd_seq_ump_event_output(state->event.hndl, &ev)) < 0) { + spa_log_warn(state->log, "failed to output event: %s", + snd_strerror(err)); + } + } while (body_size > 0); #else spa_assert_not_reached(); #endif } else { snd_seq_event_t ev; uint8_t dataMAX_EVENT_SIZE; - int size; + uint8_t *midi_data; - if ((size = spa_ump_to_midi((uint32_t *)body, body_size, data, sizeof(data))) <= 0) + switch (c->type) { + case SPA_CONTROL_UMP: + if ((size = spa_ump_to_midi((uint32_t *)body, body_size, data, sizeof(data))) <= 0) + continue; + midi_data = data; + break; + case SPA_CONTROL_Midi: + midi_data = body; + size = body_size; + break; + default: continue; + } - snd_seq_ev_clear(&ev); + if (first) + snd_seq_ev_clear(&ev); - snd_midi_event_reset_encode(stream->codec); - if ((size = snd_midi_event_encode(stream->codec, data, size, &ev)) <= 0) { + if ((size = snd_midi_event_encode(stream->codec, midi_data, size, &ev)) < 0) { spa_log_warn(state->log, "failed to encode event: %s", snd_strerror(size)); + snd_midi_event_reset_encode(stream->codec); + first = true; continue; } + first = false; + if (ev.type == SND_SEQ_EVENT_NONE) + /* this can happen when the event is not complete yet, like + * a sysex message and we need to encode some more data. */ + continue; snd_seq_ev_set_source(&ev, state->event.addr.port); snd_seq_ev_set_dest(&ev, port->addr.client, port->addr.port); @@ -900,6 +971,7 @@ spa_log_warn(state->log, "failed to output event: %s", snd_strerror(err)); } + first = true; } } }
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/alsa/alsa-seq.h -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/alsa/alsa-seq.h
Changed
@@ -80,7 +80,10 @@ struct buffer *buffer; struct spa_pod_builder builder; struct spa_pod_frame frame; + uint32_t ev_offset; + uint64_t ump_state; + uint32_t control_types; struct spa_audio_info current_format; unsigned int have_format:1; unsigned int valid:1;
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/audioconvert/audioadapter.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/audioconvert/audioadapter.c
Changed
@@ -442,28 +442,32 @@ state = 0; param = NULL; - if ((res = node_port_enum_params_sync(this, this->follower, - this->direction, 0, + if ((res = node_port_enum_params_sync(this, this->target, + SPA_DIRECTION_REVERSE(this->direction), 0, SPA_PARAM_Buffers, &state, param, ¶m, &b)) < 0) { if (res == -ENOENT) param = NULL; else { - debug_params(this, this->follower, this->direction, 0, - SPA_PARAM_Buffers, param, "follower buffers", res); + debug_params(this, this->target, + SPA_DIRECTION_REVERSE(this->direction), 0, + SPA_PARAM_Buffers, param, "target buffers", res); return res; } } state = 0; - if ((res = node_port_enum_params_sync(this, this->target, - SPA_DIRECTION_REVERSE(this->direction), 0, + if ((res = node_port_enum_params_sync(this, this->follower, + this->direction, 0, SPA_PARAM_Buffers, &state, param, ¶m, &b)) != 1) { - debug_params(this, this->target, - SPA_DIRECTION_REVERSE(this->direction), 0, - SPA_PARAM_Buffers, param, "convert buffers", res); - return -ENOTSUP; + if (res == -ENOENT) + res = 0; + else { + debug_params(this, this->follower, this->direction, 0, + SPA_PARAM_Buffers, param, "follower buffers", res); + return res < 0 ? res : -ENOTSUP; + } } if (param == NULL) return -ENOTSUP; @@ -497,7 +501,7 @@ if (this->async) buffers = SPA_MAX(2u, buffers); - spa_log_debug(this->log, "%p: buffers:%d, blocks:%d, size:%d, stride:%d align:%d %d:%d", + spa_log_info(this->log, "%p: buffers:%d, blocks:%d, size:%d, stride:%d align:%d %d:%d", this, buffers, blocks, size, stride, align, follower_alloc, conv_alloc); align = SPA_MAX(align, this->max_align); @@ -941,27 +945,13 @@ spa_node_send_command(this->follower, &SPA_NODE_COMMAND_INIT(SPA_NODE_COMMAND_ParamBegin)); - /* first try the ideal converter format, which is likely passthrough */ - tstate = 0; - fres = node_port_enum_params_sync(this, this->target, - SPA_DIRECTION_REVERSE(this->direction), 0, - SPA_PARAM_EnumFormat, &tstate, - NULL, &format, &b); - if (fres == 1) { - fstate = 0; - res = node_port_enum_params_sync(this, this->follower, - this->direction, 0, - SPA_PARAM_EnumFormat, &fstate, - format, &format, &b); - if (res == 1) - goto found; - } - - /* then try something the follower can accept */ + /* The target has been negotiated on its other ports and so it can propose + * a passthrough format or an ideal conversion. We use the suggestions of the + * target to find the best follower format */ for (fstate = 0;;) { format = NULL; - res = node_port_enum_params_sync(this, this->follower, - this->direction, 0, + res = node_port_enum_params_sync(this, this->target, + SPA_DIRECTION_REVERSE(this->direction), 0, SPA_PARAM_EnumFormat, &fstate, NULL, &format, &b); @@ -971,8 +961,8 @@ break; tstate = 0; - fres = node_port_enum_params_sync(this, this->target, - SPA_DIRECTION_REVERSE(this->direction), 0, + fres = node_port_enum_params_sync(this, this->follower, + this->direction, 0, SPA_PARAM_EnumFormat, &tstate, format, &format, &b); if (fres == 0 && res == 1) @@ -981,7 +971,6 @@ res = fres; break; } -found: if (format == NULL) { debug_params(this, this->follower, this->direction, 0, SPA_PARAM_EnumFormat, format, "follower format", res); @@ -1045,7 +1034,10 @@ break; } - if ((res = spa_node_send_command(this->target, command)) < 0) { + res = spa_node_send_command(this->target, command); + if (res == -ENOTSUP && this->target != this->follower) + res = 0; + if (res < 0) { spa_log_error(this->log, "%p: can't send command %d: %s", this, SPA_NODE_COMMAND_ID(command), spa_strerror(res));
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/audioconvert/audioconvert.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/audioconvert/audioconvert.c
Changed
@@ -362,7 +362,7 @@ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_IGNORE_LATENCY, "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, "32 bit raw UMP"); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi"); } if (this->group_name0 != '\0') itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_GROUP, this->group_name);
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/bluez5/midi-node.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/bluez5/midi-node.c
Changed
@@ -2024,13 +2024,13 @@ for (i = 0; i < N_PORTS; ++i) { struct port *port = &this->portsi; static const struct spa_dict_item in_port_items = { - SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "32 bit raw UMP"), + SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi"), SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, "in"), SPA_DICT_ITEM_INIT(SPA_KEY_PORT_ALIAS, "in"), SPA_DICT_ITEM_INIT(SPA_KEY_PORT_GROUP, "group.0"), }; static const struct spa_dict_item out_port_items = { - SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "32 bit raw UMP"), + SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi"), SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, "out"), SPA_DICT_ITEM_INIT(SPA_KEY_PORT_ALIAS, "out"), SPA_DICT_ITEM_INIT(SPA_KEY_PORT_GROUP, "group.0"),
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/control/mixer.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/control/mixer.c
Changed
@@ -298,7 +298,8 @@ *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)); + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control), + SPA_FORMAT_CONTROL_types, SPA_POD_CHOICE_FLAGS_Int(SPA_ID_INVALID)); break; default: return 0; @@ -671,6 +672,14 @@ } } +static inline bool control_needs_conversion(struct port *port, uint32_t type) +{ + /* we only converter between midi and UMP and only when the port + * does not support the current type */ + return (type == SPA_CONTROL_Midi || type == SPA_CONTROL_UMP) && + port->types && (port->types & (1u << type)) == 0; +} + static int impl_node_process(void *object) { struct impl *this = object; @@ -782,7 +791,7 @@ if (next == NULL) break; - if (outport->types && (outport->types & (1u << next->type)) == 0) { + if (control_needs_conversion(outport, next->type)) { uint8_t *data = SPA_POD_BODY(&next->value); size_t size = SPA_POD_BODY_SIZE(&next->value);
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/filter-graph/ebur128_plugin.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/filter-graph/ebur128_plugin.c
Changed
@@ -356,7 +356,7 @@ .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_CONTROL, }, { .index = PORT_OUT_SHORTTERM, - .name = "Shorttem LUFS", + .name = "Shortterm LUFS", .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_CONTROL, }, { .index = PORT_OUT_GLOBAL,
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/filter-graph/filter-graph.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/filter-graph/filter-graph.c
Changed
@@ -256,9 +256,8 @@ if (outi == NULL) continue; - port = i < graph->n_output ? &graph->outputi : NULL; - - if (port && port->desc) + port = &graph->outputi; + if (port->desc) port->desc->connect_port(*port->hndl, port->port, outi); else memset(outi, 0, n_samples * sizeof(float));
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/filter-graph/lv2_plugin.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/filter-graph/lv2_plugin.c
Changed
@@ -234,7 +234,7 @@ LV2_Options_Option options6; LV2_Feature options_feature; - const LV2_Feature *features7; + const LV2_Feature *features8; const LV2_Worker_Interface *work_iface; @@ -328,9 +328,11 @@ c->atom_Float, &fsample_rate }; i->options5 = (LV2_Options_Option) { LV2_OPTIONS_INSTANCE, 0, 0, 0, 0, NULL }; - i->options_feature.URI = LV2_OPTIONS__options; - i->options_feature.data = i->options; - i->featuresn_features++ = &i->options_feature; + i->options_feature.URI = LV2_OPTIONS__options; + i->options_feature.data = i->options; + i->featuresn_features++ = &i->options_feature; + i->featuresn_features++ = NULL; + spa_assert(n_features <= SPA_N_ELEMENTS(i->features)); i->instance = lilv_plugin_instantiate(p->p, SampleRate, i->features); if (i->instance == NULL) {
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/libcamera/libcamera-source.cpp -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/libcamera/libcamera-source.cpp
Changed
@@ -273,7 +273,7 @@ default: return spa_libcamera_enum_controls(impl, GET_OUT_PORT(impl, 0), - seq, result.index - 2, num, filter); + seq, result.index, 2, num, filter); } break; } @@ -535,7 +535,7 @@ switch (id) { case SPA_PARAM_PropInfo: - return spa_libcamera_enum_controls(impl, port, seq, start, num, filter); + return spa_libcamera_enum_controls(impl, port, seq, start, 0, num, filter); case SPA_PARAM_EnumFormat: return spa_libcamera_enum_format(impl, port, seq, start, num, filter);
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/libcamera/libcamera-utils.cpp -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/libcamera/libcamera-utils.cpp
Changed
@@ -495,7 +495,7 @@ static int spa_libcamera_enum_controls(struct impl *impl, struct port *port, int seq, - uint32_t start, uint32_t num, + uint32_t start, uint32_t offset, uint32_t num, const struct spa_pod *filter) { const ControlInfoMap &info = impl->camera->controls(); @@ -513,7 +513,7 @@ result.next = start; auto it = info.begin(); - for (skip = result.next; skip; skip--) + for (skip = result.next - offset; skip; skip--) it++; if (false) {
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/v4l2/v4l2-utils.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/v4l2/v4l2-utils.c
Changed
@@ -1873,7 +1873,12 @@ spa_log_debug(this->log, "starting"); - port->first_buffer = true; + if (port->current_format.media_subtype == SPA_MEDIA_SUBTYPE_raw || + port->current_format.media_subtype == SPA_MEDIA_SUBTYPE_mjpg || + port->current_format.media_subtype == SPA_MEDIA_SUBTYPE_jpeg) + port->first_buffer = true; + else + port->first_buffer = false; mmap_read(this); type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/videoconvert/videoadapter.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/videoconvert/videoadapter.c
Changed
@@ -416,28 +416,32 @@ state = 0; param = NULL; - if ((res = spa_node_port_enum_params_sync(this->follower, - this->direction, 0, + if ((res = spa_node_port_enum_params_sync(this->target, + SPA_DIRECTION_REVERSE(this->direction), 0, SPA_PARAM_Buffers, &state, param, ¶m, &b)) < 0) { if (res == -ENOENT) param = NULL; else { - debug_params(this, this->follower, this->direction, 0, - SPA_PARAM_Buffers, param, "follower buffers", res); + debug_params(this, this->target, + SPA_DIRECTION_REVERSE(this->direction), 0, + SPA_PARAM_Buffers, param, "target buffers", res); return res; } } state = 0; - if ((res = spa_node_port_enum_params_sync(this->target, - SPA_DIRECTION_REVERSE(this->direction), 0, + if ((res = spa_node_port_enum_params_sync(this->follower, + this->direction, 0, SPA_PARAM_Buffers, &state, param, ¶m, &b)) != 1) { - debug_params(this, this->target, - SPA_DIRECTION_REVERSE(this->direction), 0, - SPA_PARAM_Buffers, param, "convert buffers", res); - return -ENOTSUP; + if (res == -ENOENT) + res = 0; + else { + debug_params(this, this->follower, this->direction, 0, + SPA_PARAM_Buffers, param, "follower buffers", res); + return res < 0 ? res : -ENOTSUP; + } } if (param == NULL) return -ENOTSUP; @@ -471,7 +475,7 @@ if (this->async) buffers = SPA_MAX(2u, buffers); - spa_log_debug(this->log, "%p: buffers:%d, blocks:%d, size:%d, stride:%d align:%d %d:%d", + spa_log_info(this->log, "%p: buffers:%d, blocks:%d, size:%d, stride:%d align:%d %d:%d", this, buffers, blocks, size, stride, align, follower_alloc, conv_alloc); align = SPA_MAX(align, this->max_align); @@ -908,27 +912,13 @@ spa_node_send_command(this->follower, &SPA_NODE_COMMAND_INIT(SPA_NODE_COMMAND_ParamBegin)); - /* first try the ideal converter format, which is likely passthrough */ - tstate = 0; - fres = spa_node_port_enum_params_sync(this->target, - SPA_DIRECTION_REVERSE(this->direction), 0, - SPA_PARAM_EnumFormat, &tstate, - NULL, &format, &b); - if (fres == 1) { - fstate = 0; - res = spa_node_port_enum_params_sync(this->follower, - this->direction, 0, - SPA_PARAM_EnumFormat, &fstate, - format, &format, &b); - if (res == 1) - goto found; - } - - /* then try something the follower can accept */ + /* The target has been negotiated on its other ports and so it can propose + * a passthrough format or an ideal conversion. We use the suggestions of the + * target to find the best follower format */ for (fstate = 0;;) { format = NULL; - res = spa_node_port_enum_params_sync(this->follower, - this->direction, 0, + res = spa_node_port_enum_params_sync(this->target, + SPA_DIRECTION_REVERSE(this->direction), 0, SPA_PARAM_EnumFormat, &fstate, NULL, &format, &b); @@ -938,8 +928,8 @@ break; tstate = 0; - fres = spa_node_port_enum_params_sync(this->target, - SPA_DIRECTION_REVERSE(this->direction), 0, + fres = spa_node_port_enum_params_sync(this->follower, + this->direction, 0, SPA_PARAM_EnumFormat, &tstate, format, &format, &b); if (fres == 0 && res == 1) @@ -948,7 +938,6 @@ res = fres; break; } -found: if (format == NULL) { debug_params(this, this->follower, this->direction, 0, SPA_PARAM_EnumFormat, format, "follower format", res); @@ -1012,7 +1001,10 @@ break; } - if ((res = spa_node_send_command(this->target, command)) < 0) { + res = spa_node_send_command(this->target, command); + if (res == -ENOTSUP && this->target != this->follower) + res = 0; + if (res < 0) { spa_log_error(this->log, "%p: can't send command %d: %s", this, SPA_NODE_COMMAND_ID(command), spa_strerror(res));
View file
_service:download_url:pipewire-1.4.2.tar.bz2/spa/plugins/videoconvert/videoconvert-ffmpeg.c -> _service:download_url:pipewire-1.4.4.tar.bz2/spa/plugins/videoconvert/videoconvert-ffmpeg.c
Changed
@@ -228,7 +228,7 @@ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_IGNORE_LATENCY, "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, "32 bit raw UMP"); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi"); } if (this->group_name0 != '\0') itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_GROUP, this->group_name); @@ -1812,6 +1812,7 @@ } sbuf = &in_port->buffersinput->buffer_id; + input->status = SPA_STATUS_NEED_DATA; if ((dbuf = peek_buffer(this, out_port)) == NULL) { spa_log_error(this->log, "%p: out of buffers", this); @@ -1902,8 +1903,6 @@ output->buffer_id = dbuf->id; output->status = SPA_STATUS_HAVE_DATA; - input->status = SPA_STATUS_NEED_DATA; - return SPA_STATUS_HAVE_DATA; }
View file
_service:download_url:pipewire-1.4.4.tar.bz2/src/daemon/pipewire.conf.avail/50-raop.conf.in
Added
@@ -0,0 +1,4 @@ +context.modules = + # Use mDNS to detect and load module-raop-sink + { name = libpipewire-module-raop-discover } +
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/daemon/pipewire.conf.avail/meson.build -> _service:download_url:pipewire-1.4.4.tar.bz2/src/daemon/pipewire.conf.avail/meson.build
Changed
@@ -1,6 +1,7 @@ conf_files = '10-rates.conf', '20-upmix.conf', + '50-raop.conf', foreach c : conf_files
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/examples/midi-src.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/examples/midi-src.c
Changed
@@ -213,7 +213,7 @@ PW_FILTER_PORT_FLAG_MAP_BUFFERS, sizeof(struct port), pw_properties_new( - PW_KEY_FORMAT_DSP, "32 bit raw UMP", + PW_KEY_FORMAT_DSP, "8 bit raw midi", PW_KEY_PORT_NAME, "output", NULL), NULL, 0);
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/gst/gstpipewiresrc.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/gst/gstpipewiresrc.c
Changed
@@ -41,7 +41,7 @@ #define GST_CAT_DEFAULT pipewire_src_debug #define DEFAULT_ALWAYS_COPY false -#define DEFAULT_MIN_BUFFERS 8 +#define DEFAULT_MIN_BUFFERS 1 #define DEFAULT_MAX_BUFFERS INT32_MAX #define DEFAULT_RESEND_LAST false #define DEFAULT_KEEPALIVE_TIME 0
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/modules/module-client-node/remote-node.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/modules/module-client-node/remote-node.c
Changed
@@ -481,15 +481,16 @@ pw_proxy_error(proxy, res, "suspend failed"); } break; - case SPA_NODE_COMMAND_RequestProcess: - res = pw_impl_node_send_command(node, command); - break; default: - pw_log_warn("unhandled node command %d (%s)", id, - spa_debug_type_find_name(spa_type_node_command_id, id)); - res = -ENOTSUP; - pw_proxy_errorf(proxy, res, "command %d (%s) not supported", id, - spa_debug_type_find_name(spa_type_node_command_id, id)); + res = pw_impl_node_send_command(node, command); + if (res < 0) { + pw_log_warn("node command %d (%s) error: %s (%d)", id, + spa_debug_type_find_name(spa_type_node_command_id, id), + spa_strerror(res), res); + pw_proxy_errorf(proxy, res, "command %d (%s) error: %s (%d)", id, + spa_debug_type_find_name(spa_type_node_command_id, id), + spa_strerror(res), res); + } } return res; }
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/modules/module-ffado-driver.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/modules/module-ffado-driver.c
Changed
@@ -772,7 +772,7 @@ break; case ffado_stream_type_midi: props = pw_properties_new( - PW_KEY_FORMAT_DSP, "32 bit raw UMP", + PW_KEY_FORMAT_DSP, "8 bit raw midi", PW_KEY_PORT_NAME, port->name, PW_KEY_PORT_PHYSICAL, "true", PW_KEY_PORT_TERMINAL, "true",
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/modules/module-filter-chain.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/modules/module-filter-chain.c
Changed
@@ -972,7 +972,7 @@ pw_stream_update_params(impl->playback, params, 1); } -static void state_changed(void *data, enum pw_stream_state old, +static void capture_state_changed(void *data, enum pw_stream_state old, enum pw_stream_state state, const char *error) { struct impl *impl = data; @@ -1048,7 +1048,9 @@ struct spa_audio_info_raw info; spa_zero(info); if (param == NULL) { - spa_filter_graph_deactivate(graph); + pw_log_info("module %p: filter deactivate", impl); + if (capture) + spa_filter_graph_deactivate(graph); impl->rate = 0; } else { if ((res = spa_format_audio_raw_parse(param, &info)) < 0) @@ -1087,7 +1089,7 @@ .destroy = capture_destroy, .process = capture_process, .io_changed = io_changed, - .state_changed = state_changed, + .state_changed = capture_state_changed, .param_changed = capture_param_changed }; @@ -1108,7 +1110,6 @@ .destroy = playback_destroy, .process = playback_process, .io_changed = io_changed, - .state_changed = state_changed, .param_changed = playback_param_changed, }; @@ -1153,10 +1154,11 @@ SPA_PARAM_EnumFormat, &impl->capture_info); for (i = 0;; i++) { - if ((offs = pw_array_add(&offsets, sizeof(uint32_t))) != NULL) - *offs = b.b.state.offset; + uint32_t save = b.b.state.offset; if (spa_filter_graph_enum_prop_info(graph, i, &b.b, NULL) != 1) break; + if ((offs = pw_array_add(&offsets, sizeof(uint32_t))) != NULL) + *offs = save; } if ((offs = pw_array_add(&offsets, sizeof(uint32_t))) != NULL)
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/modules/module-jack-tunnel.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/modules/module-jack-tunnel.c
Changed
@@ -247,6 +247,8 @@ struct spa_pod_sequence *seq; struct spa_pod_control *c; int res; + uint8_t tmpn_samples * 4; + size_t tmp_size = 0; jack.midi_clear_buffer(dst); if (src == NULL) @@ -260,23 +262,32 @@ seq = (struct spa_pod_sequence*)pod; SPA_POD_SEQUENCE_FOREACH(seq, c) { - uint8_t data16; int size; if (c->type != SPA_CONTROL_UMP) continue; + switch (c->type) { + case SPA_CONTROL_UMP: + size = spa_ump_to_midi(SPA_POD_BODY(&c->value), + SPA_POD_BODY_SIZE(&c->value), &tmptmp_size, sizeof(tmp) - tmp_size); + if (size <= 0) + continue; + tmp_size += size; + break; + case SPA_CONTROL_Midi: + tmp_size = SPA_POD_BODY_SIZE(&c->value); + memcpy(tmp, SPA_POD_BODY(&c->value), SPA_MIN(sizeof(tmp), tmp_size)); + break; + } - size = spa_ump_to_midi(SPA_POD_BODY(&c->value), - SPA_POD_BODY_SIZE(&c->value), data, sizeof(data)); - if (size <= 0) - continue; - - if (impl->fix_midi) - fix_midi_event(data, size); - - if ((res = jack.midi_event_write(dst, c->offset, data, size)) < 0) - pw_log_warn("midi %p: can't write event: %s", dst, - spa_strerror(res)); + if (tmp0 != 0xf0 || tmptmp_size-1 == 0xf7) { + if (impl->fix_midi) + fix_midi_event(tmp, tmp_size); + if ((res = jack.midi_event_write(dst, c->offset, tmp, tmp_size)) < 0) + pw_log_warn("midi %p: can't write event: %s", dst, + spa_strerror(res)); + tmp_size = 0; + } } } @@ -503,7 +514,7 @@ } else { snprintf(name, sizeof(name), "%s_%d", prefix, i - s->info.channels); props = pw_properties_new( - PW_KEY_FORMAT_DSP, "32 bit raw UMP", + PW_KEY_FORMAT_DSP, "8 bit raw midi", PW_KEY_PORT_NAME, name, PW_KEY_PORT_PHYSICAL, "true", NULL);
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/modules/module-netjack2-driver.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/modules/module-netjack2-driver.c
Changed
@@ -45,7 +45,26 @@ /** \page page_module_netjack2_driver Netjack2 driver * * The netjack2-driver module provides a source or sink that is following a - * netjack2 manager. + * netjack2 manager. It is meant to be used over stable (ethernet) network + * connections with minimal latency and jitter. + * + * The driver normally decides how many ports it will send and receive from the + * manager. By default however, these values are set to -1 so that the manager + * decides on the number of ports. + * + * With the global or per stream audio.port and midi.ports properties this + * behaviour can be adjusted. + * + * The driver will send out UDP messages on a (typically) multicast address to + * inform the manager of the available driver. This will then instruct the manager + * to configure and start the driver. + * + * On the driver side, a sink and/or source with the specified numner of audio and + * midi ports will be created. On the manager side there will be a corresponding + * source and/or sink created respectively. + * + * The driver will be scheduled with exactly the same period as the manager but with + * a configurable number of periods of delay (see netjack2.latency, default 2). * * ## Module Name * @@ -53,7 +72,10 @@ * * ## Module Options * - * - `driver.mode`: the driver mode, sink|source|duplex, default duplex + * - `driver.mode`: the driver mode, sink|source|duplex, default duplex. This set the + * per stream audio.port and midi.ports default from -1 to 0. sink mode defaults to + * no source ports, source mode to no sink ports and duplex leaves the defaults as + * they are. * - `local.ifname = <str>`: interface name to use * - `net.ip =<str>`: multicast IP address, default "225.3.19.154" * - `net.port =<int>`: control port, default 19000 @@ -63,11 +85,11 @@ * - `source.ip =<str>`: IP address to bind to, default "0.0.0.0" * - `source.port =<int>`: port to bind to, default 0 (allocate) * - `netjack2.client-name`: the name of the NETJACK2 client. - * - `netjack2.save`: if jack port connections should be save automatically. Can also be - * placed per stream. * - `netjack2.latency`: the latency in cycles, default 2 - * - `audio.channels`: the number of audio ports. Can also be added to the stream props. + * - `audio.ports`: the number of audio ports. Can also be added to the stream props. + * A value of -1 will configure to the number of audio ports on the manager. * - `midi.ports`: the number of midi ports. Can also be added to the stream props. + * A value of -1 will configure to the number of midi ports on the manager. * - `source.props`: Extra properties for the source filter. * - `sink.props`: Extra properties for the sink filter. * @@ -93,15 +115,14 @@ * context.modules = * { name = libpipewire-module-netjack2-driver * args = { - * #driver.mode = duplex * #netjack2.client-name = PipeWire - * #netjack2.save = false * #netjack2.latency = 2 * #midi.ports = 0 + * #audio.ports = -1 * #audio.channels = 2 * #audio.position = FL FR * source.props = { - * # extra sink properties + * # extra source properties * } * sink.props = { * # extra sink properties @@ -133,15 +154,14 @@ #define NETWORK_MAX_LATENCY 30 #define DEFAULT_CLIENT_NAME "PipeWire" -#define DEFAULT_CHANNELS 2 -#define DEFAULT_POSITION " FL FR " -#define DEFAULT_MIDI_PORTS 1 +#define DEFAULT_MIDI_PORTS -1 +#define DEFAULT_AUDIO_PORTS -1 #define FOLLOWER_INIT_TIMEOUT 1 #define FOLLOWER_INIT_RETRY -1 #define MODULE_USAGE "( remote.name=<remote> ) " \ - "( driver.mode=<sink|source|duplex> ) " \ + "( driver.mode=<sink|source|duplex> ) " \ "( local.ifname=<interface name> ) " \ "( net.ip=<ip address to use, default 225.3.19.154> ) " \ "( net.port=<port to use, default 19000> ) " \ @@ -151,11 +171,11 @@ "( source.ip=<ip address to bind, default 0.0.0.0> ) " \ "( source.port=<port to bind, default 0> ) " \ "( netjack2.client-name=<name of the NETJACK2 client> ) " \ - "( netjack2.save=<bool, save ports> ) " \ "( netjack2.latency=<latency in cycles, default 2> ) " \ - "( midi.ports=<number of midi ports> ) " \ - "( audio.channels=<number of channels> ) " \ - "( audio.position=<channel map> ) " \ + "( audio.ports=<number of midi ports, default -1> ) " \ + "( midi.ports=<number of midi ports, default -1> ) " \ + "( audio.channels=<number of channels, default 0> ) " \ + "( audio.position=<channel map, default null> ) " \ "( source.props=<properties> ) " \ "( sink.props=<properties> ) " @@ -182,9 +202,13 @@ struct pw_filter *filter; struct spa_hook listener; + int32_t wanted_n_midi; + int32_t wanted_n_audio; + + struct spa_io_position *position; + struct spa_audio_info_raw info; - uint32_t n_midi; uint32_t n_ports; struct port *portsMAX_PORTS; @@ -222,8 +246,6 @@ struct spa_hook core_proxy_listener; struct spa_hook core_listener; - struct spa_io_position *position; - struct stream source; struct stream sink; @@ -369,11 +391,10 @@ static void stream_io_changed(void *data, void *port_data, uint32_t id, void *area, uint32_t size) { struct stream *s = data; - struct impl *impl = s->impl; if (port_data == NULL) { switch (id) { case SPA_IO_Position: - impl->position = area; + s->position = area; break; default: break; @@ -431,7 +452,7 @@ } else { snprintf(name, sizeof(name), "midi%d", i - s->info.channels); props = pw_properties_new( - PW_KEY_FORMAT_DSP, "32 bit raw UMP", + PW_KEY_FORMAT_DSP, "8 bit raw midi", PW_KEY_AUDIO_CHANNEL, name, PW_KEY_PORT_PHYSICAL, "true", NULL); @@ -458,6 +479,7 @@ s->portsi = port; } + pw_filter_set_active(s->filter, true); } static struct spa_pod *make_props_param(struct spa_pod_builder *b, @@ -523,7 +545,6 @@ case SPA_PARAM_PortConfig: pw_log_debug("PortConfig"); make_stream_ports(s); - pw_filter_set_active(s->filter, true); break; case SPA_PARAM_Props: pw_log_debug("Props"); @@ -558,6 +579,7 @@ const struct spa_pod *params4; uint8_t buffer1024; struct spa_pod_builder b; + int res; n_params = 0; spa_pod_builder_init(&b, buffer, sizeof(buffer)); @@ -583,12 +605,18 @@ SPA_PARAM_Format, &s->info); paramsn_params++ = make_props_param(&b, &s->volume); - return pw_filter_connect(s->filter, + if ((res = pw_filter_connect(s->filter, PW_FILTER_FLAG_INACTIVE | PW_FILTER_FLAG_DRIVER | PW_FILTER_FLAG_RT_PROCESS | PW_FILTER_FLAG_CUSTOM_LATENCY, - params, n_params); + params, n_params)) < 0) + return res; + + if (s->info.channels == 0) + make_stream_ports(s); + + return res; } static int create_filters(struct impl *impl) @@ -616,6 +644,24 @@ return nsec; } +static void update_clock(struct impl *impl, struct stream *s, uint64_t nsec, uint32_t nframes) +{ + if (s->position) { + struct spa_io_clock *c = &s->position->clock; + + c->nsec = nsec; + c->rate = SPA_FRACTION(1, impl->samplerate); + c->position = impl->frame_time; + c->duration = nframes; + c->delay = 0; + c->rate_diff = 1.0; + c->next_nsec = nsec; + + c->target_rate = c->rate; + c->target_duration = c->duration; + } +} + static void on_data_io(void *data, int fd, uint32_t mask) { @@ -648,27 +694,13 @@ impl->frame_time += nframes; - pw_log_trace_fp("process %d %u %u %p %"PRIu64, nframes, source_running, - sink_running, impl->position, impl->frame_time); + pw_log_trace_fp("process %d %u %u %"PRIu64, nframes, source_running, + sink_running, impl->frame_time); if (impl->new_xrun) { pw_log_warn("Xrun netjack2:%u PipeWire:%u", impl->nj2_xrun, impl->pw_xrun); impl->new_xrun = false; } - if (impl->position) { - struct spa_io_clock *c = &impl->position->clock; - - c->nsec = nsec; - c->rate = SPA_FRACTION(1, impl->samplerate); - c->position = impl->frame_time; - c->duration = nframes; - c->delay = 0; - c->rate_diff = 1.0; - c->next_nsec = nsec; - - c->target_rate = c->rate; - c->target_duration = c->duration; - } if (!source_running) netjack2_recv_data(&impl->peer, NULL, 0, NULL, 0); @@ -676,12 +708,16 @@ impl->done = false; impl->triggered = true; impl->driving = MODE_SOURCE; - pw_filter_trigger_process(impl->source.filter); + update_clock(impl, &impl->source, nsec, nframes); + if (pw_filter_trigger_process(impl->source.filter) < 0) + pw_log_warn("source not ready"); } else if (impl->mode == MODE_SINK && sink_running) { impl->done = false; impl->triggered = true; impl->driving = MODE_SINK; - pw_filter_trigger_process(impl->sink.filter); + update_clock(impl, &impl->sink, nsec, nframes); + if (pw_filter_trigger_process(impl->sink.filter) < 0) + pw_log_warn("sink not ready"); } else { sink_running = false; impl->done = true; @@ -706,7 +742,7 @@ static int make_socket(struct sockaddr_storage *src, socklen_t src_len, struct sockaddr_storage *dst, socklen_t dst_len, - bool loop, int ttl, int dscp) + bool loop, int ttl, int dscp, const char *ifname) { int af, fd, val, res; struct timeval timeout; @@ -722,7 +758,13 @@ pw_log_error("setsockopt failed: %m"); goto error; } - +#ifdef SO_BINDTODEVICE + if (ifname && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) { + res = -errno; + pw_log_error("setsockopt(SO_BINDTODEVICE) failed: %m"); + goto error; + } +#endif #ifdef SO_PRIORITY val = 6; if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &val, sizeof(val)) < 0) @@ -789,13 +831,12 @@ int res; struct netjack2_peer *peer = &impl->peer; uint32_t i; + const char *media; pw_log_info("got follower setup"); nj2_dump_session_params(params); nj2_session_params_ntoh(&peer->params, params); - SPA_SWAP(peer->params.send_audio_channels, peer->params.recv_audio_channels); - SPA_SWAP(peer->params.send_midi_channels, peer->params.recv_midi_channels); if (peer->params.send_audio_channels < 0 || peer->params.recv_audio_channels < 0 || @@ -807,23 +848,35 @@ pw_log_warn("invalid follower setup"); return -EINVAL; } + /* the params are from the perspective of the manager, so send is our + * receive (source) and recv is our send (sink) */ + SPA_SWAP(peer->params.send_audio_channels, peer->params.recv_audio_channels); + SPA_SWAP(peer->params.send_midi_channels, peer->params.recv_midi_channels); pw_loop_update_io(impl->main_loop, impl->setup_socket, 0); - impl->source.n_ports = peer->params.send_audio_channels + peer->params.send_midi_channels; - impl->source.info.rate = peer->params.sample_rate; - if ((uint32_t)peer->params.send_audio_channels != impl->source.info.channels) { - impl->source.info.channels = peer->params.send_audio_channels; - for (i = 0; i < SPA_MIN(impl->source.info.channels, SPA_AUDIO_MAX_CHANNELS); i++) - impl->source.info.positioni = SPA_AUDIO_CHANNEL_AUX0 + i; + impl->sink.n_ports = peer->params.send_audio_channels + peer->params.send_midi_channels; + if (impl->sink.n_ports > MAX_PORTS) { + pw_log_warn("Too many follower sink ports %d > %d", impl->sink.n_ports, MAX_PORTS); + return -EINVAL; } - impl->sink.n_ports = peer->params.recv_audio_channels + peer->params.recv_midi_channels; impl->sink.info.rate = peer->params.sample_rate; - if ((uint32_t)peer->params.recv_audio_channels != impl->sink.info.channels) { - impl->sink.info.channels = peer->params.recv_audio_channels; - for (i = 0; i < SPA_MIN(impl->sink.info.channels, SPA_AUDIO_MAX_CHANNELS); i++) + if ((uint32_t)peer->params.send_audio_channels != impl->sink.info.channels) { + impl->sink.info.channels = SPA_MIN(peer->params.send_audio_channels, (int)SPA_AUDIO_MAX_CHANNELS); + for (i = 0; i < impl->sink.info.channels; i++) impl->sink.info.positioni = SPA_AUDIO_CHANNEL_AUX0 + i; } + impl->source.n_ports = peer->params.recv_audio_channels + peer->params.recv_midi_channels; + if (impl->source.n_ports > MAX_PORTS) { + pw_log_warn("Too many follower source ports %d > %d", impl->source.n_ports, MAX_PORTS); + return -EINVAL; + } + impl->source.info.rate = peer->params.sample_rate; + if ((uint32_t)peer->params.recv_audio_channels != impl->source.info.channels) { + impl->source.info.channels = SPA_MIN(peer->params.recv_audio_channels, (int)SPA_AUDIO_MAX_CHANNELS); + for (i = 0; i < impl->source.info.channels; i++) + impl->source.info.positioni = SPA_AUDIO_CHANNEL_AUX0 + i; + } impl->samplerate = peer->params.sample_rate; impl->period_size = peer->params.period_size; @@ -843,6 +896,20 @@ pw_properties_setf(impl->source.props, PW_KEY_NODE_FORCE_QUANTUM, "%u", impl->period_size); + media = impl->sink.info.channels > 0 ? "Audio" : "Midi"; + if (pw_properties_get(impl->sink.props, PW_KEY_MEDIA_CLASS) == NULL) + pw_properties_setf(impl->sink.props, PW_KEY_MEDIA_CLASS, "%s/Sink", media); + + media = impl->source.info.channels > 0 ? "Audio" : "Midi"; + if (pw_properties_get(impl->source.props, PW_KEY_MEDIA_CLASS) == NULL) + pw_properties_setf(impl->source.props, PW_KEY_MEDIA_CLASS, "%s/Source", media); + + impl->mode = 0; + if (impl->source.n_ports > 0) + impl->mode |= MODE_SOURCE; + if (impl->sink.n_ports > 0) + impl->mode |= MODE_SINK; + if ((res = create_filters(impl)) < 0) return res; @@ -942,10 +1009,12 @@ snprintf(params.follower_name, sizeof(params.follower_name), "%s", pw_get_host_name()); params.mtu = htonl(impl->mtu); params.transport_sync = htonl(0); - params.send_audio_channels = htonl(-1); - params.recv_audio_channels = htonl(-1); - params.send_midi_channels = htonl(-1); - params.recv_midi_channels = htonl(-1); + /* send/recv is from the perspective of the manager, so what we send (sink) + * is recv on the manager and vice versa. */ + params.recv_audio_channels = htonl(impl->sink.wanted_n_audio); + params.send_audio_channels = htonl(impl->source.wanted_n_audio); + params.recv_midi_channels = htonl(impl->sink.wanted_n_midi); + params.send_midi_channels = htonl(impl->source.wanted_n_midi); params.sample_encoder = htonl(NJ2_ENCODER_FLOAT); params.follower_sync_mode = htonl(1); params.network_latency = htonl(impl->latency); @@ -982,9 +1051,11 @@ impl->ttl = pw_properties_get_uint32(impl->props, "net.ttl", DEFAULT_NET_TTL); impl->loop = pw_properties_get_bool(impl->props, "net.loop", DEFAULT_NET_LOOP); impl->dscp = pw_properties_get_uint32(impl->props, "net.dscp", DEFAULT_NET_DSCP); + str = pw_properties_get(impl->props, "local.ifname"); fd = make_socket(&impl->src_addr, impl->src_len, - &impl->dst_addr, impl->dst_len, impl->loop, impl->ttl, impl->dscp); + &impl->dst_addr, impl->dst_len, impl->loop, impl->ttl, impl->dscp, + str); if (fd < 0) { res = -errno; pw_log_error("can't create socket: %s", spa_strerror(res)); @@ -1151,8 +1222,7 @@ { spa_audio_info_raw_init_dict_keys(info, &SPA_DICT_ITEMS( - SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P"), - SPA_DICT_ITEM(SPA_KEY_AUDIO_POSITION, DEFAULT_POSITION)), + SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P")), &props->dict, SPA_KEY_AUDIO_CHANNELS, SPA_KEY_AUDIO_POSITION, NULL); @@ -1220,20 +1290,20 @@ impl->sink.impl = impl; impl->sink.direction = PW_DIRECTION_INPUT; - impl->mode = MODE_DUPLEX; if ((str = pw_properties_get(props, "driver.mode")) != NULL) { if (spa_streq(str, "source")) { - impl->mode = MODE_SOURCE; + pw_properties_set(impl->sink.props, "audio.ports", "0"); + pw_properties_set(impl->sink.props, "midi.ports", "0"); } else if (spa_streq(str, "sink")) { - impl->mode = MODE_SINK; - } else if (spa_streq(str, "duplex")) { - impl->mode = MODE_DUPLEX; - } else { + pw_properties_set(impl->source.props, "audio.ports", "0"); + pw_properties_set(impl->source.props, "midi.ports", "0"); + } else if (!spa_streq(str, "duplex")) { pw_log_error("invalid driver.mode '%s'", str); res = -EINVAL; goto error; } } + impl->latency = pw_properties_get_uint32(impl->props, "netjack2.latency", DEFAULT_NETWORK_LATENCY); @@ -1245,11 +1315,9 @@ if (pw_properties_get(props, PW_KEY_NODE_ALWAYS_PROCESS) == NULL) pw_properties_set(props, PW_KEY_NODE_ALWAYS_PROCESS, "true"); - pw_properties_set(impl->sink.props, PW_KEY_MEDIA_CLASS, "Audio/Sink"); pw_properties_set(impl->sink.props, PW_KEY_PRIORITY_DRIVER, "40000"); pw_properties_set(impl->sink.props, PW_KEY_NODE_NAME, "netjack2_driver_send"); - pw_properties_set(impl->source.props, PW_KEY_MEDIA_CLASS, "Audio/Source"); pw_properties_set(impl->source.props, PW_KEY_PRIORITY_DRIVER, "40001"); pw_properties_set(impl->source.props, PW_KEY_NODE_NAME, "netjack2_driver_receive"); @@ -1264,22 +1332,20 @@ copy_props(impl, props, PW_KEY_NODE_ALWAYS_PROCESS); copy_props(impl, props, PW_KEY_NODE_GROUP); copy_props(impl, props, PW_KEY_NODE_VIRTUAL); + copy_props(impl, props, "midi.ports"); + copy_props(impl, props, "audio.ports"); parse_audio_info(impl->source.props, &impl->source.info); parse_audio_info(impl->sink.props, &impl->sink.info); - impl->source.n_midi = pw_properties_get_uint32(impl->source.props, + impl->source.wanted_n_midi = pw_properties_get_int32(impl->source.props, "midi.ports", DEFAULT_MIDI_PORTS); - impl->sink.n_midi = pw_properties_get_uint32(impl->sink.props, + impl->sink.wanted_n_midi = pw_properties_get_int32(impl->sink.props, "midi.ports", DEFAULT_MIDI_PORTS); - - impl->source.n_ports = impl->source.n_midi + impl->source.info.channels; - impl->sink.n_ports = impl->sink.n_midi + impl->sink.info.channels; - if (impl->source.n_ports > MAX_PORTS || impl->sink.n_ports > MAX_PORTS) { - pw_log_error("too many ports"); - res = -EINVAL; - goto error; - } + impl->source.wanted_n_audio = pw_properties_get_int32(impl->source.props, + "audio.ports", DEFAULT_AUDIO_PORTS); + impl->sink.wanted_n_audio = pw_properties_get_int32(impl->sink.props, + "audio.ports", DEFAULT_AUDIO_PORTS); impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core); if (impl->core == NULL) {
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/modules/module-netjack2-manager.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/modules/module-netjack2-manager.c
Changed
@@ -49,6 +49,19 @@ * The netjack2 manager module listens for new netjack2 driver messages and will * start a communication channel with them. * + * Messages are received on a (typically) multicast address. + * + * Normally, the driver will specify the number of send and receive channels it + * wants to set up with the manager. If the driver however specifies a don't-care + * value of -1, the audio.ports and midi.ports configuration values of the manager + * are used. + * + * The manager will create the corresponding streams to send and receive data + * to/from the drivers. These are usually sink and sources but with the + * netjack2.connect property, these will be streams that will be autoconnected to + * the default source and sink by the session manager. + * + * * ## Module Name * * `libpipewire-module-netjack2-manager` @@ -67,8 +80,11 @@ * - `netjack2.period-size`: the buffer size to use, default 1024 * - `netjack2.encoding`: the encoding, float|opus|int, default float * - `netjack2.kbps`: the number of kilobits per second when encoding, default 64 - * - `audio.channels`: the number of audio ports. Can also be added to the stream props. - * - `midi.ports`: the number of midi ports. Can also be added to the stream props. + * - `audio.ports`: the number of audio ports. Can also be added to the stream props. This + * is the default suggestion for drivers that don't specify any number of audio channels. + * - `midi.ports`: the number of midi ports. Can also be added to the stream props. This + * is the default suggestion for drivers that don't specify any number of midi channels. + * - `audio.position`: default channel position for the number of audio.ports. * - `source.props`: Extra properties for the source filter. * - `sink.props`: Extra properties for the sink filter. * @@ -99,11 +115,12 @@ * #netjack2.period-size = 1024 * #netjack2.encoding = float # float|opus * #netjack2.kbps = 64 + * #audio.ports = 0 * #midi.ports = 0 * #audio.channels = 2 * #audio.position = FL FR * source.props = { - * # extra sink properties + * # extra source properties * } * sink.props = { * # extra sink properties @@ -137,8 +154,7 @@ #define DEFAULT_PERIOD_SIZE 1024 #define DEFAULT_ENCODING "float" #define DEFAULT_KBPS 64 -#define DEFAULT_CHANNELS 2 -#define DEFAULT_POSITION " FL FR " +#define DEFAULT_AUDIO_PORTS 2 #define DEFAULT_MIDI_PORTS 1 #define MODULE_USAGE "( remote.name=<remote> ) " \ @@ -151,8 +167,8 @@ "( netjack2.connect=<autoconnect ports, default false> ) " \ "( netjack2.sample-rate=<sampl erate, default 48000> ) "\ "( netjack2.period-size=<period size, default 1024> ) " \ - "( midi.ports=<number of midi ports> ) " \ - "( audio.channels=<number of channels> ) " \ + "( midi.ports=<number of midi ports, default 1> ) " \ + "( audio.channels=<number of channels, default 2> ) " \ "( audio.position=<channel map> ) " \ "( source.props=<properties> ) " \ "( sink.props=<properties> ) " @@ -183,9 +199,12 @@ struct pw_filter *filter; struct spa_hook listener; - struct spa_audio_info_raw info; + struct spa_io_position *position; + struct spa_audio_info_raw info; + uint32_t n_audio; uint32_t n_midi; + uint32_t n_ports; struct port *portsMAX_PORTS; @@ -202,7 +221,10 @@ struct spa_list link; struct impl *impl; - struct spa_io_position *position; +#define MODE_SINK (1<<0) +#define MODE_SOURCE (1<<1) +#define MODE_DUPLEX (MODE_SINK|MODE_SOURCE) + uint32_t mode; struct stream source; struct stream sink; @@ -227,6 +249,7 @@ unsigned int done:1; unsigned int new_xrun:1; unsigned int started:1; + unsigned int freeing:1; }; struct impl { @@ -235,10 +258,6 @@ struct pw_loop *data_loop; struct spa_system *system; -#define MODE_SINK (1<<0) -#define MODE_SOURCE (1<<1) -#define MODE_DUPLEX (MODE_SINK|MODE_SOURCE) - uint32_t mode; struct pw_properties *props; struct pw_properties *sink_props; struct pw_properties *source_props; @@ -284,6 +303,7 @@ struct stream *s = d; uint32_t i; + s->running = false; spa_hook_remove(&s->listener); for (i = 0; i < s->n_ports; i++) s->portsi = NULL; @@ -354,9 +374,17 @@ pw_loop_update_io(s->impl->data_loop, follower->socket, SPA_IO_IN); } -static void source_process(void *d, struct spa_io_position *position) +static int stop_follower(struct follower *follower); + +static int do_stop_follower(struct spa_loop *loop, + bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + stop_follower(user_data); + return 0; +} + +static inline void handle_source_process(struct stream *s, struct spa_io_position *position) { - struct stream *s = d; struct follower *follower = s->follower; uint32_t nframes = position->clock.duration; struct data_info midis->n_ports; @@ -365,28 +393,57 @@ set_info(s, nframes, midi, &n_midi, audio, &n_audio); - netjack2_manager_sync_wait(&follower->peer); + if (netjack2_manager_sync_wait(&follower->peer) < 0) { + pw_loop_invoke(s->impl->main_loop, do_stop_follower, 0, NULL, 0, false, follower); + return; + } netjack2_recv_data(&follower->peer, midi, n_midi, audio, n_audio); } +static void source_process(void *d, struct spa_io_position *position) +{ + struct stream *s = d; + struct follower *follower = s->follower; + + if (!(follower->mode & MODE_SINK)) + sink_process(&follower->sink, position); + + handle_source_process(s, position); +} + static void follower_free(struct follower *follower) { struct impl *impl = follower->impl; + if (follower->freeing) + return; + + follower->freeing = true; + spa_list_remove(&follower->link); - if (follower->source.filter) + if (follower->socket) { + pw_loop_destroy_source(impl->data_loop, follower->socket); + follower->socket = NULL; + } + if (follower->setup_socket) { + pw_loop_destroy_source(impl->main_loop, follower->setup_socket); + follower->setup_socket = NULL; + } + + if (follower->source.filter) { pw_filter_destroy(follower->source.filter); - if (follower->sink.filter) + follower->source.filter = NULL; + } + if (follower->sink.filter) { pw_filter_destroy(follower->sink.filter); + follower->sink.filter = NULL; + } pw_properties_free(follower->source.props); + follower->source.props = NULL; pw_properties_free(follower->sink.props); - - if (follower->socket) - pw_loop_destroy_source(impl->data_loop, follower->socket); - if (follower->setup_socket) - pw_loop_destroy_source(impl->main_loop, follower->setup_socket); + follower->sink.props = NULL; netjack2_cleanup(&follower->peer); free(follower); @@ -420,10 +477,13 @@ on_setup_io(void *data, int fd, uint32_t mask) { struct follower *follower = data; + struct impl *impl = follower->impl; if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { pw_log_warn("error:%08x", mask); - stop_follower(follower); + pw_loop_destroy_source(impl->main_loop, follower->setup_socket); + follower->setup_socket = NULL; + pw_loop_invoke(impl->main_loop, do_stop_follower, 0, NULL, 0, false, follower); return; } if (mask & SPA_IO_IN) { @@ -468,23 +528,32 @@ pw_log_warn("error:%08x", mask); pw_loop_destroy_source(impl->data_loop, follower->socket); follower->socket = NULL; + pw_loop_invoke(impl->main_loop, do_stop_follower, 0, NULL, 0, false, follower); return; } if (mask & SPA_IO_IN) { pw_loop_update_io(impl->data_loop, follower->socket, 0); - pw_filter_trigger_process(follower->source.filter); + if (follower->mode & MODE_SOURCE) { + if (pw_filter_trigger_process(follower->source.filter) < 0) { + pw_log_warn("source not ready"); + handle_source_process(&follower->source, follower->source.position); + } + } else { + /* There is no source, handle the source receive side (without ports) + * with the sink position io */ + handle_source_process(&follower->source, follower->sink.position); + } } } static void stream_io_changed(void *data, void *port_data, uint32_t id, void *area, uint32_t size) { struct stream *s = data; - struct follower *follower = s->follower; if (port_data == NULL) { switch (id) { case SPA_IO_Position: - follower->position = area; + s->position = area; break; default: break; @@ -521,6 +590,9 @@ struct spa_latency_info latency; const struct spa_pod *params1; + if (s->ready) + return; + for (i = 0; i < s->n_ports; i++) { struct port *port = s->portsi; if (port != NULL) { @@ -542,7 +614,7 @@ } else { snprintf(name, sizeof(name), "midi%d", i - s->info.channels); props = pw_properties_new( - PW_KEY_FORMAT_DSP, "32 bit raw UMP", + PW_KEY_FORMAT_DSP, "8 bit raw midi", PW_KEY_PORT_PHYSICAL, "true", PW_KEY_AUDIO_CHANNEL, name, NULL); @@ -571,6 +643,9 @@ s->portsi = port; } + s->ready = true; + if (s->follower->started) + pw_filter_set_active(s->filter, true); } static struct spa_pod *make_props_param(struct spa_pod_builder *b, @@ -636,9 +711,6 @@ case SPA_PARAM_PortConfig: pw_log_debug("PortConfig"); make_stream_ports(s); - s->ready = true; - if (s->follower->started) - pw_filter_set_active(s->filter, true); break; case SPA_PARAM_Props: pw_log_debug("Props"); @@ -674,6 +746,7 @@ uint8_t buffer1024; struct spa_pod_builder b; uint32_t flags; + int res; n_params = 0; spa_pod_builder_init(&b, buffer, sizeof(buffer)); @@ -693,7 +766,8 @@ } else { pw_filter_add_listener(s->filter, &s->listener, &source_events, s); - flags |= PW_FILTER_FLAG_TRIGGER; + if (s->follower->mode & MODE_SINK) + flags |= PW_FILTER_FLAG_TRIGGER; } reset_volume(&s->volume, s->info.channels); @@ -705,18 +779,23 @@ SPA_PARAM_Format, &s->info); paramsn_params++ = make_props_param(&b, &s->volume); - return pw_filter_connect(s->filter, flags, params, n_params); + if ((res = pw_filter_connect(s->filter, flags, params, n_params)) < 0) + return res; + + if (s->info.channels == 0) + make_stream_ports(s); + + return res; } static int create_filters(struct follower *follower) { - struct impl *impl = follower->impl; int res = 0; - if (impl->mode & MODE_SINK) + if (follower->mode & MODE_SINK) res = make_stream(&follower->sink, "NETJACK2 Send"); - if (impl->mode & MODE_SOURCE) + if (follower->mode & MODE_SOURCE) res = make_stream(&follower->source, "NETJACK2 Receive"); return res; @@ -860,6 +939,8 @@ struct follower *follower; char buffer256; struct netjack2_peer *peer; + uint32_t i; + const char *media; pw_log_info("got follower available"); nj2_dump_session_params(params); @@ -891,6 +972,12 @@ parse_audio_info(follower->source.props, &follower->source.info); parse_audio_info(follower->sink.props, &follower->sink.info); + follower->source.n_audio = pw_properties_get_uint32(follower->source.props, + "audio.ports", follower->source.info.channels ? + follower->source.info.channels : DEFAULT_AUDIO_PORTS); + follower->sink.n_audio = pw_properties_get_uint32(follower->sink.props, + "audio.ports", follower->sink.info.channels ? + follower->sink.info.channels : DEFAULT_AUDIO_PORTS); follower->source.n_midi = pw_properties_get_uint32(follower->source.props, "midi.ports", DEFAULT_MIDI_PORTS); follower->sink.n_midi = pw_properties_get_uint32(follower->sink.props, @@ -925,29 +1012,64 @@ peer->params.sample_encoder = impl->encoding; peer->params.kbps = impl->kbps; + /* params send and recv are from the manager point of view and reversed for the + * driver. So, for us send = sink and recv = source */ if (peer->params.send_audio_channels < 0) - peer->params.send_audio_channels = follower->sink.info.channels; + peer->params.send_audio_channels = follower->sink.n_audio; if (peer->params.recv_audio_channels < 0) - peer->params.recv_audio_channels = follower->source.info.channels; + peer->params.recv_audio_channels = follower->source.n_audio; if (peer->params.send_midi_channels < 0) peer->params.send_midi_channels = follower->sink.n_midi; if (peer->params.recv_midi_channels < 0) peer->params.recv_midi_channels = follower->source.n_midi; - follower->source.n_ports = peer->params.send_audio_channels + peer->params.send_midi_channels; - follower->source.info.rate = peer->params.sample_rate; - follower->source.info.channels = peer->params.send_audio_channels; - follower->sink.n_ports = peer->params.recv_audio_channels + peer->params.recv_midi_channels; - follower->sink.info.rate = peer->params.sample_rate; - follower->sink.info.channels = peer->params.recv_audio_channels; + follower->source.n_ports = peer->params.recv_audio_channels + peer->params.recv_midi_channels; + follower->source.info.rate = peer->params.sample_rate; + if ((uint32_t)peer->params.recv_audio_channels != follower->source.info.channels) { + follower->source.info.channels = SPA_MIN(peer->params.recv_audio_channels, (int)SPA_AUDIO_MAX_CHANNELS); + for (i = 0; i < follower->source.info.channels; i++) + follower->source.info.positioni = SPA_AUDIO_CHANNEL_AUX0 + i; + } + follower->sink.n_ports = peer->params.send_audio_channels + peer->params.send_midi_channels; + follower->sink.info.rate = peer->params.sample_rate; + if ((uint32_t)peer->params.send_audio_channels != follower->sink.info.channels) { + follower->sink.info.channels = SPA_MIN(peer->params.send_audio_channels, (int)SPA_AUDIO_MAX_CHANNELS); + for (i = 0; i < follower->sink.info.channels; i++) + follower->sink.info.positioni = SPA_AUDIO_CHANNEL_AUX0 + i; + } - follower->source.n_ports = follower->source.n_midi + follower->source.info.channels; - follower->sink.n_ports = follower->sink.n_midi + follower->sink.info.channels; if (follower->source.n_ports > MAX_PORTS || follower->sink.n_ports > MAX_PORTS) { - pw_log_error("too many ports"); + pw_log_error("too many ports source:%d sink:%d max:%d", follower->source.n_ports, + follower->sink.n_ports, MAX_PORTS); res = -EINVAL; goto cleanup; } + media = follower->sink.info.channels > 0 ? "Audio" : "Midi"; + if (pw_properties_get_bool(follower->sink.props, "netjack2.connect", DEFAULT_CONNECT)) { + if (pw_properties_get(follower->sink.props, PW_KEY_NODE_AUTOCONNECT) == NULL) + pw_properties_set(follower->sink.props, PW_KEY_NODE_AUTOCONNECT, "true"); + if (pw_properties_get(follower->sink.props, PW_KEY_MEDIA_CLASS) == NULL) + pw_properties_setf(follower->sink.props, PW_KEY_MEDIA_CLASS, "Stream/Input/%s", media); + } else { + if (pw_properties_get(follower->sink.props, PW_KEY_MEDIA_CLASS) == NULL) + pw_properties_setf(follower->sink.props, PW_KEY_MEDIA_CLASS, "%s/Sink", media); + } + media = follower->source.info.channels > 0 ? "Audio" : "Midi"; + if (pw_properties_get_bool(follower->source.props, "netjack2.connect", DEFAULT_CONNECT)) { + if (pw_properties_get(follower->source.props, PW_KEY_NODE_AUTOCONNECT) == NULL) + pw_properties_set(follower->source.props, PW_KEY_NODE_AUTOCONNECT, "true"); + if (pw_properties_get(follower->source.props, PW_KEY_MEDIA_CLASS) == NULL) + pw_properties_setf(follower->source.props, PW_KEY_MEDIA_CLASS, "Stream/Output/%s", media); + } else { + if (pw_properties_get(follower->source.props, PW_KEY_MEDIA_CLASS) == NULL) + pw_properties_setf(follower->source.props, PW_KEY_MEDIA_CLASS, "%s/Source", media); + } + + follower->mode = 0; + if (follower->sink.n_ports > 0) + follower->mode |= MODE_SINK; + if (follower->source.n_ports > 0) + follower->mode |= MODE_SOURCE; if ((res = create_filters(follower)) < 0) goto create_failed; @@ -1082,8 +1204,7 @@ impl->dscp = pw_properties_get_uint32(impl->props, "net.dscp", DEFAULT_NET_DSCP); str = pw_properties_get(impl->props, "local.ifname"); - fd = make_announce_socket(&impl->src_addr, impl->src_len, - pw_properties_get(impl->props, "local.ifname")); + fd = make_announce_socket(&impl->src_addr, impl->src_len, str); if (fd < 0) { res = fd; pw_log_error("can't create socket: %s", spa_strerror(res)); @@ -1173,8 +1294,7 @@ { spa_audio_info_raw_init_dict_keys(info, &SPA_DICT_ITEMS( - SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P"), - SPA_DICT_ITEM(SPA_KEY_AUDIO_POSITION, DEFAULT_POSITION)), + SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P")), &props->dict, SPA_KEY_AUDIO_CHANNELS, SPA_KEY_AUDIO_POSITION, NULL); @@ -1238,20 +1358,6 @@ impl->main_loop = pw_context_get_main_loop(context); impl->system = impl->main_loop->system; - impl->mode = MODE_DUPLEX; - if ((str = pw_properties_get(props, "tunnel.mode")) != NULL) { - if (spa_streq(str, "source")) { - impl->mode = MODE_SOURCE; - } else if (spa_streq(str, "sink")) { - impl->mode = MODE_SINK; - } else if (spa_streq(str, "duplex")) { - impl->mode = MODE_DUPLEX; - } else { - pw_log_error("invalid tunnel.mode '%s'", str); - res = -EINVAL; - goto error; - } - } impl->samplerate = pw_properties_get_uint32(impl->props, "netjack2.sample-rate", DEFAULT_SAMPLE_RATE); impl->period_size = pw_properties_get_uint32(impl->props, "netjack2.period-size", @@ -1303,33 +1409,17 @@ copy_props(impl, props, PW_KEY_NODE_LOOP_NAME); copy_props(impl, props, PW_KEY_NODE_VIRTUAL); copy_props(impl, props, PW_KEY_NODE_NETWORK); + copy_props(impl, props, PW_KEY_NODE_GROUP); copy_props(impl, props, PW_KEY_NODE_LINK_GROUP); copy_props(impl, props, PW_KEY_NODE_ALWAYS_PROCESS); copy_props(impl, props, PW_KEY_NODE_LOCK_QUANTUM); copy_props(impl, props, PW_KEY_NODE_LOCK_RATE); copy_props(impl, props, PW_KEY_AUDIO_CHANNELS); copy_props(impl, props, SPA_KEY_AUDIO_POSITION); + copy_props(impl, props, "audio.ports"); + copy_props(impl, props, "midi.ports"); copy_props(impl, props, "netjack2.connect"); - if (pw_properties_get_bool(impl->sink_props, "netjack2.connect", DEFAULT_CONNECT)) { - if (pw_properties_get(impl->sink_props, PW_KEY_NODE_AUTOCONNECT) == NULL) - pw_properties_set(impl->sink_props, PW_KEY_NODE_AUTOCONNECT, "true"); - if (pw_properties_get(impl->sink_props, PW_KEY_MEDIA_CLASS) == NULL) - pw_properties_set(impl->sink_props, PW_KEY_MEDIA_CLASS, "Stream/Input/Audio"); - } else { - if (pw_properties_get(impl->sink_props, PW_KEY_MEDIA_CLASS) == NULL) - pw_properties_set(impl->sink_props, PW_KEY_MEDIA_CLASS, "Audio/Sink"); - } - if (pw_properties_get_bool(impl->source_props, "netjack2.connect", DEFAULT_CONNECT)) { - if (pw_properties_get(impl->source_props, PW_KEY_NODE_AUTOCONNECT) == NULL) - pw_properties_set(impl->source_props, PW_KEY_NODE_AUTOCONNECT, "true"); - if (pw_properties_get(impl->source_props, PW_KEY_MEDIA_CLASS) == NULL) - pw_properties_set(impl->source_props, PW_KEY_MEDIA_CLASS, "Stream/Output/Audio"); - } else { - if (pw_properties_get(impl->source_props, PW_KEY_MEDIA_CLASS) == NULL) - pw_properties_set(impl->source_props, PW_KEY_MEDIA_CLASS, "Audio/Source"); - } - impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core); if (impl->core == NULL) { str = pw_properties_get(props, PW_KEY_REMOTE_NAME);
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/modules/module-netjack2/packets.h -> _service:download_url:pipewire-1.4.4.tar.bz2/src/modules/module-netjack2/packets.h
Changed
@@ -120,7 +120,7 @@ uint32_t cycle; /* process cycle counter */ uint32_t sub_cycle; /* midi/audio subcycle counter */ int32_t frames; /* process cycle size in frames (can be -1 to indicate entire buffer) */ - uint32_t is_last; /* is it the last packet of a given cycle ('y' or 'n') */ + uint32_t is_last; /* is it the last packet of a given cycle (1=yes or 0=no) */ } __attribute__ ((packed)); #define UDP_HEADER_SIZE 64 /* 40 bytes for IP header in IPV6, 20 in IPV4, 8 for UDP, so take 64 */
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/modules/module-netjack2/peer.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/modules/module-netjack2/peer.c
Changed
@@ -242,17 +242,78 @@ } } +static inline void *n2j_midi_buffer_reserve(struct nj2_midi_buffer *buf, + uint32_t offset, uint32_t size) +{ + struct nj2_midi_event *ev; + void *ptr; + + if (size <= 0) + return NULL; + + size_t used_size = sizeof(*buf) + buf->write_pos + + ((buf->event_count + 1) * sizeof(struct nj2_midi_event)); + + ev = &buf->eventbuf->event_count; + ev->time = offset; + ev->size = size; + if (size <= MIDI_INLINE_MAX) { + ptr = ev->buffer; + } else { + if (used_size + size > buf->buffer_size) + return NULL; + buf->write_pos += size; + ev->offset = buf->buffer_size - buf->write_pos; + ptr = SPA_PTROFF(buf, ev->offset, void); + } + buf->event_count++; + return ptr; +} + +static inline void n2j_midi_buffer_write(struct nj2_midi_buffer *buf, + uint32_t offset, void *data, uint32_t size) +{ + void *ptr = n2j_midi_buffer_reserve(buf, offset, size); + if (ptr != NULL) + memcpy(ptr, data, size); + else + buf->lost_events++; +} + +static inline void n2j_midi_buffer_append(struct nj2_midi_buffer *buf, + void *data, uint32_t size) +{ + struct nj2_midi_event *ev; + uint32_t old_size; + uint8_t *old_ptr, *new_ptr; + + ev = &buf->event--buf->event_count; + old_size = ev->size; + if (old_size <= MIDI_INLINE_MAX) { + old_ptr = ev->buffer; + } else { + buf->write_pos -= old_size; + old_ptr = SPA_PTROFF(buf, ev->offset, void); + } + new_ptr = n2j_midi_buffer_reserve(buf, ev->time, old_size + size); + if (new_ptr == NULL) { + buf->lost_events++; + } else { + memmove(new_ptr, old_ptr, old_size); + memcpy(new_ptr+old_size, data, size); + } +} + static void midi_to_netjack2(struct netjack2_peer *peer, struct nj2_midi_buffer *buf, float *src, uint32_t n_samples) { struct spa_pod *pod; struct spa_pod_sequence *seq; struct spa_pod_control *c; - struct nj2_midi_event *ev; - int free_size; + bool in_sysex = false; buf->magic = MIDI_BUFFER_MAGIC; - buf->buffer_size = peer->quantum_limit * sizeof(float); + buf->buffer_size = peer->params.period_size * sizeof(float); buf->nframes = n_samples; buf->write_pos = 0; buf->event_count = 0; @@ -269,12 +330,10 @@ seq = (struct spa_pod_sequence*)pod; - free_size = buf->buffer_size - sizeof(*buf); - SPA_POD_SEQUENCE_FOREACH(seq, c) { int size; uint8_t data16; - void *ptr; + bool was_sysex = in_sysex; if (c->type != SPA_CONTROL_UMP) continue; @@ -284,29 +343,24 @@ if (size <= 0) continue; - if (c->offset >= n_samples || - size >= free_size) { + if (c->offset >= n_samples) { buf->lost_events++; continue; } - if (peer->fix_midi) + if (!in_sysex && data0 == 0xf0) + in_sysex = true; + + if (!in_sysex && peer->fix_midi) fix_midi_event(data, size); - ev = &buf->eventbuf->event_count; - ev->time = c->offset; - ev->size = size; - if (size <= MIDI_INLINE_MAX) { - ptr = ev->buffer; - } else { - buf->write_pos += size; - ev->offset = buf->buffer_size - 1 - buf->write_pos; - free_size -= size; - ptr = SPA_PTROFF(buf, ev->offset, void); - } - memcpy(ptr, data, size); - buf->event_count++; - free_size -= sizeof(*ev); + if (in_sysex && datasize-1 == 0xf7) + in_sysex = false; + + if (was_sysex) + n2j_midi_buffer_append(buf, data, size); + else + n2j_midi_buffer_write(buf, c->offset, data, size); } if (buf->write_pos > 0) memmove(SPA_PTROFF(buf, sizeof(*buf) + buf->event_count * sizeof(struct nj2_midi_event), void), @@ -314,15 +368,27 @@ buf->write_pos); } +static inline void netjack2_clear_midi(float *dst, uint32_t size) +{ + struct spa_pod_builder b = { 0, }; + struct spa_pod_frame f; + spa_pod_builder_init(&b, dst, size); + spa_pod_builder_push_sequence(&b, &f, 0); + spa_pod_builder_pop(&b, &f); +} + static inline void netjack2_to_midi(float *dst, uint32_t size, struct nj2_midi_buffer *buf) { struct spa_pod_builder b = { 0, }; uint32_t i; struct spa_pod_frame f; + size_t offset = size - buf->write_pos - sizeof(*buf) - + (buf->event_count * sizeof(struct nj2_midi_event)); spa_pod_builder_init(&b, dst, size); spa_pod_builder_push_sequence(&b, &f, 0); - for (i = 0; buf != NULL && i < buf->event_count; i++) { + + for (i = 0; i < buf->event_count; i++) { struct nj2_midi_event *ev = &buf->eventi; uint8_t *data; size_t s; @@ -330,8 +396,8 @@ if (ev->size <= MIDI_INLINE_MAX) data = ev->buffer; - else if (ev->offset > buf->write_pos) - data = SPA_PTROFF(buf, ev->offset - buf->write_pos, void); + else if (ev->offset > offset) + data = SPA_PTROFF(buf, ev->offset - offset, void); else continue; @@ -339,9 +405,10 @@ while (s > 0) { uint32_t ump4; int ump_size = spa_ump_from_midi(&data, &s, ump, sizeof(ump), 0, &state); - if (ump_size <= 0) + if (ump_size <= 0) { + pw_log_warn("invalid MIDI received: %s", spa_strerror(ump_size)); break; - + } spa_pod_builder_control(&b, ev->time, SPA_CONTROL_UMP); spa_pod_builder_bytes(&b, ump, ump_size); } @@ -362,7 +429,7 @@ is_last = peer->params.send_midi_channels == 0 && peer->params.send_audio_channels == 0 ? 1 : 0; - strcpy(header.type, "header"); + strncpy(header.type, "header", sizeof(header.type)); header.data_type = htonl('s'); header.data_stream = htonl(peer->our_stream); header.id = htonl(peer->params.id); @@ -416,7 +483,7 @@ max_size = peer->params.mtu - sizeof(header); num_packets = (midi_size + max_size-1) / max_size; - strcpy(header.type, "header"); + strncpy(header.type, "header", sizeof(header.type)); header.data_type = htonl('m'); header.data_stream = htonl(peer->our_stream); header.id = htonl(peer->params.id); @@ -468,7 +535,7 @@ sub_period_bytes = sub_period_size * sizeof(float) + sizeof(int32_t); num_packets = nframes / sub_period_size; - strcpy(header.type, "header"); + strncpy(header.type, "header", sizeof(header.type)); header.data_type = htonl('a'); header.data_stream = htonl(peer->our_stream); header.id = htonl(peer->params.id); @@ -543,7 +610,7 @@ } } - strcpy(header.type, "header"); + strncpy(header.type, "header", sizeof(header.type)); header.data_type = htonl('a'); header.data_stream = htonl(peer->our_stream); header.id = htonl(peer->params.id); @@ -611,7 +678,7 @@ memset(ap, 0, max_encoded); } - strcpy(header.type, "header"); + strncpy(header.type, "header", sizeof(header.type)); header.data_type = htonl('a'); header.data_stream = htonl(peer->our_stream); header.id = htonl(peer->params.id); @@ -691,7 +758,7 @@ receive_error: pw_log_warn("recv error: %m"); - return 0; + return -errno; } static inline int32_t netjack2_manager_sync_wait(struct netjack2_peer *peer) @@ -735,7 +802,7 @@ receive_error: pw_log_warn("recv error: %m"); - return 0; + return -errno; } static int netjack2_recv_midi(struct netjack2_peer *peer, struct nj2_packet_header *header, uint32_t *count, @@ -1031,7 +1098,7 @@ } for (i = 0; i < n_midi; i++) { if (!midii.filled && midii.data != NULL) - netjack2_to_midi(midii.data, peer->params.period_size * sizeof(float), NULL); + netjack2_clear_midi(midii.data, peer->params.period_size * sizeof(float)); } peer->sync.cycle = ntohl(header.cycle); return 0;
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/modules/module-rtp/stream.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/modules/module-rtp/stream.c
Changed
@@ -390,7 +390,7 @@ res = -EINVAL; goto out; } - pw_properties_set(props, PW_KEY_FORMAT_DSP, "32 bit raw UMP"); + pw_properties_set(props, PW_KEY_FORMAT_DSP, "8 bit raw midi"); impl->stride = impl->format_info->size; impl->rate = pw_properties_get_uint32(props, "midi.rate", 10000); if (impl->rate == 0)
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/modules/module-vban/stream.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/modules/module-vban/stream.c
Changed
@@ -307,7 +307,7 @@ res = -EINVAL; goto out; } - pw_properties_set(props, PW_KEY_FORMAT_DSP, "32 bit raw UMP"); + pw_properties_set(props, PW_KEY_FORMAT_DSP, "8 bit raw midi"); impl->stride = impl->format_info->size; impl->rate = pw_properties_get_uint32(props, "midi.rate", 10000); if (impl->rate == 0)
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/pipewire/filter.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/pipewire/filter.c
Changed
@@ -1855,8 +1855,10 @@ add_control_dsp_port_params(impl, p, 1u << SPA_CONTROL_Midi); else if (spa_streq(str, "8 bit raw control")) add_control_dsp_port_params(impl, p, 0); - else if (spa_streq(str, "32 bit raw UMP")) + else if (spa_streq(str, "32 bit raw UMP")) { add_control_dsp_port_params(impl, p, 1u << SPA_CONTROL_UMP); + pw_properties_set(props, PW_KEY_FORMAT_DSP, "8 bit raw midi"); + } } /* then override with user provided if any */ if (update_params(impl, p, SPA_ID_INVALID, params, n_params) < 0)
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/pipewire/impl-node.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/pipewire/impl-node.c
Changed
@@ -660,19 +660,20 @@ struct resource_data *data = object; struct pw_impl_node *node = data->node; uint32_t id = SPA_NODE_COMMAND_ID(command); + int res; pw_log_debug("%p: got command %d (%s)", node, id, spa_debug_type_find_name(spa_type_node_command_id, id)); switch (id) { case SPA_NODE_COMMAND_Suspend: - suspend_node(node); + res = suspend_node(node); break; default: - spa_node_send_command(node->node, command); + res = spa_node_send_command(node->node, command); break; } - return 0; + return res; } static const struct pw_node_methods node_methods = {
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/pipewire/stream.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/pipewire/stream.c
Changed
@@ -2053,7 +2053,7 @@ pw_properties_set(impl->port_props, PW_KEY_FORMAT_DSP, str); else if (impl->media_type == SPA_MEDIA_TYPE_application && impl->media_subtype == SPA_MEDIA_SUBTYPE_control) - pw_properties_set(impl->port_props, PW_KEY_FORMAT_DSP, "32 bit raw UMP"); + pw_properties_set(impl->port_props, PW_KEY_FORMAT_DSP, "8 bit raw midi"); if (pw_properties_get(impl->port_props, PW_KEY_PORT_GROUP) == NULL) pw_properties_set(impl->port_props, PW_KEY_PORT_GROUP, "stream.0");
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/tools/midifile.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/tools/midifile.c
Changed
@@ -940,22 +940,58 @@ dump_mem(out, "Utility", ev->data, ev->size); break; case 0x1: - dump_mem(out, "SysRT", ev->data, ev->size); + { + uint8_t b3 = { (d0 >> 16) & 0x7f, (d0 >> 8) & 0x7f, d0 & 0x7f }; + switch (b0) { + case 0xf1: + fprintf(out, "MIDI Time Code Quarter Frame: type %d values %d", + b1 >> 4, b1 & 0xf); + break; + case 0xf2: + fprintf(out, "Song Position Pointer: value %d", + ((int)b2 << 7 | b1)); + break; + case 0xf3: + fprintf(out, "Song Select: value %d", b1); + break; + case 0xf6: + fprintf(out, "Tune Request"); + break; + case 0xf8: + fprintf(out, "Timing Clock"); + break; + case 0xfa: + fprintf(out, "Start Sequence"); + break; + case 0xfb: + fprintf(out, "Continue Sequence"); + break; + case 0xfc: + fprintf(out, "Stop Sequence"); + break; + case 0xfe: + fprintf(out, "Active Sensing"); + break; + case 0xff: + fprintf(out, "System Reset"); + break; + default: + dump_mem(out, "SysRT", ev->data, ev->size); + break; + } break; + } case 0x2: { struct midi_event ev1; - uint8_t msg4; + uint8_t b3 = { d0 >> 16, d0 >> 8, d0 }; ev1 = *ev; - msg0 = (d0 >> 16); - msg1 = (d0 >> 8); - msg2 = (d0); - if (msg0 >= 0xc0 && msg0 <= 0xdf) + if (b0 >= 0xc0 && b0 <= 0xdf) ev1.size = 2; else ev1.size = 3; - ev1.data = msg; + ev1.data = b; dump_event_midi1(out, &ev1); break; }
View file
_service:download_url:pipewire-1.4.2.tar.bz2/src/tools/pw-cat.c -> _service:download_url:pipewire-1.4.4.tar.bz2/src/tools/pw-cat.c
Changed
@@ -1985,7 +1985,7 @@ SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control)); - pw_properties_set(data.props, PW_KEY_FORMAT_DSP, "32 bit raw UMP"); + pw_properties_set(data.props, PW_KEY_FORMAT_DSP, "8 bit raw midi"); break; case TYPE_DSD: {
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
.