diff --git a/app.go b/app.go
index 9a51c74..036413f 100644
--- a/app.go
+++ b/app.go
@@ -23,7 +23,7 @@ func (a *App) startup(ctx context.Context) {
a.station.Fail("could not open the audio device")
return
}
- go func() { _ = a.station.Run(runCtx) }()
+ go func() { _ = a.station.Run(runCtx) }() // Run returns when the window closes.
}
func (a *App) shutdown(context.Context) {
diff --git a/build/darwin/Info.plist b/build/darwin/Info.plist
index d17a747..b742140 100644
--- a/build/darwin/Info.plist
+++ b/build/darwin/Info.plist
@@ -23,6 +23,8 @@
true
NSHumanReadableCopyright
{{.Info.Copyright}}
+ NSMicrophoneUsageDescription
+ funknetz uses the microphone to answer the talk group.
{{if .Info.FileAssociations}}
CFBundleDocumentTypes
diff --git a/frontend/dist/app.js b/frontend/dist/app.js
index bf1bc26..daff955 100644
--- a/frontend/dist/app.js
+++ b/frontend/dist/app.js
@@ -84,15 +84,5 @@ window.addEventListener("keyup", function (event) {
}
});
-window.addEventListener("blur", function () {
- spaceHeld = false;
- const app = api();
- if (!app) {
- return;
- }
- app.ReleaseButton();
- app.ReleaseSpace();
-});
-
setInterval(refresh, 100);
refresh();
diff --git a/internal/opus/opus.go b/internal/opus/opus.go
index cbb33fb..038f1eb 100644
--- a/internal/opus/opus.go
+++ b/internal/opus/opus.go
@@ -26,6 +26,7 @@ import (
"unsafe"
)
+// FrameSamples is the 20 ms frame at 16 kHz, which is what the reflector carries.
const FrameSamples = 320
// Encoder produces one raw Opus packet per 20 ms frame.
diff --git a/main.go b/main.go
index 48a6256..0532571 100644
--- a/main.go
+++ b/main.go
@@ -1,5 +1,6 @@
//go:build !bindings
+// Command funknetz is the headset station window.
package main
import (
diff --git a/main_bindings.go b/main_bindings.go
index 0720908..bad281d 100644
--- a/main_bindings.go
+++ b/main_bindings.go
@@ -1,5 +1,6 @@
//go:build bindings
+// Command funknetz is the headset station window.
package main
import (
diff --git a/station/behavior_test.go b/station/behavior_test.go
index ff0ff3b..92c2f06 100644
--- a/station/behavior_test.go
+++ b/station/behavior_test.go
@@ -360,6 +360,32 @@ func TestRemoteAudioAndTalker(t *testing.T) {
}
}
+func TestPlaybackPausesWhenTransmitting(t *testing.T) {
+ in := login(t, "DL1ABC", "key", 20, 7, []string{"OPUS"})
+ enc, err := opus.NewEncoder()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer enc.Close()
+ pkt, err := enc.Encode(make([]int16, opus.FrameSamples))
+ if err != nil {
+ t.Fatal(err)
+ }
+ in.refl.writeUDP(t, 101, 7, 1, appendBytes(nil, pkt))
+ in.refl.writeUDP(t, 101, 7, 2, appendBytes(nil, pkt))
+ if _, err := in.st.WaitPlayback(t.Context(), 2*opus.FrameSamples-1); err != nil {
+ t.Fatal(err)
+ }
+ in.st.HoldButton()
+ in.refl.writeFrame(t, 105, appendStr(appendU32(nil, 20), "DB0XYZ"))
+ if _, err := in.st.Wait(t.Context(), func(s station.State) bool { return s.Transmitting }); err != nil {
+ t.Fatal(err)
+ }
+ if pcm := in.st.TakePlayback(); len(pcm) != 0 {
+ t.Fatalf("playback %d samples, want none while transmitting", len(pcm))
+ }
+}
+
func TestMicrophoneIsNotPlayed(t *testing.T) {
in := login(t, "DL1ABC", "key", 20, 7, []string{"OPUS"})
in.st.HoldButton()
diff --git a/station/session.go b/station/session.go
index dc8e457..763d2ac 100644
--- a/station/session.go
+++ b/station/session.go
@@ -163,12 +163,12 @@ func (s *Station) session(ctx context.Context, conn net.Conn) error {
case <-ctx.Done():
timer.Stop()
return ctx.Err()
- case <-tcpErr:
+ case err := <-tcpErr:
timer.Stop()
- return errors.New("tcp closed")
- case <-udpFail:
+ return err
+ case err := <-udpFail:
timer.Stop()
- return errors.New("udp closed")
+ return err
case tcpf = <-tcpCh:
timer.Stop()
reason = "tcp"
@@ -465,12 +465,14 @@ func (s *Station) endTransmit() {
copy(frame, s.mic)
s.mic = nil
if pkt, err := s.enc.Encode(frame); err == nil {
+ // A lost datagram ends the session when the receive timer expires.
_ = s.sendUDP(udpAudio, appendBlob(nil, pkt))
}
} else {
s.mic = nil
}
if s.udp != nil {
+ // A lost datagram ends the session when the receive timer expires.
_ = s.sendUDP(udpFlush, nil)
}
}
@@ -511,6 +513,7 @@ func (s *Station) publish() {
s.state.Transmitting = tx
if tx {
s.state.Talker = s.cfg.callsign
+ s.play = nil
} else {
s.state.Talker = s.remoteTalker
}
diff --git a/station/station.go b/station/station.go
index 64f2bcf..c9db2b5 100644
--- a/station/station.go
+++ b/station/station.go
@@ -151,6 +151,7 @@ func (s *Station) WriteMicrophone(pcm []int16) {
if err != nil {
continue
}
+ // A lost datagram ends the session when the receive timer expires.
_ = s.sendUDP(udpAudio, appendBlob(nil, pkt))
}
}
@@ -159,6 +160,10 @@ func (s *Station) WriteMicrophone(pcm []int16) {
func (s *Station) TakePlayback() []int16 {
s.mu.Lock()
defer s.mu.Unlock()
+ if s.transmitting() {
+ s.play = nil
+ return nil
+ }
out := s.play
s.play = nil
return out