Skip to content

Commit 575abb7

Browse files
committed
[WIP] Updates: audio input support
1 parent 09ac8c5 commit 575abb7

23 files changed

+2941
-225
lines changed

cloud.go

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -447,35 +447,76 @@ func handleSessionRequest(
447447
}
448448
}
449449

450-
session, err := newSession(SessionConfig{
451-
ws: c,
452-
IsCloud: isCloudConnection,
453-
LocalIP: req.IP,
454-
ICEServers: req.ICEServers,
455-
Logger: scopedLogger,
456-
})
457-
if err != nil {
458-
_ = wsjson.Write(context.Background(), c, gin.H{"error": err})
459-
return err
460-
}
450+
var session *Session
451+
var err error
452+
var sd string
461453

462-
sd, err := session.ExchangeOffer(req.Sd)
463-
if err != nil {
464-
_ = wsjson.Write(context.Background(), c, gin.H{"error": err})
465-
return err
466-
}
454+
// Check if we have an existing session and handle renegotiation
467455
if currentSession != nil {
468-
writeJSONRPCEvent("otherSessionConnected", nil, currentSession)
469-
peerConn := currentSession.peerConnection
470-
go func() {
471-
time.Sleep(1 * time.Second)
472-
_ = peerConn.Close()
473-
}()
456+
scopedLogger.Info().Msg("handling renegotiation for existing session")
457+
458+
// Handle renegotiation with existing session
459+
sd, err = currentSession.ExchangeOffer(req.Sd)
460+
if err != nil {
461+
scopedLogger.Warn().Err(err).Msg("renegotiation failed, creating new session")
462+
// If renegotiation fails, fall back to creating a new session
463+
session, err = newSession(SessionConfig{
464+
ws: c,
465+
IsCloud: isCloudConnection,
466+
LocalIP: req.IP,
467+
ICEServers: req.ICEServers,
468+
Logger: scopedLogger,
469+
})
470+
if err != nil {
471+
_ = wsjson.Write(context.Background(), c, gin.H{"error": err})
472+
return err
473+
}
474+
475+
sd, err = session.ExchangeOffer(req.Sd)
476+
if err != nil {
477+
_ = wsjson.Write(context.Background(), c, gin.H{"error": err})
478+
return err
479+
}
480+
481+
// Close the old session
482+
writeJSONRPCEvent("otherSessionConnected", nil, currentSession)
483+
peerConn := currentSession.peerConnection
484+
go func() {
485+
time.Sleep(1 * time.Second)
486+
_ = peerConn.Close()
487+
}()
488+
489+
currentSession = session
490+
cloudLogger.Info().Interface("session", session).Msg("new session created after renegotiation failure")
491+
} else {
492+
scopedLogger.Info().Msg("renegotiation successful")
493+
}
494+
} else {
495+
// No existing session, create a new one
496+
scopedLogger.Info().Msg("creating new session")
497+
session, err = newSession(SessionConfig{
498+
ws: c,
499+
IsCloud: isCloudConnection,
500+
LocalIP: req.IP,
501+
ICEServers: req.ICEServers,
502+
Logger: scopedLogger,
503+
})
504+
if err != nil {
505+
_ = wsjson.Write(context.Background(), c, gin.H{"error": err})
506+
return err
507+
}
508+
509+
sd, err = session.ExchangeOffer(req.Sd)
510+
if err != nil {
511+
_ = wsjson.Write(context.Background(), c, gin.H{"error": err})
512+
return err
513+
}
514+
515+
currentSession = session
516+
cloudLogger.Info().Interface("session", session).Msg("new session accepted")
517+
cloudLogger.Trace().Interface("session", session).Msg("new session accepted")
474518
}
475519

476-
cloudLogger.Info().Interface("session", session).Msg("new session accepted")
477-
cloudLogger.Trace().Interface("session", session).Msg("new session accepted")
478-
currentSession = session
479520
_ = wsjson.Write(context.Background(), c, gin.H{"type": "answer", "data": sd})
480521
return nil
481522
}

internal/audio/api.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package audio
22

33
// StartAudioStreaming launches the in-process audio stream and delivers Opus frames to the provided callback.
4+
// This is now a wrapper around the non-blocking audio implementation for backward compatibility.
45
func StartAudioStreaming(send func([]byte)) error {
5-
return StartCGOAudioStream(send)
6+
return StartNonBlockingAudioStreaming(send)
67
}
78

