deps/patches/2.17/
==================

Why these patches are carried here and not upstream
---------------------------------------------------
(Notes for Debian / distribution reviewers.)

python3-sipsimple does not use the system pjproject.  get_dependencies.sh
unpacks the pristine pjproject 2.17 release tarball, applies this series,
and setup_pjsip.py builds only pjproject's static libraries, which are
linked into sipsimple's own extension module (sipsimple/core/_core).
Nothing from deps/ is installed as a shared library or header, so the
patched pjproject is private to this package: it cannot conflict with,
or change the ABI of, a distribution libpjproject used by other
packages (e.g. Asterisk).

The patches fall into four groups.  Groups 1-3 are not upstreamable by
nature; group 4 is.

1. Code that is not part of pjproject and which upstream does not carry
   ZRTP media encryption (12, 12a, 13, 18, 19, 29, 02): pjproject has no
   ZRTP support.  These add our pjmedia ZRTP transport (transport_zrtp.c,
   written and maintained by AG Projects) on top of the GNU ZRTP
   library (ZRTPCPP, pinned commit), plus the build wiring and fixes to
   the vendored ZRTPCPP sources.
   Sylk AEAD transport (20, 27): AES-GCM payload encryption that must
   interoperate byte-for-byte with the Sylk Mobile client.  It is an
   application protocol of ours, not a standard, so it has no place
   in pjproject.

