Skip to content

Commit 1f5862a

Browse files
committed
Match codecs with different rate or channels
Consider clock rate and channels when matching codecs. This allows to support codecs with the same MIME type but sample rate or channel count that might be different from the default ones, like PCMU, PCMA, LPCM and multiopus.
1 parent 59c7270 commit 1f5862a

File tree

4 files changed

+304
-32
lines changed

4 files changed

+304
-32
lines changed

internal/fmtp/fmtp.go

+88-18
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,30 @@ import (
88
"strings"
99
)
1010

11+
var defaultClockRates = map[string]uint32{
12+
"audio/opus": 48000,
13+
"audio/pcmu": 8000,
14+
"audio/pcma": 8000,
15+
}
16+
17+
var defaultChannelCounts = map[string]uint16{
18+
"audio/opus": 2,
19+
}
20+
21+
func defaultClockRate(mimeType string) uint32 {
22+
if def, ok := defaultClockRates[strings.ToLower(mimeType)]; ok {
23+
return def
24+
}
25+
return 90000
26+
}
27+
28+
func defaultChannelCount(mimeType string) uint16 {
29+
if def, ok := defaultChannelCounts[strings.ToLower(mimeType)]; ok {
30+
return def
31+
}
32+
return 0
33+
}
34+
1135
func parseParameters(line string) map[string]string {
1236
parameters := make(map[string]string)
1337

@@ -24,6 +48,61 @@ func parseParameters(line string) map[string]string {
2448
return parameters
2549
}
2650

51+
// ClockRateEqual checks whether two clock rates are equal.
52+
func ClockRateEqual(mimeType string, valA, valB uint32) bool {
53+
// Lots of users use formats without setting clock rate or channels.
54+
// In this case, use default values.
55+
// It would be better to remove this exception in a future major release.
56+
if valA == 0 {
57+
valA = defaultClockRate(mimeType)
58+
}
59+
if valB == 0 {
60+
valB = defaultClockRate(mimeType)
61+
}
62+
63+
return valA == valB
64+
}
65+
66+
// ChannelsEqual checks whether two channels are equal.
67+
func ChannelsEqual(mimeType string, valA, valB uint16) bool {
68+
// Lots of users use formats without setting clock rate or channels.
69+
// In this case, use default values.
70+
// It would be better to remove this exception in a future major release.
71+
if valA == 0 {
72+
valA = defaultChannelCount(mimeType)
73+
}
74+
if valB == 0 {
75+
valB = defaultChannelCount(mimeType)
76+
}
77+
78+
// RFC8866: channel count "is OPTIONAL and may be omitted
79+
// if the number of channels is one".
80+
if valA == 0 {
81+
valA = 1
82+
}
83+
if valB == 0 {
84+
valB = 1
85+
}
86+
87+
return valA == valB
88+
}
89+
90+
func paramsEqual(valA, valB map[string]string) bool {
91+
for k, v := range valA {
92+
if vb, ok := valB[k]; ok && !strings.EqualFold(vb, v) {
93+
return false
94+
}
95+
}
96+
97+
for k, v := range valB {
98+
if va, ok := valA[k]; ok && !strings.EqualFold(va, v) {
99+
return false
100+
}
101+
}
102+
103+
return true
104+
}
105+
27106
// FMTP interface for implementing custom
28107
// FMTP parsers based on MimeType.
29108
type FMTP interface {
@@ -39,7 +118,7 @@ type FMTP interface {
39118
}
40119

41120
// Parse parses an fmtp string based on the MimeType.
42-
func Parse(mimeType, line string) FMTP {
121+
func Parse(mimeType string, clockRate uint32, channels uint16, line string) FMTP {
43122
var fmtp FMTP
44123

45124
parameters := parseParameters(line)
@@ -63,6 +142,8 @@ func Parse(mimeType, line string) FMTP {
63142
default:
64143
fmtp = &genericFMTP{
65144
mimeType: mimeType,
145+
clockRate: clockRate,
146+
channels: channels,
66147
parameters: parameters,
67148
}
68149
}
@@ -72,6 +153,8 @@ func Parse(mimeType, line string) FMTP {
72153

73154
type genericFMTP struct {
74155
mimeType string
156+
clockRate uint32
157+
channels uint16
75158
parameters map[string]string
76159
}
77160

@@ -87,23 +170,10 @@ func (g *genericFMTP) Match(b FMTP) bool {
87170
return false
88171
}
89172

90-
if !strings.EqualFold(g.mimeType, fmtp.MimeType()) {
91-
return false
92-
}
93-
94-
for k, v := range g.parameters {
95-
if vb, ok := fmtp.parameters[k]; ok && !strings.EqualFold(vb, v) {
96-
return false
97-
}
98-
}
99-
100-
for k, v := range fmtp.parameters {
101-
if va, ok := g.parameters[k]; ok && !strings.EqualFold(va, v) {
102-
return false
103-
}
104-
}
105-
106-
return true
173+
return strings.EqualFold(g.mimeType, fmtp.MimeType()) &&
174+
ClockRateEqual(g.mimeType, g.clockRate, fmtp.clockRate) &&
175+
ChannelsEqual(g.mimeType, g.channels, fmtp.channels) &&
176+
paramsEqual(g.parameters, fmtp.parameters)
107177
}
108178

109179
func (g *genericFMTP) Parameter(key string) (string, bool) {

0 commit comments

Comments
 (0)