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 
alt_codec_test_alloc(pjmedia_codec_factory * factory,const pjmedia_codec_info * id)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 
alt_codec_default_attr(pjmedia_codec_factory * factory,const pjmedia_codec_info * id,pjmedia_codec_param * attr)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 
alt_codec_enum_codecs(pjmedia_codec_factory * factory,unsigned * count,pjmedia_codec_info codecs[])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 
alt_codec_alloc_codec(pjmedia_codec_factory * factory,const pjmedia_codec_info * id,pjmedia_codec ** p_codec)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 
alt_codec_dealloc_codec(pjmedia_codec_factory * factory,pjmedia_codec * codec)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 
alt_codec_deinit(void)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. */
pjsua_aud_subsys_init()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. */
pjsua_aud_subsys_start(void)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. */
pjsua_aud_subsys_destroy()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 */
aud_rtp_cb(void * user_data,void * pkt,pj_ssize_t size)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 */
aud_rtcp_cb(void * user_data,void * pkt,pj_ssize_t size)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  */
timer_to_send_aud_rtp(void * user_data)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 || !call_med->call->inv || !call_med->tp) {
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 
timer_to_send_aud_rtcp(void * user_data)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 || !call_med->call->inv || !call_med->tp) {
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. */
pjsua_aud_stop_stream(pjsua_call_media * call_med)255 void pjsua_aud_stop_stream(pjsua_call_media *call_med)
256 {
257     /* Detach our RTP/RTCP callbacks from transport */
258     if (call_med->tp) {
259     	pjmedia_transport_detach(call_med->tp, call_med);
260     }
261 
262     /* TODO: destroy your audio stream here */
263 }
264 
265 /*
266  * This function is called whenever SDP negotiation has completed
267  * successfully. Here you'd want to start your audio stream
268  * based on the info in the SDPs.
269  */
pjsua_aud_channel_update(pjsua_call_media * call_med,pj_pool_t * tmp_pool,pjmedia_stream_info * si,const pjmedia_sdp_session * local_sdp,const pjmedia_sdp_session * remote_sdp)270 pj_status_t pjsua_aud_channel_update(pjsua_call_media *call_med,
271                                      pj_pool_t *tmp_pool,
272                                      pjmedia_stream_info *si,
273 				     const pjmedia_sdp_session *local_sdp,
274 				     const pjmedia_sdp_session *remote_sdp)
275 {
276     pj_status_t status = PJ_SUCCESS;
277 
278     PJ_LOG(4,(THIS_FILE,"Alt audio channel update.."));
279     pj_log_push_indent();
280 
281     /* Check if no media is active */
282     if (si->dir != PJMEDIA_DIR_NONE) {
283 	/* Attach our RTP and RTCP callbacks to the media transport */
284 	status = pjmedia_transport_attach(call_med->tp, call_med,
285 	                                  &si->rem_addr, &si->rem_rtcp,
286 	                                  pj_sockaddr_get_len(&si->rem_addr),
287 	                                  &aud_rtp_cb, &aud_rtcp_cb);
288 
289 	/* For a demonstration, let's use a timer to send "RTP" packet
290 	 * periodically.
291 	 */
292 	pjsua_schedule_timer2(&timer_to_send_aud_rtp, call_med, 0);
293 	pjsua_schedule_timer2(&timer_to_send_aud_rtcp, call_med, 2500);
294 
295 	/* TODO:
296 	 *   - Create and start your media stream based on the parameters
297 	 *     in si
298 	 */
299     }
300 
301 on_return:
302     pj_log_pop_indent();
303     return status;
304 }
305 
pjsua_check_snd_dev_idle()306 void pjsua_check_snd_dev_idle()
307 {
308 }
309 
310 /*****************************************************************************
311  *
312  * Call API which MAY need to be re-implemented if different backend is used.
313  */
314 
315 /* Check if call has an active media session. */
pjsua_call_has_media(pjsua_call_id call_id)316 PJ_DEF(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id)
317 {
318     UNIMPLEMENTED(pjsua_call_has_media)
319     return PJ_TRUE;
320 }
321 
322 
323 /* Get the conference port identification associated with the call. */
pjsua_call_get_conf_port(pjsua_call_id call_id)324 PJ_DEF(pjsua_conf_port_id) pjsua_call_get_conf_port(pjsua_call_id call_id)
325 {
326     UNIMPLEMENTED(pjsua_call_get_conf_port)
327     return PJSUA_INVALID_ID;
328 }
329 
330 /* Get media stream info for the specified media index. */
pjsua_call_get_stream_info(pjsua_call_id call_id,unsigned med_idx,pjsua_stream_info * psi)331 PJ_DEF(pj_status_t) pjsua_call_get_stream_info( pjsua_call_id call_id,
332                                                 unsigned med_idx,
333                                                 pjsua_stream_info *psi)
334 {
335     pj_bzero(psi, sizeof(*psi));
336     UNIMPLEMENTED(pjsua_call_get_stream_info)
337     return PJ_ENOTSUP;
338 }
339 
340 /* Get media stream statistic for the specified media index.  */
pjsua_call_get_stream_stat(pjsua_call_id call_id,unsigned med_idx,pjsua_stream_stat * stat)341 PJ_DEF(pj_status_t) pjsua_call_get_stream_stat( pjsua_call_id call_id,
342                                                 unsigned med_idx,
343                                                 pjsua_stream_stat *stat)
344 {
345     pj_bzero(stat, sizeof(*stat));
346     UNIMPLEMENTED(pjsua_call_get_stream_stat)
347     return PJ_ENOTSUP;
348 }
349 
350 /*
351  * Send DTMF digits to remote using RFC 2833 payload formats.
352  */
pjsua_call_dial_dtmf(pjsua_call_id call_id,const pj_str_t * digits)353 PJ_DEF(pj_status_t) pjsua_call_dial_dtmf( pjsua_call_id call_id,
354 					  const pj_str_t *digits)
355 {
356     UNIMPLEMENTED(pjsua_call_dial_dtmf)
357     return PJ_ENOTSUP;
358 }
359 
360 /*****************************************************************************
361  * Below are auxiliary API that we don't support (feel free to implement them
362  * with the other media stack)
363  */
364 
365 /* Get maximum number of conference ports. */
pjsua_conf_get_max_ports(void)366 PJ_DEF(unsigned) pjsua_conf_get_max_ports(void)
367 {
368     UNIMPLEMENTED(pjsua_conf_get_max_ports)
369     return 0xFF;
370 }
371 
372 /* Get current number of active ports in the bridge. */
pjsua_conf_get_active_ports(void)373 PJ_DEF(unsigned) pjsua_conf_get_active_ports(void)
374 {
375     UNIMPLEMENTED(pjsua_conf_get_active_ports)
376     return 0;
377 }
378 
379 /* Enumerate all conference ports. */
pjsua_enum_conf_ports(pjsua_conf_port_id id[],unsigned * count)380 PJ_DEF(pj_status_t) pjsua_enum_conf_ports(pjsua_conf_port_id id[],
381 					  unsigned *count)
382 {
383     *count = 0;
384     UNIMPLEMENTED(pjsua_enum_conf_ports)
385     return PJ_ENOTSUP;
386 }
387 
388 /* Get information about the specified conference port */
pjsua_conf_get_port_info(pjsua_conf_port_id id,pjsua_conf_port_info * info)389 PJ_DEF(pj_status_t) pjsua_conf_get_port_info( pjsua_conf_port_id id,
390 					      pjsua_conf_port_info *info)
391 {
392     UNIMPLEMENTED(pjsua_conf_get_port_info)
393     return PJ_ENOTSUP;
394 }
395 
396 /* Add arbitrary media port to PJSUA's conference bridge. */
pjsua_conf_add_port(pj_pool_t * pool,pjmedia_port * port,pjsua_conf_port_id * p_id)397 PJ_DEF(pj_status_t) pjsua_conf_add_port( pj_pool_t *pool,
398 					 pjmedia_port *port,
399 					 pjsua_conf_port_id *p_id)
400 {
401     *p_id = PJSUA_INVALID_ID;
402     UNIMPLEMENTED(pjsua_conf_add_port)
403     /* We should return PJ_ENOTSUP here, but this API is needed by pjsua
404      * application or otherwise it will refuse to start.
405      */
406     return PJ_SUCCESS;
407 }
408 
409 /* Remove arbitrary slot from the conference bridge. */
pjsua_conf_remove_port(pjsua_conf_port_id id)410 PJ_DEF(pj_status_t) pjsua_conf_remove_port(pjsua_conf_port_id id)
411 {
412     UNIMPLEMENTED(pjsua_conf_remove_port)
413     return PJ_ENOTSUP;
414 }
415 
416 /* Establish unidirectional media flow from souce to sink. */
pjsua_conf_connect(pjsua_conf_port_id source,pjsua_conf_port_id sink)417 PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id source,
418 					pjsua_conf_port_id sink)
419 {
420     UNIMPLEMENTED(pjsua_conf_connect)
421     return PJ_ENOTSUP;
422 }
423 
424 /* Disconnect media flow from the source to destination port. */
pjsua_conf_disconnect(pjsua_conf_port_id source,pjsua_conf_port_id sink)425 PJ_DEF(pj_status_t) pjsua_conf_disconnect( pjsua_conf_port_id source,
426 					   pjsua_conf_port_id sink)
427 {
428     UNIMPLEMENTED(pjsua_conf_disconnect)
429     return PJ_ENOTSUP;
430 }
431 
432 /* Adjust the signal level to be transmitted from the bridge to the
433  * specified port by making it louder or quieter.
434  */
pjsua_conf_adjust_tx_level(pjsua_conf_port_id slot,float level)435 PJ_DEF(pj_status_t) pjsua_conf_adjust_tx_level(pjsua_conf_port_id slot,
436 					       float level)
437 {
438     UNIMPLEMENTED(pjsua_conf_adjust_tx_level)
439     return PJ_ENOTSUP;
440 }
441 
442 /* Adjust the signal level to be received from the specified port (to
443  * the bridge) by making it louder or quieter.
444  */
pjsua_conf_adjust_rx_level(pjsua_conf_port_id slot,float level)445 PJ_DEF(pj_status_t) pjsua_conf_adjust_rx_level(pjsua_conf_port_id slot,
446 					       float level)
447 {
448     UNIMPLEMENTED(pjsua_conf_adjust_rx_level)
449     return PJ_ENOTSUP;
450 }
451 
452 
453 /* Get last signal level transmitted to or received from the specified port. */
pjsua_conf_get_signal_level(pjsua_conf_port_id slot,unsigned * tx_level,unsigned * rx_level)454 PJ_DEF(pj_status_t) pjsua_conf_get_signal_level(pjsua_conf_port_id slot,
455 						unsigned *tx_level,
456 						unsigned *rx_level)
457 {
458     UNIMPLEMENTED(pjsua_conf_get_signal_level)
459     return PJ_ENOTSUP;
460 }
461 
462 /* Create a file player, and automatically connect this player to
463  * the conference bridge.
464  */
pjsua_player_create(const pj_str_t * filename,unsigned options,pjsua_player_id * p_id)465 PJ_DEF(pj_status_t) pjsua_player_create( const pj_str_t *filename,
466 					 unsigned options,
467 					 pjsua_player_id *p_id)
468 {
469     UNIMPLEMENTED(pjsua_player_create)
470     return PJ_ENOTSUP;
471 }
472 
473 /* Create a file playlist media port, and automatically add the port
474  * to the conference bridge.
475  */
pjsua_playlist_create(const pj_str_t file_names[],unsigned file_count,const pj_str_t * label,unsigned options,pjsua_player_id * p_id)476 PJ_DEF(pj_status_t) pjsua_playlist_create( const pj_str_t file_names[],
477 					   unsigned file_count,
478 					   const pj_str_t *label,
479 					   unsigned options,
480 					   pjsua_player_id *p_id)
481 {
482     UNIMPLEMENTED(pjsua_playlist_create)
483     return PJ_ENOTSUP;
484 }
485 
486 /* Get conference port ID associated with player. */
pjsua_player_get_conf_port(pjsua_player_id id)487 PJ_DEF(pjsua_conf_port_id) pjsua_player_get_conf_port(pjsua_player_id id)
488 {
489     UNIMPLEMENTED(pjsua_player_get_conf_port)
490     return -1;
491 }
492 
493 /* Get the media port for the player. */
pjsua_player_get_port(pjsua_player_id id,pjmedia_port ** p_port)494 PJ_DEF(pj_status_t) pjsua_player_get_port( pjsua_player_id id,
495 					   pjmedia_port **p_port)
496 {
497     UNIMPLEMENTED(pjsua_player_get_port)
498     return PJ_ENOTSUP;
499 }
500 
501 /* Get number of bits per sample of the WAV payload */
pjsua_player_get_info(pjsua_player_id id,pjmedia_wav_player_info * info)502 PJ_DEF(pj_status_t) pjsua_player_get_info(pjsua_player_id id,
503                                           pjmedia_wav_player_info *info)
504 {
505     UNIMPLEMENTED(pjsua_player_get_info)
506     return PJ_ENOTSUP;
507 }
508 
509 /* Get position in samples */
pjsua_player_get_pos(pjsua_player_id id)510 PJ_DEF(pj_ssize_t) pjsua_player_get_pos(pjsua_player_id id)
511 {
512     UNIMPLEMENTED(pjsua_player_get_pos)
513     return -PJ_ENOTSUP;
514 }
515 
516 /* Set playback position. */
pjsua_player_set_pos(pjsua_player_id id,pj_uint32_t samples)517 PJ_DEF(pj_status_t) pjsua_player_set_pos( pjsua_player_id id,
518 					  pj_uint32_t samples)
519 {
520     UNIMPLEMENTED(pjsua_player_set_pos)
521     return PJ_ENOTSUP;
522 }
523 
524 /* Close the file, remove the player from the bridge, and free
525  * resources associated with the file player.
526  */
pjsua_player_destroy(pjsua_player_id id)527 PJ_DEF(pj_status_t) pjsua_player_destroy(pjsua_player_id id)
528 {
529     UNIMPLEMENTED(pjsua_player_destroy)
530     return PJ_ENOTSUP;
531 }
532 
533 /* Create a file recorder, and automatically connect this recorder to
534  * the conference bridge.
535  */
pjsua_recorder_create(const pj_str_t * filename,unsigned enc_type,void * enc_param,pj_ssize_t max_size,unsigned options,pjsua_recorder_id * p_id)536 PJ_DEF(pj_status_t) pjsua_recorder_create( const pj_str_t *filename,
537 					   unsigned enc_type,
538 					   void *enc_param,
539 					   pj_ssize_t max_size,
540 					   unsigned options,
541 					   pjsua_recorder_id *p_id)
542 {
543     UNIMPLEMENTED(pjsua_recorder_create)
544     return PJ_ENOTSUP;
545 }
546 
547 
548 /* Get conference port associated with recorder. */
pjsua_recorder_get_conf_port(pjsua_recorder_id id)549 PJ_DEF(pjsua_conf_port_id) pjsua_recorder_get_conf_port(pjsua_recorder_id id)
550 {
551     UNIMPLEMENTED(pjsua_recorder_get_conf_port)
552     return -1;
553 }
554 
555 /* Get the media port for the recorder. */
pjsua_recorder_get_port(pjsua_recorder_id id,pjmedia_port ** p_port)556 PJ_DEF(pj_status_t) pjsua_recorder_get_port( pjsua_recorder_id id,
557 					     pjmedia_port **p_port)
558 {
559     UNIMPLEMENTED(pjsua_recorder_get_port)
560     return PJ_ENOTSUP;
561 }
562 
563 /* Destroy recorder (this will complete recording). */
pjsua_recorder_destroy(pjsua_recorder_id id)564 PJ_DEF(pj_status_t) pjsua_recorder_destroy(pjsua_recorder_id id)
565 {
566     UNIMPLEMENTED(pjsua_recorder_destroy)
567     return PJ_ENOTSUP;
568 }
569 
570 /* Enum sound devices. */
pjsua_enum_aud_devs(pjmedia_aud_dev_info info[],unsigned * count)571 PJ_DEF(pj_status_t) pjsua_enum_aud_devs( pjmedia_aud_dev_info info[],
572 					 unsigned *count)
573 {
574     UNIMPLEMENTED(pjsua_enum_aud_devs)
575     return PJ_ENOTSUP;
576 }
577 
pjsua_enum_snd_devs(pjmedia_snd_dev_info info[],unsigned * count)578 PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_snd_dev_info info[],
579 					 unsigned *count)
580 {
581     UNIMPLEMENTED(pjsua_enum_snd_devs)
582     return PJ_ENOTSUP;
583 }
584 
585 /* Select or change sound device. */
pjsua_set_snd_dev(int capture_dev,int playback_dev)586 PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev, int playback_dev)
587 {
588     UNIMPLEMENTED(pjsua_set_snd_dev)
589     return PJ_SUCCESS;
590 }
591 
592 /* Get currently active sound devices. */
pjsua_get_snd_dev(int * capture_dev,int * playback_dev)593 PJ_DEF(pj_status_t) pjsua_get_snd_dev(int *capture_dev, int *playback_dev)
594 {
595     *capture_dev = *playback_dev = PJSUA_INVALID_ID;
596     UNIMPLEMENTED(pjsua_get_snd_dev)
597     return PJ_ENOTSUP;
598 }
599 
600 /* Use null sound device. */
pjsua_set_null_snd_dev(void)601 PJ_DEF(pj_status_t) pjsua_set_null_snd_dev(void)
602 {
603     UNIMPLEMENTED(pjsua_set_null_snd_dev)
604     return PJ_ENOTSUP;
605 }
606 
607 /* Use no device! */
pjsua_set_no_snd_dev(void)608 PJ_DEF(pjmedia_port*) pjsua_set_no_snd_dev(void)
609 {
610     UNIMPLEMENTED(pjsua_set_no_snd_dev)
611     return NULL;
612 }
613 
614 /* Configure the AEC settings of the sound port. */
pjsua_set_ec(unsigned tail_ms,unsigned options)615 PJ_DEF(pj_status_t) pjsua_set_ec(unsigned tail_ms, unsigned options)
616 {
617     UNIMPLEMENTED(pjsua_set_ec)
618     return PJ_ENOTSUP;
619 }
620 
621 /* Get current AEC tail length. */
pjsua_get_ec_tail(unsigned * p_tail_ms)622 PJ_DEF(pj_status_t) pjsua_get_ec_tail(unsigned *p_tail_ms)
623 {
624     UNIMPLEMENTED(pjsua_get_ec_tail)
625     return PJ_ENOTSUP;
626 }
627 
628 /* Check whether the sound device is currently active. */
pjsua_snd_is_active(void)629 PJ_DEF(pj_bool_t) pjsua_snd_is_active(void)
630 {
631     UNIMPLEMENTED(pjsua_snd_is_active)
632     return PJ_FALSE;
633 }
634 
635 /* Configure sound device setting to the sound device being used. */
pjsua_snd_set_setting(pjmedia_aud_dev_cap cap,const void * pval,pj_bool_t keep)636 PJ_DEF(pj_status_t) pjsua_snd_set_setting( pjmedia_aud_dev_cap cap,
637 					   const void *pval, pj_bool_t keep)
638 {
639     UNIMPLEMENTED(pjsua_snd_set_setting)
640     return PJ_ENOTSUP;
641 }
642 
643 /* Retrieve a sound device setting. */
pjsua_snd_get_setting(pjmedia_aud_dev_cap cap,void * pval)644 PJ_DEF(pj_status_t) pjsua_snd_get_setting(pjmedia_aud_dev_cap cap, void *pval)
645 {
646     UNIMPLEMENTED(pjsua_snd_get_setting)
647     return PJ_ENOTSUP;
648 }
649