2. API extensions that exist for sipsimple's Cython bindings
   03, 04, 05, 06, 08, 11, 32, 40, 42, 52, 53, 54, 57 add callbacks,
   accessors and device backends that sipsimple's Python API is built
   on: ICE state and stop callbacks, SIP header and subscription
   helpers, audio device change observers, the framebuffer video
   renderer, our own AVFoundation capture backend (which replaces
   upstream's darwin/metal backend on macOS), screen capture devices,
   changing encoder size mid-call, V4L2 frame rate enumeration, and an
   ARGB format.  They extend pjproject's public structs and function
   tables, and some replace upstream design choices rather than adding
   to them.  Building sipsimple against an unpatched pjproject fails at
   compile time.

3. Defaults and policy that are sipsimple's choice, not bugs
   07 (mono Opus, low latency x264 tuning), 08 (no automatic b=TIAS),
   24 (always offer rtcp-fb), 44 and 45 (VP8/VP9 rate control and
   quality), 48 (H.264 profile-level-id matching libwebrtc), 28 (a
   tls_name Route URI parameter that selects the TLS SNI name, which is
   not a standard parameter), and 59 (TLS certificate logging at level
   1).  They are tuned for interop with Sylk Mobile, Blink and
   WebRTC-based peers, and upstream is right to keep its own defaults.

4. Bug fixes in upstream code paths
   09 (WebRTC AEC wrapper), 25, 30, 31, 33, 34 (use-after-free and
   lifetime bugs), 55, 56 (vid_port frame buffer and capture size), and
   15 (currently a no-op, see its header).
   Several of these only trigger under sipsimple's object lifetime model:
   media pools are released from Python, so teardown ordering differs
   from pjsua's.  Each could still be offered upstream.  Until a
   pjproject release contains an equivalent fix, the patch is carried
   here.  On every pjproject version bump, patches whose fix landed
   upstream are dropped (see "Dropped permanently" below, e.g. the
   FFmpeg 5 migration and the Darwin semaphore rewrite).

Every patch has a header comment that says what it changes and why.


Patch series for pjsip 2.17, the only supported pjsip version.
get_dependencies.sh applies every [0-9][0-9]_*.patch in this folder in
numerical order (GNU patch, -p0 from deps/).

The 2.12 series (deps/patches/[0-9][0-9]_*.patch and deps/patches/pending/)
has been removed; it is still in darcs history.


Numbering convention
--------------------
NN_ prefixes follow the old 2.12 series so each patch can be traced back
through darcs history.  A patch dropped in the 2.17 rebase simply doesn't
exist here; do not renumber.  New 2.17-only patches use NN >= 40.
Numbers of folded/removed patches are not reused.


Current status (October 2026)
=============================

Present in this folder
----------------------

Foundation / build:
  02_zsrtp_link.patch                  2.17-only - tweak ZSRTP linker flags
                                       so the GnuTLS / OpenSSL split in
                                       2.17 doesn't dead-strip cryptopp.

Core SIP / dialog / signalling:
  03_pjsip_signaling.patch             ported - INVITE / dialog rework
                                       around 2.14 + RFC 6026 timing.
  04_pjnath_ice_strans.patch           ported - early-candidate wiring,
                                       offset-tracker hunk split fix.
  11_transport_ice.patch               ported - drops on_ice_complete2
                                       (upstream); pjmedia_ice_cb hunk
                                       verified.
  27_pjmedia_rebind_remote_peer.patch  ported - depends on 20.
  28_pjsip_tls_route_sni_selector.patch
                                       ported - was renamed from
                                       28_pjsip_tls_lis_create_*; same
                                       feature, simplified hook point.
  33_pjsip_inv_cause_text_bound.patch  ported - rebased for the 2.17
                                       sip_inv.c whitespace sweep and
                                       the (int)inv->cause cast; bounds
                                       inv->cause_text into inv->pool
                                       so a transaction-pool reason
                                       phrase can't outlive its source.
  34_conf_get_frame_port_ref.patch     2.17-only - closes the get-frame
                                       half of the conference-port UAF
                                       that patch 30 only fixed on the
                                       removal side.  Wraps the two
                                       pjmedia_port_get_frame() calls
                                       in conf.c::read_port() with
                                       pj_grp_lock_add_ref/dec_ref so
                                       the audio I/O thread can't
                                       dispatch through a freed
                                       function-pointer table during
                                       hangup.
  30_conf_port_grp_lock_uaf.patch      ported - 2.17-only re-derivation
                                       of the conference-port UAF fix.
  31_stream_transport_grp_lock_uaf.patch
                                       ported - 2.17-only re-derivation
                                       of the stream-transport UAF fix.

Media / SDP / codecs:
  07_codecs.patch                      ported - opus mono advertisement,
                                       x264 preset/tune retune for lower
                                       latency, and PROFILE_H264_HIGH
                                       support in the SDP fmtp switch.
                                       (Only AVCODEC_HAS_ENCODE and
                                       avcodec_get_frame_defaults hunks
                                       stay out - both subsumed by
                                       2.17's FFmpeg 5+ migration.)
  08_media_core.patch                  ported - vid_tee mutex wrap, RTCP
                                       PLI, mixer_port, KEYFRAME_REQUESTED
                                       event, real EC reset, TIAS disable,
                                       MIXER signature.  Skipped:
                                       converter.c debug logging.
  09_aec.patch                         2.17 rewrite (Sep 2026) - NOT a
                                       port of the 2.12 file.  The 2.12
                                       09_aec.patch added the 2013 AG
                                       echo_webrtc_aec.c but nothing has
                                       compiled it since the May 2021
                                       pjsip 2.10 migration; every build
                                       since used upstream echo_webrtc.c.
                                       This patch fixes upstream's wrapper
                                       instead: QMF band split at 32 kHz
                                       (resample at 48 kHz), capture high
                                       pass filter, band aware NS,
                                       thread safe deferred reset, new
                                       pjmedia_echo_resync() /
                                       pjmedia_snd_port_resync_ec_state(),
                                       EC resume uses resync, WebRTC delay
                                       correction after 2 s instead of
                                       15 s, thread safe statistics
                                       (pjmedia_snd_port_get_ec_stat ->
                                       AudioMixer.ec_statistics).  Builds
                                       splitting_filter.c.
                                       Details + measurements in the patch
                                       header, docs/EchoCancellation.txt
                                       and aec-harness/.
  15_vpx.patch                         ported - verified, no-op guard,
                                       preserves 2.12 behaviour.
  20_sylk_aead_transport.patch         ported - Makefile hunk re-targeted
                                       against vanilla 2.17.
  24_video_sdp_rtcp_fb.patch           ported - 4-space indent, clean.
  22_srtp_transport_get_info_uaf.patch ported - 2.17 already NULLs the
                                       libsrtp ctx pointers; this port
                                       adds the SSRC-zero on stop and
                                       the session_inited guards in
                                       get_info as defense-in-depth.
  25_libswscale_converter_uaf.patch    ported - clean 4-space.

Devices:
  05_audio_device.patch                ported - the ~1100 line audio
                                       device patch rebased after the 2.13
                                       whitespace sweep.
  06_video_device.patch                ported - includes the real
                                       pjmedia_vid_dev_fb_set_callback
                                       and fb_dev.c.  Was a heavy lift
                                       (~1800 lines) because the 2.15
                                       Metal renderer landed upstream.
                                       June 2026: folds in the
                                       avf_factory_refresh() crash fix
                                       (heap overflow + nil-name deref)
                                       and the AVCaptureDevice retain/
                                       release UAF fix - both were bugs
                                       in the avf_dev.m this patch
                                       introduces, so they are fixed at
                                       source rather than layered on top.
                                       Supersedes the interim 50/51.
  (16_mac_audio_vpio_disable,          FOLDED into 05 (June 2026) - these
   21_alsa_dev_pjsip217_log,           only adapted to the coreaudio_dev.m /
   35_alsa_dev_add_dev_custom_call)    alsa_dev.c API changes that patch 05
                                       itself makes, so they are now baked
                                       into patch 05 and the standalone
                                       patches were removed.  Patch 05's
                                       audio file sections were regenerated
                                       from pristine 2.17 to the final state.
                                       See patch 05's header for details.

ZRTP (copy-as-is from 2.12 - the ZRTPCPP source is version-independent):
  13_zsrtp.patch                       copy-as-is - ZRTPCPP wrapper.
  18_fix_uint_zrtp.patch               copy-as-is - ZRTPCPP source,
                                       pinned commit.
  19_fix_zrtp_cstdint_include.patch    copy-as-is - ZRTPCPP source.
  29_zsrtp_hmac_ctx_lifetime.patch     copy-as-is - OpenSSL 3 HMAC_CTX
                                       lifetime fix + -DZRTP_OPENSSL on
                                       the Makefile.  Source files
                                       byte-identical to 2.12 so the
                                       same patch applies; Makefile
                                       lands with line offset from 13.

ZRTP / SRTP (2.17 needed surgery):
  12_transport_zrtp.patch              ported - the ~2100 line transport
                                       glue, intertwined with 2.17's
                                       SRTP / ZRTP changes.
                                       June 2026: the transport_zrtp.c
                                       crash/locking fixes formerly carried
                                       as separate patches 46/47/49 are now
                                       folded into the file this patch
                                       creates (all were bugs in our own
                                       module).  Net result is byte-identical
                                       to 12 -> 46 -> 47 -> 49.
  12a_zrtp_pjmedia_h_makefile.patch    ported - companion to 12, exposes
                                       transport_zrtp.h via pjmedia.h
                                       and adds the .o to the Makefile.
                                       (.obsolete sibling is dead weight
                                       and can be deleted.)

VP9 / VPX (4 patches working together):
  23_vpx_packetizer_libwebrtc_interop.patch
                                       PARKED no-op - vanilla 2.17's
                                       1-byte VP9 descriptor (B / E only)
                                       is what libwebrtc actually wants.
                                       Adding RFC-9628 fields broke Sylk
                                       Mobile decode.  Kept as a slot
                                       holder + rationale log.
  44_vpx_encoder_rate_control.patch    2.17-only - 1.5 Mbps target, VBR,
                                       dropframe_thresh=0.  Without this
                                       the encoder produced ~0.8 fps to
                                       Sylk Mobile.
  45_vpx_encoder_quality_preset.patch  2.17-only - cpu_used 9->4,
                                       rc_max_quantizer 56->48.  Removes
                                       the pixelated / blocky picture
                                       once 44 fixed framerate.

New 2.17-only support:
  40_videodev_extra_objs.patch         Makefile add-ons for the AVF /
                                       fb_dev objects landed by patch 06.
  42_pjmedia_argb_format.patch         Adds PJMEDIA_FORMAT_ARGB to the
                                       format registry + libyuv I420
                                       conversion path used by the
                                       FrameBufferVideoRenderer.
  (46_zrtp_detach_race_null_deref,     FOLDED into 12 (June 2026) - these
   47_zrtp_cb_lock_sync,               three transport_zrtp.c crash/locking
   49_zrtp_cb2_lock_body)              fixes were bugs in our own module and
                                       are now baked into the file patch 12
                                       creates; the standalone patches were
                                       removed.  See patch 12's header for
                                       what each one did.
  48_h264_sylk_mobile_interop.patch    2.17-only - H.264 SDP fmtp:
                                       profile-level-id 42e01e -> 42e01f
                                       (Constrained Baseline Level 3.0
                                       -> 3.1), strips the leading space
                                       from " packetization-mode".
                                       Matches Sylk Mobile / libwebrtc
                                       / standard WebRTC, unlocking
                                       720p negotiation on Mac -> Sylk
                                       Mobile H.264 calls.
  52_linux_screen_capture.patch        2.17-only - "My screen" capture
                                       device on Linux (screen_dev.c):
                                       xdg-desktop-portal ScreenCast over
                                       GDBus + PipeWire, letterboxed I420
                                       via libswscale, the Linux side of
                                       patch 32. Built when setup_pjsip.py
                                       finds libpipewire-0.3 and GIO
                                       (PJMEDIA_VIDEO_DEV_HAS_SCREEN); stubs
                                       elsewhere. Python side:
                                       sipsimple.core.screen_capture_info()
                                       and friends (_core.video.pxi).
  53_vid_stream_set_enc_size.patch     2.17-only - pjmedia_vid_stream_set_enc_size():
                                       change the encoding size/bitrate
                                       during a call without renegotiation
                                       (own encoder instance, swapped on the
                                       encoding thread, keyframe forced).
                                       Python side:
                                       VideoStream.set_encoder_size().
  54_v4l2_frame_rates.patch            2.17-only - V4L2 capture devices
                                       record the highest frame rate of
                                       each size they list (VIDIOC_ENUM_
                                       FRAMEINTERVALS, via libv4l2) instead
                                       of DEFAULT_FPS. Python side:
                                       Engine.get_video_device_formats().
  55_vid_port_grow_frame_buffer.patch  2.17-only - received video bigger
                                       than negotiated (720p from Blink
                                       for macOS on a level 3.0 call) was
                                       garbled: the renderer port's frame
                                       buffer kept its creation size while
                                       the converter followed the decoder,
                                       so sws_scale read past its end.
                                       vid_port grows the buffer on
                                       FMT_CHANGED and never converts a
                                       short one; vid_stream grows its
                                       decoding buffer too (1080p on a
                                       level 3.0 call). Applies after 53.
  56_vid_port_capture_exact_size.patch 2.17-only - 720p from the camera was
                                       a 4:3 picture stretched to 16:9:
                                       find_closest_fmt() only looks at
                                       the sizes of the matched pixel
                                       format (YUYV, up to 640x480 on UVC
                                       cameras that have 720p as MJPEG),
                                       so the converter scaled 640x480 up.
                                       vid_port opens the requested size
                                       in another format that has it and
                                       converts only the pixel format.
                                       Applies after 55.
  57_avf_capture_keep_aspect.patch     2.17-only - macOS: 720p from the
                                       camera was a 4:3 picture stretched
                                       to 16:9: the session ran at
                                       PresetHigh (4:3 on Continuity and
                                       4:3 cameras) and the output filled
                                       the requested size, and a camera
                                       without a 16:9 format was opened at
                                       its nearest size and stretched by
                                       vid_port's converter. avf_dev also
                                       lists 1920x1080 / 1280x720 / 640x480
                                       for every camera in every pixel
                                       format (built-in / Continuity
                                       cameras list only 420v/420f, which
                                       left them a lone 640x480 default)
                                       so vid_port opens the exact size,
                                       and sets an
                                       activeFormat of the requested shape
                                       (exact size, else the smallest
                                       larger), so the output only scales
                                       down, and sets it again with the
                                       device locked across startRunning
                                       (macOS reapplies the preset at start
                                       otherwise). The output uses
                                       AVVideoScalingModeResizeAspectFill,
                                       so a camera without a format of that
                                       shape is cropped, not stretched.
  58_v4l2_open_cloexec.patch           2.17-only - camera resolution
                                       changes failed with EBUSY after a
                                       child process (gsettings monitor)
                                       inherited the open camera and kept
                                       its buffers. v4l2_dev opens the
                                       devices close-on-exec.
                                       Applies after 32.
  59_tls_cert_logging.patch            rebase of 2.12's 02 (TLS hunks) +
                                       14 - logs local/remote cert
                                       subject, issuer, expiry and peer
                                       after each handshake, plus the
                                       SNI name a TLS client sends.
                                       Hooks ssl_update_certs_info(), so
                                       the verify callback doesn't log
                                       twice; %.*s instead of 14's
                                       write past slen.


Dropped permanently
-------------------
  10_ffmpeg_util.patch                 FFmpeg 5+ migration is upstreamed.
  17_fix_ffmpeg.patch                  Same.
  30_diag_log_stream_info_from_sdp     Diagnostic-only ("do NOT ship").
  pending/02_pjlib_darwin.patch        GCD semaphores are upstream now.
                                       Its ssl_sock_ossl.c TLS logging
                                       hunks live on as 59.
  pending/14_pjsip_tls_log_fix.patch   Folded into 59.
  31_zrtp_detach_race_null_deref.old   Was .old in 2.12 too.


Still TODO
----------

Tier 5+ (heavy):
  01_build_system.patch                Makefile / config_auto rebase
                                       against the 2.17 object list.
                                       The 2.17 build works without it
                                       (individual patches touch their
                                       own Makefile fragments) so this
                                       is cleanup, not a blocker.


Cython / sipsimple-side work pending
------------------------------------
Patch 08 added two C symbols that nothing in Python calls yet:

  * pjmedia_rtcp_build_rtcp_pli() - needs a cdef extern in
    _core.pxd plus a wrapper on whatever owns the RTCP session, so
    sipsimple can actually request keyframes from peers when its
    decoder loses sync.

  * pjmedia_snd_port_reset_ec_state() is now real (was a no-op stub)
    and, since 09_aec, deferred to the capture thread.  AudioMixer
    exposes it as reset_ec(); the new resync_ec() (patch 09) is what
    AudioStream uses on start and direction change.  AudioMixer passes
    PJMEDIA_ECHO_USE_NOISE_SUPPRESSOR | AGGRESSIVENESS_AGGRESSIVE as
    ec_options (_core.sound.pxi, _ec_options).


Rebase / verification order
---------------------------
Patches apply in numeric order.  No special sequencing is needed for
the currently-present set; just run:

    ./get_dependencies.sh --version 2.17

and every "Applying patch ..." line should be followed by zero
"FAILED" or "rejects" lines.  Hunks landing with offset / fuzz are
fine; rejections need a manual look.


Notes for future ports
----------------------
gpatch's offset-tracker carries across hunks within a single file
section.  If a hunk further down a patch silently misapplies after
an earlier hunk added a large block, split the second hunk into its
own  --- pjsip_orig/...  / +++ pjsip/...  section so the tracker
resets.  See patch 04 for the pattern.

Blank context lines in a unified diff must start with a single space.
Most editors (including the tooling that generated some of these
patches) strip trailing whitespace, which turns blank context lines
into bare newlines and corrupts the patch.  When in doubt, run:

    awk '/^@@/{h=1;print;next} /^(---|\+\+\+) /{h=0;print;next} \
         h && /^$/{print " ";next} {print}' patch.patch > patch.fixed
