jamulussoftware / jamulussoftware/jamulus

Reused channel slot records the previous occupant's audio

オープン 初心者向け
#3,901 コメント 3 件 リアクション 1 件 担当者 0 名 GitHub で見る
AI bug
主要言語
C
スター
1.1k
フォーク
248
平均マージ
2日 3時間
マージ済み PR(30日)
9

説明

**🤖 AI:** A channel slot reused by a new client can have the *previous* occupant's audio attributed to it. On an `-R` server the stale frame lands in the new client's own recording, at full amplitude.

**Root cause.** Between disconnect and the new occupant negotiating transport properties a channel sits at `CT_NONE`, so [decoder selection](https://github.com/jamulussoftware/jamulus/blob/5146a072ee15425564b0d7845cd7616a24a271b1/src/server.cpp#L894-L897) leaves `CurOpusDecoder` null. In that window nothing writes the channel's decode buffer: [the OPUS decode](https://github.com/jamulussoftware/jamulus/blob/5146a072ee15425564b0d7845cd7616a24a271b1/src/server.cpp#L981-L992) is skipped for want of a decoder, and `bIsRawAudio` is false because `iCeltNumCodedBytes` has been reset to `CELT_MINIMUM_NUM_BYTES`. `vecvecsData` is indexed by position in the active-channel list rather than by channel ID, so it still holds the previous occupant's decoded audio — which is then [passed to the recorder](https://github.com/jamulussoftware/jamulus/blob/5146a072ee15425564b0d7845cd7616a24a271b1/src/server.cpp#L754-L758) and read by the mix.

**Reproduced 3 of 3 on `5146a072`.** Client A sends a 440 Hz tone and disconnects; after a gap client B takes the freed slot and sends only silence. B's own pre-identification recording is exactly 128 samples of A's tone — one OPUS frame, `DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES` — at 440 Hz energy fraction 0.999 or above. A's own stub is silent in the same runs, so this is not a recorder artifact. Reconnect gaps of 100, 250 and 500 ms all reproduce it.

**Scope: recordings.** `vecvecsData` also feeds [the mix](https://github.com/jamulussoftware/jamulus/blob/5146a072ee15425564b0d7845cd7616a24a271b1/src/server.cpp#L1099), so the same stale samples are a candidate for the live path — but they do not survive there audibly. On a server run without `-R`, what a passive listener receives is statistically unchanged by the fix below: the residual artifact at slot handover measures about 59 dB under the source (peak sample 29 of 32767) both with it and without.

**Fix** — contribute silence in the no-decoder branch:

```cpp
else
{
CurOpusDecoder = nullptr;

// CT_NONE: nothing else writes this buffer, and it is indexed by position in
// the active-channel list, so it still holds the previous occupant's audio
memset ( &vecvecsData[iChanCnt][0], 0, vecvecsData[iChanCnt].Size() * sizeof ( int16_t ) );
}
```

With that applied, B's stub reads 0.0 in 3 of 3 runs and A's own tone still records normally.

One subtlety: zero the whole worst-case buffer rather than `iClientFrameSizeSamples` worth. [That variable is still zero](https://github.com/jamulussoftware/jamulus/blob/5146a072ee15425564b0d7845cd7616a24a271b1/src/server.cpp#L837) in this branch, since it is only set in the `CT_OPUS` and `CT_OPUS64` arms, so a `memset` scaled by it writes no bytes at all.

---

🤖 *This message was written by AI and reviewed by @mcfnord.*

コントリビューションガイド

コントリビューションガイドを開く

調査の方向性

src/server.cpp の参照されている行にあるデコーダー選択分岐から始め、続いて vecvecsData が recorder に渡される方法を追跡します。録音を有効にして client A/client B のハンドオーバーを再現し、新しいクライアントの識別前フレームが無音であり、元のトーンは引き続き正常に録音されることを確認します。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
cpp
領域
audio-video-rtc
issue の種類
バグ
難易度
2/5
見積もり時間
1〜3時間
活発さ
活発
明瞭さ
明確に書かれている
初心者へのやさしさ
82/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。