Commit Graph

1102 Commits

Author SHA1 Message Date
isaac 2caf643db0 CustomImpl WIP 2026-05-02 12:04:33 +02:00
isaac c1baac8635 GroupInstanceReferenceImpl: remove handleActiveAudioSsrcs
ActiveAudioSsrcs was a test-SFU-only colibri message. With the test
SFU no longer sending it, the handler is dead code. Removing now
before introducing the new discovery path so we don't briefly have
two paths inserting into _remoteSsrcs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 10:57:58 +02:00
isaac 9c1b8f31c1 test sfu: remove ActiveAudioSsrcs broadcast
The test-only ActiveAudioSsrcs colibri message is being replaced by
ReferenceImpl's per-receiver FrameTransformer-based discovery (next
commits). Removing the message first forces every subsequent test
run to exercise the new code path — keeping the message in place
would let test passes mask production-real bugs.

T1/T2 currently FAIL as expected; T3-T5 likewise — the muted-peer
invariant cannot hold without working discovery. All restored by the
end of this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 10:47:29 +02:00
isaac 3160270a35 ReferenceImpl: real audio levels via per-receiver PCM sink
Replace GroupInstanceReferenceImpl's hardcoded 0.1 synthetic
audio level (reported for every known SSRC, regardless of whether
the participant was actually producing audio) with a real
peak-amplitude reading per remote receiver.

Implementation:
- New GRAudioLevelSink (webrtc::AudioTrackSinkInterface)
  attached to each remote audio track after onRenegotiationComplete
  via the new wireRemoteAudioLevelSinks(). Tracks per-window peak
  amplitude in PCM, normalized to RFC 6464's "0 dBov = full-scale
  sine wave" reference (peak / (32768/sqrt(2))) so the value is
  comparable to CustomImpl's pow(10, -dbov/20) reading.
- pollAudioLevels() now reads consumeLevel() from each sink and
  skips entries whose sink has produced no samples since the last
  poll, eliminating phantom level entries for known-but-silent
  SSRCs.
- buildRemoteAnswer() now includes the remote SSRC on each
  recvonly audio m-line. Without a signaled SSRC the
  AudioRtpReceiver calls SetDefaultRawAudioSink and only one of N
  transceivers' RemoteAudioSource ever receives PCM (the rest stay
  silent and our sinks never fire). MID is excluded from audio
  m-lines, so BUNDLE demuxes by SSRC.
- Result for a 3000-amplitude sine through Opus: ~0.126, matching
  CustomImpl's reading.

Test infrastructure (CLI):
- New --mute-participants <ids> flag (comma-separated participant
  IDs) keeps a participant muted after join.
- ParticipantState gains a per-source-SSRC max-level map.
- validateGroupState enforces: no peer may report a muted
  participant's SSRC at level >= 0.05. The relaxed audio-received
  check applies only to unmuted participants.

