Skip to content

Commit 6d1c823

Browse files
authored
Better compliance with the DTMF RFC4733 (#126)
Better compliance with the DTMF RFC4733.
1 parent 8338859 commit 6d1c823

File tree

3 files changed

+97
-13
lines changed

3 files changed

+97
-13
lines changed

pkg/media/dtmf/dtmf.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,20 +264,34 @@ func Write(ctx context.Context, audio media.PCM16Writer, events *rtp.Stream, dig
264264
// generate telephony events
265265
if events != nil && len(freq) != 0 {
266266
dur := step + totalDur - remaining
267+
first := totalDur == remaining
268+
end := remaining-step <= 0
267269

268270
n, err := Encode(buf[:], Event{
269271
Code: code,
270272
Volume: eventVolume,
271273
Dur: uint16(dur / (time.Second / SampleRate)),
272-
End: remaining-step <= 0,
274+
End: end,
273275
})
274276
if err != nil {
275277
return err
276278
}
277-
err = events.WritePayload(buf[:n], totalDur == remaining)
279+
// all packets for a digit must be sent with the same timestamp
280+
err = events.WritePayloadAtCurrent(buf[:n], first)
278281
if err != nil {
279282
return err
280283
}
284+
if end {
285+
// must repeat edn event 3 times, as per RFC
286+
if err = events.WritePayloadAtCurrent(buf[:n], first); err != nil {
287+
return err
288+
}
289+
if err = events.WritePayloadAtCurrent(buf[:n], first); err != nil {
290+
return err
291+
}
292+
// advance the timestamp now
293+
events.Delay(uint32(totalDur / (time.Second / SampleRate)))
294+
}
281295
}
282296
remaining -= step
283297
ts += step

pkg/media/dtmf/dtmf_test.go

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,74 @@ func TestDTMFDelay(t *testing.T) {
7878
w := rtp.NewSeqWriter(&buf).NewStream(101, SampleRate)
7979
err := Write(context.Background(), nil, w, "1w23")
8080
require.NoError(t, err)
81-
require.Len(t, buf, 39)
81+
8282
const packetDur = uint32(SampleRate / int(time.Second/rtp.DefFrameDur))
83-
for i, p := range buf {
84-
ts := packetDur * uint32(i)
85-
if i >= 26 {
86-
ts += 4 * (SampleRate / 4) // 2 * 250ms + 500ms
87-
} else if i >= 13 {
88-
ts += 3 * (SampleRate / 4) // 250ms after tone + 500ms user-defined
83+
type packet struct {
84+
SequenceNumber uint16
85+
Timestamp uint32
86+
Marker bool
87+
Event
88+
}
89+
var (
90+
exp []packet
91+
seq uint16
92+
ts uint32
93+
)
94+
expectDigit := func(code byte, digit byte) {
95+
start := ts
96+
const n = 13
97+
for i := 0; i < n-1; i++ {
98+
exp = append(exp, packet{
99+
SequenceNumber: seq,
100+
Timestamp: start, // should be the same for all events
101+
Marker: i == 0,
102+
Event: Event{
103+
Code: code,
104+
Digit: digit,
105+
Volume: eventVolume,
106+
Dur: uint16(i+1) * uint16(packetDur),
107+
End: false,
108+
},
109+
})
110+
ts += packetDur
111+
seq++
112+
}
113+
// end event must be sent 3 times with the same duration
114+
for i := 0; i < 3; i++ {
115+
exp = append(exp, packet{
116+
SequenceNumber: seq,
117+
Timestamp: start, // should be the same for all events
118+
Marker: false,
119+
Event: Event{
120+
Code: code,
121+
Digit: digit,
122+
Volume: eventVolume,
123+
Dur: uint16(n) * uint16(packetDur),
124+
End: true,
125+
},
126+
})
127+
seq++
89128
}
90-
require.EqualValues(t, uint16(i), p.SequenceNumber)
91-
require.EqualValues(t, ts, p.Timestamp, "i=%d, dt=%v", i, p.Timestamp-ts)
129+
ts += packetDur
130+
// delay between digits
131+
ts += uint32(eventDur / (time.Second / SampleRate))
132+
// rounding error (12.5 events in a sec)
133+
ts -= packetDur / 2
134+
}
135+
expectDigit(1, '1')
136+
ts += SampleRate / 2 // 500ms delay
137+
expectDigit(2, '2')
138+
expectDigit(3, '3')
139+
var got []packet
140+
for _, p := range buf {
141+
e, err := Decode(p.Payload)
142+
require.NoError(t, err)
143+
got = append(got, packet{
144+
SequenceNumber: p.SequenceNumber,
145+
Timestamp: p.Timestamp,
146+
Marker: p.Marker,
147+
Event: e,
148+
})
92149
}
150+
require.Equal(t, exp, got)
93151
}

pkg/media/rtp/rtp.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,30 @@ type Stream struct {
124124
ev Event
125125
}
126126

127-
func (s *Stream) WritePayload(data []byte, marker bool) error {
127+
func (s *Stream) writePayload(inc bool, data []byte, marker bool) error {
128128
s.mu.Lock()
129129
defer s.mu.Unlock()
130130
s.ev.Payload = data
131131
s.ev.Marker = marker
132132
if err := s.s.WriteEvent(&s.ev); err != nil {
133133
return err
134134
}
135-
s.ev.Timestamp += s.packetDur
135+
if inc {
136+
s.ev.Timestamp += s.packetDur
137+
}
136138
return nil
137139
}
138140

141+
// WritePayload writes the payload to RTP and increments the timestamp.
142+
func (s *Stream) WritePayload(data []byte, marker bool) error {
143+
return s.writePayload(true, data, marker)
144+
}
145+
146+
// WritePayloadAtCurrent writes the payload to RTP at the current timestamp.
147+
func (s *Stream) WritePayloadAtCurrent(data []byte, marker bool) error {
148+
return s.writePayload(false, data, marker)
149+
}
150+
139151
func (s *Stream) Delay(dur uint32) {
140152
s.mu.Lock()
141153
defer s.mu.Unlock()

0 commit comments

Comments
 (0)