Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package baresip for openSUSE:Factory checked in at 2026-11-05 18:20:21 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/baresip (Old) and /work/SRC/openSUSE:Factory/.baresip.new.3759290 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "baresip" Thu Nov 5 18:20:21 2026 rev:23 rq:1395054 version:4.13.0 Changes: -------- --- /work/SRC/openSUSE:Factory/baresip/baresip.changes 2026-10-17 21:25:00.265884143 +0200 +++ /work/SRC/openSUSE:Factory/.baresip.new.3759290/baresip.changes 2026-11-05 18:22:01.922995285 +0100 @@ -1,0 +2,17 @@ +Wed Nov 4 20:31:29 UTC 2026 - Martin Hauke <[email protected]> + +- Update to version 4.13.0 + * call: add call_set_close_headers(). + * amr: respect mode-set instead of using max. + * audio: add functions to start and stop the transmit thread. + * rtprecv: strip padding from rtp packet. + * modules/gzrtp: multistream fix. + * webrtc/demo: add loopback switch. + * modules/gzrtp: menc_event_h first argument needs to be string. + * sdp: refactor sdp_decode_multipart handling and add test. + * jbuf: increase jitter influence. + * webrtc_aec: enable echo canceller via ApplyConfig. + * audio: remember ausrc module and device. + * test/sni: replace test certs from libre. + +------------------------------------------------------------------- Old: ---- baresip-4.12.0.tar.gz New: ---- baresip-4.13.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ baresip.spec ++++++ --- /var/tmp/diff_new_pack.aMb36F/_old 2026-11-05 18:22:03.957079841 +0100 +++ /var/tmp/diff_new_pack.aMb36F/_new 2026-11-05 18:22:03.959079924 +0100 @@ -17,10 +17,10 @@ # -%global sover 29 +%global sover 30 %global libname lib%{name}%{sover} Name: baresip -Version: 4.12.0 +Version: 4.13.0 Release: 0 Summary: Modular SIP useragent License: BSD-3-Clause ++++++ baresip-4.12.0.tar.gz -> baresip-4.13.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/.github/workflows/fedora.yml new/baresip-4.13.0/.github/workflows/fedora.yml --- old/baresip-4.12.0/.github/workflows/fedora.yml 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/.github/workflows/fedora.yml 2026-11-04 20:53:25.000000000 +0100 @@ -35,7 +35,7 @@ build: needs: dependency runs-on: ubuntu-latest - container: fedora + container: fedora:44 steps: - uses: actions/checkout@v5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/.github/workflows/windows.yml new/baresip-4.13.0/.github/workflows/windows.yml --- old/baresip-4.12.0/.github/workflows/windows.yml 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/.github/workflows/windows.yml 2026-11-04 20:53:25.000000000 +0100 @@ -47,10 +47,13 @@ steps: - uses: actions/checkout@v5 - - name: Install OpenSSL + - name: Download pre-compiled OpenSSL if: ${{ matrix.config.openssl }} + shell: bash run: | - choco install --no-progress ${{ matrix.config.choco }} openssl + curl -fsSL -o openssl.zip "https://github.com/baresip/tools/releases/download/v2026.10.0/openssl-windows-x64.zip" + 7z x openssl.zip + echo "OPENSSL_ROOT_DIR=$GITHUB_WORKSPACE\\openssl-windows-x64" >> $GITHUB_ENV - uses: sreimers/pr-dependency-action@v1 with: @@ -70,7 +73,7 @@ shell: cmd run: | call "${{ matrix.config.environment_script }}" - cmake -S . -B build -G "Ninja" -DCMAKE_C_FLAGS="/WX" -DCMAKE_BUILD_TYPE=${{ matrix.config.build }} -DCMAKE_DISABLE_FIND_PACKAGE_OpenSSL=${{ matrix.config.disable_openssl }} + cmake -S . -B build -G "Ninja" -DCMAKE_C_FLAGS="/WX" -DCMAKE_BUILD_TYPE=${{ matrix.config.build }} -DCMAKE_DISABLE_FIND_PACKAGE_OpenSSL=${{ matrix.config.disable_openssl }} -DOPENSSL_USE_STATIC_LIBS=TRUE cmake --build build -j - name: selftest diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/CHANGELOG.md new/baresip-4.13.0/CHANGELOG.md --- old/baresip-4.12.0/CHANGELOG.md 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/CHANGELOG.md 2026-11-04 20:53:25.000000000 +0100 @@ -5,6 +5,31 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## v4.13.0 - 2026-11-04 + +### What's Changed +* ci/win: use OpenSSL tools build (replaces unstable choco) by @sreimers in https://github.com/baresip/baresip/pull/3847 +* call: add call_set_close_headers() by @ProgrammerIn-wonderland in https://github.com/baresip/baresip/pull/3846 +* amr: respect mode-set instead of using max by @ProgrammerIn-wonderland in https://github.com/baresip/baresip/pull/3849 +* audio: add functions to start and stop the transmit thread by @allesrebel in https://github.com/baresip/baresip/pull/3843 +* rtprecv: strip padding from rtp packet by @sreimers in https://github.com/baresip/baresip/pull/3854 +* modules/gzrtp: multistream fix by @juha-h in https://github.com/baresip/baresip/pull/3857 +* webrtc/demo: add loopback switch by @sreimers in https://github.com/baresip/baresip/pull/3855 +* modules/gzrtp: menc_event_h first argument needs to be string by @juha-h in https://github.com/baresip/baresip/pull/3859 +* sdp: refactor sdp_decode_multipart handling and add test by @sreimers in https://github.com/baresip/baresip/pull/3860 +* jbuf: increase jitter influence by @cspiel1 in https://github.com/baresip/baresip/pull/3869 +* webrtc_aec: enable echo canceller via ApplyConfig by @Andreasdahlberg in https://github.com/baresip/baresip/pull/3863 +* docs: update THANKS file by @alfredh in https://github.com/baresip/baresip/pull/3862 +* audio: remember ausrc module and device by @cspiel1 in https://github.com/baresip/baresip/pull/3864 +* test/sni: replace test certs from libre by @sreimers in https://github.com/baresip/baresip/pull/3884 + +### New Contributors +* @ProgrammerIn-wonderland made their first contribution in https://github.com/baresip/baresip/pull/3846 +* @Andreasdahlberg made their first contribution in https://github.com/baresip/baresip/pull/3863 + +**Full Changelog**: https://github.com/baresip/baresip/compare/v4.12.0...v4.13.0 + + ## v4.12.0 - 2026-09-30 ### What's Changed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/CMakeLists.txt new/baresip-4.13.0/CMakeLists.txt --- old/baresip-4.12.0/CMakeLists.txt 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/CMakeLists.txt 2026-11-04 20:53:25.000000000 +0100 @@ -13,9 +13,9 @@ cmake_minimum_required(VERSION 3.18...4.0) -project(baresip VERSION 4.12.0) +project(baresip VERSION 4.13.0) -set(PROJECT_SOVERSION 29) # bump if ABI breaks +set(PROJECT_SOVERSION 30) # bump if ABI breaks # Pre-release identifier, comment out on a release # Increment for breaking changes (dev2, dev3...) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/docs/THANKS new/baresip-4.13.0/docs/THANKS --- old/baresip-4.12.0/docs/THANKS 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/docs/THANKS 2026-11-04 20:53:25.000000000 +0100 @@ -3,10 +3,13 @@ @elektm93 @glenvt18 @jungle-boogie +@mbattista @premultiply +@viordash Aaron Herting AlexMarlo Andreas Shimokawa +Andrew Webster Atle Samuelsen Charles Lehner Christian Hoene @@ -19,6 +22,7 @@ Dusan Stevanovic EJC Lindner Fadeev Alexander +Franz Auernigg Gary Metalle Geoff Stewart Hans Petter Selasky @@ -30,18 +34,25 @@ Jonathan Sieber José Luis Millán Juha Heinanen +Llu�s Batlle i Rossell Lorenzo Mangani Luigi Rizzo Maciej Koman Marcel Battista Matthias Apitz +Maximilian Fridrich Mikhail Barg +Nicholas Cook Nicolas Tizon Ola Palm Olle E. Johansson +Philipp Hancke Richard Perez +Robert Mittermaier Robert Scheck Sebastian Reimers +Shridhar Majali +Silvio Fosso Stefan Sayer Steve Underwood Thibault Gueslin @@ -54,4 +65,7 @@ Commend.com +Nvidia Corporation Sveriges Radio +Telio Telecom +Wire Swiss diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/include/baresip.h new/baresip-4.13.0/include/baresip.h --- old/baresip-4.12.0/include/baresip.h 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/include/baresip.h 2026-11-04 20:53:25.000000000 +0100 @@ -13,7 +13,7 @@ /** Defines the Baresip version string */ -#define BARESIP_VERSION "4.12.0" +#define BARESIP_VERSION "4.13.0" #ifndef NET_MAX_NS @@ -235,6 +235,7 @@ void call_hangup(struct call *call, uint16_t scode, const char *reason); void call_hangupf(struct call *call, uint16_t scode, const char *reason, const char *fmt, ...); +int call_set_close_headers(struct call *call, const char *fmt, ...); int call_modify(struct call *call); int call_hold(struct call *call, bool hold); void call_set_audio_ldir(struct call *call, enum sdp_dir dir); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/mk/Doxyfile new/baresip-4.13.0/mk/Doxyfile --- old/baresip-4.12.0/mk/Doxyfile 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/mk/Doxyfile 2026-11-04 20:53:25.000000000 +0100 @@ -4,7 +4,7 @@ # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = baresip -PROJECT_NUMBER = 4.12.0 +PROJECT_NUMBER = 4.13.0 OUTPUT_DIRECTORY = ../baresip-dox CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/modules/amr/amr.c new/baresip-4.13.0/modules/amr/amr.c --- old/baresip-4.12.0/modules/amr/amr.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/modules/amr/amr.c 2026-11-04 20:53:25.000000000 +0100 @@ -57,6 +57,7 @@ struct auenc_state { const struct amr_aucodec *ac; void *enc; /**< Encoder state */ + int mode; /**< Mode we send, <= mode-set */ }; struct audec_state { @@ -141,16 +142,21 @@ #ifdef AMR_NB case 8000: st->enc = Encoder_Interface_init(0); + st->mode = amr_mode_set_max(fmtp, MR122); break; #endif #ifdef AMR_WB case 16000: st->enc = E_IF_init(); + st->mode = amr_mode_set_max(fmtp, 8); break; #endif } + debug("amr: %s encoder mode %d (fmtp \"%s\")\n", ac->name, + st->mode, fmtp ? fmtp : ""); + if (!st->enc) err = ENOMEM; @@ -280,7 +286,7 @@ if (fmt != AUFMT_S16LE) return ENOTSUP; - n = IF2E_IF_encode(st->enc, 8, sampv, &buf[1], 0); + n = IF2E_IF_encode(st->enc, st->mode, sampv, &buf[1], 0); if (n <= 0) return EPROTO; @@ -347,7 +353,8 @@ if (fmt != AUFMT_S16LE) return ENOTSUP; - r = Encoder_Interface_Encode(st->enc, MR122, sampv, &buf[1], 0); + r = Encoder_Interface_Encode(st->enc, (enum Mode)st->mode, sampv, + &buf[1], 0); if (r <= 0) return EPROTO; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/modules/amr/amr.h new/baresip-4.13.0/modules/amr/amr.h --- old/baresip-4.12.0/modules/amr/amr.h 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/modules/amr/amr.h 2026-11-04 20:53:25.000000000 +0100 @@ -11,5 +11,6 @@ }; bool amr_octet_align(const char *fmtp); +int amr_mode_set_max(const char *fmtp, int maxmode); int amr_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, bool offer, void *arg); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/modules/amr/sdp.c new/baresip-4.13.0/modules/amr/sdp.c --- old/baresip-4.12.0/modules/amr/sdp.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/modules/amr/sdp.c 2026-11-04 20:53:25.000000000 +0100 @@ -25,19 +25,73 @@ } +/* The value of mode-set may contain spaces ("0, 1, 2") */ +static bool mode_set_get(const char *fmtp, struct pl *ms) +{ + struct pl v; + + if (!fmtp || re_regex(fmtp, str_len(fmtp), + "mode-set[ \t]*=[ \t]*[0-9, \t]+", + NULL, NULL, &v)) + return false; + + while (v.l && (v.p[v.l-1] == ' ' || v.p[v.l-1] == '\t' || + v.p[v.l-1] == ',')) + --v.l; + + *ms = v; + return v.l > 0; +} + + +/* The highest mode in a mode-set must not be above the maxmode specified by + * the server. In the case that the server didn't specify the mode, then the + * max mode is used */ +int amr_mode_set_max(const char *fmtp, int maxmode) +{ + struct pl ms; + int best = -1; + + if (!mode_set_get(fmtp, &ms)) + return maxmode; + + while (ms.l) { + struct pl num; + + if (re_regex(ms.p, ms.l, "[0-9]+", &num)) + break; + + if ((int)pl_u32(&num) <= maxmode && (int)pl_u32(&num) > best) + best = pl_u32(&num); + + ms.l -= num.p + num.l - ms.p; + ms.p = num.p + num.l; + } + + return best >= 0 ? best : maxmode; +} + + int amr_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, bool offer, void *arg) { const struct amr_aucodec *amr_ac = arg; - (void)offer; + struct pl ms = PL_INIT; + bool has_ms = false; if (!mb || !fmt || !amr_ac) return 0; - if (amr_ac->aligned) { - return mbuf_printf(mb, "a=fmtp:%s octet-align=1\r\n", - fmt->id); - } + /* An answer repeats the offer's mode-set (RFC 4867 8.3.1) */ + if (!offer) + has_ms = mode_set_get(fmt->rparams, &ms); + + if (!amr_ac->aligned && !has_ms) + return 0; - return 0; + return mbuf_printf(mb, "a=fmtp:%s %s%s%r\r\n", fmt->id, + amr_ac->aligned ? "octet-align=1" : "", + amr_ac->aligned && has_ms ? ";mode-set=" : + has_ms ? "mode-set=" : "", + &ms); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/modules/gzrtp/session.cpp new/baresip-4.13.0/modules/gzrtp/session.cpp --- old/baresip-4.12.0/modules/gzrtp/session.cpp 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/modules/gzrtp/session.cpp 2026-11-04 20:53:25.000000000 +0100 @@ -136,41 +136,42 @@ ++m_encrypted; - if (m_encrypted == m_streams.size() && m_master) { - info("zrtp: All streams are encrypted (%s), " + if (stream == m_master) { + + info("zrtp: Master stream <%s> is encrypted (%s), " "SAS is [%s] (%s)\n", - m_master->get_ciphers(), - m_master->get_sas(), + m_master->media_name(), + m_master->get_ciphers(), m_master->get_sas(), (m_master->sas_verified())? "verified" : "NOT VERIFIED"); + if (m_master->sas_verified() && m_master->session()->eventh) { if (re_snprintf(buf, sizeof(buf), "%d", m_master->session()->id())) (m_master->session()->eventh) - (MENC_EVENT_PEER_VERIFIED, - buf, + (MENC_EVENT_PEER_VERIFIED, buf, NULL, m_master->session()->arg); else warning("zrtp: failed to print" " verified argument\n"); + if (m_streams.size() > 1) { + debug("zrtp: Starting other streams (%d)\n", + m_streams.size() - 1); + for (std::vector<Stream *>::iterator it = + m_streams.begin(); + it != m_streams.end(); + ++it) { + if (*it != m_master) { + (*it)->start(m_master); + } + } } - return; + } } - if (stream != m_master) - return; - - // Master stream has just entered secure state. Start other - // streams in the multistream mode. - - debug("zrtp: Starting other streams (%d)\n", m_streams.size() - 1); - - for (std::vector<Stream *>::iterator it = m_streams.begin(); - it != m_streams.end(); ++it) { - - if (*it != m_master) { - (*it)->start(m_master); - } + if (m_encrypted == m_streams.size()) { + info("zrtp: All streams are encrypted (%s)\n", + m_master->get_ciphers()); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/modules/webrtc_aec/aec.cpp new/baresip-4.13.0/modules/webrtc_aec/aec.cpp --- old/baresip-4.12.0/modules/webrtc_aec/aec.cpp 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/modules/webrtc_aec/aec.cpp 2026-11-04 20:53:25.000000000 +0100 @@ -49,6 +49,7 @@ struct aec *aec; int err = 0; Config config; + AudioProcessing::Config processing; if (!stp || !ctx || !prm) return EINVAL; @@ -98,6 +99,13 @@ goto out; } + processing.echo_canceller.enabled = true; + processing.echo_canceller.mobile_mode = false; + processing.gain_controller1.enabled = true; + processing.gain_controller1.mode = + AudioProcessing::Config::GainController1::kAdaptiveDigital; + aec->inst->ApplyConfig(processing); + out: if (err) mem_deref(aec); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/src/audio.c new/baresip-4.13.0/src/audio.c --- old/baresip-4.12.0/src/audio.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/src/audio.c 2026-11-04 20:53:25.000000000 +0100 @@ -126,6 +126,8 @@ struct stream *strm; /**< Generic media stream */ struct telev *telev; /**< Telephony events */ struct config_audio cfg; /**< Audio configuration */ + char *ausrc_mod; /**< Initial audio source module */ + char *ausrc_dev; /**< Initial audio source device */ bool started; /**< Stream is started flag */ bool level_enabled; /**< Audio level RTP ext. enabled */ RE_ATOMIC bool conference; /**< Local conference flag */ @@ -172,16 +174,26 @@ } +static void stop_transmit_thread(struct autx *tx) +{ + if (!re_atomic_rlx(&tx->thr.run)) + return; + + re_atomic_rlx_set(&tx->thr.run, false); + + int result = thrd_join(tx->thr.tid, NULL); + if (result != thrd_success) + debug("audio: failed to join transmit thread (%d)\n", result); +} + + static void stop_tx(struct autx *tx, struct audio *a) { if (!tx || !a) return; stream_enable_tx(a->strm, false); - if (re_atomic_rlx(&tx->thr.run)) { - re_atomic_rlx_set(&tx->thr.run, false); - thrd_join(tx->thr.tid, NULL); - } + stop_transmit_thread(tx); /* audio source must be stopped first */ tx->ausrc = mem_deref(tx->ausrc); @@ -214,6 +226,8 @@ mem_deref(a->strm); mem_deref(a->telev); mem_deref(a->aur); + mem_deref(a->ausrc_mod); + mem_deref(a->ausrc_dev); mem_deref(a->tx.mtx); } @@ -783,20 +797,21 @@ goto out; if (acc && acc->ausrc_mod) { - - tx->module = mem_ref(acc->ausrc_mod); - tx->device = mem_ref(acc->ausrc_dev); + a->ausrc_mod = mem_ref(acc->ausrc_mod); + a->ausrc_dev = mem_ref(acc->ausrc_dev); info("audio: using account specific source: (%s,%s)\n", tx->module, tx->device); } else { - err = str_dup(&tx->module, a->cfg.src_mod); - err |= str_dup(&tx->device, a->cfg.src_dev); + err = str_dup(&a->ausrc_mod, a->cfg.src_mod); + err |= str_dup(&a->ausrc_dev, a->cfg.src_dev); if (err) goto out; } + tx->module = mem_ref(a->ausrc_mod); + tx->device = mem_ref(a->ausrc_dev); tx->ptime = ptime; tx->ts_ext = tx->ts_base = rand_u16(); tx->marker = true; @@ -917,6 +932,20 @@ } +static int start_transmit_thread(struct autx *tx, struct audio *a) +{ + if (re_atomic_rlx(&tx->thr.run)) + return 0; + + re_atomic_rlx_set(&tx->thr.run, true); + int err = thread_create_name(&tx->thr.tid, "Audio TX", tx_thread, a); + if (err) + re_atomic_rlx_set(&tx->thr.run, false); + + return err; +} + + static void aufilt_param_set(struct aufilt_prm *prm, const struct aucodec *ac, enum aufmt fmt) { @@ -1109,17 +1138,9 @@ mtx_unlock(tx->mtx); tx->as = ausrc_find(ausrcl, tx->module); - if (!re_atomic_rlx(&tx->thr.run)) { - re_atomic_rlx_set(&tx->thr.run, true); - err = thread_create_name(&tx->thr.tid, - "Audio TX", - tx_thread, a); - if (err) { - re_atomic_rlx_set(&tx->thr.run, - false); - return err; - } - } + err = start_transmit_thread(tx, a); + if (err) + return err; info("audio: source started with sample format %s\n", aufmt_name(tx->src_fmt)); @@ -1735,7 +1756,7 @@ int audio_set_source(struct audio *au, const char *mod, const char *device) { struct autx *tx; - int err; + int err = 0; if (!au) return EINVAL; @@ -1743,9 +1764,15 @@ tx = &au->tx; /* stop the audio device first */ + tx->module = mem_deref(tx->module); + tx->device = mem_deref(tx->device); tx->ausrc = mem_deref(tx->ausrc); if (str_isset(mod)) { + err = str_dup(&tx->module, mod); + err |= str_dup(&tx->device, device); + if (err) + return err; err = ausrc_alloc(&tx->ausrc, baresip_ausrcl(), mod, &tx->ausrc_prm, device, @@ -1758,8 +1785,12 @@ tx->as = ausrc_find(baresip_ausrcl(), mod); } + else { + err = str_dup(&tx->module, au->ausrc_mod); + err |= str_dup(&tx->device, au->ausrc_dev); + } - return 0; + return err; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/src/call.c new/baresip-4.13.0/src/call.c --- old/baresip-4.12.0/src/call.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/src/call.c 2026-11-04 20:53:25.000000000 +0100 @@ -3166,6 +3166,33 @@ } +/** + * Set custom SIP headers for the BYE (or 200 OK to a BYE) ending the call + * + * @param call Call object + * @param fmt Formatted headers, each ending in CRLF, or NULL to clear + * + * @return 0 if success, otherwise errorcode + */ +int call_set_close_headers(struct call *call, const char *fmt, ...) +{ + va_list ap; + int err; + + if (!call || !call->sess) + return EINVAL; + + if (!fmt) + return sipsess_set_close_headers(call->sess, NULL); + + va_start(ap, fmt); + err = sipsess_set_close_headers(call->sess, "%v", fmt, &ap); + va_end(ap); + + return err; +} + + void call_set_xrtpstat(struct call *call) { if (!call) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/src/jbuf.c new/baresip-4.13.0/src/jbuf.c --- old/baresip-4.12.0/src/jbuf.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/src/jbuf.c 2026-11-04 20:53:25.000000000 +0100 @@ -346,7 +346,7 @@ if (jb->p.late_pkts >= JBUF_LATE_TRESHOLD) { jb->p.late_pkts = 0; - jb->p.jitter_offset = 2 * jitter; + jb->p.jitter_offset = 3 * jitter; RE_TRACE_ID_INSTANT_I( "jbuf", "jitter_adjust", delay_ms(jb->p.jitter_offset, jb->srate), jb->id); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/src/rtprecv.c new/baresip-4.13.0/src/rtprecv.c --- old/baresip-4.12.0/src/rtprecv.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/src/rtprecv.c 2026-11-04 20:53:25.000000000 +0100 @@ -388,6 +388,23 @@ } +/* RFC 3550 section 5.1 -- the last octet contains the padding count */ +static void rtprecv_strip_padding(const struct rtp_header *hdr, + struct mbuf *mb) +{ + size_t left = mbuf_get_left(mb); + + if (!hdr->pad || !left) + return; + + uint8_t padc = mb->buf[mb->end - 1]; + if (!padc || padc > left) + return; + + mb->end -= padc; +} + + static bool rtprecv_filter_pt(struct rtp_receiver *rx, const struct rtp_header *hdr) { @@ -469,6 +486,8 @@ } mtx_unlock(rx->mtx); + rtprecv_strip_padding(hdr, mb); + if (ssrc_changed) rtprecv_resync(rx, hdr); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/src/sdp.c new/baresip-4.13.0/src/sdp.c --- old/baresip-4.12.0/src/sdp.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/src/sdp.c 2026-11-04 20:53:25.000000000 +0100 @@ -71,21 +71,24 @@ } -static void decode_part(const struct pl *part, struct mbuf *mb) +static bool decode_part_next(const struct pl *part, struct mbuf *mb) { struct pl hdrs, body; if (re_regex(part->p, part->l, "\r\n\r\n[^]+", &body)) - return; + return true; hdrs.p = part->p; - hdrs.l = body.p - part->p - 2; + hdrs.l = body.p - part->p; if (0 == re_regex(hdrs.p, hdrs.l, "application/sdp")) { + mb->pos += hdrs.l; + mb->end = mb->pos + body.l; - mb->pos += (body.p - (char *)mbuf_buf(mb)); - mb->end = mb->pos + body.l; + return false; } + + return true; } @@ -100,45 +103,40 @@ int sdp_decode_multipart(const struct pl *ctype_prm, struct mbuf *mb) { struct pl p, bnd; - char bnd_str[64]; - char *s, *e; - char *buf = NULL; - int err; + char bnd_str[73]; if (!ctype_prm || !mb) return EINVAL; /* fetch the boundary tag, excluding quotes */ - err = re_regex(ctype_prm->p, ctype_prm->l, - "boundary=[~]+", &bnd); + int err = re_regex(ctype_prm->p, ctype_prm->l, "boundary=[~]+", &bnd); if (err) return err; - err = pl_strcpy(&bnd, bnd_str, sizeof(bnd_str)); - if (err) - return err; + int bnd_slen = re_snprintf(bnd_str, sizeof(bnd_str), "--%r", &bnd); + if (bnd_slen == -1) + return EMSGSIZE; - err = mbuf_strdup(mb, &buf, mbuf_get_left(mb)); - if (err) - return err; + pl_set_mbuf(&p, mb); /* find 1st boundary */ - s = strstr(buf, bnd_str); + const char *s = pl_strstr(&p, bnd_str); + if (!s) + return EBADMSG; /* iterate over each part */ - while (s) { - e = strstr(s + bnd.l, bnd_str); + do { + mbuf_advance(mb, s - (char *)mbuf_buf(mb) + bnd_slen); + pl_set_mbuf(&p, mb); + + const char *e = pl_strstr(&p, bnd_str); if (!e) break; - p.p = s + bnd.l + 2; - p.l = e - p.p - 2; + p.l = e - p.p; + s = e; - decode_part(&p, mb); - - s = e; - } + } while (decode_part_next(&p, mb)); - mem_deref(buf); return 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/test/call.c new/baresip-4.13.0/test/call.c --- old/baresip-4.12.0/test/call.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/test/call.c 2026-11-04 20:53:25.000000000 +0100 @@ -3639,3 +3639,164 @@ mem_deref(debug_str); return err; } + + +struct multipart_uas { + struct fixture *f; + struct sip *sip; + struct sipsess_sock *sock; + struct sipsess *sess; +}; + + +static const char multipart_body[] = + "--bnd42\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "not an sdp\r\n" + "--bnd42\r\n" + "Content-Type: application/sdp\r\n" + "\r\n" + "v=0\r\n" + "o=- 1 1 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "c=IN IP4 127.0.0.1\r\n" + "t=0 0\r\n" + "m=audio 50000 RTP/AVP 0\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=sendrecv\r\n" + "--bnd42--\r\n"; + + +static void multipart_uas_close_handler(int err, const struct sip_msg *msg, + void *arg) +{ + struct multipart_uas *uas = arg; + (void)msg; + + uas->sess = mem_deref(uas->sess); + + fixture_abort(uas->f, err ? err : EPROTO); +} + + +static void multipart_uas_conn_handler(const struct sip_msg *msg, void *arg) +{ + struct multipart_uas *uas = arg; + struct mbuf *mb; + int err; + + mb = mbuf_alloc(sizeof(multipart_body)); + if (!mb) { + err = ENOMEM; + goto out; + } + + err = mbuf_write_str(mb, multipart_body); + if (err) + goto out; + + mb->pos = 0; + + err = sipsess_accept(&uas->sess, uas->sock, msg, 200, "OK", + REL100_DISABLED, "uas", + "multipart/mixed;boundary=bnd42", mb, + NULL, NULL, false, NULL, NULL, NULL, NULL, NULL, + multipart_uas_close_handler, uas, NULL); + + out: + mem_deref(mb); + + if (err) { + (void)sip_treply(NULL, uas->sip, msg, 500, "Server Error"); + fixture_abort(uas->f, err); + } +} + + +static int multipart_uas_init(struct multipart_uas *uas, struct sa *laddr) +{ + int err; + + err = sa_set_str(laddr, "127.0.0.1", 0); + if (err) + return err; + + err = sip_alloc(&uas->sip, NULL, 32, 32, 32, "multipart_uas", + NULL, NULL); + if (err) + return err; + + err = sip_transp_add(uas->sip, SIP_TRANSP_UDP, laddr); + if (err) + return err; + + err = sip_transp_laddr(uas->sip, laddr, SIP_TRANSP_UDP, NULL); + if (err) + return err; + + return sipsess_listen(&uas->sock, uas->sip, 32, + multipart_uas_conn_handler, uas); +} + + +static void multipart_uas_close(struct multipart_uas *uas) +{ + mem_deref(uas->sess); + sipsess_close_all(uas->sock); + mem_deref(uas->sock); + sip_close(uas->sip, true); + mem_deref(uas->sip); +} + + +/* + * Call from A to a raw SIP UAS that answers with a multipart/mixed body, + * where the SDP is the second part. + */ +int test_call_multipart(void) +{ + struct fixture fix, *f = &fix; + struct multipart_uas uas = {0}; + struct cancel_rule *cr; + struct sa laddr; + const struct sdp_media *m; + char uri[128]; + int err = 0; + + fixture_init(f); + + uas.f = f; + + err = multipart_uas_init(&uas, &laddr); + TEST_ERR(err); + + f->estab_action = ACTION_NOTHING; + cancel_rule_new(BEVENT_CALL_ESTABLISHED, f->a.ua, 0, 0, 1); + + re_snprintf(uri, sizeof(uri), "sip:uas@%J", &laddr); + + err = ua_connect(f->a.ua, NULL, NULL, uri, VIDMODE_OFF); + TEST_ERR(err); + + err = re_main_timeout(5000); + cancel_rule_pop(); + TEST_ERR(err); + err = fix.err; + TEST_ERR(err); + + ASSERT_EQ(1, fix.a.n_established); + ASSERT_EQ(0, fix.a.n_closed); + + /* verify that the SDP part was decoded */ + m = stream_sdpmedia(audio_strm(call_audio(ua_call(f->a.ua)))); + ASSERT_TRUE(m != NULL); + ASSERT_EQ(50000, sdp_media_rport(m)); + ASSERT_TRUE(sdp_media_rformat(m, "PCMU") != NULL); + + out: + fixture_close(f); + multipart_uas_close(&uas); + + return err; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/test/data/sni/client-interm.pem new/baresip-4.13.0/test/data/sni/client-interm.pem --- old/baresip-4.12.0/test/data/sni/client-interm.pem 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/test/data/sni/client-interm.pem 2026-11-04 20:53:25.000000000 +0100 @@ -1,35 +1,36 @@ -----BEGIN CERTIFICATE----- -MIICOzCCAeGgAwIBAgIUOGllk+RwWh0SaiOIlZ28iDr9CUQwCgYIKoZIzj0EAwIw -VzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDzANBgNVBAoMBlJl -dGVzdDEiMCAGA1UEAwwZTXIgUmV0ZXN0IEludGVybWVkaWF0ZSBDQTAgFw0yMjEy -MjkwOTMxMDRaGA8yMTIyMTIwMzA5MzEwNFowTzELMAkGA1UEBhMCQVUxEzARBgNV -BAgMClNvbWUtU3RhdGUxDzANBgNVBAoMBlJldGVzdDEaMBgGA1UEAwwRcmV0ZXN0 -LmNsaWVudC5vcmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARpvxjuwaXKPM2d -M9G1DNYQR/cXacJw1ZlFgDT/PqolekRtjOUtFTs+2NAC5F8so3So9QS+XOBel851 -ZIfSZznco4GQMIGNMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgbAMB0GA1Ud -DgQWBBQl0oAqn8/QfeOxwRS4iic96jokKDAfBgNVHSMEGDAWgBTGQwW6wdqJ1o5Y -G1KSgeBw+jOwPzAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG -CCsGAQUFBwMCMAoGCCqGSM49BAMCA0gAMEUCIEkiN/wpykIISrCZtFDa3SslEJL/ -i3bUUAKrHMab52xtAiEAkA0z6aDhxITnxIfqG3RqPR/NTlyJ8JVtrLcbHFRWRzI= +MIICQzCCAemgAwIBAgIRANrVtMcY+CeYIqn2kSGF8T4wCgYIKoZIzj0EAwIwVzEL +MAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDzANBgNVBAoMBlJldGVz +dDEiMCAGA1UEAwwZTXIgUmV0ZXN0IEludGVybWVkaWF0ZSBDQTAgFw0yNjExMDEx +MjAxNDlaGA8yMTI2MTAwODEyMDE0OVowTzELMAkGA1UEBhMCQVUxEzARBgNVBAgM +ClNvbWUtU3RhdGUxDzANBgNVBAoMBlJldGVzdDEaMBgGA1UEAwwRcmV0ZXN0LmNs +aWVudC5vcmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATEcOGooeGZH6pxu4MI +1aUW8d7nJ63qwb7KA3etPi2hiGEzGi7Ymu9wDkSwM9sm/O1LijhpxwiJGva0YZM8 +xqMCo4GbMIGYMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQG +CCsGAQUFBwMBBggrBgEFBQcDAjAcBgNVHREEFTATghFyZXRlc3QuY2xpZW50Lm9y +ZzAdBgNVHQ4EFgQUvvOenRU7PIXT/iu3kB3/cTDnUNMwHwYDVR0jBBgwFoAU4MAa +P1mU2radk2uH8VmDwBdEUXIwCgYIKoZIzj0EAwIDSAAwRQIgGg6B5/07PhCxWfe9 +sPmd52phTqPphVwnoN5PaM7Ru3wCIQDkHzwPvelsJ4kq3+qEFyztvNkvDKovJwq0 +EiMNbSGi3Q== -----END CERTIFICATE----- -----BEGIN EC PARAMETERS----- BggqhkjOPQMBBw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- -MHcCAQEEIJ76xyjJn4C6ZaQRszt0rNwKq0LBz/Re9QZPeDyBW4r0oAoGCCqGSM49 -AwEHoUQDQgAEab8Y7sGlyjzNnTPRtQzWEEf3F2nCcNWZRYA0/z6qJXpEbYzlLRU7 -PtjQAuRfLKN0qPUEvlzgXpfOdWSH0mc53A== +MHcCAQEEIM+6J+5FxqQwNTtlEyhCgyQg+ClZzJddMoGzLGMX3WmPoAoGCCqGSM49 +AwEHoUQDQgAExHDhqKHhmR+qcbuDCNWlFvHe5yet6sG+ygN3rT4toYhhMxou2Jrv +cA5EsDPbJvztS4o4accIiRr2tGGTPMajAg== -----END EC PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIIB/TCCAaOgAwIBAgIBATAKBggqhkjOPQQDAjBPMQswCQYDVQQGEwJBVTETMBEG -A1UECAwKU29tZS1TdGF0ZTEPMA0GA1UECgwGUmV0ZXN0MRowGAYDVQQDDBFNciBS -ZXRlc3QgUm9vdCBDQTAgFw0yMjEyMjkwOTIzNTRaGA8yMTIyMTIwNDA5MjM1NFow -VzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDzANBgNVBAoMBlJl -dGVzdDEiMCAGA1UEAwwZTXIgUmV0ZXN0IEludGVybWVkaWF0ZSBDQTBZMBMGByqG -SM49AgEGCCqGSM49AwEHA0IABHn8RqyvhhIdMK0o0wc+mKfO97SghjB3FlKBLjQT -+jIOVW3YboDBgPCRwdjGFugc661MyIHQrT74FXSpkYOWhtKjZjBkMB0GA1UdDgQW -BBTGQwW6wdqJ1o5YG1KSgeBw+jOwPzAfBgNVHSMEGDAWgBSzp+1VNAQC/frGxi3S -P0yfFD7bMjASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAKBggq -hkjOPQQDAgNIADBFAiEApEk3i06Pmp8JcWf+zP63qTIWRvXqi4wScxgyc9f9nLsC -IEp5w8tyc7NxZFlAzH0ENl7L9zyLOoj685m5qnI/g9n2 +MIICCzCCAbKgAwIBAgIQFADkThPTHsMoisiEFGKJ9zAKBggqhkjOPQQDAjBPMQsw +CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEPMA0GA1UECgwGUmV0ZXN0 +MRowGAYDVQQDDBFNciBSZXRlc3QgUm9vdCBDQTAgFw0yNjExMDExMjAxNDlaGA8y +MTI2MTAwODEyMDE0OVowVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3Rh +dGUxDzANBgNVBAoMBlJldGVzdDEiMCAGA1UEAwwZTXIgUmV0ZXN0IEludGVybWVk +aWF0ZSBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPkzZ5C3bcWsWSZFdqnx +U/Q2AZwtnvlquXbuJJfF6erUg856Z98cOz+Hy3p96wWVQZC3Q5ffbEAAzRRfs+PA +keejZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud +DgQWBBTgwBo/WZTatp2Ta4fxWYPAF0RRcjAfBgNVHSMEGDAWgBQCZaxMTRK4A1qM +xvp6g1HWimh0lzAKBggqhkjOPQQDAgNHADBEAiBBhdSztskI5dfQ1iRn6qs4nSN4 +7cmU3y4TQx4+10OIaQIgP2kveUN83sDvpUP5KomXZE3p3gPYkUZ0+QTSv1NIEBw= -----END CERTIFICATE----- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/test/data/sni/root-ca.pem new/baresip-4.13.0/test/data/sni/root-ca.pem --- old/baresip-4.12.0/test/data/sni/root-ca.pem 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/test/data/sni/root-ca.pem 2026-11-04 20:53:25.000000000 +0100 @@ -1,13 +1,13 @@ -----BEGIN CERTIFICATE----- -MIIB9DCCAZugAwIBAgIUGWM5J2Oi1FhuZiq1agTkmWGNOqEwCgYIKoZIzj0EAwIw +MIICBTCCAaugAwIBAgIUFn1nuklp7tcUa9BvqKEdC7yjJ7owCgYIKoZIzj0EAwIw TzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDzANBgNVBAoMBlJl -dGVzdDEaMBgGA1UEAwwRTXIgUmV0ZXN0IFJvb3QgQ0EwIBcNMjIxMjI5MDkyMDEx -WhgPMjEyMjEyMDUwOTIwMTFaME8xCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l +dGVzdDEaMBgGA1UEAwwRTXIgUmV0ZXN0IFJvb3QgQ0EwIBcNMjYxMTAxMTIwMTQ5 +WhgPMjEyNjEwMDgxMjAxNDlaME8xCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l LVN0YXRlMQ8wDQYDVQQKDAZSZXRlc3QxGjAYBgNVBAMMEU1yIFJldGVzdCBSb290 -IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErdUhTL7f5A5qa4GGcJEWkwBa -l1Q7XU8DSKOiSsVnJ0w3TLHMXXoEx83yOF9yyp5xbxMtr3rSZEpFfQ6VVZ9FyKNT -MFEwHQYDVR0OBBYEFLOn7VU0BAL9+sbGLdI/TJ8UPtsyMB8GA1UdIwQYMBaAFLOn -7VU0BAL9+sbGLdI/TJ8UPtsyMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwID -RwAwRAIgcml4Q6W/zcUnzPI9eb97FNBqLNwWRTlh3JPDplpfj4MCIBVrXpAPEfVy -JsCIPpxLjYPRhvfdRIZGgvzTP5q4mGaT +IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2FDHd4Y81EsyRvMPdGN6KT+f +A+y0Dhjr1eq2dqFjiA86NhJeJa62luy56vky7HpDjDMw++XPDAXa/qZVmlC5iKNj +MGEwHQYDVR0OBBYEFAJlrExNErgDWozG+nqDUdaKaHSXMB8GA1UdIwQYMBaAFAJl +rExNErgDWozG+nqDUdaKaHSXMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMAoGCCqGSM49BAMCA0gAMEUCIBo3APbW/3iZsItsfw6a/W98mx0QxhIsId/k +LLicHX5eAiEA1mjs+c4FMZHUTUk8Xod3idFsgutUe1luQ9rl/t0Jlk4= -----END CERTIFICATE----- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/test/data/sni/server-interm.pem new/baresip-4.13.0/test/data/sni/server-interm.pem --- old/baresip-4.12.0/test/data/sni/server-interm.pem 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/test/data/sni/server-interm.pem 2026-11-04 20:53:25.000000000 +0100 @@ -1,37 +1,36 @@ -----BEGIN CERTIFICATE----- -MIIClDCCAjmgAwIBAgIUa79XJUJxiZsuE19rM05mJwE/AuowCgYIKoZIzj0EAwIw -VzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDzANBgNVBAoMBlJl -dGVzdDEiMCAGA1UEAwwZTXIgUmV0ZXN0IEludGVybWVkaWF0ZSBDQTAgFw0yMjEy -MjkwOTMxMThaGA8yMTIyMTIwMzA5MzExOFowTzELMAkGA1UEBhMCQVUxEzARBgNV -BAgMClNvbWUtU3RhdGUxDzANBgNVBAoMBlJldGVzdDEaMBgGA1UEAwwRcmV0ZXN0 -LnNlcnZlci5vcmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQIJmj//cAvgPmv -VYe5IbVUg65pQzpTwRskbFqpDqUnIqkcdFHPHCtqAVg8bkTsXBETB76m44ejAps/ -F1cii/Rfo4HoMIHlMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgbAMB0GA1Ud -DgQWBBSTjuar4J+Cv02G6QpqgCflL7swsDB3BgNVHSMEcDBugBTGQwW6wdqJ1o5Y -G1KSgeBw+jOwP6FTpFEwTzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3Rh -dGUxDzANBgNVBAoMBlJldGVzdDEaMBgGA1UEAwwRTXIgUmV0ZXN0IFJvb3QgQ0GC -AQEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD -AjAKBggqhkjOPQQDAgNJADBGAiEAhfU/r3G88n0V3h5jc7FwgWL+9ig+SGlc6mPG -FsqI0eECIQCMLbYDZgMPpaFPzCWKVAmp9wxzLLpX9++C/v4Y4FVOAg== +MIICQzCCAemgAwIBAgIRALD6BXDqXz39AiNMZmPS6wUwCgYIKoZIzj0EAwIwVzEL +MAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDzANBgNVBAoMBlJldGVz +dDEiMCAGA1UEAwwZTXIgUmV0ZXN0IEludGVybWVkaWF0ZSBDQTAgFw0yNjExMDEx +MjAxNDlaGA8yMTI2MTAwODEyMDE0OVowTzELMAkGA1UEBhMCQVUxEzARBgNVBAgM +ClNvbWUtU3RhdGUxDzANBgNVBAoMBlJldGVzdDEaMBgGA1UEAwwRcmV0ZXN0LnNl +cnZlci5vcmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQSMEMmY+Ho0OXbDOFr +4QODrLBcfGdMY60Ikmn1TgruwyZV/nYOU0FG45eXfc/tss+I+rv14lcBBgtDehe5 +0pzDo4GbMIGYMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQG +CCsGAQUFBwMBBggrBgEFBQcDAjAcBgNVHREEFTATghFyZXRlc3Quc2VydmVyLm9y +ZzAdBgNVHQ4EFgQU+qmWsvWBVB8MUIMGo6M51Z78Ll4wHwYDVR0jBBgwFoAU4MAa +P1mU2radk2uH8VmDwBdEUXIwCgYIKoZIzj0EAwIDSAAwRQIhAMRLhp8S61+UZ5gT +LJXtmL/66exDoCCHVZvM5Rd6DjG0AiAvPzB+/7loHXKbMoysjLZn6L5W+bS7NItI +Rwxd2KYFiw== -----END CERTIFICATE----- -----BEGIN EC PARAMETERS----- BggqhkjOPQMBBw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- -MHcCAQEEIJMwouMCx2+QTFwiuo2GUYPgtmTGpx/7+0rkcw6//GQvoAoGCCqGSM49 -AwEHoUQDQgAECCZo//3AL4D5r1WHuSG1VIOuaUM6U8EbJGxaqQ6lJyKpHHRRzxwr -agFYPG5E7FwREwe+puOHowKbPxdXIov0Xw== +MHcCAQEEIK6KhreraGn2QIlylpnbGgfS0cZHVHIH7nnucdZrUSdWoAoGCCqGSM49 +AwEHoUQDQgAEEjBDJmPh6NDl2wzha+EDg6ywXHxnTGOtCJJp9U4K7sMmVf52DlNB +RuOXl33P7bLPiPq79eJXAQYLQ3oXudKcww== -----END EC PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIIB/TCCAaOgAwIBAgIBATAKBggqhkjOPQQDAjBPMQswCQYDVQQGEwJBVTETMBEG -A1UECAwKU29tZS1TdGF0ZTEPMA0GA1UECgwGUmV0ZXN0MRowGAYDVQQDDBFNciBS -ZXRlc3QgUm9vdCBDQTAgFw0yMjEyMjkwOTIzNTRaGA8yMTIyMTIwNDA5MjM1NFow -VzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDzANBgNVBAoMBlJl -dGVzdDEiMCAGA1UEAwwZTXIgUmV0ZXN0IEludGVybWVkaWF0ZSBDQTBZMBMGByqG -SM49AgEGCCqGSM49AwEHA0IABHn8RqyvhhIdMK0o0wc+mKfO97SghjB3FlKBLjQT -+jIOVW3YboDBgPCRwdjGFugc661MyIHQrT74FXSpkYOWhtKjZjBkMB0GA1UdDgQW -BBTGQwW6wdqJ1o5YG1KSgeBw+jOwPzAfBgNVHSMEGDAWgBSzp+1VNAQC/frGxi3S -P0yfFD7bMjASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAKBggq -hkjOPQQDAgNIADBFAiEApEk3i06Pmp8JcWf+zP63qTIWRvXqi4wScxgyc9f9nLsC -IEp5w8tyc7NxZFlAzH0ENl7L9zyLOoj685m5qnI/g9n2 +MIICCzCCAbKgAwIBAgIQFADkThPTHsMoisiEFGKJ9zAKBggqhkjOPQQDAjBPMQsw +CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEPMA0GA1UECgwGUmV0ZXN0 +MRowGAYDVQQDDBFNciBSZXRlc3QgUm9vdCBDQTAgFw0yNjExMDExMjAxNDlaGA8y +MTI2MTAwODEyMDE0OVowVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3Rh +dGUxDzANBgNVBAoMBlJldGVzdDEiMCAGA1UEAwwZTXIgUmV0ZXN0IEludGVybWVk +aWF0ZSBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPkzZ5C3bcWsWSZFdqnx +U/Q2AZwtnvlquXbuJJfF6erUg856Z98cOz+Hy3p96wWVQZC3Q5ffbEAAzRRfs+PA +keejZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud +DgQWBBTgwBo/WZTatp2Ta4fxWYPAF0RRcjAfBgNVHSMEGDAWgBQCZaxMTRK4A1qM +xvp6g1HWimh0lzAKBggqhkjOPQQDAgNHADBEAiBBhdSztskI5dfQ1iRn6qs4nSN4 +7cmU3y4TQx4+10OIaQIgP2kveUN83sDvpUP5KomXZE3p3gPYkUZ0+QTSv1NIEBw= -----END CERTIFICATE----- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/test/main.c new/baresip-4.13.0/test/main.c --- old/baresip-4.12.0/test/main.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/test/main.c 2026-11-04 20:53:25.000000000 +0100 @@ -37,6 +37,7 @@ TEST(test_call_mediaenc), TEST(test_call_medianat), TEST(test_call_mixausrc), + TEST(test_call_multipart), TEST(test_call_multiple), TEST(test_call_progress), TEST(test_call_reject), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/test/test.h new/baresip-4.13.0/test/test.h --- old/baresip-4.12.0/test/test.h 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/test/test.h 2026-11-04 20:53:25.000000000 +0100 @@ -210,6 +210,7 @@ int test_call_mediaenc(void); int test_call_medianat(void); int test_call_mixausrc(void); +int test_call_multipart(void); int test_call_multiple(void); int test_call_progress(void); int test_call_reject(void); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/webrtc/src/demo.c new/baresip-4.13.0/webrtc/src/demo.c --- old/baresip-4.12.0/webrtc/src/demo.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/webrtc/src/demo.c 2026-11-04 20:53:25.000000000 +0100 @@ -31,6 +31,14 @@ }; +static bool loopback_requested(const struct http_msg *msg) +{ + const struct http_hdr *hdr = http_msg_xhdr(msg, "Loopback"); + + return hdr && 0 == pl_strcasecmp(&hdr->val, "true"); +} + + static int handle_put_sdp(struct session *sess, const struct http_msg *msg) { struct session_description sd = {-1, NULL}; @@ -134,6 +142,7 @@ sess->pc_config = pc_config; sess->pc_config.offerer = false; /* browser is offerer */ + sess->loopback = loopback_requested(msg); /* sync reply */ http_reply(conn, 201, "Created", @@ -152,6 +161,7 @@ sess->pc_config = pc_config; sess->pc_config.offerer = true; /* baresip-webrtc is offerer */ + sess->loopback = loopback_requested(msg); err = session_start(sess, &sess->pc_config, demo.mnat, demo.menc); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/webrtc/src/demo.h new/baresip-4.13.0/webrtc/src/demo.h --- old/baresip-4.12.0/webrtc/src/demo.h 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/webrtc/src/demo.h 2026-11-04 20:53:25.000000000 +0100 @@ -16,6 +16,7 @@ struct rtc_configuration pc_config; struct http_conn *conn_pending; char id[4]; + bool loopback; }; int session_new(struct list *sessl, struct session **sessp); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/webrtc/src/main.c new/baresip-4.13.0/webrtc/src/main.c --- old/baresip-4.12.0/webrtc/src/main.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/webrtc/src/main.c 2026-11-04 20:53:25.000000000 +0100 @@ -33,6 +33,7 @@ "opus", "g722", "ausine", + "aubridge", /* video */ "vp8", @@ -40,7 +41,8 @@ "vp9", "av1", "avformat", - "fakevideo" + "fakevideo", + "vidbridge" }; static const char *ice_server = NULL; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/webrtc/src/sess.c new/baresip-4.13.0/webrtc/src/sess.c --- old/baresip-4.12.0/webrtc/src/sess.c 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/webrtc/src/sess.c 2026-11-04 20:53:25.000000000 +0100 @@ -134,16 +134,39 @@ const struct rtc_configuration *pc_config, const struct mnat *mnat, const struct menc *menc) { - const struct config *config = conf_config(); - int err; - if (!sess) return EINVAL; if (sess->pc) return EALREADY; - err = peerconnection_new(&sess->pc, pc_config, mnat, menc, + struct config config = *conf_config(); + + str_ncpy(config.audio.play_mod, "aubridge", + sizeof(config.audio.play_mod)); + str_ncpy(config.audio.play_dev, sess->id, + sizeof(config.audio.play_dev)); + + if (sess->loopback) { + + info("demo: session '%s' using loopback\n", sess->id); + + str_ncpy(config.audio.src_mod, "aubridge", + sizeof(config.audio.src_mod)); + str_ncpy(config.audio.src_dev, sess->id, + sizeof(config.audio.src_dev)); + + str_ncpy(config.video.src_mod, "vidbridge", + sizeof(config.video.src_mod)); + str_ncpy(config.video.src_dev, sess->id, + sizeof(config.video.src_dev)); + str_ncpy(config.video.disp_mod, "vidbridge", + sizeof(config.video.disp_mod)); + str_ncpy(config.video.disp_dev, sess->id, + sizeof(config.video.disp_dev)); + } + + int err = peerconnection_new(&sess->pc, pc_config, mnat, menc, peerconnection_gather_handler, peerconnection_estab_handler, peerconnection_close_handler, sess); @@ -152,7 +175,7 @@ return err; } - err = peerconnection_add_audio_track(sess->pc, config, + err = peerconnection_add_audio_track(sess->pc, &config, baresip_aucodecl(), SDP_SENDRECV); if (err) { warning("demo: add_audio failed (%m)\n", err); @@ -160,7 +183,7 @@ } err = peerconnection_add_video_track( - sess->pc, config, baresip_vidcodecl(), + sess->pc, &config, baresip_vidcodecl(), baresip_vidfiltl(), SDP_SENDRECV); if (err) { warning("demo: add_video failed (%m)\n", err); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/webrtc/www/index.html new/baresip-4.13.0/webrtc/www/index.html --- old/baresip-4.12.0/webrtc/www/index.html 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/webrtc/www/index.html 2026-11-04 20:53:25.000000000 +0100 @@ -33,6 +33,9 @@ <input id="recvonly" type="checkbox" /> <label for="recvonly">Recvonly</label> + + <input id="loopback" type="checkbox" title="echo camera and microphone"/> + <label for="loopback">Loopback</label> </div> <p id="session_id"></p> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/baresip-4.12.0/webrtc/www/js/main.js new/baresip-4.13.0/webrtc/www/js/main.js --- old/baresip-4.12.0/webrtc/www/js/main.js 2026-09-30 19:40:56.000000000 +0200 +++ new/baresip-4.13.0/webrtc/www/js/main.js 2026-11-04 20:53:25.000000000 +0100 @@ -12,6 +12,7 @@ const remoteVideo = document.getElementById('remoteVideo'); const offerer = document.getElementById('offerer'); const recvonly = document.getElementById('recvonly'); +const loopback = document.getElementById('loopback'); connectButton.onclick = connect_call; disconnectButton.onclick = disconnect_call; @@ -269,6 +270,9 @@ else xhr.open("POST", '' + loc + 'connect', true); + if (loopback.checked && !recvonly.checked) + xhr.setRequestHeader("Loopback", "true"); + xhr.onreadystatechange = function() { if (this.readyState === XMLHttpRequest.DONE &&
