feat(tci): name the transmit audio source when keying, per the protocol
The specification settles what a night of experiments could only guess at. TRX takes an optional THIRD argument naming the signal source — tci, mic1, mic2, micPC, ecoder2 — and TCI 2.0 says it plainly: 'The signal for transmitting is always taken from the microphone selected in the ExpertSDR3. If a third-party software connected via TCI wants to transmit its audio signal, you must specify the third argument - TCI.' Without it the radio sends no chrono at all, whatever the mode. That is what the SSB attempts ran into, and what was misread here as 'digital modes only' — the mode was never the rule, the missing argument was. So OpsLog says it, following the 'To radio' device: 'tci' when the voice keyer owns the transmission, nothing at all otherwise, which leaves the operator's own microphone alone for every other PTT. Nobody has to find that setting in ExpertSDR3 and set it again for every mode, which is how it is remembered there. Two more things from the same document. A chrono with no audio ready is now answered with silence rather than left unanswered — the vendor calls that preferable. And the receive stream declares float32 and two channels instead of trusting the defaults: they are the documented defaults, but a default is something another program sharing this radio can have changed, and a stream in an unexpected format is heard as noise rather than as a mistake.
This commit is contained in:
@@ -45,6 +45,31 @@ func (a *App) tciTXPlayer(pcm []byte, rate, ch, bits int, stop <-chan struct{})
|
||||
return player.PlayTXAudio(pcm, rate, ch, bits, stop)
|
||||
}
|
||||
|
||||
// applyTCITXSource tells the radio where to take its transmit audio from,
|
||||
// following the "To radio" device.
|
||||
//
|
||||
// This is the setting an operator would otherwise have to find in ExpertSDR3
|
||||
// and set again for every mode, because it is remembered per mode there. It is
|
||||
// the third argument of TRX, so OpsLog can simply say it each time it keys —
|
||||
// and a radio told nothing keeps the operator's microphone, which is what
|
||||
// every PTT that is not a voice message should do.
|
||||
func (a *App) applyTCITXSource() {
|
||||
if a.cat == nil {
|
||||
return
|
||||
}
|
||||
cfg, _ := a.GetAudioSettings()
|
||||
src := ""
|
||||
if cfg.ToRadio == audio.NetworkDeviceID {
|
||||
src = "tci"
|
||||
}
|
||||
_ = a.cat.TCIAudioDo(func(t cat.TCIAudioController) error {
|
||||
if s, ok := t.(interface{ SetTXAudioSource(string) }); ok {
|
||||
s.SetTXAudioSource(src)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// installTCITXPlayer offers the radio as an audio output, or withdraws it.
|
||||
//
|
||||
// Withdrawing matters as much as offering: a radio that has gone away must stop
|
||||
@@ -56,5 +81,6 @@ func (a *App) installTCITXPlayer(on bool) {
|
||||
return
|
||||
}
|
||||
audio.SetNetworkPlayer(a.tciTXPlayer)
|
||||
a.applyTCITXSource()
|
||||
applog.Printf("tci: the radio is available as an audio output — no virtual cable needed for the voice keyer")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user