Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjsip-apps / src / 3rdparty_media_sample / alt_pjsua_aud.c
1 /* $Id$ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include <pjsua-lib/pjsua.h>
20 #include <pjsua-lib/pjsua_internal.h>
21
22 #if defined(PJSUA_MEDIA_HAS_PJMEDIA) && PJSUA_MEDIA_HAS_PJMEDIA != 0
23 #  error The PJSUA_MEDIA_HAS_PJMEDIA should be declared as zero
24 #endif
25
26
27 #define THIS_FILE               "alt_pjsua_aud.c"
28 #define UNIMPLEMENTED(func)     PJ_LOG(2,(THIS_FILE, "*** Call to unimplemented function %s ***", #func));
29
30
31 /*****************************************************************************
32  * Our dummy codecs. Since we won't use any PJMEDIA codecs, we need to declare
33  * our own codecs and register them to PJMEDIA's codec manager. We just need
34  * the info so that they can be listed in SDP. The encoding and decoding will
35  * happen in your third party media stream and will not use these codecs,
36  * hence the "dummy" name.
37  */
38 static struct alt_codec
39 {
40     pj_str_t    encoding_name;
41     pj_uint8_t  payload_type;
42     unsigned    clock_rate;
43     unsigned    channel_cnt;
44     unsigned    frm_ptime;
45     unsigned    avg_bps;
46     unsigned    max_bps;
47 } codec_list[] =
48 {
49     /* G.729 */
50     { { "G729", 4 }, 18, 8000, 1, 10, 8000, 8000 },
51     /* PCMU */
52     { { "PCMU", 4 }, 0, 8000, 1, 10, 64000, 64000 },
53     /* Our proprietary high end low bit rate (5kbps) codec, if you wish */
54     { { "FOO", 3 }, PJMEDIA_RTP_PT_START+0, 16000, 1, 20, 5000, 5000 },
55 };
56
57 static struct alt_codec_factory
58 {
59     pjmedia_codec_factory       base;
60 } alt_codec_factory;
61
62 static pj_status_t alt_codec_test_alloc( pjmedia_codec_factory *factory,
63                                          const pjmedia_codec_info *id )
64 {
65     unsigned i;
66     for (i=0; i<PJ_ARRAY_SIZE(codec_list); ++i) {
67         if (pj_stricmp(&id->encoding_name, &codec_list[i].encoding_name)==0)
68             return PJ_SUCCESS;
69     }
70     return PJ_ENOTSUP;
71 }
72
73 static pj_status_t alt_codec_default_attr( pjmedia_codec_factory *factory,
74                                            const pjmedia_codec_info *id,
75                                            pjmedia_codec_param *attr )
76 {
77     struct alt_codec *ac;
78     unsigned i;
79
80     PJ_UNUSED_ARG(factory);
81
82     for (i=0; i<PJ_ARRAY_SIZE(codec_list); ++i) {
83         if (pj_stricmp(&id->encoding_name, &codec_list[i].encoding_name)==0)
84             break;
85     }
86     if (i == PJ_ARRAY_SIZE(codec_list))
87         return PJ_ENOTFOUND;
88
89     ac = &codec_list[i];
90
91     pj_bzero(attr, sizeof(pjmedia_codec_param));
92     attr->info.clock_rate = ac->clock_rate;
93     attr->info.channel_cnt = ac->channel_cnt;
94     attr->info.avg_bps = ac->avg_bps;
95     attr->info.max_bps = ac->max_bps;
96     attr->info.pcm_bits_per_sample = 16;
97     attr->info.frm_ptime = ac->frm_ptime;
98     attr->info.pt = ac->payload_type;
99
100     attr->setting.frm_per_pkt = 1;
101     attr->setting.vad = 1;
102     attr->setting.plc = 1;
103
104     return PJ_SUCCESS;
105 }
106
107 static pj_status_t alt_codec_enum_codecs(pjmedia_codec_factory *factory,
108                                          unsigned *count,
109                                          pjmedia_codec_info codecs[])
110 {
111     unsigned i;
112
113     for (i=0; i<*count && i<PJ_ARRAY_SIZE(codec_list); ++i) {
114         struct alt_codec *ac = &codec_list[i];
115         pj_bzero(&codecs[i], sizeof(pjmedia_codec_info));
116         codecs[i].encoding_name = ac->encoding_name;
117         codecs[i].pt = ac->payload_type;
118         codecs[i].type = PJMEDIA_TYPE_AUDIO;
119         codecs[i].clock_rate = ac->clock_rate;
120         codecs[i].channel_cnt = ac->channel_cnt;
121     }
122
123     *count = i;
124
125     return PJ_SUCCESS;
126 }
127
128 static pj_status_t alt_codec_alloc_codec(pjmedia_codec_factory *factory,
129                                          const pjmedia_codec_info *id,
130                                          pjmedia_codec **p_codec)
131 {
132     /* This will never get called since we won't be using this codec */
133     UNIMPLEMENTED(alt_codec_alloc_codec)
134     return PJ_ENOTSUP;
135 }
136
137 static pj_status_t alt_codec_dealloc_codec( pjmedia_codec_factory *factory,
138                                             pjmedia_codec *codec )
139 {
140     /* This will never get called */
141     UNIMPLEMENTED(alt_codec_dealloc_codec)
142     return PJ_ENOTSUP;
143 }
144
145 static pj_status_t alt_codec_deinit(void)
146 {
147     pjmedia_codec_mgr *codec_mgr;
148     codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
149     return pjmedia_codec_mgr_unregister_factory(codec_mgr,
150                                                 &alt_codec_factory.base);
151
152 }
153
154 static pjmedia_codec_factory_op alt_codec_factory_op =
155 {
156     &alt_codec_test_alloc,
157     &alt_codec_default_attr,
158     &alt_codec_enum_codecs,
159     &alt_codec_alloc_codec,
160     &alt_codec_dealloc_codec,
161     &alt_codec_deinit
162 };
163
164
165 /*****************************************************************************
166  * API
167  */
168
169 /* Initialize third party media library. */
170 pj_status_t pjsua_aud_subsys_init()
171 {
172     pjmedia_codec_mgr *codec_mgr;
173     pj_status_t status;
174
175     /* Register our "dummy" codecs */
176     alt_codec_factory.base.op = &alt_codec_factory_op;
177     codec_mgr = pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt);
178     status = pjmedia_codec_mgr_register_factory(codec_mgr,
179                                                 &alt_codec_factory.base);
180     if (status != PJ_SUCCESS)
181         return status;
182
183     /* TODO: initialize your evil library here */
184     return PJ_SUCCESS;
185 }
186
187 /* Start (audio) media library. */
188 pj_status_t pjsua_aud_subsys_start(void)
189 {
190     /* TODO: */
191     return PJ_SUCCESS;
192 }
193
194 /* Cleanup and deinitialize third party media library. */
195 pj_status_t pjsua_aud_subsys_destroy()
196 {
197     /* TODO: */
198     return PJ_SUCCESS;
199 }
200
201 /* Our callback to receive incoming RTP packets */
202 static void aud_rtp_cb(void *user_data, void *pkt, pj_ssize_t size)
203 {
204     pjsua_call_media *call_med = (pjsua_call_media*) user_data;
205
206     /* TODO: Do something with the packet */
207     PJ_LOG(4,(THIS_FILE, "RX %d bytes audio RTP packet", (int)size));
208 }
209
210 /* Our callback to receive RTCP packets */
211 static void aud_rtcp_cb(void *user_data, void *pkt, pj_ssize_t size)
212 {
213     pjsua_call_media *call_med = (pjsua_call_media*) user_data;
214
215     /* TODO: Do something with the packet here */
216     PJ_LOG(4,(THIS_FILE, "RX %d bytes audio RTCP packet", (int)size));
217 }
218
219 /* A demo function to send dummy "RTP" packets periodically. You would not
220  * need to have this function in the real app!
221  */
222 static void timer_to_send_aud_rtp(void *user_data)
223 {
224     pjsua_call_media *call_med = (pjsua_call_media*) user_data;
225     const char *pkt = "Not RTP packet";
226
227     if (call_med->call->inv == NULL) {
228         /* Call has been disconnected. There is race condition here as
229          * this cb may be called sometime after call has been disconnected */
230         return;
231     }
232
233     pjmedia_transport_send_rtp(call_med->tp, pkt, strlen(pkt));
234
235     pjsua_schedule_timer2(&timer_to_send_aud_rtp, call_med, 2000);
236 }
237
238 static void timer_to_send_aud_rtcp(void *user_data)
239 {
240     pjsua_call_media *call_med = (pjsua_call_media*) user_data;
241     const char *pkt = "Not RTCP packet";
242
243     if (call_med->call->inv == NULL) {
244         /* Call has been disconnected. There is race condition here as
245          * this cb may be called sometime after call has been disconnected */
246         return;
247     }
248
249     pjmedia_transport_send_rtcp(call_med->tp, pkt, strlen(pkt));
250
251     pjsua_schedule_timer2(&timer_to_send_aud_rtcp, call_med, 5000);
252 }
253
254 /* Stop the audio stream of a call. */
255 void pjsua_aud_stop_stream(pjsua_call_media *call_med)
256 {
257     /* Detach our RTP/RTCP callbacks from transport */
258     pjmedia_transport_detach(call_med->tp, call_med);
259
260     /* TODO: destroy your audio stream here */
261 }
262
263 /*
264  * This function is called whenever SDP negotiation has completed
265  * successfully. Here you'd want to start your audio stream
266  * based on the info in the SDPs.
267  */
268 pj_status_t pjsua_aud_channel_update(pjsua_call_media *call_med,
269                                      pj_pool_t *tmp_pool,
270                                      pjmedia_stream_info *si,
271                                      const pjmedia_sdp_session *local_sdp,
272                                      const pjmedia_sdp_session *remote_sdp)
273 {
274     pj_status_t status = PJ_SUCCESS;
275
276     PJ_LOG(4,(THIS_FILE,"Alt audio channel update.."));
277     pj_log_push_indent();
278
279     /* Check if no media is active */
280     if (si->dir != PJMEDIA_DIR_NONE) {
281         /* Attach our RTP and RTCP callbacks to the media transport */
282         status = pjmedia_transport_attach(call_med->tp, call_med,
283                                           &si->rem_addr, &si->rem_rtcp,
284                                           pj_sockaddr_get_len(&si->rem_addr),
285                                           &aud_rtp_cb, &aud_rtcp_cb);
286
287         /* For a demonstration, let's use a timer to send "RTP" packet
288          * periodically.
289          */
290         pjsua_schedule_timer2(&timer_to_send_aud_rtp, call_med, 0);
291         pjsua_schedule_timer2(&timer_to_send_aud_rtcp, call_med, 2500);
292
293         /* TODO:
294          *   - Create and start your media stream based on the parameters
295          *     in si
296          */
297     }
298
299 on_return:
300     pj_log_pop_indent();
301     return status;
302 }
303
304
305 /*****************************************************************************
306  *
307  * Call API which MAY need to be re-implemented if different backend is used.
308  */
309
310 /* Check if call has an active media session. */
311 PJ_DEF(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id)
312 {
313     UNIMPLEMENTED(pjsua_call_has_media)
314     return PJ_TRUE;
315 }
316
317
318 /* Get the conference port identification associated with the call. */
319 PJ_DEF(pjsua_conf_port_id) pjsua_call_get_conf_port(pjsua_call_id call_id)
320 {
321     UNIMPLEMENTED(pjsua_call_get_conf_port)
322     return PJSUA_INVALID_ID;
323 }
324
325 /* Get media stream info for the specified media index. */
326 PJ_DEF(pj_status_t) pjsua_call_get_stream_info( pjsua_call_id call_id,
327                                                 unsigned med_idx,
328                                                 pjsua_stream_info *psi)
329 {
330     pj_bzero(psi, sizeof(*psi));
331     UNIMPLEMENTED(pjsua_call_get_stream_info)
332     return PJ_ENOTSUP;
333 }
334
335 /* Get media stream statistic for the specified media index.  */
336 PJ_DEF(pj_status_t) pjsua_call_get_stream_stat( pjsua_call_id call_id,
337                                                 unsigned med_idx,
338                                                 pjsua_stream_stat *stat)
339 {
340     pj_bzero(stat, sizeof(*stat));
341     UNIMPLEMENTED(pjsua_call_get_stream_stat)
342     return PJ_ENOTSUP;
343 }
344
345 /*
346  * Send DTMF digits to remote using RFC 2833 payload formats.
347  */
348 PJ_DEF(pj_status_t) pjsua_call_dial_dtmf( pjsua_call_id call_id,
349                                           const pj_str_t *digits)
350 {
351     UNIMPLEMENTED(pjsua_call_dial_dtmf)
352     return PJ_ENOTSUP;
353 }
354
355 /*****************************************************************************
356  * Below are auxiliary API that we don't support (feel free to implement them
357  * with the other media stack)
358  */
359
360 /* Get maximum number of conference ports. */
361 PJ_DEF(unsigned) pjsua_conf_get_max_ports(void)
362 {
363     UNIMPLEMENTED(pjsua_conf_get_max_ports)
364     return 0xFF;
365 }
366
367 /* Get current number of active ports in the bridge. */
368 PJ_DEF(unsigned) pjsua_conf_get_active_ports(void)
369 {
370     UNIMPLEMENTED(pjsua_conf_get_active_ports)
371     return 0;
372 }
373
374 /* Enumerate all conference ports. */
375 PJ_DEF(pj_status_t) pjsua_enum_conf_ports(pjsua_conf_port_id id[],
376                                           unsigned *count)
377 {
378     *count = 0;
379     UNIMPLEMENTED(pjsua_enum_conf_ports)
380     return PJ_ENOTSUP;
381 }
382
383 /* Get information about the specified conference port */
384 PJ_DEF(pj_status_t) pjsua_conf_get_port_info( pjsua_conf_port_id id,
385                                               pjsua_conf_port_info *info)
386 {
387     UNIMPLEMENTED(pjsua_conf_get_port_info)
388     return PJ_ENOTSUP;
389 }
390
391 /* Add arbitrary media port to PJSUA's conference bridge. */
392 PJ_DEF(pj_status_t) pjsua_conf_add_port( pj_pool_t *pool,
393                                          pjmedia_port *port,
394                                          pjsua_conf_port_id *p_id)
395 {
396     *p_id = PJSUA_INVALID_ID;
397     UNIMPLEMENTED(pjsua_conf_add_port)
398     /* We should return PJ_ENOTSUP here, but this API is needed by pjsua
399      * application or otherwise it will refuse to start.
400      */
401     return PJ_SUCCESS;
402 }
403
404 /* Remove arbitrary slot from the conference bridge. */
405 PJ_DEF(pj_status_t) pjsua_conf_remove_port(pjsua_conf_port_id id)
406 {
407     UNIMPLEMENTED(pjsua_conf_remove_port)
408     return PJ_ENOTSUP;
409 }
410
411 /* Establish unidirectional media flow from souce to sink. */
412 PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id source,
413                                         pjsua_conf_port_id sink)
414 {
415     UNIMPLEMENTED(pjsua_conf_connect)
416     return PJ_ENOTSUP;
417 }
418
419 /* Disconnect media flow from the source to destination port. */
420 PJ_DEF(pj_status_t) pjsua_conf_disconnect( pjsua_conf_port_id source,
421                                            pjsua_conf_port_id sink)
422 {
423     UNIMPLEMENTED(pjsua_conf_disconnect)
424     return PJ_ENOTSUP;
425 }
426
427 /* Adjust the signal level to be transmitted from the bridge to the
428  * specified port by making it louder or quieter.
429  */
430 PJ_DEF(pj_status_t) pjsua_conf_adjust_tx_level(pjsua_conf_port_id slot,
431                                                float level)
432 {
433     UNIMPLEMENTED(pjsua_conf_adjust_tx_level)
434     return PJ_ENOTSUP;
435 }
436
437 /* Adjust the signal level to be received from the specified port (to
438  * the bridge) by making it louder or quieter.
439  */
440 PJ_DEF(pj_status_t) pjsua_conf_adjust_rx_level(pjsua_conf_port_id slot,
441                                                float level)
442 {
443     UNIMPLEMENTED(pjsua_conf_adjust_rx_level)
444     return PJ_ENOTSUP;
445 }
446
447
448 /* Get last signal level transmitted to or received from the specified port. */
449 PJ_DEF(pj_status_t) pjsua_conf_get_signal_level(pjsua_conf_port_id slot,
450                                                 unsigned *tx_level,
451                                                 unsigned *rx_level)
452 {
453     UNIMPLEMENTED(pjsua_conf_get_signal_level)
454     return PJ_ENOTSUP;
455 }
456
457 /* Create a file player, and automatically connect this player to
458  * the conference bridge.
459  */
460 PJ_DEF(pj_status_t) pjsua_player_create( const pj_str_t *filename,
461                                          unsigned options,
462                                          pjsua_player_id *p_id)
463 {
464     UNIMPLEMENTED(pjsua_player_create)
465     return PJ_ENOTSUP;
466 }
467
468 /* Create a file playlist media port, and automatically add the port
469  * to the conference bridge.
470  */
471 PJ_DEF(pj_status_t) pjsua_playlist_create( const pj_str_t file_names[],
472                                            unsigned file_count,
473                                            const pj_str_t *label,
474                                            unsigned options,
475                                            pjsua_player_id *p_id)
476 {
477     UNIMPLEMENTED(pjsua_playlist_create)
478     return PJ_ENOTSUP;
479 }
480
481 /* Get conference port ID associated with player. */
482 PJ_DEF(pjsua_conf_port_id) pjsua_player_get_conf_port(pjsua_player_id id)
483 {
484     UNIMPLEMENTED(pjsua_player_get_conf_port)
485     return -1;
486 }
487
488 /* Get the media port for the player. */
489 PJ_DEF(pj_status_t) pjsua_player_get_port( pjsua_player_id id,
490                                            pjmedia_port **p_port)
491 {
492     UNIMPLEMENTED(pjsua_player_get_port)
493     return PJ_ENOTSUP;
494 }
495
496 /* Set playback position. */
497 PJ_DEF(pj_status_t) pjsua_player_set_pos( pjsua_player_id id,
498                                           pj_uint32_t samples)
499 {
500     UNIMPLEMENTED(pjsua_player_set_pos)
501     return PJ_ENOTSUP;
502 }
503
504 /* Close the file, remove the player from the bridge, and free
505  * resources associated with the file player.
506  */
507 PJ_DEF(pj_status_t) pjsua_player_destroy(pjsua_player_id id)
508 {
509     UNIMPLEMENTED(pjsua_player_destroy)
510     return PJ_ENOTSUP;
511 }
512
513 /* Create a file recorder, and automatically connect this recorder to
514  * the conference bridge.
515  */
516 PJ_DEF(pj_status_t) pjsua_recorder_create( const pj_str_t *filename,
517                                            unsigned enc_type,
518                                            void *enc_param,
519                                            pj_ssize_t max_size,
520                                            unsigned options,
521                                            pjsua_recorder_id *p_id)
522 {
523     UNIMPLEMENTED(pjsua_recorder_create)
524     return PJ_ENOTSUP;
525 }
526
527
528 /* Get conference port associated with recorder. */
529 PJ_DEF(pjsua_conf_port_id) pjsua_recorder_get_conf_port(pjsua_recorder_id id)
530 {
531     UNIMPLEMENTED(pjsua_recorder_get_conf_port)
532     return -1;
533 }
534
535 /* Get the media port for the recorder. */
536 PJ_DEF(pj_status_t) pjsua_recorder_get_port( pjsua_recorder_id id,
537                                              pjmedia_port **p_port)
538 {
539     UNIMPLEMENTED(pjsua_recorder_get_port)
540     return PJ_ENOTSUP;
541 }
542
543 /* Destroy recorder (this will complete recording). */
544 PJ_DEF(pj_status_t) pjsua_recorder_destroy(pjsua_recorder_id id)
545 {
546     UNIMPLEMENTED(pjsua_recorder_destroy)
547     return PJ_ENOTSUP;
548 }
549
550 /* Enum sound devices. */
551 PJ_DEF(pj_status_t) pjsua_enum_aud_devs( pjmedia_aud_dev_info info[],
552                                          unsigned *count)
553 {
554     UNIMPLEMENTED(pjsua_enum_aud_devs)
555     return PJ_ENOTSUP;
556 }
557
558 PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_snd_dev_info info[],
559                                          unsigned *count)
560 {
561     UNIMPLEMENTED(pjsua_enum_snd_devs)
562     return PJ_ENOTSUP;
563 }
564
565 /* Select or change sound device. */
566 PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev, int playback_dev)
567 {
568     UNIMPLEMENTED(pjsua_set_snd_dev)
569     return PJ_SUCCESS;
570 }
571
572 /* Get currently active sound devices. */
573 PJ_DEF(pj_status_t) pjsua_get_snd_dev(int *capture_dev, int *playback_dev)
574 {
575     *capture_dev = *playback_dev = PJSUA_INVALID_ID;
576     UNIMPLEMENTED(pjsua_get_snd_dev)
577     return PJ_ENOTSUP;
578 }
579
580 /* Use null sound device. */
581 PJ_DEF(pj_status_t) pjsua_set_null_snd_dev(void)
582 {
583     UNIMPLEMENTED(pjsua_set_null_snd_dev)
584     return PJ_ENOTSUP;
585 }
586
587 /* Use no device! */
588 PJ_DEF(pjmedia_port*) pjsua_set_no_snd_dev(void)
589 {
590     UNIMPLEMENTED(pjsua_set_no_snd_dev)
591     return NULL;
592 }
593
594 /* Configure the AEC settings of the sound port. */
595 PJ_DEF(pj_status_t) pjsua_set_ec(unsigned tail_ms, unsigned options)
596 {
597     UNIMPLEMENTED(pjsua_set_ec)
598     return PJ_ENOTSUP;
599 }
600
601 /* Get current AEC tail length. */
602 PJ_DEF(pj_status_t) pjsua_get_ec_tail(unsigned *p_tail_ms)
603 {
604     UNIMPLEMENTED(pjsua_get_ec_tail)
605     return PJ_ENOTSUP;
606 }
607
608 /* Check whether the sound device is currently active. */
609 PJ_DEF(pj_bool_t) pjsua_snd_is_active(void)
610 {
611     UNIMPLEMENTED(pjsua_snd_is_active)
612     return PJ_FALSE;
613 }
614
615 /* Configure sound device setting to the sound device being used. */
616 PJ_DEF(pj_status_t) pjsua_snd_set_setting( pjmedia_aud_dev_cap cap,
617                                            const void *pval, pj_bool_t keep)
618 {
619     UNIMPLEMENTED(pjsua_snd_set_setting)
620     return PJ_ENOTSUP;
621 }
622
623 /* Retrieve a sound device setting. */
624 PJ_DEF(pj_status_t) pjsua_snd_get_setting(pjmedia_aud_dev_cap cap, void *pval)
625 {
626     UNIMPLEMENTED(pjsua_snd_get_setting)
627     return PJ_ENOTSUP;
628 }