Skip to content

Commit 68f950f

Browse files
committed
Disable resampler on the input audio.
1 parent ec3f57b commit 68f950f

File tree

7 files changed

+50
-20
lines changed

7 files changed

+50
-20
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/icholy/digest v1.1.0
1212
github.com/jfreymuth/oggvorbis v1.0.5
1313
github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731
14-
github.com/livekit/media-sdk v0.0.0-20250927154350-bd99739b439b
14+
github.com/livekit/media-sdk v0.0.0-20251020111046-39b1e9ba8b6f // FIXME: update when PR is merged
1515
github.com/livekit/mediatransportutil v0.0.0-20250519131108-fb90f5acfded
1616
github.com/livekit/protocol v1.42.3-0.20251016122026-bc6809b5bdc8
1717
github.com/livekit/psrpc v0.7.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ github.com/lithammer/shortuuid/v4 v4.2.0 h1:LMFOzVB3996a7b8aBuEXxqOBflbfPQAiVzkI
125125
github.com/lithammer/shortuuid/v4 v4.2.0/go.mod h1:D5noHZ2oFw/YaKCfGy0YxyE7M0wMbezmMjPdhyEFe6Y=
126126
github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5ATTo469PQPkqzdoU7be46ryiCDO3boc=
127127
github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ=
128-
github.com/livekit/media-sdk v0.0.0-20250927154350-bd99739b439b h1:dPf9i0JPyf0Sg0VMvkKBhdLPn7G93ERE9VCavlc07iA=
129-
github.com/livekit/media-sdk v0.0.0-20250927154350-bd99739b439b/go.mod h1:7ssWiG+U4xnbvLih9WiZbhQP6zIKMjgXdUtIE1bm/E8=
128+
github.com/livekit/media-sdk v0.0.0-20251020111046-39b1e9ba8b6f h1:1ClgvL3L2VyTonJ8dkXiBGGumw1D0CfYQxE35iyokrE=
129+
github.com/livekit/media-sdk v0.0.0-20251020111046-39b1e9ba8b6f/go.mod h1:7ssWiG+U4xnbvLih9WiZbhQP6zIKMjgXdUtIE1bm/E8=
130130
github.com/livekit/mediatransportutil v0.0.0-20250519131108-fb90f5acfded h1:ylZPdnlX1RW9Z15SD4mp87vT2D2shsk0hpLJwSPcq3g=
131131
github.com/livekit/mediatransportutil v0.0.0-20250519131108-fb90f5acfded/go.mod h1:mSNtYzSf6iY9xM3UX42VEI+STHvMgHmrYzEHPcdhB8A=
132132
github.com/livekit/protocol v1.42.3-0.20251016122026-bc6809b5bdc8 h1:JSAUNDIK36tYjvnahJihmOXISuco5xvKy5msXLp855A=

