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