Synchronize connection-owned stream access
This commit is contained in:
committed by
Brandon McGinty
parent
f0aa5ff35a
commit
e9ba7f580a
+17
-9
@@ -97,6 +97,14 @@ type Barnard struct {
|
||||
// reconnect replaces them. It is intentionally idempotent for repeated
|
||||
// disconnect notifications.
|
||||
func (b *Barnard) cleanupConnectionAudio() {
|
||||
// Connection audio operations that use both resources take FileStreamMutex
|
||||
// before connectionMutex, so cleanup follows that order as well.
|
||||
b.FileStreamMutex.Lock()
|
||||
if b.FileStream != nil {
|
||||
_ = b.FileStream.Stop()
|
||||
b.FileStream = nil
|
||||
}
|
||||
b.FileStreamMutex.Unlock()
|
||||
b.connectionMutex.Lock()
|
||||
if b.Stream != nil {
|
||||
stream := b.Stream
|
||||
@@ -104,12 +112,6 @@ func (b *Barnard) cleanupConnectionAudio() {
|
||||
stream.Destroy()
|
||||
}
|
||||
b.connectionMutex.Unlock()
|
||||
b.FileStreamMutex.Lock()
|
||||
if b.FileStream != nil {
|
||||
_ = b.FileStream.Stop()
|
||||
b.FileStream = nil
|
||||
}
|
||||
b.FileStreamMutex.Unlock()
|
||||
}
|
||||
|
||||
func (b *Barnard) cleanupToneTestAudio() {
|
||||
@@ -266,9 +268,13 @@ func (b *Barnard) TreeItemKeyPress(ui *uiterm.Ui, tree *uiterm.Tree, item uiterm
|
||||
for _, u := range users {
|
||||
// Explicitly set user mute state to match channel state
|
||||
if channelWillBeMuted && !u.LocallyMuted() {
|
||||
b.UserConfig.ToggleMute(u)
|
||||
if err := b.UserConfig.ToggleMute(u); err != nil {
|
||||
b.AddOutputLine("Mute: could not save setting: " + err.Error())
|
||||
}
|
||||
} else if !channelWillBeMuted && u.LocallyMuted() {
|
||||
b.UserConfig.ToggleMute(u)
|
||||
if err := b.UserConfig.ToggleMute(u); err != nil {
|
||||
b.AddOutputLine("Mute: could not save setting: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
b.updateUserGain(u)
|
||||
@@ -297,7 +303,9 @@ func (b *Barnard) TreeItemKeyPress(ui *uiterm.Ui, tree *uiterm.Tree, item uiterm
|
||||
if treeItem.User != nil {
|
||||
if key == *b.Hotkeys.MuteToggle {
|
||||
// Toggle mute for single user
|
||||
b.UserConfig.ToggleMute(treeItem.User)
|
||||
if err := b.UserConfig.ToggleMute(treeItem.User); err != nil {
|
||||
b.AddOutputLine("Mute: could not save setting: " + err.Error())
|
||||
}
|
||||
b.updateUserGain(treeItem.User)
|
||||
b.RebuildUserChannelTreePreservingSelection()
|
||||
b.Ui.Refresh()
|
||||
|
||||
@@ -47,7 +47,7 @@ func (b *Barnard) exitWithError(err error) {
|
||||
|
||||
func (b *Barnard) connect(reconnect bool) bool {
|
||||
var err error
|
||||
_, err = gumble.DialWithDialer(new(net.Dialer), b.Config, &b.TLSConfig)
|
||||
_, err = gumble.DialWithDialer(&net.Dialer{Timeout: 15 * time.Second}, b.Config, &b.TLSConfig)
|
||||
if err != nil {
|
||||
if reconnect {
|
||||
b.Log(err.Error())
|
||||
@@ -295,11 +295,11 @@ func (b *Barnard) OnUserChange(e *gumble.UserChangeEvent) {
|
||||
if b.isChannelMuted(e.User.Channel.ID) {
|
||||
// Only mute if not already muted
|
||||
if !e.User.LocallyMuted() {
|
||||
b.UserConfig.ToggleMute(e.User)
|
||||
if err := b.UserConfig.ToggleMute(e.User); err != nil {
|
||||
b.AddOutputLine("Mute: could not save setting: " + err.Error())
|
||||
}
|
||||
if b.Stream != nil {
|
||||
b.Stream.UpdateUserGain(e.User)
|
||||
}
|
||||
b.updateUserGain(e.User)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-1
@@ -116,10 +116,28 @@ func DialWithDialer(dialer *net.Dialer, config *Config, tlsConfig *tls.Config) (
|
||||
}
|
||||
start := time.Now()
|
||||
|
||||
conn, err := tls.DialWithDialer(dialer, "tcp", config.Address, tlsConfig)
|
||||
rawConn, err := dialer.Dial("tcp", config.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn := tls.Client(rawConn, tlsConfig)
|
||||
// net.Dialer.Timeout covers only the TCP dial. Apply the same bounded
|
||||
// deadline to TLS negotiation so a peer that accepts but never responds
|
||||
// cannot block startup indefinitely.
|
||||
if dialer.Timeout > 0 {
|
||||
if err := conn.SetDeadline(start.Add(dialer.Timeout)); err != nil {
|
||||
rawConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := conn.Handshake(); err != nil {
|
||||
rawConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := conn.SetDeadline(time.Time{}); err != nil {
|
||||
rawConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
Conn: NewConn(conn),
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.stormux.org/storm/barnard/gumble/gumble"
|
||||
"git.stormux.org/storm/barnard/gumble/gumbleopenal"
|
||||
"git.stormux.org/storm/barnard/recording"
|
||||
"git.stormux.org/storm/barnard/uiterm"
|
||||
)
|
||||
@@ -179,10 +180,10 @@ func (b *Barnard) finishRecordingStart() {
|
||||
}
|
||||
b.Recorder = recorder
|
||||
b.recordingStarting = false
|
||||
// Recorder operations take RecordingMutex before connectionMutex. This
|
||||
// prevents disconnect cleanup from destroying a stream during attachment.
|
||||
b.withStream(func(stream *gumbleopenal.Stream) { stream.SetRecorder(recorder) })
|
||||
b.RecordingMutex.Unlock()
|
||||
if b.Stream != nil {
|
||||
b.Stream.SetRecorder(recorder)
|
||||
}
|
||||
b.AddOutputLine(fmt.Sprintf("Recording started: %s", recorder.Path()))
|
||||
b.Notify("recordstart", "me", recorder.Path())
|
||||
b.renderGeneralStatus()
|
||||
@@ -205,9 +206,7 @@ func (b *Barnard) detachRecorder() (*recording.Recorder, string, bool) {
|
||||
}
|
||||
b.Recorder = nil
|
||||
b.recordingStarting = false
|
||||
if b.Stream != nil {
|
||||
b.Stream.SetRecorder(nil)
|
||||
}
|
||||
b.withStream(func(stream *gumbleopenal.Stream) { stream.SetRecorder(nil) })
|
||||
return recorder, path, wasPending
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,9 @@ func (b *Barnard) OnTimestampToggle(ui *uiterm.Ui, key uiterm.Key) {
|
||||
|
||||
func (b *Barnard) OnNoiseSuppressionToggle(ui *uiterm.Ui, key uiterm.Key) {
|
||||
enabled := !b.UserConfig.GetNoiseSuppressionEnabled()
|
||||
b.UserConfig.SetNoiseSuppressionEnabled(enabled)
|
||||
if err := b.UserConfig.SetNoiseSuppressionEnabled(enabled); err != nil {
|
||||
b.AddOutputLine("Noise suppression: could not save setting: " + err.Error())
|
||||
}
|
||||
b.NoiseSuppressor.SetEnabled(enabled)
|
||||
|
||||
if enabled {
|
||||
@@ -198,7 +200,9 @@ func (b *Barnard) CommandMicDown(ui *uiterm.Ui, cmd string) {
|
||||
|
||||
func (b *Barnard) CommandNoiseSuppressionToggle(ui *uiterm.Ui, cmd string) {
|
||||
enabled := !b.UserConfig.GetNoiseSuppressionEnabled()
|
||||
b.UserConfig.SetNoiseSuppressionEnabled(enabled)
|
||||
if err := b.UserConfig.SetNoiseSuppressionEnabled(enabled); err != nil {
|
||||
b.AddOutputLine("Noise suppression: could not save setting: " + err.Error())
|
||||
}
|
||||
b.NoiseSuppressor.SetEnabled(enabled)
|
||||
|
||||
if enabled {
|
||||
@@ -266,11 +270,18 @@ func (b *Barnard) CommandPlayFile(ui *uiterm.Ui, cmd string) {
|
||||
// Enable stereo encoder for file playback
|
||||
b.Client.EnableStereoEncoder()
|
||||
|
||||
// Auto-start transmission if not already transmitting
|
||||
if !b.isTransmitting() && b.Stream != nil {
|
||||
err := b.Stream.StartSource(b.UserConfig.GetInputDevice())
|
||||
if err != nil {
|
||||
b.AddOutputLine(fmt.Sprintf("Error starting transmission: %s", err.Error()))
|
||||
// Auto-start transmission if not already transmitting. FileStreamMutex is
|
||||
// held here, before withStream's connection mutex, matching cleanup.
|
||||
if !b.isTransmitting() {
|
||||
var startErr error
|
||||
started := b.withStream(func(stream *gumbleopenal.Stream) {
|
||||
startErr = stream.StartSource(b.UserConfig.GetInputDevice())
|
||||
})
|
||||
if !started {
|
||||
startErr = errors.New("audio unavailable while reconnecting")
|
||||
}
|
||||
if startErr != nil {
|
||||
b.AddOutputLine(fmt.Sprintf("Error starting transmission: %s", startErr))
|
||||
b.FileStream.Stop()
|
||||
b.Client.DisableStereoEncoder()
|
||||
return
|
||||
@@ -327,8 +338,8 @@ func (b *Barnard) setTransmit(ui *uiterm.Ui, val int) {
|
||||
close(b.toneTestStop)
|
||||
b.toneTestStop = nil
|
||||
}
|
||||
} else if b.Stream != nil {
|
||||
b.Stream.StopSource()
|
||||
} else {
|
||||
b.withStream(func(stream *gumbleopenal.Stream) { _ = stream.StopSource() })
|
||||
}
|
||||
} else if !b.isConnected() {
|
||||
b.Notify("error", "me", "no tx while disconnected")
|
||||
@@ -347,7 +358,8 @@ func (b *Barnard) setTransmit(ui *uiterm.Ui, val int) {
|
||||
b.Notify("micup", "me", "")
|
||||
b.UpdateGeneralStatus(" Tx ", true)
|
||||
} else {
|
||||
err := b.Stream.StartSource(b.UserConfig.GetInputDevice())
|
||||
started := b.withStream(func(stream *gumbleopenal.Stream) {
|
||||
err := stream.StartSource(b.UserConfig.GetInputDevice())
|
||||
if err != nil {
|
||||
b.setTransmitting(false)
|
||||
if fatalAudioOpenError(err) {
|
||||
@@ -358,9 +370,14 @@ func (b *Barnard) setTransmit(ui *uiterm.Ui, val int) {
|
||||
}
|
||||
b.Notify("error", "me", err.Error())
|
||||
b.UpdateGeneralStatus(err.Error(), true)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
b.Notify("micup", "me", "")
|
||||
b.UpdateGeneralStatus(" Tx ", true)
|
||||
})
|
||||
if !started {
|
||||
b.setTransmitting(false)
|
||||
b.UpdateGeneralStatus("audio unavailable while reconnecting", true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -371,25 +388,29 @@ func fatalAudioOpenError(err error) bool {
|
||||
}
|
||||
|
||||
func (b *Barnard) OnMicVolumeDown(ui *uiterm.Ui, key uiterm.Key) {
|
||||
if b.ToneTest || b.Stream == nil {
|
||||
if b.ToneTest {
|
||||
return
|
||||
}
|
||||
b.Stream.SetMicVolume(-0.1, true)
|
||||
b.UserConfig.SetMicVolume(b.Stream.GetMicVolume())
|
||||
b.withStream(func(stream *gumbleopenal.Stream) {
|
||||
stream.SetMicVolume(-0.1, true)
|
||||
b.UserConfig.SetMicVolume(stream.GetMicVolume())
|
||||
if err := b.UserConfig.SaveConfig(); err != nil {
|
||||
b.AddOutputLine("Microphone: could not save volume: " + err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b *Barnard) OnMicVolumeUp(ui *uiterm.Ui, key uiterm.Key) {
|
||||
if b.ToneTest || b.Stream == nil {
|
||||
if b.ToneTest {
|
||||
return
|
||||
}
|
||||
b.Stream.SetMicVolume(0.1, true)
|
||||
b.UserConfig.SetMicVolume(b.Stream.GetMicVolume())
|
||||
b.withStream(func(stream *gumbleopenal.Stream) {
|
||||
stream.SetMicVolume(0.1, true)
|
||||
b.UserConfig.SetMicVolume(stream.GetMicVolume())
|
||||
if err := b.UserConfig.SaveConfig(); err != nil {
|
||||
b.AddOutputLine("Microphone: could not save volume: " + err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b *Barnard) OnQuitPress(ui *uiterm.Ui, key uiterm.Key) {
|
||||
|
||||
+13
-10
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"git.stormux.org/storm/barnard/gumble/gumble"
|
||||
"git.stormux.org/storm/barnard/gumble/gumbleopenal"
|
||||
"git.stormux.org/storm/barnard/uiterm"
|
||||
"sort"
|
||||
)
|
||||
@@ -37,10 +38,8 @@ func (ti TreeItem) TreeItemStyle(fg, bg uiterm.Attribute, active bool) (uiterm.A
|
||||
}
|
||||
|
||||
func (b *Barnard) changeVolume(users []*gumble.User, change float32) {
|
||||
b.withStream(func(stream *gumbleopenal.Stream) {
|
||||
for _, u := range users {
|
||||
if b.Stream == nil {
|
||||
continue
|
||||
}
|
||||
var boost uint16
|
||||
var ng float32
|
||||
curboost := float32((u.Boost() - 1)) / 10
|
||||
@@ -57,24 +56,28 @@ func (b *Barnard) changeVolume(users []*gumble.User, change float32) {
|
||||
}
|
||||
u.SetBoost(boost)
|
||||
u.SetVolume(ng)
|
||||
b.Stream.UpdateUserGain(u)
|
||||
stream.UpdateUserGain(u)
|
||||
b.UserConfig.UpdateConfig(u)
|
||||
}
|
||||
b.UserConfig.SaveConfig()
|
||||
if err := b.UserConfig.SaveConfig(); err != nil {
|
||||
b.AddOutputLine("Volume: could not save setting: " + err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b *Barnard) resetVolume(users []*gumble.User) {
|
||||
b.withStream(func(stream *gumbleopenal.Stream) {
|
||||
for _, u := range users {
|
||||
if b.Stream == nil {
|
||||
continue
|
||||
}
|
||||
// Reset to original volume (1.0) and boost (1)
|
||||
u.SetBoost(uint16(1))
|
||||
u.SetVolume(1.0)
|
||||
b.Stream.UpdateUserGain(u)
|
||||
stream.UpdateUserGain(u)
|
||||
b.UserConfig.UpdateConfig(u)
|
||||
}
|
||||
b.UserConfig.SaveConfig()
|
||||
if err := b.UserConfig.SaveConfig(); err != nil {
|
||||
b.AddOutputLine("Volume: could not save setting: " + err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func makeUsersArray(users gumble.Users) []*gumble.User {
|
||||
|
||||
Reference in New Issue
Block a user