1 /* $Id$ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <pjmedia/endpoint.h>
21 #include <pjmedia/errno.h>
22 #include <pjmedia/sdp.h>
23 #include <pjmedia/vid_codec.h>
24 #include <pjmedia-audiodev/audiodev.h>
25 #include <pj/assert.h>
26 #include <pj/ioqueue.h>
27 #include <pj/lock.h>
28 #include <pj/log.h>
29 #include <pj/os.h>
30 #include <pj/pool.h>
31 #include <pj/sock.h>
32 #include <pj/string.h>
33 
34 
35 #define THIS_FILE   "endpoint.c"
36 
37 static const pj_str_t STR_IN = { "IN", 2 };
38 static const pj_str_t STR_IP4 = { "IP4", 3};
39 static const pj_str_t STR_IP6 = { "IP6", 3};
40 static const pj_str_t STR_RTP_AVP = { "RTP/AVP", 7 };
41 static const pj_str_t STR_SDP_NAME = { "pjmedia", 7 };
42 static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };
43 
44 
45 
46 /* Config to control rtpmap inclusion for static payload types */
47 pj_bool_t pjmedia_add_rtpmap_for_static_pt =
48 	    PJMEDIA_ADD_RTPMAP_FOR_STATIC_PT;
49 
50 /* Config to control use of RFC3890 TIAS */
51 pj_bool_t pjmedia_add_bandwidth_tias_in_sdp =
52             PJMEDIA_ADD_BANDWIDTH_TIAS_IN_SDP;
53 
54 
55 
56 /* Worker thread proc. */
57 static int PJ_THREAD_FUNC worker_proc(void*);
58 
59 
60 #define MAX_THREADS	16
61 
62 
63 /* List of media endpoint exit callback. */
64 typedef struct exit_cb
65 {
66     PJ_DECL_LIST_MEMBER		    (struct exit_cb);
67     pjmedia_endpt_exit_callback	    func;
68 } exit_cb;
69 
70 
71 /** Concrete declaration of media endpoint. */
72 struct pjmedia_endpt
73 {
74     /** Pool. */
75     pj_pool_t		 *pool;
76 
77     /** Pool factory. */
78     pj_pool_factory	 *pf;
79 
80     /** Codec manager. */
81     pjmedia_codec_mgr	  codec_mgr;
82 
83     /** IOqueue instance. */
84     pj_ioqueue_t 	 *ioqueue;
85 
86     /** Do we own the ioqueue? */
87     pj_bool_t		  own_ioqueue;
88 
89     /** Number of threads. */
90     unsigned		  thread_cnt;
91 
92     /** IOqueue polling thread, if any. */
93     pj_thread_t		 *thread[MAX_THREADS];
94 
95     /** To signal polling thread to quit. */
96     pj_bool_t		  quit_flag;
97 
98     /** Is telephone-event enable */
99     pj_bool_t		  has_telephone_event;
100 
101     /** List of exit callback. */
102     exit_cb		  exit_cb_list;
103 };
104 
105 /**
106  * Initialize and get the instance of media endpoint.
107  */
pjmedia_endpt_create2(pj_pool_factory * pf,pj_ioqueue_t * ioqueue,unsigned worker_cnt,pjmedia_endpt ** p_endpt)108 PJ_DEF(pj_status_t) pjmedia_endpt_create2(pj_pool_factory *pf,
109 					  pj_ioqueue_t *ioqueue,
110 					  unsigned worker_cnt,
111 					  pjmedia_endpt **p_endpt)
112 {
113     pj_pool_t *pool;
114     pjmedia_endpt *endpt;
115     unsigned i;
116     pj_status_t status;
117 
118     status = pj_register_strerror(PJMEDIA_ERRNO_START, PJ_ERRNO_SPACE_SIZE,
119 				  &pjmedia_strerror);
120     pj_assert(status == PJ_SUCCESS);
121 
122     PJ_ASSERT_RETURN(pf && p_endpt, PJ_EINVAL);
123     PJ_ASSERT_RETURN(worker_cnt <= MAX_THREADS, PJ_EINVAL);
124 
125     pool = pj_pool_create(pf, "med-ept", PJMEDIA_POOL_LEN_ENDPT,
126 						PJMEDIA_POOL_INC_ENDPT, NULL);
127     if (!pool)
128 	return PJ_ENOMEM;
129 
130     endpt = PJ_POOL_ZALLOC_T(pool, struct pjmedia_endpt);
131     endpt->pool = pool;
132     endpt->pf = pf;
133     endpt->ioqueue = ioqueue;
134     endpt->thread_cnt = worker_cnt;
135     endpt->has_telephone_event = PJ_TRUE;
136 
137     /* Initialize audio subsystem.
138      * To avoid pjmedia's dependendy on pjmedia-audiodev, the initialization
139      * (and shutdown) of audio subsystem will be done in the application
140      * level instead, when it calls inline functions pjmedia_endpt_create()
141      * and pjmedia_endpt_destroy().
142      */
143     //status = pjmedia_aud_subsys_init(pf);
144     //if (status != PJ_SUCCESS)
145     //	goto on_error;
146 
147     /* Init codec manager. */
148     status = pjmedia_codec_mgr_init(&endpt->codec_mgr, endpt->pf);
149     if (status != PJ_SUCCESS)
150 	goto on_error;
151 
152     /* Initialize exit callback list. */
153     pj_list_init(&endpt->exit_cb_list);
154 
155     /* Create ioqueue if none is specified. */
156     if (endpt->ioqueue == NULL) {
157 
158 	endpt->own_ioqueue = PJ_TRUE;
159 
160 	status = pj_ioqueue_create( endpt->pool, PJ_IOQUEUE_MAX_HANDLES,
161 				    &endpt->ioqueue);
162 	if (status != PJ_SUCCESS)
163 	    goto on_error;
164 
165 	if (worker_cnt == 0) {
166 	    PJ_LOG(4,(THIS_FILE, "Warning: no worker thread is created in"
167 				 "media endpoint for internal ioqueue"));
168 	}
169     }
170 
171     /* Create worker threads if asked. */
172     for (i=0; i<worker_cnt; ++i) {
173 	status = pj_thread_create( endpt->pool, "media", &worker_proc,
174 				   endpt, 0, 0, &endpt->thread[i]);
175 	if (status != PJ_SUCCESS)
176 	    goto on_error;
177     }
178 
179 
180     *p_endpt = endpt;
181     return PJ_SUCCESS;
182 
183 on_error:
184 
185     /* Destroy threads */
186     for (i=0; i<endpt->thread_cnt; ++i) {
187 	if (endpt->thread[i]) {
188 	    pj_thread_destroy(endpt->thread[i]);
189 	}
190     }
191 
192     /* Destroy internal ioqueue */
193     if (endpt->ioqueue && endpt->own_ioqueue)
194 	pj_ioqueue_destroy(endpt->ioqueue);
195 
196     pjmedia_codec_mgr_destroy(&endpt->codec_mgr);
197     //pjmedia_aud_subsys_shutdown();
198     pj_pool_release(pool);
199     return status;
200 }
201 
202 /**
203  * Get the codec manager instance.
204  */
pjmedia_endpt_get_codec_mgr(pjmedia_endpt * endpt)205 PJ_DEF(pjmedia_codec_mgr*) pjmedia_endpt_get_codec_mgr(pjmedia_endpt *endpt)
206 {
207     return &endpt->codec_mgr;
208 }
209 
210 /**
211  * Deinitialize media endpoint.
212  */
pjmedia_endpt_destroy2(pjmedia_endpt * endpt)213 PJ_DEF(pj_status_t) pjmedia_endpt_destroy2 (pjmedia_endpt *endpt)
214 {
215     exit_cb *ecb;
216 
217     pjmedia_endpt_stop_threads(endpt);
218 
219     /* Destroy internal ioqueue */
220     if (endpt->ioqueue && endpt->own_ioqueue) {
221 	pj_ioqueue_destroy(endpt->ioqueue);
222 	endpt->ioqueue = NULL;
223     }
224 
225     endpt->pf = NULL;
226 
227     pjmedia_codec_mgr_destroy(&endpt->codec_mgr);
228     //pjmedia_aud_subsys_shutdown();
229 
230     /* Call all registered exit callbacks */
231     ecb = endpt->exit_cb_list.next;
232     while (ecb != &endpt->exit_cb_list) {
233 	(*ecb->func)(endpt);
234 	ecb = ecb->next;
235     }
236 
237     pj_pool_release (endpt->pool);
238 
239     return PJ_SUCCESS;
240 }
241 
pjmedia_endpt_set_flag(pjmedia_endpt * endpt,pjmedia_endpt_flag flag,const void * value)242 PJ_DEF(pj_status_t) pjmedia_endpt_set_flag( pjmedia_endpt *endpt,
243 					    pjmedia_endpt_flag flag,
244 					    const void *value)
245 {
246     PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
247 
248     switch (flag) {
249     case PJMEDIA_ENDPT_HAS_TELEPHONE_EVENT_FLAG:
250 	endpt->has_telephone_event = *(pj_bool_t*)value;
251 	break;
252     default:
253 	return PJ_EINVAL;
254     }
255 
256     return PJ_SUCCESS;
257 }
258 
pjmedia_endpt_get_flag(pjmedia_endpt * endpt,pjmedia_endpt_flag flag,void * value)259 PJ_DEF(pj_status_t) pjmedia_endpt_get_flag( pjmedia_endpt *endpt,
260 					    pjmedia_endpt_flag flag,
261 					    void *value)
262 {
263     PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
264 
265     switch (flag) {
266     case PJMEDIA_ENDPT_HAS_TELEPHONE_EVENT_FLAG:
267 	*(pj_bool_t*)value = endpt->has_telephone_event;
268 	break;
269     default:
270 	return PJ_EINVAL;
271     }
272 
273     return PJ_SUCCESS;
274 }
275 
276 /**
277  * Get the ioqueue instance of the media endpoint.
278  */
pjmedia_endpt_get_ioqueue(pjmedia_endpt * endpt)279 PJ_DEF(pj_ioqueue_t*) pjmedia_endpt_get_ioqueue(pjmedia_endpt *endpt)
280 {
281     PJ_ASSERT_RETURN(endpt, NULL);
282     return endpt->ioqueue;
283 }
284 
285 /**
286  * Get the number of worker threads in media endpoint.
287  */
pjmedia_endpt_get_thread_count(pjmedia_endpt * endpt)288 PJ_DEF(unsigned) pjmedia_endpt_get_thread_count(pjmedia_endpt *endpt)
289 {
290     PJ_ASSERT_RETURN(endpt, 0);
291     return endpt->thread_cnt;
292 }
293 
294 /**
295  * Get a reference to one of the worker threads of the media endpoint
296  */
pjmedia_endpt_get_thread(pjmedia_endpt * endpt,unsigned index)297 PJ_DEF(pj_thread_t*) pjmedia_endpt_get_thread(pjmedia_endpt *endpt,
298 					      unsigned index)
299 {
300     PJ_ASSERT_RETURN(endpt, NULL);
301     PJ_ASSERT_RETURN(index < endpt->thread_cnt, NULL);
302 
303     /* here should be an assert on index >= 0 < endpt->thread_cnt */
304 
305     return endpt->thread[index];
306 }
307 
308 /**
309  * Stop and destroy the worker threads of the media endpoint
310  */
pjmedia_endpt_stop_threads(pjmedia_endpt * endpt)311 PJ_DEF(pj_status_t) pjmedia_endpt_stop_threads(pjmedia_endpt *endpt)
312 {
313     unsigned i;
314 
315     PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
316 
317     endpt->quit_flag = 1;
318 
319     /* Destroy threads */
320     for (i=0; i<endpt->thread_cnt; ++i) {
321 	if (endpt->thread[i]) {
322 	    pj_thread_join(endpt->thread[i]);
323 	    pj_thread_destroy(endpt->thread[i]);
324 	    endpt->thread[i] = NULL;
325 	}
326     }
327 
328     return PJ_SUCCESS;
329 }
330 
331 /**
332  * Worker thread proc.
333  */
worker_proc(void * arg)334 static int PJ_THREAD_FUNC worker_proc(void *arg)
335 {
336     pjmedia_endpt *endpt = (pjmedia_endpt*) arg;
337 
338     while (!endpt->quit_flag) {
339 	pj_time_val timeout = { 0, 500 };
340 	pj_ioqueue_poll(endpt->ioqueue, &timeout);
341     }
342 
343     return 0;
344 }
345 
346 /**
347  * Create pool.
348  */
pjmedia_endpt_create_pool(pjmedia_endpt * endpt,const char * name,pj_size_t initial,pj_size_t increment)349 PJ_DEF(pj_pool_t*) pjmedia_endpt_create_pool( pjmedia_endpt *endpt,
350 					      const char *name,
351 					      pj_size_t initial,
352 					      pj_size_t increment)
353 {
354     pj_assert(endpt != NULL);
355 
356     return pj_pool_create(endpt->pf, name, initial, increment, NULL);
357 }
358 
359 /* Common initialization for both audio and video SDP media line */
init_sdp_media(pjmedia_sdp_media * m,pj_pool_t * pool,const pj_str_t * media_type,const pjmedia_sock_info * sock_info)360 static pj_status_t init_sdp_media(pjmedia_sdp_media *m,
361                                   pj_pool_t *pool,
362                                   const pj_str_t *media_type,
363 				  const pjmedia_sock_info *sock_info)
364 {
365     char tmp_addr[PJ_INET6_ADDRSTRLEN];
366     pjmedia_sdp_attr *attr;
367     const pj_sockaddr *addr;
368 
369     pj_strdup(pool, &m->desc.media, media_type);
370 
371     addr = &sock_info->rtp_addr_name;
372 
373     /* Validate address family */
374     PJ_ASSERT_RETURN(addr->addr.sa_family == pj_AF_INET() ||
375                      addr->addr.sa_family == pj_AF_INET6(),
376                      PJ_EAFNOTSUP);
377 
378     /* SDP connection line */
379     m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
380     m->conn->net_type = STR_IN;
381     m->conn->addr_type = (addr->addr.sa_family==pj_AF_INET())? STR_IP4:STR_IP6;
382     pj_sockaddr_print(addr, tmp_addr, sizeof(tmp_addr), 0);
383     pj_strdup2(pool, &m->conn->addr, tmp_addr);
384 
385     /* Port and transport in media description */
386     m->desc.port = pj_sockaddr_get_port(addr);
387     m->desc.port_count = 1;
388     pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP);
389 
390     /* Add "rtcp" attribute */
391 #if defined(PJMEDIA_HAS_RTCP_IN_SDP) && PJMEDIA_HAS_RTCP_IN_SDP!=0
392     if (sock_info->rtcp_addr_name.addr.sa_family != 0) {
393 	attr = pjmedia_sdp_attr_create_rtcp(pool, &sock_info->rtcp_addr_name);
394 	if (attr)
395 	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
396     }
397 #endif
398 
399     /* Add sendrecv attribute. */
400     attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
401     attr->name = STR_SENDRECV;
402     m->attr[m->attr_count++] = attr;
403 
404     return PJ_SUCCESS;
405 }
406 
407 /* Create m=audio SDP media line */
pjmedia_endpt_create_audio_sdp(pjmedia_endpt * endpt,pj_pool_t * pool,const pjmedia_sock_info * si,unsigned options,pjmedia_sdp_media ** p_m)408 PJ_DEF(pj_status_t) pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt,
409                                                    pj_pool_t *pool,
410                                                    const pjmedia_sock_info *si,
411                                                    unsigned options,
412                                                    pjmedia_sdp_media **p_m)
413 {
414     const pj_str_t STR_AUDIO = { "audio", 5 };
415     pjmedia_sdp_media *m;
416     pjmedia_sdp_attr *attr;
417     unsigned i;
418     unsigned max_bitrate = 0;
419     pj_status_t status;
420 #if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
421 	    PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0
422     unsigned televent_num = 0;
423     unsigned televent_clockrates[8];
424 #endif
425     unsigned used_pt_num = 0;
426     unsigned used_pt[PJMEDIA_MAX_SDP_FMT];
427 
428     PJ_UNUSED_ARG(options);
429 
430     /* Check that there are not too many codecs */
431     PJ_ASSERT_RETURN(endpt->codec_mgr.codec_cnt <= PJMEDIA_MAX_SDP_FMT,
432 		     PJ_ETOOMANY);
433 
434     /* Insert PJMEDIA_RTP_PT_TELEPHONE_EVENTS as used PT */
435 #if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
436 	    PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0
437     if (endpt->has_telephone_event) {
438 	used_pt[used_pt_num++] = PJMEDIA_RTP_PT_TELEPHONE_EVENTS;
439 
440 #  if PJMEDIA_TELEPHONE_EVENT_ALL_CLOCKRATES==0
441 	televent_num = 1;
442 	televent_clockrates[0] = 8000;
443 #  endif
444 
445     }
446 #endif
447 
448     /* Create and init basic SDP media */
449     m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
450     status = init_sdp_media(m, pool, &STR_AUDIO, si);
451     if (status != PJ_SUCCESS)
452 	return status;
453 
454     /* Add format, rtpmap, and fmtp (when applicable) for each codec */
455     for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {
456 
457 	pjmedia_codec_info *codec_info;
458 	pjmedia_sdp_rtpmap rtpmap;
459 	char tmp_param[3];
460 	pjmedia_codec_param codec_param;
461 	pj_str_t *fmt;
462 	unsigned pt;
463 
464 	if (endpt->codec_mgr.codec_desc[i].prio == PJMEDIA_CODEC_PRIO_DISABLED)
465 	    break;
466 
467 	codec_info = &endpt->codec_mgr.codec_desc[i].info;
468 	pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr, codec_info,
469 					    &codec_param);
470 	fmt = &m->desc.fmt[m->desc.fmt_count++];
471 	pt = codec_info->pt;
472 
473 	/* Rearrange dynamic payload type to make sure it is inside 96-127
474 	 * range and not being used by other codec/tel-event.
475 	 */
476 	if (pt >= 96) {
477 	    unsigned pt_check = 96;
478 	    unsigned j = 0;
479 	    while (j < used_pt_num && pt_check <= 127) {
480 		if (pt_check==used_pt[j]) {
481 		    pt_check++;
482 		    j = 0;
483 		} else {
484 		    j++;
485 		}
486 	    }
487 	    if (pt_check > 127) {
488 		/* No more available PT */
489 		PJ_LOG(4,(THIS_FILE, "Warning: no available dynamic "
490 			  "payload type for audio codec"));
491 		break;
492 	    }
493 	    pt = pt_check;
494 	}
495 
496 	/* Take a note of used dynamic PT */
497 	if (pt >= 96)
498 	    used_pt[used_pt_num++] = pt;
499 
500 	fmt->ptr = (char*) pj_pool_alloc(pool, 8);
501 	fmt->slen = pj_utoa(pt, fmt->ptr);
502 
503 	rtpmap.pt = *fmt;
504 	rtpmap.enc_name = codec_info->encoding_name;
505 
506 #if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0)
507 	if (pt == PJMEDIA_RTP_PT_G722)
508 	    rtpmap.clock_rate = 8000;
509 	else
510 	    rtpmap.clock_rate = codec_info->clock_rate;
511 #else
512 	rtpmap.clock_rate = codec_info->clock_rate;
513 #endif
514 
515 	/* For audio codecs, rtpmap parameters denotes the number
516 	 * of channels, which can be omited if the value is 1.
517 	 */
518 	if (codec_info->type == PJMEDIA_TYPE_AUDIO &&
519 	    codec_info->channel_cnt > 1)
520 	{
521 	    /* Can only support one digit channel count */
522 	    pj_assert(codec_info->channel_cnt < 10);
523 
524 	    tmp_param[0] = (char)('0' + codec_info->channel_cnt);
525 
526 	    rtpmap.param.ptr = tmp_param;
527 	    rtpmap.param.slen = 1;
528 
529 	} else {
530 	    rtpmap.param.ptr = "";
531 	    rtpmap.param.slen = 0;
532 	}
533 
534 	if (pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
535 	    pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
536 	    m->attr[m->attr_count++] = attr;
537 	}
538 
539 	/* Add fmtp params */
540 	if (codec_param.setting.dec_fmtp.cnt > 0) {
541 	    enum { MAX_FMTP_STR_LEN = 160 };
542 	    char buf[MAX_FMTP_STR_LEN];
543 	    unsigned buf_len = 0, n, ii;
544 	    pjmedia_codec_fmtp *dec_fmtp = &codec_param.setting.dec_fmtp;
545 
546 	    /* Print codec PT */
547 	    n = pj_ansi_snprintf(buf, MAX_FMTP_STR_LEN - buf_len,
548 				 "%d", pt);
549 	    buf_len = PJ_MIN(buf_len + n, MAX_FMTP_STR_LEN);
550 
551 	    for (ii = 0; ii < dec_fmtp->cnt; ++ii) {
552 		pj_size_t test_len = 2;
553 
554 		/* Check if buf still available */
555 		test_len = dec_fmtp->param[ii].val.slen +
556 			   dec_fmtp->param[ii].name.slen + 2;
557 		if (test_len + buf_len >= MAX_FMTP_STR_LEN)
558 		    return PJ_ETOOBIG;
559 
560 		/* Print delimiter */
561 		n = pj_ansi_snprintf(&buf[buf_len],
562 				     MAX_FMTP_STR_LEN - buf_len,
563 				     (ii == 0?" ":";"));
564 		buf_len = PJ_MIN(buf_len + n, MAX_FMTP_STR_LEN);
565 
566 		/* Print an fmtp param */
567 		if (dec_fmtp->param[ii].name.slen)
568 		    n = pj_ansi_snprintf(&buf[buf_len],
569 					 MAX_FMTP_STR_LEN - buf_len,
570 					 "%.*s=%.*s",
571 					 (int)dec_fmtp->param[ii].name.slen,
572 					 dec_fmtp->param[ii].name.ptr,
573 					 (int)dec_fmtp->param[ii].val.slen,
574 					  dec_fmtp->param[ii].val.ptr);
575 		else
576 		    n = pj_ansi_snprintf(&buf[buf_len],
577 					 MAX_FMTP_STR_LEN - buf_len,
578 					 "%.*s",
579 					 (int)dec_fmtp->param[ii].val.slen,
580 					 dec_fmtp->param[ii].val.ptr);
581 
582 		buf_len = PJ_MIN(buf_len + n, MAX_FMTP_STR_LEN);
583 	    }
584 
585 	    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
586 
587 	    attr->name = pj_str("fmtp");
588 	    attr->value = pj_strdup3(pool, buf);
589 	    m->attr[m->attr_count++] = attr;
590 	}
591 
592 	/* Find maximum bitrate in this media */
593 	if (max_bitrate < codec_param.info.max_bps)
594 	    max_bitrate = codec_param.info.max_bps;
595 
596 	/* List clock rate of audio codecs for generating telephone-event */
597 #if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
598 	    PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0 && \
599 	    PJMEDIA_TELEPHONE_EVENT_ALL_CLOCKRATES != 0
600 	if (endpt->has_telephone_event) {
601 	    unsigned j;
602 
603 	    for (j=0; j<televent_num; ++j) {
604 		if (televent_clockrates[j] == rtpmap.clock_rate)
605 		    break;
606 	    }
607 	    if (j==televent_num &&
608 		televent_num<PJ_ARRAY_SIZE(televent_clockrates))
609 	    {
610 		/* List this clockrate for tel-event generation */
611 		televent_clockrates[televent_num++] = rtpmap.clock_rate;
612 	    }
613 	}
614 #endif
615     }
616 
617 #if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
618 	    PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0
619     /*
620      * Add support telephony event
621      */
622     if (endpt->has_telephone_event) {
623 	for (i=0; i<televent_num; i++) {
624 	    char buf[160];
625 	    unsigned j = 0;
626 	    unsigned pt;
627 
628 	    /* Find PT for this tel-event */
629 	    if (i == 0) {
630 		/* First telephony-event always uses preconfigured PT
631 		 * PJMEDIA_RTP_PT_TELEPHONE_EVENTS.
632 		 */
633 		pt = PJMEDIA_RTP_PT_TELEPHONE_EVENTS;
634 	    } else {
635 		/* Otherwise, find any free PT slot, starting from
636 		 * (PJMEDIA_RTP_PT_TELEPHONE_EVENTS + 1).
637 		 */
638 		pt = PJMEDIA_RTP_PT_TELEPHONE_EVENTS + 1;
639 		while (j < used_pt_num && pt <= 127) {
640 		    if (pt == used_pt[j]) {
641 			pt++;
642 			j = 0;
643 		    } else {
644 			j++;
645 		    }
646 		}
647 		if (pt > 127) {
648 		    /* Not found? Find more, but now starting from 96 */
649 		    pt = 96;
650 		    j = 0;
651 		    while (j < used_pt_num &&
652 			   pt < PJMEDIA_RTP_PT_TELEPHONE_EVENTS)
653 		    {
654 			if (pt == used_pt[j]) {
655 			    pt++;
656 			    j = 0;
657 			} else {
658 			    j++;
659 			}
660 		    }
661 		    if (pt >= PJMEDIA_RTP_PT_TELEPHONE_EVENTS) {
662 			/* No more available PT */
663 			PJ_LOG(4,(THIS_FILE, "Warning: no available dynamic "
664 				  "payload type for telephone-event"));
665 			break;
666 		    }
667 		}
668 	    }
669 	    used_pt[used_pt_num++] = pt;
670 
671 	    /* Print tel-event PT */
672 	    pj_ansi_snprintf(buf, sizeof(buf), "%d", pt);
673 	    m->desc.fmt[m->desc.fmt_count++] = pj_strdup3(pool, buf);
674 
675 	    /* Add rtpmap. */
676 	    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
677 	    attr->name = pj_str("rtpmap");
678 	    pj_ansi_snprintf(buf, sizeof(buf), "%d telephone-event/%d",
679 			     pt, televent_clockrates[i]);
680 	    attr->value = pj_strdup3(pool, buf);
681 	    m->attr[m->attr_count++] = attr;
682 
683 	    /* Add fmtp */
684 	    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
685 	    attr->name = pj_str("fmtp");
686 #if defined(PJMEDIA_HAS_DTMF_FLASH) && PJMEDIA_HAS_DTMF_FLASH!= 0
687 	    pj_ansi_snprintf(buf, sizeof(buf), "%d 0-16", pt);
688 #else
689 	    pj_ansi_snprintf(buf, sizeof(buf), "%d 0-15", pt);
690 #endif
691 	    attr->value = pj_strdup3(pool, buf);
692 	    m->attr[m->attr_count++] = attr;
693 	}
694     }
695 #endif
696 
697     /* Put bandwidth info in media level using bandwidth modifier "TIAS"
698      * (RFC3890).
699      */
700     if (max_bitrate && pjmedia_add_bandwidth_tias_in_sdp) {
701 	const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
702 	pjmedia_sdp_bandw *b;
703 
704 	b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
705 	b->modifier = STR_BANDW_MODIFIER;
706 	b->value = max_bitrate;
707 	m->bandw[m->bandw_count++] = b;
708     }
709 
710     *p_m = m;
711     return PJ_SUCCESS;
712 }
713 
714 
715 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
716 
717 /* Create m=video SDP media line */
pjmedia_endpt_create_video_sdp(pjmedia_endpt * endpt,pj_pool_t * pool,const pjmedia_sock_info * si,unsigned options,pjmedia_sdp_media ** p_m)718 PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt,
719                                                    pj_pool_t *pool,
720                                                    const pjmedia_sock_info *si,
721                                                    unsigned options,
722                                                    pjmedia_sdp_media **p_m)
723 {
724 
725 
726     const pj_str_t STR_VIDEO = { "video", 5 };
727     pjmedia_sdp_media *m;
728     pjmedia_vid_codec_info codec_info[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
729     unsigned codec_prio[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
730     pjmedia_sdp_attr *attr;
731     unsigned cnt, i;
732     unsigned max_bitrate = 0;
733     pj_status_t status;
734 
735     PJ_UNUSED_ARG(options);
736 
737     /* Make sure video codec manager is instantiated */
738     if (!pjmedia_vid_codec_mgr_instance())
739 	pjmedia_vid_codec_mgr_create(endpt->pool, NULL);
740 
741     /* Create and init basic SDP media */
742     m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
743     status = init_sdp_media(m, pool, &STR_VIDEO, si);
744     if (status != PJ_SUCCESS)
745 	return status;
746 
747     cnt = PJ_ARRAY_SIZE(codec_info);
748     status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt,
749 					       codec_info, codec_prio);
750 
751     /* Check that there are not too many codecs */
752     PJ_ASSERT_RETURN(0 <= PJMEDIA_MAX_SDP_FMT,
753 		     PJ_ETOOMANY);
754 
755     /* Add format, rtpmap, and fmtp (when applicable) for each codec */
756     for (i=0; i<cnt; ++i) {
757 	pjmedia_sdp_rtpmap rtpmap;
758 	pjmedia_vid_codec_param codec_param;
759 	pj_str_t *fmt;
760 	pjmedia_video_format_detail *vfd;
761 
762 	pj_bzero(&rtpmap, sizeof(rtpmap));
763 
764 	if (codec_prio[i] == PJMEDIA_CODEC_PRIO_DISABLED)
765 	    break;
766 
767 	if (i > PJMEDIA_MAX_SDP_FMT) {
768 	    /* Too many codecs, perhaps it is better to tell application by
769 	     * returning appropriate status code.
770 	     */
771 	    PJ_PERROR(3,(THIS_FILE, PJ_ETOOMANY,
772 			"Skipping some video codecs"));
773 	    break;
774 	}
775 
776         /* Must support RTP packetization */
777         if ((codec_info[i].packings & PJMEDIA_VID_PACKING_PACKETS) == 0)
778 	{
779 	    continue;
780 	}
781 
782 	pjmedia_vid_codec_mgr_get_default_param(NULL, &codec_info[i],
783 						&codec_param);
784 
785 	fmt = &m->desc.fmt[m->desc.fmt_count++];
786 	fmt->ptr = (char*) pj_pool_alloc(pool, 8);
787 	fmt->slen = pj_utoa(codec_info[i].pt, fmt->ptr);
788 	rtpmap.pt = *fmt;
789 
790 	/* Encoding name */
791 	rtpmap.enc_name = codec_info[i].encoding_name;
792 
793 	/* Clock rate */
794 	rtpmap.clock_rate = codec_info[i].clock_rate;
795 
796 	if (codec_info[i].pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
797 	    pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
798 	    m->attr[m->attr_count++] = attr;
799 	}
800 
801 	/* Add fmtp params */
802 	if (codec_param.dec_fmtp.cnt > 0) {
803 	    enum { MAX_FMTP_STR_LEN = 160 };
804 	    char buf[MAX_FMTP_STR_LEN];
805 	    unsigned buf_len = 0, n, j;
806 	    pjmedia_codec_fmtp *dec_fmtp = &codec_param.dec_fmtp;
807 
808 	    /* Print codec PT */
809 	    n = pj_ansi_snprintf(buf, MAX_FMTP_STR_LEN - buf_len,
810 				 "%d",
811 				 codec_info[i].pt);
812 	    buf_len = PJ_MIN(buf_len + n, MAX_FMTP_STR_LEN);
813 
814 	    for (j = 0; j < dec_fmtp->cnt; ++j) {
815 		pj_size_t test_len = 2;
816 
817 		/* Check if buf still available */
818 		test_len = dec_fmtp->param[j].val.slen +
819 			   dec_fmtp->param[j].name.slen + 2;
820 		if (test_len + buf_len >= MAX_FMTP_STR_LEN)
821 		    return PJ_ETOOBIG;
822 
823 		/* Print delimiter */
824 		n = pj_ansi_snprintf(&buf[buf_len],
825 				     MAX_FMTP_STR_LEN - buf_len,
826 				     (j == 0?" ":";"));
827 	    	buf_len = PJ_MIN(buf_len + n, MAX_FMTP_STR_LEN);
828 
829 		/* Print an fmtp param */
830 		if (dec_fmtp->param[j].name.slen)
831 		    n = pj_ansi_snprintf(&buf[buf_len],
832 					 MAX_FMTP_STR_LEN - buf_len,
833 					 "%.*s=%.*s",
834 					 (int)dec_fmtp->param[j].name.slen,
835 					 dec_fmtp->param[j].name.ptr,
836 					 (int)dec_fmtp->param[j].val.slen,
837 					 dec_fmtp->param[j].val.ptr);
838 		else
839 		    n = pj_ansi_snprintf(&buf[buf_len],
840 					 MAX_FMTP_STR_LEN - buf_len,
841 					 "%.*s",
842 					 (int)dec_fmtp->param[j].val.slen,
843 					 dec_fmtp->param[j].val.ptr);
844 
845 		buf_len = PJ_MIN(buf_len + n, MAX_FMTP_STR_LEN);
846 	    }
847 
848 	    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
849 
850 	    attr->name = pj_str("fmtp");
851 	    attr->value = pj_strdup3(pool, buf);
852 	    m->attr[m->attr_count++] = attr;
853 	}
854 
855 	/* Find maximum bitrate in this media */
856 	vfd = pjmedia_format_get_video_format_detail(&codec_param.enc_fmt,
857 						     PJ_TRUE);
858 	if (vfd && max_bitrate < vfd->max_bps)
859 	    max_bitrate = vfd->max_bps;
860     }
861 
862     /* Put bandwidth info in media level using bandwidth modifier "TIAS"
863      * (RFC3890).
864      */
865     if (max_bitrate && pjmedia_add_bandwidth_tias_in_sdp) {
866 	const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
867 	pjmedia_sdp_bandw *b;
868 
869 	b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
870 	b->modifier = STR_BANDW_MODIFIER;
871 	b->value = max_bitrate;
872 	m->bandw[m->bandw_count++] = b;
873     }
874 
875     *p_m = m;
876     return PJ_SUCCESS;
877 }
878 
879 #endif /* PJMEDIA_HAS_VIDEO */
880 
881 
882 /**
883  * Create a "blank" SDP session description. The SDP will contain basic SDP
884  * fields such as origin, time, and name, but without any media lines.
885  */
pjmedia_endpt_create_base_sdp(pjmedia_endpt * endpt,pj_pool_t * pool,const pj_str_t * sess_name,const pj_sockaddr * origin,pjmedia_sdp_session ** p_sdp)886 PJ_DEF(pj_status_t) pjmedia_endpt_create_base_sdp( pjmedia_endpt *endpt,
887 						   pj_pool_t *pool,
888 						   const pj_str_t *sess_name,
889 						   const pj_sockaddr *origin,
890 						   pjmedia_sdp_session **p_sdp)
891 {
892     char tmp_addr[PJ_INET6_ADDRSTRLEN];
893     pj_time_val tv;
894     pjmedia_sdp_session *sdp;
895 
896     /* Sanity check arguments */
897     PJ_ASSERT_RETURN(endpt && pool && p_sdp, PJ_EINVAL);
898 
899     sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);
900 
901     pj_gettimeofday(&tv);
902     sdp->origin.user = pj_str("-");
903     sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
904     sdp->origin.net_type = STR_IN;
905 
906     if (origin->addr.sa_family == pj_AF_INET()) {
907  	sdp->origin.addr_type = STR_IP4;
908     } else if (origin->addr.sa_family == pj_AF_INET6()) {
909  	sdp->origin.addr_type = STR_IP6;
910     } else {
911  	pj_assert(!"Invalid address family");
912  	return PJ_EAFNOTSUP;
913     }
914 
915     pj_strdup2(pool, &sdp->origin.addr,
916  	       pj_sockaddr_print(origin, tmp_addr, sizeof(tmp_addr), 0));
917 
918     if (sess_name)
919 	pj_strdup(pool, &sdp->name, sess_name);
920     else
921 	sdp->name = STR_SDP_NAME;
922 
923     /* SDP time and attributes. */
924     sdp->time.start = sdp->time.stop = 0;
925     sdp->attr_count = 0;
926 
927     /* Done */
928     *p_sdp = sdp;
929 
930     return PJ_SUCCESS;
931 }
932 
933 /**
934  * Create a SDP session description that describes the endpoint
935  * capability.
936  */
pjmedia_endpt_create_sdp(pjmedia_endpt * endpt,pj_pool_t * pool,unsigned stream_cnt,const pjmedia_sock_info sock_info[],pjmedia_sdp_session ** p_sdp)937 PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
938 					      pj_pool_t *pool,
939 					      unsigned stream_cnt,
940 					      const pjmedia_sock_info sock_info[],
941 					      pjmedia_sdp_session **p_sdp )
942 {
943     const pj_sockaddr *addr0;
944     pjmedia_sdp_session *sdp;
945     pjmedia_sdp_media *m;
946     pj_status_t status;
947 
948     /* Sanity check arguments */
949     PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL);
950     PJ_ASSERT_RETURN(stream_cnt < PJMEDIA_MAX_SDP_MEDIA, PJ_ETOOMANY);
951 
952     addr0 = &sock_info[0].rtp_addr_name;
953 
954     /* Create and initialize basic SDP session */
955     status = pjmedia_endpt_create_base_sdp(endpt, pool, NULL, addr0, &sdp);
956     if (status != PJ_SUCCESS)
957 	return status;
958 
959     /* Audio is first, by convention */
960     status = pjmedia_endpt_create_audio_sdp(endpt, pool,
961                                             &sock_info[0], 0, &m);
962     if (status != PJ_SUCCESS)
963 	return status;
964     sdp->media[sdp->media_count++] = m;
965 
966 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
967     {
968 	unsigned i;
969 
970 	/* The remaining stream, if any, are videos (by convention as well) */
971 	for (i=1; i<stream_cnt; ++i) {
972 	    status = pjmedia_endpt_create_video_sdp(endpt, pool,
973 						    &sock_info[i], 0, &m);
974 	    if (status != PJ_SUCCESS)
975 		return status;
976 	    sdp->media[sdp->media_count++] = m;
977 	}
978     }
979 #endif
980 
981     /* Done */
982     *p_sdp = sdp;
983 
984     return PJ_SUCCESS;
985 }
986 
987 
988 
989 #if PJ_LOG_MAX_LEVEL >= 3
good_number(char * buf,pj_int32_t val)990 static const char *good_number(char *buf, pj_int32_t val)
991 {
992     if (val < 1000) {
993 	pj_ansi_sprintf(buf, "%d", val);
994     } else if (val < 1000000) {
995 	pj_ansi_sprintf(buf, "%d.%dK",
996 			val / 1000,
997 			(val % 1000) / 100);
998     } else {
999 	pj_ansi_sprintf(buf, "%d.%02dM",
1000 			val / 1000000,
1001 			(val % 1000000) / 10000);
1002     }
1003 
1004     return buf;
1005 }
1006 #endif
1007 
pjmedia_endpt_dump(pjmedia_endpt * endpt)1008 PJ_DEF(pj_status_t) pjmedia_endpt_dump(pjmedia_endpt *endpt)
1009 {
1010 
1011 #if PJ_LOG_MAX_LEVEL >= 3
1012     unsigned i, count;
1013     pjmedia_codec_info codec_info[32];
1014     unsigned prio[32];
1015 
1016     PJ_LOG(3,(THIS_FILE, "Dumping PJMEDIA capabilities:"));
1017 
1018     count = PJ_ARRAY_SIZE(codec_info);
1019     if (pjmedia_codec_mgr_enum_codecs(&endpt->codec_mgr,
1020 				      &count, codec_info, prio) != PJ_SUCCESS)
1021     {
1022 	PJ_LOG(3,(THIS_FILE, " -error: failed to enum codecs"));
1023 	return PJ_SUCCESS;
1024     }
1025 
1026     PJ_LOG(3,(THIS_FILE, "  Total number of installed codecs: %d", count));
1027     for (i=0; i<count; ++i) {
1028 	const char *type;
1029 	pjmedia_codec_param param;
1030 	char bps[32];
1031 
1032 	switch (codec_info[i].type) {
1033 	case PJMEDIA_TYPE_AUDIO:
1034 	    type = "Audio"; break;
1035 	case PJMEDIA_TYPE_VIDEO:
1036 	    type = "Video"; break;
1037 	default:
1038 	    type = "Unknown type"; break;
1039 	}
1040 
1041 	if (pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr,
1042 						&codec_info[i],
1043 						&param) != PJ_SUCCESS)
1044 	{
1045 	    pj_bzero(&param, sizeof(pjmedia_codec_param));
1046 	}
1047 
1048 	PJ_LOG(3,(THIS_FILE,
1049 		  "   %s codec #%2d: pt=%d (%.*s @%dKHz/%d, %sbps, %dms%s%s%s%s%s)",
1050 		  type, i, codec_info[i].pt,
1051 		  (int)codec_info[i].encoding_name.slen,
1052 		  codec_info[i].encoding_name.ptr,
1053 		  codec_info[i].clock_rate/1000,
1054 		  codec_info[i].channel_cnt,
1055 		  good_number(bps, param.info.avg_bps),
1056 		  param.info.frm_ptime * param.setting.frm_per_pkt,
1057 		  (param.setting.vad ? " vad" : ""),
1058 		  (param.setting.cng ? " cng" : ""),
1059 		  (param.setting.plc ? " plc" : ""),
1060 		  (param.setting.penh ? " penh" : ""),
1061 		  (prio[i]==PJMEDIA_CODEC_PRIO_DISABLED?" disabled":"")));
1062     }
1063 #endif
1064 
1065     return PJ_SUCCESS;
1066 }
1067 
pjmedia_endpt_atexit(pjmedia_endpt * endpt,pjmedia_endpt_exit_callback func)1068 PJ_DEF(pj_status_t) pjmedia_endpt_atexit( pjmedia_endpt *endpt,
1069 					  pjmedia_endpt_exit_callback func)
1070 {
1071     exit_cb *new_cb;
1072 
1073     PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL);
1074 
1075     if (endpt->quit_flag)
1076 	return PJ_EINVALIDOP;
1077 
1078     new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb);
1079     new_cb->func = func;
1080 
1081     pj_enter_critical_section();
1082     pj_list_push_back(&endpt->exit_cb_list, new_cb);
1083     pj_leave_critical_section();
1084 
1085     return PJ_SUCCESS;
1086 }
1087