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