1 /**
2 * @file telev.c Telephony Events implementation (RFC 4733)
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6 #include <ctype.h>
7 #include <re_types.h>
8 #include <re_mem.h>
9 #include <re_mbuf.h>
10 #include <re_list.h>
11 #include <re_tmr.h>
12 #include <re_net.h>
13 #include <re_telev.h>
14
15
16 /*
17 * Implements a subset of RFC 4733,
18 * "RTP Payload for DTMF Digits, Telephony Tones, and Telephony Signals"
19 *
20 * Call telev_send() to send telephony events, and telev_recv() to receive.
21 * The function telev_poll() must be called periodically, with a minimum
22 * and stable interval of less than or equal to packet time (e.g. 50ms)
23 *
24 * NOTE: RTP timestamp and sequence number is kept in application
25 *
26 *
27 * Example sending:
28 *
29 * ms M ts seq ev dur End
30 *
31 * press X -->
32 * 50 1 0 1 X 400 0
33 * 100 0 0 2 X 800 0
34 * 150 0 0 3 X 1200 0
35 * 200 0 0 4 X 1600 0
36 * ... . . . . .... .
37 * release X -->
38 * 250 0 0 5 X 1600 1
39 * 300 0 0 6 X 1600 1
40 * press Y -->
41 * 350 1 2000 7 Y 400 0
42 * ... . .... . . ... .
43 */
44
45
46 enum {
47 TXC_DIGIT_MIN = 9,
48 TXC_END = 3,
49 EVENT_END = 0xff,
50 PAYLOAD_SIZE = 4,
51 VOLUME = 10,
52 QUEUE_SIZE = 8192,
53 };
54
55
56 enum state {
57 IDLE,
58 SENDING,
59 ENDING,
60 };
61
62
63 struct telev_fmt {
64 uint8_t event;
65 bool end;
66 uint8_t vol;
67 uint16_t dur;
68 };
69
70
71 /** Defines a Telephony Events state */
72 struct telev {
73 /* tx */
74 struct mbuf *mb;
75 uint32_t ptime;
76 uint16_t pdur;
77 enum state state;
78 int event;
79 uint16_t dur;
80 uint32_t txc;
81
82 /* rx */
83 int rx_event;
84 bool rx_end;
85 };
86
87
88 const char telev_rtpfmt[] = "telephone-event";
89
90
payload_encode(struct mbuf * mb,int event,bool end,uint16_t dur)91 static int payload_encode(struct mbuf *mb, int event, bool end, uint16_t dur)
92 {
93 size_t pos;
94 int err;
95
96 if (!mb)
97 return EINVAL;
98
99 pos = mb->pos;
100
101 err = mbuf_write_u8(mb, event);
102 err |= mbuf_write_u8(mb, (end ? 0x80 : 0x00) | (VOLUME & 0x3f));
103 err |= mbuf_write_u16(mb, htons(dur));
104
105 if (err)
106 mb->pos = pos;
107
108 return err;
109 }
110
111
payload_decode(struct mbuf * mb,struct telev_fmt * fmt)112 static int payload_decode(struct mbuf *mb, struct telev_fmt *fmt)
113 {
114 uint8_t b;
115
116 if (!mb || !fmt)
117 return EINVAL;
118
119 if (mbuf_get_left(mb) < PAYLOAD_SIZE)
120 return ENOENT;
121
122 fmt->event = mbuf_read_u8(mb);
123 b = mbuf_read_u8(mb);
124 fmt->end = (b & 0x80) == 0x80;
125 fmt->vol = (b & 0x3f);
126 fmt->dur = ntohs(mbuf_read_u16(mb));
127
128 return 0;
129 }
130
131
destructor(void * arg)132 static void destructor(void *arg)
133 {
134 struct telev *t = arg;
135
136 mem_deref(t->mb);
137 }
138
139
140 /**
141 * Allocate a new Telephony Events state
142 *
143 * @param tp Pointer to allocated object
144 * @param ptime Packet time in [ms]
145 *
146 * @return 0 if success, otherwise errorcode
147 */
telev_alloc(struct telev ** tp,uint32_t ptime)148 int telev_alloc(struct telev **tp, uint32_t ptime)
149 {
150 struct telev *t;
151 int err = 0;
152
153 if (!tp || !ptime)
154 return EINVAL;
155
156 t = mem_zalloc(sizeof(*t), destructor);
157 if (!t)
158 return ENOMEM;
159
160 t->mb = mbuf_alloc(16);
161 if (!t->mb) {
162 err = ENOMEM;
163 goto out;
164 }
165
166 t->state = IDLE;
167 t->ptime = ptime;
168 t->pdur = ptime * 8;
169 t->rx_event = -1;
170
171 out:
172 if (err)
173 mem_deref(t);
174 else
175 *tp = t;
176
177 return err;
178 }
179
180
181 /**
182 * Sets the sampling rate
183 *
184 * @param tel Telephony Event state
185 * @param srate Sampling rate in [Hz]
186 *
187 * @return 0 if success, otherwise errorcode
188 */
telev_set_srate(struct telev * tel,uint32_t srate)189 int telev_set_srate(struct telev *tel, uint32_t srate)
190 {
191 if (!tel || !srate)
192 return EINVAL;
193
194 tel->pdur = tel->ptime * srate / 1000;
195
196 return 0;
197 }
198
199
200 /**
201 * Send a Telephony Event
202 *
203 * @param tel Telephony Event state
204 * @param event The Event to send
205 * @param end End-of-event flag
206 *
207 * @return 0 if success, otherwise errorcode
208 */
telev_send(struct telev * tel,int event,bool end)209 int telev_send(struct telev *tel, int event, bool end)
210 {
211 size_t pos;
212 int err;
213
214 if (!tel)
215 return EINVAL;
216
217 if (tel->mb->end >= QUEUE_SIZE)
218 return EOVERFLOW;
219
220 pos = tel->mb->pos;
221
222 tel->mb->pos = tel->mb->end;
223 err = mbuf_write_u8(tel->mb, end ? EVENT_END : event);
224 tel->mb->pos = pos;
225
226 return err;
227 }
228
229
230 /**
231 * Receive a Telephony Event
232 *
233 * @param tel Telephony Event state
234 * @param mb Buffer to decode
235 * @param event The received event, set on return
236 * @param end End-of-event flag, set on return
237 *
238 * @return 0 if success, otherwise errorcode
239 */
telev_recv(struct telev * tel,struct mbuf * mb,int * event,bool * end)240 int telev_recv(struct telev *tel, struct mbuf *mb, int *event, bool *end)
241 {
242 struct telev_fmt fmt;
243 int err;
244
245 if (!tel || !mb || !event || !end)
246 return EINVAL;
247
248 err = payload_decode(mb, &fmt);
249 if (err)
250 return err;
251
252 if (fmt.end) {
253 if (tel->rx_end)
254 return EALREADY;
255
256 *event = fmt.event;
257 *end = true;
258 tel->rx_event = -1;
259 tel->rx_end = true;
260 return 0;
261 }
262
263 if (fmt.event == tel->rx_event)
264 return EALREADY;
265
266 *event = tel->rx_event = fmt.event;
267 *end = tel->rx_end = false;
268
269 return 0;
270 }
271
272
273 /**
274 * Poll a Telephony Event state for sending
275 *
276 * @param tel Telephony Event state
277 * @param marker Marker bit, set on return
278 * @param mb Buffer with encoded data to send
279 *
280 * @return 0 if success, otherwise errorcode
281 */
telev_poll(struct telev * tel,bool * marker,struct mbuf * mb)282 int telev_poll(struct telev *tel, bool *marker, struct mbuf *mb)
283 {
284 bool mrk = false;
285 int err = ENOENT;
286
287 if (!tel || !marker || !mb)
288 return EINVAL;
289
290 switch (tel->state) {
291
292 case IDLE:
293 if (!mbuf_get_left(tel->mb))
294 break;
295
296 mrk = true;
297
298 tel->event = mbuf_read_u8(tel->mb);
299 tel->dur = tel->pdur;
300 tel->state = SENDING;
301 tel->txc = 1;
302
303 err = payload_encode(mb, tel->event, false, tel->dur);
304 break;
305
306 case SENDING:
307 tel->dur += tel->pdur;
308
309 err = payload_encode(mb, tel->event, false, tel->dur);
310
311 if (++tel->txc < TXC_DIGIT_MIN)
312 break;
313
314 if (!mbuf_get_left(tel->mb))
315 break;
316
317 if (mbuf_read_u8(tel->mb) != EVENT_END)
318 tel->mb->pos--;
319
320 tel->state = ENDING;
321 tel->txc = 0;
322 break;
323
324 case ENDING:
325 err = payload_encode(mb, tel->event, true, tel->dur);
326
327 if (++tel->txc < TXC_END)
328 break;
329
330 if (!mbuf_get_left(tel->mb))
331 tel->mb->pos = tel->mb->end = 0;
332
333 tel->state = IDLE;
334 break;
335 }
336
337 if (!err)
338 *marker = mrk;
339
340 return err;
341 }
342
343
344 /**
345 * Convert DTMF digit to Event code
346 *
347 * @param digit DTMF Digit
348 *
349 * @return Event code, or -1 if error
350 */
telev_digit2code(int digit)351 int telev_digit2code(int digit)
352 {
353 if (isdigit(digit))
354 return digit - '0';
355 else if (digit == '*')
356 return 10;
357 else if (digit == '#')
358 return 11;
359 else if ('a' <= digit && digit <= 'd')
360 return digit - 'a' + 12;
361 else if ('A' <= digit && digit <= 'D')
362 return digit - 'A' + 12;
363 else
364 return -1;
365 }
366
367
368 /**
369 * Convert Event code to DTMF digit
370 *
371 * @param code Event code
372 *
373 * @return DTMF Digit, or -1 if error
374 */
telev_code2digit(int code)375 int telev_code2digit(int code)
376 {
377 static const char map[] = "0123456789*#ABCD";
378
379 if (code < 0 || code >= 16)
380 return -1;
381
382 return map[code];
383 }
384