fix(icom): only forward-moving audio packets reach the sink
Every audio packet was delivered as if it were the next 20 ms, duplicates and late retransmits included. The monitor's capped ring quietly threw the surplus away, so the speakers sounded fine — but the recorder keeps every sample it is given, and the file came out longer than the QSO, slowed and stuttering, each lost-then-resent packet heard twice. trackRxSeq now says whether a packet advances the stream, and only those are handed on.
This commit is contained in:
@@ -134,12 +134,19 @@ func (a *icomAudio) audioPump() {
|
||||
case typ == 0x05: // rig-initiated disconnect
|
||||
debugLog.Printf("icom audio: rig sent DISCONNECT — audio stream dropped by the rig")
|
||||
case typ == 0x00 && k > icaAudioOffset: // audio data packet
|
||||
a.trackRxSeq(icnLE.Uint16(buf[6:]))
|
||||
fresh := a.trackRxSeq(icnLE.Uint16(buf[6:]))
|
||||
if a.dumped < icaDumpFirst {
|
||||
a.dumped++
|
||||
debugLog.Printf("icom audio raw #%d: len=%d head=% X", a.dumped, k, buf[:min(icaAudioOffset+8, k)])
|
||||
}
|
||||
if a.sink != nil {
|
||||
// Only a packet that ADVANCES the sequence reaches the sink. A
|
||||
// duplicate or a late retransmit used to be delivered as if it
|
||||
// were the next 20 ms of audio: the monitor's capped ring threw
|
||||
// the surplus away (the speakers stayed clean), but the recorder
|
||||
// keeps every sample it is given — the file grew longer than the
|
||||
// QSO and played back slowed and stuttering, each lost-then-
|
||||
// resent packet heard twice.
|
||||
if fresh && a.sink != nil {
|
||||
payload := append([]byte(nil), buf[icaAudioOffset:k]...)
|
||||
a.sink(payload)
|
||||
}
|
||||
@@ -159,26 +166,36 @@ func (a *icomAudio) audioPump() {
|
||||
// trackRxSeq / sendRetransmitReq mirror icomNet's receive-side retransmit exactly
|
||||
// (audio is as loss-sensitive as the scope stream). Duplicated deliberately so
|
||||
// the audio stream owns its own seq state with no shared locking.
|
||||
func (a *icomAudio) trackRxSeq(seq uint16) {
|
||||
//
|
||||
// The return value says whether this packet moves the stream FORWARD — the
|
||||
// only kind the sink may hear. A duplicate is the same 20 ms again; a late
|
||||
// retransmit would play old audio in the middle of new. Both are accounted
|
||||
// for here and dropped by the caller.
|
||||
func (a *icomAudio) trackRxSeq(seq uint16) bool {
|
||||
if !a.rxHaveSeq {
|
||||
a.rxHaveSeq = true
|
||||
a.rxLastSeq = seq
|
||||
return
|
||||
return true
|
||||
}
|
||||
switch d := int16(seq - a.rxLastSeq); {
|
||||
case d == 0:
|
||||
return false
|
||||
case d < 0:
|
||||
delete(a.rxMissing, seq)
|
||||
return false
|
||||
case d == 1:
|
||||
a.rxLastSeq = seq
|
||||
return true
|
||||
case int(d) <= icnMaxMissing:
|
||||
for f := a.rxLastSeq + 1; f != seq; f++ {
|
||||
a.rxMissing[f] = 0
|
||||
}
|
||||
a.rxLastSeq = seq
|
||||
return true
|
||||
default:
|
||||
a.rxMissing = make(map[uint16]int)
|
||||
a.rxLastSeq = seq
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user