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 &&

Reply via email to