89
// StopAudioStreaming stops the in-process audio stream.
10+
// This is now a wrapper around the non-blocking audio implementation for backward compatibility.
911
func StopAudioStreaming() {
10-
StopCGOAudioStream()
12+
StopNonBlockingAudioStreaming()
1113
}

internal/audio/audio.go

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package audio
22

33
import (
4+
"errors"
45
"sync/atomic"
56
"time"
67
// Explicit import for CGO audio stream glue
78
)
89

10+
var (
11+
ErrAudioAlreadyRunning = errors.New("audio already running")
12+
)
13+
914
const MaxAudioFrameSize = 1500
1015

1116
// AudioQuality represents different audio quality presets
@@ -46,6 +51,13 @@ var (
4651
Channels: 2,
4752
FrameSize: 20 * time.Millisecond,
4853
}
54+
currentMicrophoneConfig = AudioConfig{
55+
Quality: AudioQualityMedium,
56+
Bitrate: 32,
57+
SampleRate: 48000,
58+
Channels: 1,
59+
FrameSize: 20 * time.Millisecond,
60+
}
4961
metrics AudioMetrics
5062
)
5163

@@ -55,14 +67,14 @@ func GetAudioQualityPresets() map[AudioQuality]AudioConfig {
5567
AudioQualityLow: {
5668
Quality: AudioQualityLow,
5769
Bitrate: 32,
58-
SampleRate: 48000,
59-
Channels: 2,
60-
FrameSize: 20 * time.Millisecond,
70+
SampleRate: 22050,
71+
Channels: 1,
72+
FrameSize: 40 * time.Millisecond,
6173
},
6274
AudioQualityMedium: {
6375
Quality: AudioQualityMedium,
6476
Bitrate: 64,
65-
SampleRate: 48000,
77+
SampleRate: 44100,
6678
Channels: 2,
6779
FrameSize: 20 * time.Millisecond,
6880
},
@@ -75,14 +87,48 @@ func GetAudioQualityPresets() map[AudioQuality]AudioConfig {
7587
},
7688
AudioQualityUltra: {
7789
Quality: AudioQualityUltra,
78-
Bitrate: 256,
90+
Bitrate: 192,
7991
SampleRate: 48000,
8092
Channels: 2,
8193
FrameSize: 10 * time.Millisecond,
8294
},
8395
}
8496
}
8597

98+
// GetMicrophoneQualityPresets returns predefined quality configurations for microphone input
99+
func GetMicrophoneQualityPresets() map[AudioQuality]AudioConfig {
100+
return map[AudioQuality]AudioConfig{
101+
AudioQualityLow: {
102+
Quality: AudioQualityLow,
103+
Bitrate: 16,
104+
SampleRate: 16000,
105+
Channels: 1,
106+
FrameSize: 40 * time.Millisecond,
107+
},
108+
AudioQualityMedium: {
109+
Quality: AudioQualityMedium,
110+
Bitrate: 32,
111+
SampleRate: 22050,
112+
Channels: 1,
113+
FrameSize: 20 * time.Millisecond,
114+
},
115+
AudioQualityHigh: {
116+
Quality: AudioQualityHigh,
117+
Bitrate: 64,
118+
SampleRate: 44100,
119+
Channels: 1,
120+
FrameSize: 20 * time.Millisecond,
121+
},
122+
AudioQualityUltra: {
123+
Quality: AudioQualityUltra,
124+
Bitrate: 96,
125+
SampleRate: 48000,
126+
Channels: 1,
127+
FrameSize: 10 * time.Millisecond,
128+
},
129+
}
130+
}
131+
86132
// SetAudioQuality updates the current audio quality configuration
87133
func SetAudioQuality(quality AudioQuality) {
88134
presets := GetAudioQualityPresets()
@@ -96,6 +142,19 @@ func GetAudioConfig() AudioConfig {
96142
return currentConfig
97143
}
98144

145+
// SetMicrophoneQuality updates the current microphone quality configuration
146+
func SetMicrophoneQuality(quality AudioQuality) {
147+
presets := GetMicrophoneQualityPresets()
148+
if config, exists := presets[quality]; exists {
149+
currentMicrophoneConfig = config
150+
}
151+
}
152+
153+
// GetMicrophoneConfig returns the current microphone configuration
154+
func GetMicrophoneConfig() AudioConfig {
155+
return currentMicrophoneConfig
156+
}
157+
99158
// GetAudioMetrics returns current audio metrics
100159
func GetAudioMetrics() AudioMetrics {
101160
return AudioMetrics{

0 commit comments

Comments
 (0)