pkg/sip/inbound.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,7 @@ func (c *inboundCall) runMediaConn(offerData []byte, enc livekit.SIPMediaEncrypt
863863
MediaTimeout: c.s.conf.MediaTimeout,
864864
EnableJitterBuffer: c.jitterBuf,
865865
Stats: &c.stats.Port,
866+
NoInputResample: !RoomResample,
866867
}, RoomSampleRate)
867868
if err != nil {
868869
return nil, err

pkg/sip/media.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ func (s *Stats) MarshalJSON() ([]byte, error) {
149149
const (
150150
channels = 1
151151
RoomSampleRate = 48000
152+
RoomResample = false
152153
)
153154

154155
func newRTPStatsHandler(mon *stats.CallMonitor, typ string, r rtp.Handler) rtp.Handler {

pkg/sip/media_port.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ type MediaOptions struct {
130130
MediaTimeout time.Duration
131131
Stats *PortStats
132132
EnableJitterBuffer bool
133+
NoInputResample bool
133134
}
134135

135136
func NewMediaPort(log logger.Logger, mon *stats.CallMonitor, opts *MediaOptions, sampleRate int) (*MediaPort, error) {
@@ -157,6 +158,10 @@ func NewMediaPortWith(log logger.Logger, mon *stats.CallMonitor, conn UDPConn, o
157158
conn = c
158159
}
159160
mediaTimeout := make(chan struct{})
161+
inSampleRate := sampleRate
162+
if opts.NoInputResample {
163+
inSampleRate = -1 // set only after SDP is accepted
164+
}
160165
p := &MediaPort{
161166
log: log,
162167
opts: opts,
@@ -167,7 +172,7 @@ func NewMediaPortWith(log logger.Logger, mon *stats.CallMonitor, conn UDPConn, o
167172
jitterEnabled: opts.EnableJitterBuffer,
168173
port: newUDPConn(log, conn),
169174
audioOut: msdk.NewSwitchWriter(sampleRate),
170-
audioIn: msdk.NewSwitchWriter(sampleRate),
175+
audioIn: msdk.NewSwitchWriter(inSampleRate),
171176
stats: opts.Stats,
172177
}
173178
p.timeoutInitial.Store(&opts.MediaTimeoutInitial)
@@ -585,14 +590,19 @@ func (p *MediaPort) setupOutput() error {
585590

586591
func (p *MediaPort) setupInput() {
587592
// Decoding pipeline (SIP RTP -> LK PCM)
588-
audioHandler := p.conf.Audio.Codec.DecodeRTP(p.audioIn, p.conf.Audio.Type)
593+
codec := p.conf.Audio.Codec
594+
codecInfo := codec.Info()
595+
if p.opts.NoInputResample {
596+
p.audioIn.SetSampleRate(codecInfo.SampleRate)
597+
}
598+
audioHandler := codec.DecodeRTP(p.audioIn, p.conf.Audio.Type)
589599
p.audioInHandler = audioHandler
590600

591601
mux := rtp.NewMux(nil)
592602
mux.SetDefault(newRTPStatsHandler(p.mon, "", nil))
593603
mux.Register(
594604
p.conf.Audio.Type, newRTPHandlerCount(
595-
newRTPStatsHandler(p.mon, p.conf.Audio.Codec.Info().SDPName, audioHandler),
605+
newRTPStatsHandler(p.mon, codecInfo.SDPName, audioHandler),
596606
&p.stats.AudioPackets, &p.stats.AudioBytes,
597607
),
598608
)

pkg/sip/media_port_test.go

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,9 @@ func TestMediaPort(t *testing.T) {
199199
log := logger.GetLogger()
200200

201201
m1, err := NewMediaPortWith(log.WithName("one"), nil, c1, &MediaOptions{
202-
IP: newIP("1.1.1.1"),
203-
Ports: rtcconfig.PortRange{Start: 10000},
202+
IP: newIP("1.1.1.1"),
203+
Ports: rtcconfig.PortRange{Start: 10000},
204+
NoInputResample: true,
204205
}, tconf.Rate)
205206
require.NoError(t, err)
206207
defer m1.Close()
@@ -235,11 +236,13 @@ func TestMediaPort(t *testing.T) {
235236
err = m2.SetConfig(conf)
236237
require.NoError(t, err)
237238

238-
require.Equal(t, info.SDPName, m1.Config().Audio.Codec.Info().SDPName)
239-
require.Equal(t, info.SDPName, m2.Config().Audio.Codec.Info().SDPName)
239+
codec1 := m1.Config().Audio.Codec
240+
codec2 := m2.Config().Audio.Codec
241+
require.Equal(t, info.SDPName, codec1.Info().SDPName)
242+
require.Equal(t, info.SDPName, codec2.Info().SDPName)
240243

241244
var buf1 msdk.PCM16Sample
242-
bw1 := msdk.NewPCM16BufferWriter(&buf1, tconf.Rate)
245+
bw1 := msdk.NewPCM16BufferWriter(&buf1, codec1.Info().SampleRate)
243246
m1.WriteAudioTo(bw1)
244247

245248
var buf2 msdk.PCM16Sample
@@ -257,7 +260,8 @@ func TestMediaPort(t *testing.T) {
257260
sample2[i] = -5116
258261
}
259262

260-
writes := 1
263+
writes1 := 1
264+
writes2 := 1
261265
if tconf.Rate == nativeRate {
262266
expChain := fmt.Sprintf("Switch(%d) -> %s(encode) -> RTP(%d)", nativeRate, name, nativeRate)
263267
require.Equal(t, expChain, w1.String())
@@ -271,20 +275,31 @@ func TestMediaPort(t *testing.T) {
271275
require.Equal(t, expChain, w1.String())
272276
require.Equal(t, expChain, w2.String())
273277

274-
expChain = fmt.Sprintf("RTP(%d) -> %s(decode) -> Resample(%d->48000) -> Switch(48000) -> Buffer(48000)", nativeRate, name, nativeRate)
275-
require.Equal(t, expChain, PrintAudioInWriter(m1))
276-
require.Equal(t, expChain, PrintAudioInWriter(m2))
277-
278-
writes += 2 // resampler will buffer a few frames
278+
// This side does not resample the received audio, it uses sample rate of the RTP source.
279+
expChain1 := fmt.Sprintf("RTP(%d) -> %s(decode) -> Switch(%d) -> Buffer(%d)", nativeRate, name, nativeRate, nativeRate)
280+
// This side resamples the received audio to the expected sample rate.
281+
expChain2 := fmt.Sprintf("RTP(%d) -> %s(decode) -> Resample(%d->48000) -> Switch(48000) -> Buffer(48000)", nativeRate, name, nativeRate)
282+
require.Equal(t, expChain1, PrintAudioInWriter(m1))
283+
require.Equal(t, expChain2, PrintAudioInWriter(m2))
284+
285+
// resampler will buffer a few frames
286+
writes1 += 2
287+
writes2 += 2
288+
// a few more because of higher resample quality required
279289
if nativeRate == 8000 {
280-
writes += 3 // a few more because of higher resample quality required
290+
writes1 += 3
291+
writes2 += 5
292+
}
293+
if strings.HasPrefix(info.SDPName, "G722/") {
294+
writes2 += 1
281295
}
282296
}
283297

284-
for range writes {
298+
for range writes1 {
285299
err = w1.WriteSample(sample1)
286300
require.NoError(t, err)
287-
301+
}
302+
for range writes2 {
288303
err = w2.WriteSample(sample2)
289304
require.NoError(t, err)
290305
}
@@ -309,6 +324,7 @@ func TestMediaPort(t *testing.T) {
309324
}
310325

311326
func checkPCM(t testing.TB, exp, got msdk.PCM16Sample) {
327+
t.Helper()
312328
require.Equal(t, len(exp), len(got))
313329
expSamples := slices.Clone(exp)
314330
slices.Sort(expSamples)
@@ -338,6 +354,7 @@ func newMediaPair(t testing.TB, opt1, opt2 *MediaOptions) (m1, m2 *MediaPort) {
338354

339355
opt1.IP = newIP("1.1.1.1")
340356
opt1.Ports = rtcconfig.PortRange{Start: 10000}
357+
opt1.NoInputResample = true
341358

342359
opt2.IP = newIP("2.2.2.2")
343360
opt2.Ports = rtcconfig.PortRange{Start: 20000}

pkg/sip/outbound.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ func (c *Client) newCall(ctx context.Context, conf *config.Config, log logger.Lo
136136
MediaTimeout: c.conf.MediaTimeout,
137137
EnableJitterBuffer: call.jitterBuf,
138138
Stats: &call.stats.Port,
139+
NoInputResample: !RoomResample,
139140
}, RoomSampleRate)
140141
if err != nil {
141142
call.close(errors.Wrap(err, "media failed"), callDropped, "media-failed", livekit.DisconnectReason_UNKNOWN_REASON)

0 commit comments

Comments
 (0)