# freeswitch-0001 — mod_conference.c: relationship list scan inside per-sample audio mixing (O(M²·R·S)) **Severity:** CRITICAL **File:** `src/mod/applications/mod_conference/mod_conference.c` **Lines:** 617-673 (audio mixing loop) ## Pattern ```c // Outer: for each output member for (omember = conference->members; omember; omember = omember->next) { // Middle: for each audio sample for (x = 0; x < bytes / 2; x++) { ... if (conference->relationship_total) { // Inner: for each input member for (imember = conference->members; imember; imember = imember->next) { // Innermost: linear scan of singly-linked relationship list for (rel = imember->relationships; rel; rel = rel->next) { if (rel->id == omember->id || rel->id == 0) { ... break; } } if (!found) { for (rel = omember->relationships; rel; rel = rel->next) { if (rel->id == imember->id || rel->id == 0) { ... break; } } } } } } } ``` `conference_relationship_t` is a singly-linked list (mod_conference.h:770-774). The innermost relationship scan is O(R) per (omember, imember, sample) triple. ## Complexity O(S × M × M × R) per mix cycle where: - S = samples per frame (typically 160 at 8kHz/20ms) - M = member count - R = relationships per member At M=20 members, S=160, R=5 relationships: 20×20×160×5 = **3,200,000 ops per mix cycle** (50Hz). = **160M ops/sec** just for relationship scanning, all inside a mutex-held loop. ## Root Cause The relationship check is nested inside the per-sample loop. The relationship result (can A hear B?) does not change per-sample — it only changes on relationship updates. ## Fix **Pre-compute relationship matrix outside the sample loop:** Before `for (x = 0; x < bytes/2; x++)`, build a boolean matrix or set: ```c // Per mixing frame (outside sample loop): // For each (omember, imember) pair, check relationships once → store in a bitmask // Then the per-sample loop just does: if (exclude_matrix[omember_idx][imember_idx]) z -= rptr[x]; ``` Alternative: use `switch_core_hash` keyed by `(omember->id << 32) | imember->id` for O(1) lookup, pre-computed at frame start, invalidated only on `conference_member_add_relationship()`. ## Speedup (estimated) Relationship check moves from O(R) inside O(S×M²) to O(1) table lookup: **~500× at M=20, R=5**. Full fix moves relationship resolution entirely outside the sample loop: O(S×M²) → O(M²+S×M).