This is a pre-requisite for the upcoming SSRC-discovery work
(per-receiver level sinks must already exist before
onRenegotiationComplete starts wiring them up for tap-discovered
SSRCs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 10:44:21 +02:00
isaac 454718339e Merge commit 'aaa583f1a9aabb558c4a35085f7bdeeb54f28390' into development 2026-04-30 22:22:01 +02:00
isaac aaa583f1a9 feat: add testbench (CLI tool, Go SFU, Dockerfile, docs)
Brings the testbench source into the submodule:
- tools/cli/ — C++ CLI test tool (P2P, reflector, group, group-churn modes)
- tools/go_sfu/ — Go/Pion SFU library, c-archive linked into tgcalls_cli
- Dockerfile — multi-stage Linux container build
- CLAUDE.md (top-level), tools/cli/CLAUDE.md, tools/go_sfu/CLAUDE.md — docs

Bazel build glue (.bazelrc, MODULE.bazel, third-party BUILD edits, tgcalls_core
target) remains in the outer repo since the dependency stack lives there;
labels and paths in this repo reference the outer-repo workspace root.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 19:00:55 +02:00
isaac 1f119d8f32 min_bitrate_bps 2026-04-30 18:48:26 +02:00
isaac 43d03b0b82 Merge commit 'b0245de959b57ae6d000da0dd6d3c082a7c0c0be' into development 2026-04-30 14:48:55 +04:00
isaac a6ea40ebf1 Fix camera rotation 2026-04-21 13:38:59 +04:00
Isaac b0245de959 feat: add video support to group calls (CustomImpl + ReferenceImpl)
Enable H264 simulcast video in group calls for both GroupInstanceCustomImpl
and GroupInstanceReferenceImpl, with reactive channel setup mirroring the
real Telegram app's flow.

Infrastructure:
- DiscardPacketsWithUnknownSsrc field trial prevents outgoing video channel
  from stealing incoming RTP for unregistered SSRCs
- dataChannelMessageReceived callback on GroupInstanceDescriptor forwards
  Colibri messages (ActiveVideoSsrcs) to the application layer

ReferenceImpl video implementation:
- Pre-allocate 6 video SSRCs (3 layers x primary + RTX) at construction
- SDP munging: replace PeerConnection's auto-generated StreamParams with
  pre-allocated SSRCs + SIM + FID groups before SetLocalDescription
- Video source activated via sender()->SetTrack() (no renegotiation)
- Incoming video: recvonly transceivers with explicit remote SSRCs in answer
  (required because DiscardPacketsWithUnknownSsrc is process-wide)
- Video sinks wired explicitly after SetRemoteDescription (OnTrack doesn't
  fire for locally-created recvonly transceivers)
- Colibri ReceiverVideoConstraints sent over data channel to control SFU
  forwarding; SFU responds with SenderVideoConstraints + proactive PLI

Squashed from:
- feat: enable DiscardPacketsWithUnknownSsrc field trial for video group calls
- feat: add dataChannelMessageReceived callback to GroupInstanceDescriptor
- feat(group-ref): store video configuration from descriptor
- feat(group-ref): pre-allocate video SSRCs and include in join payload
- feat(group-ref): add video encoder/decoder factories to PeerConnectionFactory
- feat(group-ref): implement setVideoSource with SDP munging for simulcast SSRCs
- feat(group-ref): extend buildRemoteAnswer with video m-line construction
- feat(group-ref): forward data channel messages to app for video signaling
- feat(group-ref): implement setRequestedVideoChannels with Colibri constraints
- feat(group-ref): implement addIncomingVideoOutput with video sink wiring
- fix(group-ref): activate outgoing video after join response is applied
- feat(group-ref): add video support to GroupInstanceReferenceImpl
2026-04-15 20:10:17 +02:00
Isaac 08cd6d5bb5 feat: add GroupInstanceReferenceImpl — PeerConnection-based group calls
Alternative group call implementation using standard WebRTC PeerConnection
instead of the manual ICE/DTLS/SRTP management in GroupInstanceCustomImpl.
Implements the same GroupInstanceInterface (~1500 lines vs ~4700).

Uses a single PeerConnection to the SFU with:
- sendrecv audio transceiver (outgoing audio)
- recvonly audio transceivers added dynamically per remote SSRC
- data channel for Colibri protocol (ActiveAudioSsrcs discovery)
- Programmatic SDP construction via cricket::SessionDescription API

Key implementation details:
- Loopback ICE enabled (network_ignore_mask=0) for localhost SFU
- RTP header extensions copied from local offer per m-line (BUNDLE-safe)
- MID extension excluded from remote answer to prevent wrong-channel routing
- Renegotiation mirrors local offer mids exactly in constructed answer
- Synthetic audio levels (0.1) for known remote SSRCs
- Serialized renegotiation (one offer/answer at a time)

Squashed from:
- feat: add GroupInstanceReferenceImpl — PeerConnection-based group call client
- fix: add missing jsep_session_description.h include
- fix: enable loopback ICE and add remote candidates
- fix: add RTP header extensions to SDP answer
- fix: rewrite buildRemoteAnswer to mirror local offer mids for renegotiation
- fix: simplify audio level polling to use known remote SSRCs directly
2026-04-15 20:09:53 +02:00
Isaac eb2bd7d160 feat: add InstanceV2CompatImpl for cross-version interop (v14.0.0)
New implementation that uses WebRTC PeerConnection internally but speaks
V2Impl's signaling protocol (InitialSetupMessage, NegotiateChannelsMessage,
CandidatesMessage). Enables bidirectional calls between PeerConnection-based
clients and V2Impl clients (versions 7.0.0-13.0.0).

Architecture: PeerConnection <-> SignalingTranslator <-> EncryptedConnection
<-> SignalingSctpConnection

Key components:
- SignalingTranslator: converts between cricket::SessionDescription and V2Impl
  signaling messages using JsepSessionDescription programmatic API (no SDP
  string round-trips)
- Shared conversion functions extracted to Signaling.h/.cpp for use by both
  ContentNegotiationContext (V2Impl) and SignalingTranslator (CompatImpl)
- Data channel works for CompatImpl<->CompatImpl calls; padded as rejected
  when paired with V2Impl (which has no PeerConnection)

100% success rate at 30% loss in both call directions.

Squashed from:
- refactor: extract signaling content conversion functions to Signaling.h/.cpp
- feat: add SignalingTranslator for V2Impl signaling <-> PeerConnection conversion
- feat: add InstanceV2CompatImpl — PeerConnection with V2Impl signaling (version 14.0.0)
- feat: add data channel support to InstanceV2CompatImpl
2026-04-15 20:09:41 +02:00
Isaac 212a874da1 fix: use-after-free in InstanceV2ReferenceImpl::writeStateLogRecords()
writeStateLogRecords() captured a raw Call* pointer on the media thread
and posted it to the worker thread. If stop() called
_peerConnection->Close() (which destroys Call) between the post and
worker thread execution, the worker thread would dereference a dangling
pointer. WebRTC's call_ptr_ is Call* const and never nulled after Close(),
so the existing null check didn't catch this.

Fix: add _isStopped atomic flag, set before Close() in stop(), checked
in the worker thread lambda before accessing call.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 20:09:31 +02:00
Isaac 24fd51b749 feat: SCTP signaling improvements for reliable connection establishment
Add writable gate for role-based SCTP handshake ordering: caller
(isOutgoing=true) starts writable and sends INIT immediately; callee
starts not-writable and defers Connect() until first received packet
triggers setWritable(true).

Implement CustomDcSctpSocket to fix WebRTC's missing timer backoff cap
on t1_init and t1_cookie handshake timers. Without this, simultaneous-open
under packet loss causes 20+ second stalls due to unlimited exponential
backoff (1s, 2s, 4s, 8s...). With the fix: 400ms init, 750ms max backoff,
yielding ~18 attempts in 15s and 100% success at 30% loss.

Timer values are configurable via JSON custom parameters:
- network_sctp_t1_init_ms, network_sctp_t1_cookie_ms, network_sctp_max_backoff_ms

Squashed from:
- feat: add SCTP writable gate for role-based handshake ordering
- chore: whitespace cleanup in NativeNetworkingImpl
- fix: CustomDcSctpSocket with t1 timer backoff cap for signaling SCTP
2026-04-15 20:09:28 +02:00
Isaac 616810f153 build: add #include <cstdint> for GCC 15 compatibility 2026-04-15 20:09:18 +02:00
Isaac 8099768559 Merge commit '63ac02c987f3cecedfb299f4eec0b6cef0300faa' into development 2026-02-13 18:00:49 +04:00
Isaac 014653852e peer tag should be 16 bytes 2026-02-13 18:00:46 +04:00
Isaac e36b2c7e42 Use full ice mode 2026-02-13 18:00:34 +04:00
Mikhail Filimonov 63ac02c987 Merge branch 'development' of github.com:john-preston/tgcalls into development 2025-11-15 11:31:17 +04:00
Mikhail Filimonov de1f864a21 - isBroadcast for macos 2025-11-15 11:31:09 +04:00
Isaac 24876ebca7 Merge commit '81331889bf295647c6ba985d5f7d72faad047ad6' into development 2025-11-10 03:27:19 +08:00
dkaraush 81331889bf fix audio cracks on rtmp stream (appearing on android) 2025-11-08 09:45:04 +03:00
Isaac cbec8c2af5 Merge commit '24694f64b03e301ec2c90792566046e61a2c4967' into development 2025-11-05 22:36:56 +04:00
Isaac 452117d21f Add connectionMode 2025-11-05 22:36:49 +04:00
John Preston 24694f64b0 Fix build with Xcode. 2025-08-08 09:52:08 +04:00
John Preston d78b0507c5 Merge remote-tracking branch 'origin/development' into HEAD 2025-07-11 19:17:44 +04:00
Isaac 47d3534333 Support Xcode 26 2025-07-01 19:34:31 +02:00
Isaac a8accf0f90 darwin: cleanup ios-release-11.13 2025-06-28 23:46:51 +02:00
Isaac 5ddc3ccf20 Merge commit '70f4fada838d63d18e0722b58d64b8de399c260c' into development 2025-06-17 19:10:51 +04:00
Isaac 6dbfeded8a Update gitignore 2025-06-17 19:10:36 +04:00
Isaac a0a649e5b9 Catch invalid H264 frames after encryption 2025-06-17 19:10:06 +04:00
Isaac 5ba6d9b12d Group call audio level frame resampling if needed 2025-06-17 19:08:20 +04:00
Isaac 992d67db3b Cleanup old ffmpeg 2025-06-17 19:07:17 +04:00
Mikhail Filimonov 70f4fada83 attemp streaming fix 2025-06-04 11:34:56 +01:00
Fela c89f009c29 Add updated nalu size to header 2025-05-02 19:21:17 +04:00
Fela 211cad3bc2 Optimize nalu rewrite during encode 2025-05-02 19:09:42 +04:00
Fela 803b907981 Always encode long nalu start codes 2025-05-02 17:38:47 +04:00
Mikhail Filimonov b043bef2df macos audio fix 2025-04-18 15:20:32 +01:00
Isaac 1348de6aa6 Fix conference audio/video 2025-04-18 00:57:53 +04:00
Isaac 79d6b6612b Remove legacy 2025-04-17 23:55:59 +04:00
Isaac ea93dec2c8 Update audio level clipping 2025-04-16 00:07:12 +04:00
Isaac 6e2b9e10cc Merge commit 'ac6c0fa5c88903ff723a2110915018a76b200aa3' into development 2025-04-15 23:03:25 +04:00
Isaac 31eb5d2071 Update audio level 2025-04-15 23:02:46 +04:00
Mikhail Filimonov ac6c0fa5c8 - macos 2025-04-15 22:02:37 +03:00
Isaac e87034dbdd Update encryption API 2025-04-15 19:28:35 +04:00
Isaac 66b0eb006b Audio levels 2025-04-15 18:10:56 +04:00
Isaac 36161286bd Merge commit 'c215f9cef67d2737bcc4c82842f50b985064e5f9' into development 2025-04-14 21:14:27 +04:00
Isaac b082fee3d8 Guard against unusual NAL ordering 2025-04-14 21:13:54 +04:00
Mikhail Filimonov c215f9cef6 macos bump 2025-04-13 22:48:05 +03:00
Mikhail Filimonov 7f04d5360f macos update 2025-04-04 19:22:51 +04:00