1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License `
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  * Moises Silva <moises.silva@gmail.com> (Multiple endpoints work sponsored by Comrex Corporation)
28  * Raymond Chandler <intralanman@freeswitch.org>
29  *
30  *
31  * mod_portaudio.c -- PortAudio Endpoint Module
32  *
33  */
34 
35 #include "switch.h"
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <math.h>
40 #include <string.h>
41 #include "pablio.h"
42 
43 #define MY_EVENT_RINGING "portaudio::ringing"
44 #define MY_EVENT_MAKE_CALL "portaudio::makecall"
45 #define MY_EVENT_CALL_HELD "portaudio::callheld"
46 #define MY_EVENT_CALL_RESUMED "portaudio::callresumed"
47 #define MY_EVENT_ERROR_AUDIO_DEV "portaudio::audio_dev_error"
48 #define SWITCH_PA_CALL_ID_VARIABLE "pa_call_id"
49 
50 #define MIN_STREAM_SAMPLE_RATE 8000
51 #define STREAM_SAMPLES_PER_PACKET(stream) ((stream->codec_ms * stream->sample_rate) / 1000)
52 
53 SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load);
54 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_shutdown);
55 //SWITCH_MODULE_RUNTIME_FUNCTION(mod_portaudio_runtime);
56 SWITCH_MODULE_DEFINITION(mod_portaudio, mod_portaudio_load, mod_portaudio_shutdown, NULL);
57 
58 static switch_memory_pool_t *module_pool = NULL;
59 switch_endpoint_interface_t *portaudio_endpoint_interface;
60 
61 #define SAMPLE_TYPE  paInt16
62 typedef int16_t SAMPLE;
63 
64 typedef switch_status_t (*pa_command_t) (char **argv, int argc, switch_stream_handle_t *stream);
65 
66 typedef enum {
67 	GFLAG_NONE = 0,
68 	GFLAG_EAR = (1 << 0),
69 	GFLAG_MOUTH = (1 << 1),
70 	GFLAG_RING = (1 << 2)
71 } GFLAGS;
72 
73 typedef enum {
74 	TFLAG_IO = (1 << 0),
75 	TFLAG_INBOUND = (1 << 1),
76 	TFLAG_OUTBOUND = (1 << 2),
77 	TFLAG_DTMF = (1 << 3),
78 	TFLAG_VOICE = (1 << 4),
79 	TFLAG_HANGUP = (1 << 5),
80 	TFLAG_LINEAR = (1 << 6),
81 	TFLAG_ANSWER = (1 << 7),
82 	TFLAG_HUP = (1 << 8),
83 	TFLAG_MASTER = (1 << 9),
84 	TFLAG_AUTO_ANSWER = (1 << 10)
85 } TFLAGS;
86 
87 struct audio_stream {
88 	int indev;
89 	int outdev;
90 	PABLIO_Stream *stream;
91 	switch_timer_t write_timer;
92 	struct audio_stream *next;
93 };
94 typedef struct audio_stream audio_stream_t;
95 
96 /* Audio stream that can be shared across endpoints */
97 typedef struct _shared_audio_stream_t {
98 	/*! Friendly name for this stream */
99 	char name[255];
100 	/*! Sampling rate */
101 	int sample_rate;
102 	/*! Buffer packetization (and therefore timing) */
103 	int codec_ms;
104 	/*! The PA input device */
105 	int indev;
106 	/*! Input channels being used */
107 	uint8_t inchan_used[MAX_IO_CHANNELS];
108 	/*! The PA output device */
109 	int outdev;
110 	/*! Output channels being used */
111 	uint8_t outchan_used[MAX_IO_CHANNELS];
112 	/*! How many channels to create (for both indev and outdev) */
113 	int channels;
114 	/*! The io stream helper to buffer audio */
115 	PABLIO_Stream *stream;
116 	/* It can be shared after all :-)  */
117 	switch_mutex_t *mutex;
118 } shared_audio_stream_t;
119 
120 typedef struct private_object private_t;
121 /* Endpoint that can be called via portaudio/endpoint/<endpoint-name> */
122 typedef struct _audio_endpoint {
123 	/*! Friendly name for this endpoint */
124 	char name[255];
125 
126 	/*! Input stream for this endpoint */
127 	shared_audio_stream_t *in_stream;
128 
129 	/*! Output stream for this endpoint */
130 	shared_audio_stream_t *out_stream;
131 
132 	/*! Channel index within the input stream where we get the audio for this endpoint */
133 	int inchan;
134 
135 	/*! Channel index within the output stream where we get the audio for this endpoint */
136 	int outchan;
137 
138 	/*! Associated private information if involved in a call */
139 	private_t *master;
140 
141 	/*! For timed read and writes */
142 	switch_timer_t read_timer;
143 	switch_timer_t write_timer;
144 
145 	/* We need our own read frame */
146 	switch_frame_t read_frame;
147 	unsigned char read_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
148 
149 	/* Needed codecs for the core to read/write in the proper format */
150 	switch_codec_t read_codec;
151 	switch_codec_t write_codec;
152 
153 	/*! Let's be safe */
154 	switch_mutex_t *mutex;
155 } audio_endpoint_t;
156 
157 struct private_object {
158 	unsigned int flags;
159 	switch_core_session_t *session;
160 	switch_caller_profile_t *caller_profile;
161 	char call_id[50];
162 	int sample_rate;
163 	int codec_ms;
164 	switch_mutex_t *flag_mutex;
165 	char *hold_file;
166 	switch_file_handle_t fh;
167 	switch_file_handle_t *hfh;
168 	switch_frame_t hold_frame;
169 	unsigned char holdbuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
170 	audio_endpoint_t *audio_endpoint;
171 	struct private_object *next;
172 };
173 
174 
175 static struct {
176 	int debug;
177 	int port;
178 	char *cid_name;
179 	char *cid_num;
180 	char *dialplan;
181 	char *context;
182 	char *ring_file;
183 	char *hold_file;
184 	char *timer_name;
185 	int ringdev;
186 	int indev;
187 	int outdev;
188 	int call_id;
189 	int unload_device_fail;
190 	switch_hash_t *call_hash;
191 	switch_mutex_t *device_lock;
192 	switch_mutex_t *pvt_lock;
193 	switch_mutex_t *streams_lock;
194 	switch_mutex_t *flag_mutex;
195 	switch_mutex_t *pa_mutex;
196 	int sample_rate;
197 	int codec_ms;
198 	audio_stream_t *main_stream;
199 	audio_stream_t *ring_stream;
200 	switch_codec_t read_codec;
201 	switch_codec_t write_codec;
202 	switch_frame_t read_frame;
203 	switch_frame_t cng_frame;
204 	unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
205 	unsigned char cngbuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
206 	private_t *call_list;
207 	audio_stream_t *stream_list;
208 	/*! Streams that can be used by multiple endpoints at the same time */
209 	switch_hash_t *sh_streams;
210 	/*! Endpoints configured */
211 	switch_hash_t *endpoints;
212 	int ring_interval;
213 	GFLAGS flags;
214 	switch_timer_t read_timer;
215 	switch_timer_t readfile_timer;
216 	switch_timer_t hold_timer;
217 	int dual_streams;
218 	time_t deactivate_timer;
219 	int live_stream_switch;
220 	int no_auto_resume_call;
221 	int no_ring_during_call;
222 	int codecs_inited;
223 	int stream_in_use; //only really used by playdev
224 	int destroying_streams;
225 } globals;
226 
227 
228 #define PA_MASTER 1
229 #define PA_SLAVE 0
230 
231 
232 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan);
233 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_context, globals.context);
234 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_cid_name, globals.cid_name);
235 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_cid_num, globals.cid_num);
236 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_ring_file, globals.ring_file);
237 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_hold_file, globals.hold_file);
238 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_timer_name, globals.timer_name);
239 #define is_master(t) switch_test_flag(t, TFLAG_MASTER)
240 
241 static void add_pvt(private_t *tech_pvt, int master);
242 static void remove_pvt(private_t *tech_pvt);
243 static switch_status_t channel_on_init(switch_core_session_t *session);
244 static switch_status_t channel_on_hangup(switch_core_session_t *session);
245 static switch_status_t channel_on_destroy(switch_core_session_t *session);
246 static switch_status_t channel_on_routing(switch_core_session_t *session);
247 static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
248 static switch_status_t channel_on_soft_execute(switch_core_session_t *session);
249 static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
250 													switch_caller_profile_t *outbound_profile,
251 													switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags,
252 													switch_call_cause_t *cancel_cause);
253 static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
254 static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
255 static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
256 
257 static switch_status_t create_codecs(int restart);
258 static void create_hold_event(private_t *tech_pvt, int unhold);
259 static audio_stream_t * find_audio_stream(int indev, int outdev, int already_locked);
260 static audio_stream_t * get_audio_stream(int indev, int outdev);
261 static audio_stream_t * create_audio_stream(int indev, int outdev);
262 PaError open_audio_stream(PABLIO_Stream **stream, const PaStreamParameters * inputParameters, const PaStreamParameters * outputParameters);
263 static switch_status_t switch_audio_stream();
264 static void add_stream(audio_stream_t *stream, int already_locked);
265 static void remove_stream(audio_stream_t *stream, int already_locked);
266 static switch_status_t destroy_audio_stream(int indev, int outdev);
267 static switch_status_t destroy_actual_stream(audio_stream_t *stream);
268 static void destroy_audio_streams();
269 static switch_status_t validate_main_audio_stream();
270 static switch_status_t validate_ring_audio_stream();
271 
272 static int dump_info(int verbose);
273 static switch_status_t load_config(void);
274 static int get_dev_by_name(char *name, int in);
275 static int get_dev_by_number(char *numstr, int in);
276 SWITCH_STANDARD_API(pa_cmd);
277 
278 /*
279    State methods they get called when the state changes to the specific state
280    returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
281    so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
282 */
channel_on_init(switch_core_session_t * session)283 static switch_status_t channel_on_init(switch_core_session_t *session)
284 {
285 	switch_channel_t *channel;
286 
287 	if (session) {
288 		if ((channel = switch_core_session_get_channel(session))) {
289 			switch_channel_set_flag(channel, CF_AUDIO);
290 		}
291 	}
292 
293 	return SWITCH_STATUS_SUCCESS;
294 }
295 
channel_on_routing(switch_core_session_t * session)296 static switch_status_t channel_on_routing(switch_core_session_t *session)
297 {
298 
299 	switch_channel_t *channel = switch_core_session_get_channel(session);
300 	private_t *tech_pvt = switch_core_session_get_private(session);
301 	switch_time_t last;
302 	int waitsec = globals.ring_interval * 1000000;
303 	switch_file_handle_t fh = { 0 };
304 	const char *val, *ring_file = NULL, *hold_file = NULL;
305 	int16_t abuf[2048];
306 
307 	switch_assert(tech_pvt != NULL);
308 
309 	last = switch_micro_time_now() - waitsec;
310 
311 	if ((val = switch_channel_get_variable(channel, "pa_hold_file"))) {
312 		hold_file = val;
313 	} else {
314 		hold_file = globals.hold_file;
315 	}
316 
317 	if (hold_file) {
318 		tech_pvt->hold_file = switch_core_session_strdup(session, hold_file);
319 	}
320 	if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
321 		if (!tech_pvt->audio_endpoint && validate_main_audio_stream() != SWITCH_STATUS_SUCCESS) {
322 			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
323 			return SWITCH_STATUS_FALSE;
324 		}
325 
326 		if (!tech_pvt->audio_endpoint &&
327 		    switch_test_flag(tech_pvt, TFLAG_OUTBOUND) &&
328 		    !switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) {
329 
330 			add_pvt(tech_pvt, PA_SLAVE);
331 
332 			ring_file = globals.ring_file;
333 			if ((val = switch_channel_get_variable(channel, "pa_ring_file"))) {
334 				ring_file = val;
335 			}
336 
337 			if (switch_test_flag((&globals), GFLAG_RING)) {
338 				ring_file = NULL;
339 			}
340 			switch_set_flag_locked((&globals), GFLAG_RING);
341 			if (ring_file) {
342 				if (switch_core_file_open(&fh,
343 										  ring_file,
344 										  globals.read_codec.implementation->number_of_channels,
345 										  globals.read_codec.implementation->actual_samples_per_second,
346 										  SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) == SWITCH_STATUS_SUCCESS) {
347 
348 					if (validate_ring_audio_stream() != SWITCH_STATUS_SUCCESS) {
349 						switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
350 						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Ring Error!\n");
351 						switch_core_file_close(&fh);
352 						return SWITCH_STATUS_GENERR;
353 					}
354 				} else {
355 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot open %s, disabling ring file!\n", ring_file);
356 					ring_file = NULL;
357 				}
358 			}
359 		}
360 
361 		if (tech_pvt->audio_endpoint || switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) {
362 			switch_mutex_lock(globals.pvt_lock);
363 			add_pvt(tech_pvt, PA_MASTER);
364 			if (switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) {
365 				switch_channel_mark_answered(channel);
366 				switch_set_flag(tech_pvt, TFLAG_ANSWER);
367 			}
368 			switch_mutex_unlock(globals.pvt_lock);
369 			switch_yield(1000000);
370 		} else {
371 			switch_channel_mark_ring_ready(channel);
372 		}
373 
374 		while (switch_channel_get_state(channel) == CS_ROUTING &&
375 		       !switch_channel_test_flag(channel, CF_ANSWERED) &&
376 		       !switch_test_flag(tech_pvt, TFLAG_ANSWER)) {
377 			switch_size_t olen = globals.readfile_timer.samples;
378 
379 			if (switch_micro_time_now() - last >= waitsec) {
380 				char buf[512];
381 				switch_event_t *event;
382 
383 				switch_snprintf(buf, sizeof(buf), "BRRRRING! BRRRRING! call %s\n", tech_pvt->call_id);
384 
385 				if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_RINGING) == SWITCH_STATUS_SUCCESS) {
386 					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_info", buf);
387 					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call_id", tech_pvt->call_id); /* left behind for backwards compatability */
388 					switch_channel_set_variable(channel, SWITCH_PA_CALL_ID_VARIABLE, tech_pvt->call_id);
389 					switch_channel_event_set_data(channel, event);
390 					switch_event_fire(&event);
391 				}
392 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s\n", buf);
393 				last = switch_micro_time_now();
394 			}
395 
396 			if (ring_file) {
397 				if (switch_core_timer_next(&globals.readfile_timer) != SWITCH_STATUS_SUCCESS) {
398 					switch_core_file_close(&fh);
399 					break;
400 				}
401 				switch_core_file_read(&fh, abuf, &olen);
402 				if (olen == 0) {
403 					unsigned int pos = 0;
404 					switch_core_file_seek(&fh, &pos, 0, SEEK_SET);
405 				}
406 
407 				if (globals.ring_stream && (! switch_test_flag(globals.call_list, TFLAG_MASTER) ||
408 							( !globals.no_ring_during_call && globals.main_stream != globals.ring_stream)) ) { //if there is a ring stream and not an active call or if there is an active call and we are allowed to ring during it AND the ring stream is not the main stream
409 						WriteAudioStream(globals.ring_stream->stream, abuf, (long) olen, 0, &globals.ring_stream->write_timer);
410 				}
411 			} else {
412 				switch_yield(10000);
413 			}
414 		}
415 		switch_clear_flag_locked((&globals), GFLAG_RING);
416 	}
417 
418 	if (ring_file) {
419 		switch_core_file_close(&fh);
420 	}
421 
422 	if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
423 		if (!switch_test_flag(tech_pvt, TFLAG_ANSWER) &&
424 		    !switch_channel_test_flag(channel, CF_ANSWERED)) {
425 			switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER);
426 			return SWITCH_STATUS_SUCCESS;
427 		}
428 		switch_set_flag(tech_pvt, TFLAG_ANSWER);
429 	}
430 
431 	switch_set_flag_locked(tech_pvt, TFLAG_IO);
432 
433 
434 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n",
435 					  switch_channel_get_name(switch_core_session_get_channel(session)));
436 	return SWITCH_STATUS_SUCCESS;
437 }
438 
channel_on_execute(switch_core_session_t * session)439 static switch_status_t channel_on_execute(switch_core_session_t *session)
440 {
441 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n",
442 					  switch_channel_get_name(switch_core_session_get_channel(session)));
443 	return SWITCH_STATUS_SUCCESS;
444 }
445 
find_audio_stream(int indev,int outdev,int already_locked)446 static audio_stream_t* find_audio_stream(int indev, int outdev, int already_locked)
447 {
448 	audio_stream_t *cur_stream;
449 
450 	if (! globals.stream_list) {
451 		return NULL;
452 	}
453 
454 	if (! already_locked) {
455 		switch_mutex_lock(globals.streams_lock);
456 	}
457 	cur_stream = globals.stream_list;
458 
459 	while (cur_stream != NULL) {
460 		if (cur_stream->outdev == outdev) {
461 			if (indev == -1 || cur_stream->indev == indev) {
462 				if (! already_locked) {
463 					switch_mutex_unlock(globals.streams_lock);
464 				}
465 				return cur_stream;
466 			}
467 		}
468 		cur_stream = cur_stream->next;
469 	}
470 	if (! already_locked) {
471 		switch_mutex_unlock(globals.streams_lock);
472 	}
473 	return NULL;
474 }
475 
destroy_audio_streams()476 static void destroy_audio_streams()
477 {
478 	int close_wait = 4;
479 	globals.destroying_streams = 1;
480 
481 	while (globals.stream_in_use && close_wait--) {
482 		switch_yield(250000);
483 	}
484 	while (globals.stream_list != NULL) {
485 		destroy_audio_stream(globals.stream_list->indev, globals.stream_list->outdev);
486 	}
487 	globals.destroying_streams = 0;
488 }
489 
validate_main_audio_stream()490 static switch_status_t validate_main_audio_stream()
491 {
492 	if (globals.read_timer.timer_interface) {
493 		switch_core_timer_sync(&globals.read_timer);
494 	}
495 
496 	if (globals.main_stream) {
497 		if (globals.main_stream->write_timer.timer_interface) {
498 			switch_core_timer_sync(&(globals.main_stream->write_timer));
499 		}
500 
501 		return SWITCH_STATUS_SUCCESS;
502 	}
503 
504 	globals.main_stream = get_audio_stream(globals.indev, globals.outdev);
505 
506 	if (globals.main_stream) {
507 		return SWITCH_STATUS_SUCCESS;
508 	}
509 
510 	return SWITCH_STATUS_FALSE;
511 }
512 
validate_ring_audio_stream()513 static switch_status_t validate_ring_audio_stream()
514 {
515 	if (globals.ringdev == -1) {
516 		return SWITCH_STATUS_SUCCESS;
517 	}
518 	if (globals.ring_stream) {
519 		if (globals.ring_stream->write_timer.timer_interface) {
520 			switch_core_timer_sync(&(globals.ring_stream->write_timer));
521 		}
522 		return SWITCH_STATUS_SUCCESS;
523 	}
524 	globals.ring_stream = get_audio_stream(-1, globals.ringdev);
525 	if (globals.ring_stream) {
526 		return SWITCH_STATUS_SUCCESS;
527 	}
528 
529 	return SWITCH_STATUS_FALSE;
530 }
531 
destroy_actual_stream(audio_stream_t * stream)532 static switch_status_t destroy_actual_stream(audio_stream_t *stream)
533 {
534 	if (stream == NULL) {
535 		return SWITCH_STATUS_FALSE;
536 	}
537 
538 	if (globals.main_stream == stream) {
539 		globals.main_stream = NULL;
540 	}
541 
542 	if (globals.ring_stream == stream) {
543 		globals.ring_stream = NULL;
544 	}
545 
546 	CloseAudioStream(stream->stream);
547 	stream->stream = NULL;
548 
549 	if (stream->write_timer.timer_interface) {
550 		switch_core_timer_destroy(&stream->write_timer);
551 	}
552 
553 	switch_safe_free(stream);
554 	return SWITCH_STATUS_SUCCESS;
555 }
destroy_audio_stream(int indev,int outdev)556 static switch_status_t destroy_audio_stream(int indev, int outdev)
557 {
558 	audio_stream_t *stream;
559 
560 	switch_mutex_lock(globals.streams_lock);
561 	stream = find_audio_stream(indev, outdev,1);
562 	if (stream == NULL) {
563 		switch_mutex_unlock(globals.streams_lock);
564 		return SWITCH_STATUS_FALSE;
565 	}
566 
567 	remove_stream(stream, 1);
568 	switch_mutex_unlock(globals.streams_lock);
569 
570 	destroy_actual_stream(stream);
571 	return SWITCH_STATUS_SUCCESS;
572 }
573 
574 
destroy_codecs(void)575 static void destroy_codecs(void)
576 {
577 
578 	if (switch_core_codec_ready(&globals.read_codec)) {
579 		switch_core_codec_destroy(&globals.read_codec);
580 	}
581 
582 	if (switch_core_codec_ready(&globals.write_codec)) {
583 		switch_core_codec_destroy(&globals.write_codec);
584 	}
585 
586 	if (globals.read_timer.timer_interface) {
587 		switch_core_timer_destroy(&globals.read_timer);
588 	}
589 
590 	if (globals.readfile_timer.timer_interface) {
591 		switch_core_timer_destroy(&globals.readfile_timer);
592 	}
593 
594 	if (globals.hold_timer.timer_interface) {
595 		switch_core_timer_destroy(&globals.hold_timer);
596 	}
597 
598 	globals.codecs_inited = 0;
599 }
600 
create_hold_event(private_t * tech_pvt,int unhold)601 static void create_hold_event(private_t *tech_pvt, int unhold)
602 {
603 	switch_event_t *event;
604 	char * event_id;
605 
606 	if (unhold) {
607 		event_id = MY_EVENT_CALL_RESUMED;
608 	} else {
609 		event_id = MY_EVENT_CALL_HELD;
610 	}
611 
612 	if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, event_id) == SWITCH_STATUS_SUCCESS) {
613 		switch_channel_event_set_data(switch_core_session_get_channel(tech_pvt->session), event);
614 		switch_event_fire(&event);
615 	}
616 }
617 
add_stream(audio_stream_t * stream,int already_locked)618 static void add_stream(audio_stream_t * stream, int already_locked)
619 {
620 	audio_stream_t *last;
621 
622 	if (! already_locked) {
623 		switch_mutex_lock(globals.streams_lock);
624 	}
625 	for (last = globals.stream_list; last && last->next; last = last->next);
626 	if (last == NULL) {
627 		globals.stream_list = stream;
628 	} else {
629 		last->next = stream;
630 	}
631 	if (! already_locked) {
632 		switch_mutex_unlock(globals.streams_lock);
633 	}
634 }
remove_stream(audio_stream_t * stream,int already_locked)635 static void remove_stream(audio_stream_t * stream, int already_locked)
636 {
637 	audio_stream_t *previous;
638 	if (! already_locked) {
639 		switch_mutex_lock(globals.streams_lock);
640 	}
641 	if (globals.stream_list == stream) {
642 		globals.stream_list = stream->next;
643 	} else {
644 		for (previous = globals.stream_list; previous && previous->next && previous->next != stream; previous = previous->next) {
645 			;
646 		}
647 		if (previous) {
648 			previous->next = stream->next;
649 		}
650 	}
651 	if (! already_locked) {
652 		switch_mutex_unlock(globals.streams_lock);
653 	}
654 }
655 
add_pvt(private_t * tech_pvt,int master)656 static void add_pvt(private_t *tech_pvt, int master)
657 {
658 	private_t *tp;
659 	uint8_t in_list = 0;
660 
661 	switch_mutex_lock(globals.pvt_lock);
662 
663 	if (*tech_pvt->call_id == '\0') {
664 		switch_mutex_lock(globals.pa_mutex);
665 		switch_snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", ++globals.call_id);
666 		switch_channel_set_variable(switch_core_session_get_channel(tech_pvt->session), SWITCH_PA_CALL_ID_VARIABLE, tech_pvt->call_id);
667 		switch_core_hash_insert(globals.call_hash, tech_pvt->call_id, tech_pvt);
668 		if (!tech_pvt->audio_endpoint) {
669 			switch_core_session_set_read_codec(tech_pvt->session, &globals.read_codec);
670 			switch_core_session_set_write_codec(tech_pvt->session, &globals.write_codec);
671 		}
672 		switch_mutex_unlock(globals.pa_mutex);
673 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Added call %s\n", tech_pvt->call_id);
674 	}
675 
676 	for (tp = globals.call_list; tp; tp = tp->next) {
677 		if (tp == tech_pvt) {
678 			in_list = 1;
679 		}
680 		if (master && switch_test_flag(tp, TFLAG_MASTER) ) {
681 			switch_clear_flag_locked(tp, TFLAG_MASTER);
682 			create_hold_event(tp, 0);
683 		}
684 	}
685 
686 
687 	if (master) {
688 		if (!in_list) {
689 			tech_pvt->next = globals.call_list;
690 			globals.call_list = tech_pvt;
691 		}
692 		switch_set_flag_locked(tech_pvt, TFLAG_MASTER);
693 
694 	} else if (!in_list) {
695 		for (tp = globals.call_list; tp && tp->next; tp = tp->next);
696 		if (tp) {
697 			tp->next = tech_pvt;
698 		} else {
699 			globals.call_list = tech_pvt;
700 		}
701 	}
702 
703 	switch_mutex_unlock(globals.pvt_lock);
704 }
705 
remove_pvt(private_t * tech_pvt)706 static void remove_pvt(private_t *tech_pvt)
707 {
708 	private_t *tp, *last = NULL;
709 	int was_master = 0;
710 
711 	switch_mutex_lock(globals.pvt_lock);
712 	for (tp = globals.call_list; tp; tp = tp->next) {
713 
714 		if (tp == tech_pvt) {
715 			if (switch_test_flag(tp, TFLAG_MASTER)) {
716 				switch_clear_flag_locked(tp, TFLAG_MASTER);
717 				was_master = 1;
718 			}
719 			if (last) {
720 				last->next = tp->next;
721 			} else {
722 				globals.call_list = tp->next;
723 			}
724 		}
725 		last = tp;
726 	}
727 
728 	if (globals.call_list) {
729 		if (was_master && ! globals.no_auto_resume_call) {
730 			switch_set_flag_locked(globals.call_list, TFLAG_MASTER);
731 			create_hold_event(globals.call_list, 1);
732 		}
733 	} else {
734 		globals.deactivate_timer = switch_epoch_time_now(NULL) + 2;
735 		destroy_audio_streams();
736 	}
737 
738 	switch_mutex_unlock(globals.pvt_lock);
739 }
740 
tech_close_file(private_t * tech_pvt)741 static void tech_close_file(private_t *tech_pvt)
742 {
743 	if (tech_pvt->hfh) {
744 		tech_pvt->hfh = NULL;
745 		switch_core_file_close(&tech_pvt->fh);
746 	}
747 }
748 
channel_on_destroy(switch_core_session_t * session)749 static switch_status_t channel_on_destroy(switch_core_session_t *session)
750 {
751 	//private_t *tech_pvt = switch_core_session_get_private(session);
752 	//switch_assert(tech_pvt != NULL);
753 	return SWITCH_STATUS_SUCCESS;
754 }
755 
756 static int release_stream_channel(shared_audio_stream_t *stream, int index, int input);
channel_on_hangup(switch_core_session_t * session)757 static switch_status_t channel_on_hangup(switch_core_session_t *session)
758 {
759 	private_t *tech_pvt = switch_core_session_get_private(session);
760 	switch_assert(tech_pvt != NULL);
761 
762 	if (tech_pvt->audio_endpoint) {
763 		audio_endpoint_t *endpoint = tech_pvt->audio_endpoint;
764 
765 		tech_pvt->audio_endpoint = NULL;
766 
767 		switch_mutex_lock(endpoint->mutex);
768 
769 		release_stream_channel(endpoint->in_stream, endpoint->inchan, 1);
770 		release_stream_channel(endpoint->out_stream, endpoint->outchan, 0);
771 		switch_core_timer_destroy(&endpoint->read_timer);
772 		switch_core_timer_destroy(&endpoint->write_timer);
773 		switch_core_codec_destroy(&endpoint->read_codec);
774 		switch_core_codec_destroy(&endpoint->write_codec);
775 		endpoint->master = NULL;
776 
777 		switch_mutex_unlock(endpoint->mutex);
778 	}
779 
780 	switch_mutex_lock(globals.pa_mutex);
781 	switch_core_hash_delete(globals.call_hash, tech_pvt->call_id);
782 	switch_mutex_unlock(globals.pa_mutex);
783 
784 	switch_clear_flag_locked(tech_pvt, TFLAG_IO);
785 	switch_set_flag_locked(tech_pvt, TFLAG_HUP);
786 
787 	remove_pvt(tech_pvt);
788 
789 	tech_close_file(tech_pvt);
790 
791 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n",
792 					  switch_channel_get_name(switch_core_session_get_channel(session)));
793 
794 	return SWITCH_STATUS_SUCCESS;
795 }
796 
channel_kill_channel(switch_core_session_t * session,int sig)797 static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig)
798 {
799 	switch_channel_t *channel = switch_core_session_get_channel(session);
800 	private_t *tech_pvt = switch_core_session_get_private(session);
801 	switch_assert(tech_pvt != NULL);
802 
803 	switch (sig) {
804 	case SWITCH_SIG_KILL:
805 		switch_set_flag_locked(tech_pvt, TFLAG_HUP);
806 		switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
807 		break;
808 	default:
809 		break;
810 	}
811 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL KILL\n", switch_channel_get_name(channel));
812 
813 	return SWITCH_STATUS_SUCCESS;
814 }
815 
channel_on_soft_execute(switch_core_session_t * session)816 static switch_status_t channel_on_soft_execute(switch_core_session_t *session)
817 {
818 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL TRANSMIT\n");
819 	return SWITCH_STATUS_SUCCESS;
820 }
821 
channel_on_exchange_media(switch_core_session_t * session)822 static switch_status_t channel_on_exchange_media(switch_core_session_t *session)
823 {
824 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL LOOPBACK\n");
825 	return SWITCH_STATUS_SUCCESS;
826 }
827 
828 
channel_send_dtmf(switch_core_session_t * session,const switch_dtmf_t * dtmf)829 static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
830 {
831 	private_t *tech_pvt = switch_core_session_get_private(session);
832 	switch_assert(tech_pvt != NULL);
833 
834 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "DTMF ON CALL %s [%c]\n", tech_pvt->call_id, dtmf->digit);
835 
836 	return SWITCH_STATUS_SUCCESS;
837 }
838 
channel_endpoint_read(audio_endpoint_t * endpoint,switch_frame_t ** frame)839 static switch_status_t channel_endpoint_read(audio_endpoint_t *endpoint, switch_frame_t **frame)
840 {
841 	int samples = 0;
842 
843 	if (!endpoint->in_stream) {
844 		switch_core_timer_next(&endpoint->read_timer);
845 		*frame = &globals.cng_frame;
846 		return SWITCH_STATUS_SUCCESS;
847 	}
848 
849 	endpoint->read_frame.data = endpoint->read_buf;
850 	endpoint->read_frame.buflen = sizeof(endpoint->read_buf);
851 	endpoint->read_frame.source = __FILE__;
852 	samples = ReadAudioStream(endpoint->in_stream->stream,
853 			endpoint->read_frame.data, STREAM_SAMPLES_PER_PACKET(endpoint->in_stream),
854 			endpoint->inchan, &endpoint->read_timer);
855 
856 	if (!samples) {
857 		switch_core_timer_next(&endpoint->read_timer);
858 		*frame = &globals.cng_frame;
859 		return SWITCH_STATUS_SUCCESS;
860 	}
861 
862 	endpoint->read_frame.datalen = (samples * sizeof(int16_t));
863 	endpoint->read_frame.samples = samples;
864 	endpoint->read_frame.codec = &endpoint->read_codec;
865 	*frame = &endpoint->read_frame;
866 	return SWITCH_STATUS_SUCCESS;
867 }
868 
channel_read_frame(switch_core_session_t * session,switch_frame_t ** frame,switch_io_flag_t flags,int stream_id)869 static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
870 {
871 	private_t *tech_pvt = switch_core_session_get_private(session);
872 	int samples = 0;
873 	switch_status_t status = SWITCH_STATUS_FALSE;
874 	switch_assert(tech_pvt != NULL);
875 
876 	if (tech_pvt->audio_endpoint) {
877 		return channel_endpoint_read(tech_pvt->audio_endpoint, frame);
878 	}
879 
880 	if (!globals.main_stream) {
881 		goto normal_return;
882 	}
883 
884 	if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
885 		goto normal_return;
886 	}
887 
888 	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
889 		goto cng_wait;
890 	}
891 
892 	if (!is_master(tech_pvt)) {
893 		if (tech_pvt->hold_file) {
894 			switch_size_t olen = globals.read_codec.implementation->samples_per_packet;
895 
896 			if (!tech_pvt->hfh) {
897 				int sample_rate = globals.sample_rate;
898 				if (switch_core_file_open(&tech_pvt->fh,
899 										  tech_pvt->hold_file,
900 										  globals.read_codec.implementation->number_of_channels,
901 										  globals.read_codec.implementation->actual_samples_per_second,
902 										  SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
903 					tech_pvt->hold_file = NULL;
904 					goto cng_wait;
905 				}
906 
907 				tech_pvt->hfh = &tech_pvt->fh;
908 				tech_pvt->hold_frame.data = tech_pvt->holdbuf;
909 				tech_pvt->hold_frame.buflen = sizeof(tech_pvt->holdbuf);
910 				tech_pvt->hold_frame.rate = sample_rate;
911 				tech_pvt->hold_frame.codec = &globals.write_codec;
912 			}
913 
914 			if (switch_core_timer_next(&globals.hold_timer) != SWITCH_STATUS_SUCCESS) {
915 				switch_core_file_close(&tech_pvt->fh);
916 				goto cng_nowait;
917 			}
918 			switch_core_file_read(tech_pvt->hfh, tech_pvt->hold_frame.data, &olen);
919 
920 			if (olen == 0) {
921 				unsigned int pos = 0;
922 				switch_core_file_seek(tech_pvt->hfh, &pos, 0, SEEK_SET);
923 				goto cng_nowait;
924 			}
925 
926 			tech_pvt->hold_frame.datalen = (uint32_t) (olen * sizeof(int16_t));
927 			tech_pvt->hold_frame.samples = (uint32_t) olen;
928 			*frame = &tech_pvt->hold_frame;
929 
930 			status = SWITCH_STATUS_SUCCESS;
931 			goto normal_return;
932 		}
933 
934 		goto cng_wait;
935 	}
936 
937 	if (tech_pvt->hfh) {
938 		tech_close_file(tech_pvt);
939 	}
940 
941 	switch_mutex_lock(globals.device_lock);
942 	samples = ReadAudioStream(globals.main_stream->stream, globals.read_frame.data, globals.read_codec.implementation->samples_per_packet, 0, &globals.read_timer);
943 	switch_mutex_unlock(globals.device_lock);
944 
945 	if (samples) {
946 		globals.read_frame.datalen = samples * 2;
947 		globals.read_frame.samples = samples;
948 
949 		*frame = &globals.read_frame;
950 
951 		if (!switch_test_flag((&globals), GFLAG_MOUTH)) {
952 			memset(globals.read_frame.data, 255, globals.read_frame.datalen);
953 		}
954 		status = SWITCH_STATUS_SUCCESS;
955 	} else {
956 		goto cng_nowait;
957 	}
958 
959 normal_return:
960 	return status;
961 
962   cng_nowait:
963 	*frame = &globals.cng_frame;
964 	return SWITCH_STATUS_SUCCESS;
965 
966   cng_wait:
967 	switch_core_timer_next(&globals.hold_timer);
968 	*frame = &globals.cng_frame;
969 	return SWITCH_STATUS_SUCCESS;
970 
971 }
972 
channel_endpoint_write(audio_endpoint_t * endpoint,switch_frame_t * frame)973 static switch_status_t channel_endpoint_write(audio_endpoint_t *endpoint, switch_frame_t *frame)
974 {
975 	if (!endpoint->out_stream) {
976 		switch_core_timer_next(&endpoint->write_timer);
977 		return SWITCH_STATUS_SUCCESS;
978 	}
979 	if (!endpoint->master) {
980 		return SWITCH_STATUS_SUCCESS;
981 	}
982 	if (switch_test_flag(endpoint->master, TFLAG_HUP)) {
983 		return SWITCH_STATUS_FALSE;
984 	}
985 	if (!switch_test_flag(endpoint->master, TFLAG_IO)) {
986 		return SWITCH_STATUS_SUCCESS;
987 	}
988 	WriteAudioStream(endpoint->out_stream->stream, (short *)frame->data,
989 			(int)(frame->datalen / sizeof(SAMPLE)),
990 			endpoint->outchan, &(endpoint->write_timer));
991 	return SWITCH_STATUS_SUCCESS;
992 }
993 
channel_write_frame(switch_core_session_t * session,switch_frame_t * frame,switch_io_flag_t flags,int stream_id)994 static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
995 {
996 	switch_status_t status = SWITCH_STATUS_FALSE;
997 	private_t *tech_pvt = switch_core_session_get_private(session);
998 	switch_assert(tech_pvt != NULL);
999 
1000 	if (tech_pvt->audio_endpoint) {
1001 		return channel_endpoint_write(tech_pvt->audio_endpoint, frame);
1002 	}
1003 
1004 	if (!globals.main_stream) {
1005 		return SWITCH_STATUS_FALSE;
1006 	}
1007 
1008 	if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
1009 		return SWITCH_STATUS_FALSE;
1010 	}
1011 
1012 	if (!is_master(tech_pvt) || !switch_test_flag(tech_pvt, TFLAG_IO)) {
1013 		return SWITCH_STATUS_SUCCESS;
1014 	}
1015 
1016 	if (globals.main_stream) {
1017 		if (switch_test_flag((&globals), GFLAG_EAR)) {
1018 			WriteAudioStream(globals.main_stream->stream, (short *) frame->data, (int) (frame->datalen / sizeof(SAMPLE)), 0, &(globals.main_stream->write_timer));
1019 		}
1020 		status = SWITCH_STATUS_SUCCESS;
1021 	}
1022 
1023 	return status;
1024 }
1025 
channel_answer_channel(switch_core_session_t * session)1026 static switch_status_t channel_answer_channel(switch_core_session_t *session)
1027 {
1028 	return SWITCH_STATUS_SUCCESS;
1029 }
1030 
channel_receive_message(switch_core_session_t * session,switch_core_session_message_t * msg)1031 static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
1032 {
1033 	private_t *tech_pvt = switch_core_session_get_private(session);
1034 	switch_assert(tech_pvt != NULL);
1035 
1036 	switch (msg->message_id) {
1037 	case SWITCH_MESSAGE_INDICATE_ANSWER:
1038 		channel_answer_channel(session);
1039 		break;
1040 	case SWITCH_MESSAGE_INDICATE_PROGRESS:
1041 		{
1042 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Engage Early Media\n");
1043 			switch_set_flag_locked(tech_pvt, TFLAG_IO);
1044 		}
1045 	default:
1046 		break;
1047 	}
1048 	return SWITCH_STATUS_SUCCESS;
1049 }
1050 
1051 switch_state_handler_table_t portaudio_event_handlers = {
1052 	/*.on_init */ channel_on_init,
1053 	/*.on_routing */ channel_on_routing,
1054 	/*.on_execute */ channel_on_execute,
1055 	/*.on_hangup */ channel_on_hangup,
1056 	/*.on_exchange_media */ channel_on_exchange_media,
1057 	/*.on_soft_execute */ channel_on_soft_execute,
1058 	/*.on_consume_media */ NULL,
1059 	/*.on_hibernate */ NULL,
1060 	/*.on_reset */ NULL,
1061 	/*.on_park */ NULL,
1062 	/*.on_reporting */ NULL,
1063 	/*.on_destroy */ channel_on_destroy
1064 };
1065 
1066 switch_io_routines_t portaudio_io_routines = {
1067 	/*.outgoing_channel */ channel_outgoing_channel,
1068 	/*.read_frame */ channel_read_frame,
1069 	/*.write_frame */ channel_write_frame,
1070 	/*.kill_channel */ channel_kill_channel,
1071 	/*.send_dtmf */ channel_send_dtmf,
1072 	/*.receive_message */ channel_receive_message
1073 };
1074 
1075 static int create_shared_audio_stream(shared_audio_stream_t *stream);
1076 static int destroy_shared_audio_stream(shared_audio_stream_t *stream);
take_stream_channel(shared_audio_stream_t * stream,int index,int input)1077 static int take_stream_channel(shared_audio_stream_t *stream, int index, int input)
1078 {
1079 	int rc = 0;
1080 	if (!stream) {
1081 		return rc;
1082 	}
1083 
1084 	switch_mutex_lock(stream->mutex);
1085 
1086 	if (!stream->stream && create_shared_audio_stream(stream)) {
1087 		rc = -1;
1088 		goto done;
1089 	}
1090 
1091 	if (input) {
1092 	       	if (stream->inchan_used[index]) {
1093 			rc = -1;
1094 			goto done;
1095 		}
1096 		stream->inchan_used[index] = 1;
1097 	} else {
1098 		if (!input && stream->outchan_used[index]) {
1099 			rc = -1;
1100 			goto done;
1101 		}
1102 		stream->outchan_used[index] = 1;
1103 	}
1104 
1105 done:
1106 	switch_mutex_unlock(stream->mutex);
1107 	return rc;
1108 }
1109 
release_stream_channel(shared_audio_stream_t * stream,int index,int input)1110 static int release_stream_channel(shared_audio_stream_t *stream, int index, int input)
1111 {
1112 	int i = 0;
1113 	int destroy_stream = 1;
1114 	int rc = 0;
1115 
1116 	if (!stream) {
1117 		return rc;
1118 	}
1119 
1120 	switch_mutex_lock(stream->mutex);
1121 
1122 	if (input) {
1123 		stream->inchan_used[index] = 0;
1124 	} else {
1125 		stream->outchan_used[index] = 0;
1126 	}
1127 
1128 	for (i = 0; i < stream->channels; i++) {
1129 		if (stream->inchan_used[i] || stream->outchan_used[i]) {
1130 			destroy_stream = 0;
1131 		}
1132 	}
1133 	if (destroy_stream) {
1134 		destroy_shared_audio_stream(stream);
1135 	}
1136 
1137 	switch_mutex_unlock(stream->mutex);
1138 	return rc;
1139 }
1140 
1141 /* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
1142    that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
1143 */
channel_outgoing_channel(switch_core_session_t * session,switch_event_t * var_event,switch_caller_profile_t * outbound_profile,switch_core_session_t ** new_session,switch_memory_pool_t ** pool,switch_originate_flag_t flags,switch_call_cause_t * cancel_cause)1144 static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
1145 													switch_caller_profile_t *outbound_profile,
1146 													switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags,
1147 													switch_call_cause_t *cancel_cause)
1148 {
1149 	char name[128];
1150 	const char *id = NULL;
1151 	private_t *tech_pvt = NULL;
1152 	switch_channel_t *channel = NULL;
1153 	switch_caller_profile_t *caller_profile = NULL;
1154 	switch_call_cause_t retcause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
1155 	int codec_ms = -1;
1156 	int samples_per_packet = -1;
1157 	int sample_rate = 0;
1158 	audio_endpoint_t *endpoint = NULL;
1159 	char *endpoint_name = NULL;
1160 	const char *endpoint_answer = NULL;
1161 
1162 	if (!outbound_profile) {
1163 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n");
1164 		return retcause;
1165 	}
1166 
1167 	if (!(*new_session = switch_core_session_request_uuid(portaudio_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, flags, pool, switch_event_get_header(var_event, "origination_uuid")))) {
1168 		return retcause;
1169 	}
1170 
1171 	switch_core_session_add_stream(*new_session, NULL);
1172 	if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) {
1173 		memset(tech_pvt, 0, sizeof(*tech_pvt));
1174 		switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(*new_session));
1175 		channel = switch_core_session_get_channel(*new_session);
1176 		switch_core_session_set_private(*new_session, tech_pvt);
1177 		tech_pvt->session = *new_session;
1178 	} else {
1179 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
1180 		switch_core_session_destroy(new_session);
1181 		return retcause;
1182 	}
1183 
1184 	if (outbound_profile->destination_number && !strncasecmp(outbound_profile->destination_number, "endpoint", sizeof("endpoint")-1)) {
1185 		endpoint = NULL;
1186 		endpoint_name = switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number);
1187 		endpoint_name = strchr(endpoint_name, '/');
1188 		if (!endpoint_name) {
1189 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "No portaudio endpoint specified\n");
1190 			goto error;
1191 		}
1192 		endpoint_name++;
1193 		endpoint = switch_core_hash_find(globals.endpoints, endpoint_name);
1194 		if (!endpoint) {
1195 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "Invalid portaudio endpoint %s\n", endpoint_name);
1196 			goto error;
1197 		}
1198 
1199 		switch_mutex_lock(endpoint->mutex);
1200 
1201 		if (endpoint->master) {
1202 			/* someone already has this endpoint */
1203 			retcause = SWITCH_CAUSE_USER_BUSY;
1204 			goto error;
1205 		}
1206 
1207 		codec_ms = endpoint->in_stream ? endpoint->in_stream->codec_ms : endpoint->out_stream->codec_ms;
1208 		samples_per_packet = endpoint->in_stream ?
1209 			STREAM_SAMPLES_PER_PACKET(endpoint->in_stream) : STREAM_SAMPLES_PER_PACKET(endpoint->out_stream);
1210 		sample_rate = endpoint->in_stream ? endpoint->in_stream->sample_rate : endpoint->out_stream->sample_rate;
1211 
1212 		if (switch_core_timer_init(&endpoint->read_timer,
1213 				   globals.timer_name, codec_ms,
1214 				   samples_per_packet, module_pool) != SWITCH_STATUS_SUCCESS) {
1215 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint->name);
1216 			goto error;
1217 		}
1218 
1219 		/* The write timer must be setup regardless */
1220 		if (switch_core_timer_init(&endpoint->write_timer,
1221 				   globals.timer_name, codec_ms,
1222 				   samples_per_packet, module_pool) != SWITCH_STATUS_SUCCESS) {
1223 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint->name);
1224 			goto error;
1225 		}
1226 
1227 		if (switch_core_codec_init(&endpoint->read_codec,
1228 								   "L16", NULL, NULL, sample_rate, codec_ms, 1,
1229 								   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
1230 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
1231 			goto error;
1232 		}
1233 
1234 		if (switch_core_codec_init(&endpoint->write_codec,
1235 								   "L16", NULL, NULL, sample_rate, codec_ms, 1,
1236 								   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
1237 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
1238 			goto error;
1239 		}
1240 		switch_core_session_set_read_codec(tech_pvt->session, &endpoint->read_codec);
1241 		switch_core_session_set_write_codec(tech_pvt->session, &endpoint->write_codec);
1242 
1243 		/* try to acquire the stream */
1244 		if (take_stream_channel(endpoint->in_stream, endpoint->inchan, 1)) {
1245 			retcause = SWITCH_CAUSE_USER_BUSY;
1246 			goto error;
1247 		}
1248 		if (take_stream_channel(endpoint->out_stream, endpoint->outchan, 0)) {
1249 			release_stream_channel(endpoint->in_stream, endpoint->inchan, 1);
1250 			retcause = SWITCH_CAUSE_USER_BUSY;
1251 			goto error;
1252 		}
1253 		switch_snprintf(name, sizeof(name), "portaudio/endpoint-%s", endpoint_name);
1254 		if (var_event && (endpoint_answer = (switch_event_get_header(var_event, "endpoint_answer")))) {
1255 			if (switch_true(endpoint_answer)) {
1256 				switch_set_flag(tech_pvt, TFLAG_AUTO_ANSWER);
1257 			}
1258 		} else {
1259 			switch_set_flag(tech_pvt, TFLAG_AUTO_ANSWER);
1260 		}
1261 		endpoint->master = tech_pvt;
1262 		tech_pvt->audio_endpoint = endpoint;
1263 		switch_mutex_unlock(endpoint->mutex);
1264 	} else {
1265 		id = !zstr(outbound_profile->caller_id_number) ? outbound_profile->caller_id_number : "na";
1266 		switch_snprintf(name, sizeof(name), "portaudio/%s", id);
1267 		if (outbound_profile->destination_number && !strcasecmp(outbound_profile->destination_number, "auto_answer")) {
1268 			switch_set_flag(tech_pvt, TFLAG_AUTO_ANSWER);
1269 		}
1270 	}
1271 	switch_channel_set_name(channel, name);
1272 	caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
1273 	switch_channel_set_caller_profile(channel, caller_profile);
1274 	tech_pvt->caller_profile = caller_profile;
1275 
1276 	switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND);
1277 	switch_channel_set_state(channel, CS_INIT);
1278 	switch_channel_set_flag(channel, CF_AUDIO);
1279 	return SWITCH_CAUSE_SUCCESS;
1280 
1281 error:
1282 	if (endpoint) {
1283 		if (!endpoint->master) {
1284 			if (endpoint->read_timer.interval) {
1285 				switch_core_timer_destroy(&endpoint->read_timer);
1286 			}
1287 			if (endpoint->write_timer.interval) {
1288 				switch_core_timer_destroy(&endpoint->write_timer);
1289 			}
1290 			if (endpoint->read_codec.codec_interface) {
1291 				switch_core_codec_destroy(&endpoint->read_codec);
1292 			}
1293 			if (endpoint->write_codec.codec_interface) {
1294 				switch_core_codec_destroy(&endpoint->write_codec);
1295 			}
1296 		}
1297 		switch_mutex_unlock(endpoint->mutex);
1298 	}
1299 	if (new_session && *new_session) {
1300 		switch_core_session_destroy(new_session);
1301 	}
1302 	return retcause;
1303 }
1304 
1305 
SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load)1306 SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load)
1307 {
1308 	switch_status_t status;
1309 	switch_api_interface_t *api_interface;
1310 
1311 	module_pool = pool;
1312 
1313 	if (paNoError != Pa_Initialize()) {
1314 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot initialize port audio!\n");
1315 		return SWITCH_STATUS_TERM;
1316 	}
1317 
1318 	memset(&globals, 0, sizeof(globals));
1319 
1320 	switch_core_hash_init(&globals.call_hash);
1321 	switch_core_hash_init(&globals.sh_streams);
1322 	switch_core_hash_init(&globals.endpoints);
1323 	switch_mutex_init(&globals.device_lock, SWITCH_MUTEX_NESTED, module_pool);
1324 	switch_mutex_init(&globals.pvt_lock, SWITCH_MUTEX_NESTED, module_pool);
1325 	switch_mutex_init(&globals.streams_lock, SWITCH_MUTEX_NESTED, module_pool);
1326 	switch_mutex_init(&globals.flag_mutex, SWITCH_MUTEX_NESTED, module_pool);
1327 	switch_mutex_init(&globals.pa_mutex, SWITCH_MUTEX_NESTED, module_pool);
1328 	globals.codecs_inited = 0;
1329 	globals.read_frame.data = globals.databuf;
1330 	globals.read_frame.buflen = sizeof(globals.databuf);
1331 	globals.cng_frame.data = globals.cngbuf;
1332 	globals.cng_frame.buflen = sizeof(globals.cngbuf);
1333 	switch_set_flag((&globals.cng_frame), SFF_CNG);
1334 	globals.flags = GFLAG_EAR | GFLAG_MOUTH;
1335 	/* dual streams makes portaudio on solaris choke */
1336 #if defined(sun) || defined(__sun)
1337 	globals.dual_streams = 0;
1338 #endif
1339 
1340 	if ((status = load_config()) != SWITCH_STATUS_SUCCESS) {
1341 		return status;
1342 	}
1343 
1344 	if (dump_info(0)) {
1345 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't find any audio devices!\n");
1346 		return SWITCH_STATUS_TERM;
1347 	}
1348 
1349 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
1350 					  "Input Device: %d, Output Device: %d, Ring Device: %d Sample Rate: %d MS: %d\n", globals.indev,
1351 					  globals.outdev, globals.ringdev, globals.sample_rate, globals.codec_ms);
1352 
1353 
1354 	if (switch_event_reserve_subclass(MY_EVENT_RINGING) != SWITCH_STATUS_SUCCESS) {
1355 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass!\n");
1356 		return SWITCH_STATUS_GENERR;
1357 	}
1358 
1359 	if (switch_event_reserve_subclass(MY_EVENT_MAKE_CALL) != SWITCH_STATUS_SUCCESS) {
1360 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass!\n");
1361 		return SWITCH_STATUS_GENERR;
1362 	}
1363 	if (switch_event_reserve_subclass(MY_EVENT_CALL_HELD) != SWITCH_STATUS_SUCCESS) {
1364 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass!\n");
1365 		return SWITCH_STATUS_GENERR;
1366 	}
1367 	if (switch_event_reserve_subclass(MY_EVENT_CALL_RESUMED) != SWITCH_STATUS_SUCCESS) {
1368 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass!\n");
1369 		return SWITCH_STATUS_GENERR;
1370 	}
1371 
1372 	if (switch_event_reserve_subclass(MY_EVENT_ERROR_AUDIO_DEV) != SWITCH_STATUS_SUCCESS) {
1373 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass!\n");
1374 		return SWITCH_STATUS_GENERR;
1375 	}
1376 
1377 
1378 	/* connect my internal structure to the blank pointer passed to me */
1379 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
1380 	portaudio_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
1381 	portaudio_endpoint_interface->interface_name = "portaudio";
1382 	portaudio_endpoint_interface->io_routines = &portaudio_io_routines;
1383 	portaudio_endpoint_interface->state_handler = &portaudio_event_handlers;
1384 
1385 	SWITCH_ADD_API(api_interface, "pa", "PortAudio", pa_cmd, "<command> [<args>]");
1386 	switch_console_set_complete("add pa help");
1387 	switch_console_set_complete("add pa dump");
1388 	switch_console_set_complete("add pa call");
1389 	switch_console_set_complete("add pa answer");
1390 	switch_console_set_complete("add pa hangup");
1391 	switch_console_set_complete("add pa list");
1392 	switch_console_set_complete("add pa switch");
1393 	switch_console_set_complete("add pa dtmf");
1394 	switch_console_set_complete("add pa flags");
1395 	switch_console_set_complete("add pa devlist");
1396 	switch_console_set_complete("add pa indev");
1397 	switch_console_set_complete("add pa outdev");
1398 	switch_console_set_complete("add pa preparestream");
1399 	switch_console_set_complete("add pa switchstream");
1400 	switch_console_set_complete("add pa closestreams");
1401 	switch_console_set_complete("add pa ringdev");
1402 	switch_console_set_complete("add pa ringfile");
1403 	switch_console_set_complete("add pa play");
1404 	switch_console_set_complete("add pa playdev");
1405 	switch_console_set_complete("add pa looptest");
1406 	switch_console_set_complete("add pa shstreams");
1407 	switch_console_set_complete("add pa endpoints");
1408 
1409 	/* indicate that the module should continue to be loaded */
1410 	return SWITCH_STATUS_SUCCESS;
1411 }
1412 
check_device(char * devstr,int check_input)1413 static int check_device(char *devstr, int check_input)
1414 {
1415 	int devval;
1416 	if (devstr[0] == '#') {
1417 		devval = get_dev_by_number(devstr + 1, check_input);
1418 	} else {
1419 		devval = get_dev_by_name(devstr, check_input);
1420 	}
1421 	return devval;
1422 }
1423 
load_streams(switch_xml_t streams)1424 static switch_status_t load_streams(switch_xml_t streams)
1425 {
1426 	switch_status_t status = SWITCH_STATUS_SUCCESS;
1427 	switch_xml_t param, mystream;
1428 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading streams ...\n");
1429 	for (mystream = switch_xml_child(streams, "stream"); mystream; mystream = mystream->next) {
1430 		shared_audio_stream_t *stream = NULL;
1431 		int devval = -1;
1432 		char *stream_name = (char *) switch_xml_attr_soft(mystream, "name");
1433 
1434 		if (!stream_name) {
1435 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing stream name attribute, skipping ...\n");
1436 			continue;
1437 		}
1438 
1439 		/* check if that stream name is not already used */
1440 		stream = switch_core_hash_find(globals.sh_streams, stream_name);
1441 		if (stream) {
1442 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "A stream with name '%s' already exists\n", stream_name);
1443 			continue;
1444 		}
1445 
1446 		stream = switch_core_alloc(module_pool, sizeof(*stream));
1447 		if (!stream) {
1448 			continue;
1449 		}
1450 		switch_mutex_init(&stream->mutex, SWITCH_MUTEX_NESTED, module_pool);
1451 		stream->indev = -1;
1452 		stream->outdev = -1;
1453 		stream->sample_rate = globals.sample_rate;
1454 		stream->codec_ms = globals.codec_ms;
1455 		stream->channels = 1;
1456 		switch_snprintf(stream->name, sizeof(stream->name), "%s", stream_name);
1457 		for (param = switch_xml_child(mystream, "param"); param; param = param->next) {
1458 			char *var = (char *) switch_xml_attr_soft(param, "name");
1459 			char *val = (char *) switch_xml_attr_soft(param, "value");
1460 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parsing stream '%s' parameter %s = %s\n", stream_name, var, val);
1461 			if (!strcmp(var, "indev")) {
1462 				devval = check_device(val, 1);
1463 				if (devval < 0) {
1464 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
1465 							"Invalid indev specified for stream '%s'\n", stream_name);
1466 					stream->indev = -1;
1467 					continue;
1468 				}
1469 				stream->indev = devval;
1470 			} else if (!strcmp(var, "outdev")) {
1471 				devval = check_device(val, 0);
1472 				if (devval < 0) {
1473 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
1474 							"Invalid outdev specified for stream '%s'\n", stream_name);
1475 					stream->outdev = -1;
1476 					continue;
1477 				}
1478 				stream->outdev = devval;
1479 			} else if (!strcmp(var, "sample-rate")) {
1480 				stream->sample_rate = atoi(val);
1481 				if (stream->sample_rate < MIN_STREAM_SAMPLE_RATE) {
1482 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
1483 							"Invalid sample rate specified for stream '%s', forcing to 8000\n", stream_name);
1484 					stream->sample_rate = MIN_STREAM_SAMPLE_RATE;
1485 				}
1486 			} else if (!strcmp(var, "codec-ms")) {
1487 				int tmp = atoi(val);
1488 				if (switch_check_interval(stream->sample_rate, tmp)) {
1489 					stream->codec_ms = tmp;
1490 				} else {
1491 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
1492 									  "codec-ms must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
1493 				}
1494 			} else if (!strcmp(var, "channels")) {
1495 				stream->channels = atoi(val);
1496 				if (stream->channels < 1 || stream->channels > MAX_IO_CHANNELS) {
1497 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
1498 							"Invalid number of channels specified for stream '%s', forcing to 1\n", stream_name);
1499 					stream->channels = 1;
1500 				}
1501 			}
1502 		}
1503 		if (stream->indev < 0 && stream->outdev < 0) {
1504 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
1505 					"You need at least one device for stream '%s'\n", stream_name);
1506 			continue;
1507 		}
1508 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
1509 				"Created stream '%s', sample-rate = %d, codec-ms = %d\n", stream->name, stream->sample_rate, stream->codec_ms);
1510 		switch_core_hash_insert(globals.sh_streams, stream->name, stream);
1511 	}
1512 	return status;
1513 }
1514 
check_stream_compat(shared_audio_stream_t * in_stream,shared_audio_stream_t * out_stream)1515 static int check_stream_compat(shared_audio_stream_t *in_stream, shared_audio_stream_t *out_stream)
1516 {
1517 	if (!in_stream || !out_stream) {
1518 		/* nothing to be compatible with */
1519 		return 0;
1520 	}
1521 	if (in_stream->sample_rate != out_stream->sample_rate) {
1522 		return -1;
1523 	}
1524 	if (in_stream->codec_ms != out_stream->codec_ms) {
1525 		return -1;
1526 	}
1527 	return 0;
1528 }
1529 
check_stream(char * streamstr,int check_input,int * chanindex)1530 static shared_audio_stream_t *check_stream(char *streamstr, int check_input, int *chanindex)
1531 {
1532 	shared_audio_stream_t *stream = NULL;
1533 	int cnum = 0;
1534 	char stream_name[255];
1535 	char *chan = NULL;
1536 
1537 	*chanindex = -1;
1538 
1539 	switch_snprintf(stream_name, sizeof(stream_name), "%s", streamstr);
1540 
1541 	chan = strchr(stream_name, ':');
1542 	if (!chan) {
1543 		return NULL;
1544 	}
1545 	*chan = 0;
1546 	chan++;
1547 	cnum = atoi(chan);
1548 
1549 	stream = switch_core_hash_find(globals.sh_streams, stream_name);
1550 	if (!stream) {
1551 		return NULL;
1552 	}
1553 
1554 	if (cnum < 0 || cnum > stream->channels) {
1555 		return NULL;
1556 	}
1557 
1558 	if (check_input && stream->indev < 0) {
1559 		return NULL;
1560 	}
1561 
1562 	if (!check_input && stream->outdev < 0) {
1563 		return NULL;
1564 	}
1565 
1566 	*chanindex = cnum;
1567 
1568 	return stream;
1569 }
1570 
load_endpoints(switch_xml_t endpoints)1571 static switch_status_t load_endpoints(switch_xml_t endpoints)
1572 {
1573 	switch_status_t status = SWITCH_STATUS_SUCCESS;
1574 	switch_xml_t param, myendpoint;
1575 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading endpoints ...\n");
1576 	for (myendpoint = switch_xml_child(endpoints, "endpoint"); myendpoint; myendpoint = myendpoint->next) {
1577 		audio_endpoint_t *endpoint = NULL;
1578 		shared_audio_stream_t *stream = NULL;
1579 		char *endpoint_name = (char *) switch_xml_attr_soft(myendpoint, "name");
1580 
1581 		if (!endpoint_name) {
1582 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing endpoint name attribute, skipping ...\n");
1583 			continue;
1584 		}
1585 
1586 		/* check if that endpoint name is not already used */
1587 		endpoint = switch_core_hash_find(globals.endpoints, endpoint_name);
1588 		if (endpoint) {
1589 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "An endpoint with name '%s' already exists\n", endpoint_name);
1590 			continue;
1591 		}
1592 
1593 		endpoint = switch_core_alloc(module_pool, sizeof(*endpoint));
1594 		if (!endpoint) {
1595 			continue;
1596 		}
1597 		switch_mutex_init(&endpoint->mutex, SWITCH_MUTEX_NESTED, module_pool);
1598 		endpoint->inchan = -1;
1599 		endpoint->outchan = -1;
1600 		switch_snprintf(endpoint->name, sizeof(endpoint->name), "%s", endpoint_name);
1601 		for (param = switch_xml_child(myendpoint, "param"); param; param = param->next) {
1602 			char *var = (char *) switch_xml_attr_soft(param, "name");
1603 			char *val = (char *) switch_xml_attr_soft(param, "value");
1604 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parsing endpoint '%s' parameter %s = %s\n", endpoint_name, var, val);
1605 			if (!strcmp(var, "instream")) {
1606 				stream = check_stream(val, 1, &endpoint->inchan) ;
1607 				if (!stream) {
1608 					endpoint->in_stream = NULL;
1609 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
1610 							"Invalid instream specified for endpoint '%s'\n", endpoint_name);
1611 					continue;
1612 				}
1613 				endpoint->in_stream = stream;
1614 			} else if (!strcmp(var, "outstream")) {
1615 				stream = check_stream(val, 0, &endpoint->outchan);
1616 				if (!stream) {
1617 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
1618 							"Invalid outstream specified for endpoint '%s'\n", endpoint_name);
1619 					endpoint->out_stream = NULL;
1620 					continue;
1621 				}
1622 				endpoint->out_stream = stream;
1623 			}
1624 		}
1625 		if (!endpoint->in_stream && !endpoint->out_stream) {
1626 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
1627 					"You need at least one stream for endpoint '%s'\n", endpoint_name);
1628 			continue;
1629 		}
1630 		if (check_stream_compat(endpoint->in_stream, endpoint->out_stream)) {
1631 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
1632 					"Incompatible input and output streams for endpoint '%s'\n", endpoint_name);
1633 			continue;
1634 		}
1635 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
1636 				"Created endpoint '%s', instream = %s, outstream = %s\n", endpoint->name,
1637 				endpoint->in_stream ? endpoint->in_stream->name : "(none)",
1638 				endpoint->out_stream ? endpoint->out_stream->name : "(none)");
1639 		switch_core_hash_insert(globals.endpoints, endpoint->name, endpoint);
1640 	}
1641 	return status;
1642 }
1643 
load_config(void)1644 static switch_status_t load_config(void)
1645 {
1646 	char *cf = "portaudio.conf";
1647 	switch_xml_t cfg, xml, settings, streams, endpoints, param;
1648 	switch_status_t status = SWITCH_STATUS_SUCCESS;
1649 
1650 	if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
1651 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
1652 		return SWITCH_STATUS_TERM;
1653 	}
1654 	destroy_audio_streams();
1655 	destroy_codecs();
1656 	globals.dual_streams = 0;
1657 	globals.live_stream_switch = 0;
1658 	globals.no_auto_resume_call = 0;
1659 	globals.no_ring_during_call = 0;
1660 	globals.indev = globals.outdev = globals.ringdev = -1;
1661 	globals.sample_rate = 8000;
1662 	globals.unload_device_fail = 0;
1663 
1664 	if ((settings = switch_xml_child(cfg, "settings"))) {
1665 		for (param = switch_xml_child(settings, "param"); param; param = param->next) {
1666 			char *var = (char *) switch_xml_attr_soft(param, "name");
1667 			char *val = (char *) switch_xml_attr_soft(param, "value");
1668 
1669 			if (!strcmp(var, "debug")) {
1670 				globals.debug = atoi(val);
1671 			} else if (!strcmp(var, "ring-interval")) {
1672 				globals.ring_interval = atoi(val);
1673 			} else if (!strcmp(var, "no-auto-resume-call")) {
1674 				if (switch_true(val)) {
1675 					globals.no_auto_resume_call = 1;
1676 				} else {
1677 					globals.no_auto_resume_call = 0;
1678 				}
1679 			} else if (!strcmp(var, "no-ring-during-call")) {
1680 				if (switch_true(val)) {
1681 					globals.no_ring_during_call = 1;
1682 				} else {
1683 					globals.no_ring_during_call = 0;
1684 				}
1685 			} else if (!strcmp(var, "live-stream-switch")) {
1686 				if (switch_true(val)) {
1687 					globals.live_stream_switch = 1;
1688 				} else {
1689 					globals.live_stream_switch = 0;
1690 				}
1691 			} else if (!strcmp(var, "ring-file")) {
1692 				set_global_ring_file(val);
1693 			} else if (!strcmp(var, "hold-file")) {
1694 				set_global_hold_file(val);
1695 			} else if (!strcmp(var, "dual-streams")) {
1696 				if (switch_true(val)) {
1697 					globals.dual_streams = 1;
1698 				} else {
1699 					globals.dual_streams = 0;
1700 				}
1701 			} else if (!strcmp(var, "timer-name")) {
1702 				set_global_timer_name(val);
1703 			} else if (!strcmp(var, "sample-rate")) {
1704 				globals.sample_rate = atoi(val);
1705 			} else if (!strcmp(var, "codec-ms")) {
1706 				int tmp = atoi(val);
1707 				if (switch_check_interval(globals.sample_rate, tmp)) {
1708 					globals.codec_ms = tmp;
1709 				} else {
1710 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
1711 									  "codec-ms must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
1712 				}
1713 			} else if (!strcmp(var, "dialplan")) {
1714 				set_global_dialplan(val);
1715 			} else if (!strcmp(var, "context")) {
1716 				set_global_context(val);
1717 			} else if (!strcmp(var, "cid-name")) {
1718 				set_global_cid_name(val);
1719 			} else if (!strcmp(var, "cid-num")) {
1720 				set_global_cid_num(val);
1721 			} else if (!strcmp(var, "indev")) {
1722 				if (*val == '#') {
1723 					globals.indev = get_dev_by_number(val + 1, 1);
1724 				} else {
1725 					globals.indev = get_dev_by_name(val, 1);
1726 				}
1727 			} else if (!strcmp(var, "outdev")) {
1728 				if (*val == '#') {
1729 					globals.outdev = get_dev_by_number(val + 1, 0);
1730 				} else {
1731 					globals.outdev = get_dev_by_name(val, 0);
1732 				}
1733 			} else if (!strcmp(var, "ringdev")) {
1734 				if (*val == '#') {
1735 					globals.ringdev = get_dev_by_number(val + 1, 0);
1736 				} else {
1737 					globals.ringdev = get_dev_by_name(val, 0);
1738 				}
1739 			} else if (!strcasecmp(var, "unload-on-device-fail")) {
1740 				globals.unload_device_fail = switch_true(val);
1741 			}
1742 		}
1743 	}
1744 
1745 	if (!globals.dialplan) {
1746 		set_global_dialplan("XML");
1747 	}
1748 
1749 	if (!globals.context) {
1750 		set_global_context("default");
1751 	}
1752 
1753 	if (!globals.sample_rate) {
1754 		globals.sample_rate = 8000;
1755 	}
1756 
1757 	if (!globals.codec_ms) {
1758 		globals.codec_ms = 20;
1759 	}
1760 
1761 	globals.cng_frame.datalen = switch_samples_per_packet(globals.sample_rate, globals.codec_ms) * 2;
1762 
1763 	if (!globals.ring_interval) {
1764 		globals.ring_interval = 5;
1765 	}
1766 
1767 	if (!globals.timer_name) {
1768 		set_global_timer_name("soft");
1769 	}
1770 
1771 	if (globals.indev < 0) {
1772 		globals.indev = get_dev_by_name(NULL, 1);
1773 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "global indev [%d]\n", globals.indev);
1774 		if (globals.indev > -1) {
1775 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Switching to default input device\n");
1776 		} else {
1777 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find an input device\n");
1778 			if (globals.unload_device_fail) {
1779 				status = SWITCH_STATUS_GENERR;
1780 			}
1781 		}
1782 	}
1783 
1784 	if (globals.outdev < 0) {
1785 		globals.outdev = get_dev_by_name(NULL, 0);
1786 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "global outdev [%d]\n", globals.outdev);
1787 		if (globals.outdev > -1) {
1788 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Switching to default output device\n");
1789 		} else {
1790 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find an output device\n");
1791 			if (globals.unload_device_fail) {
1792 				status = SWITCH_STATUS_GENERR;
1793 			}
1794 		}
1795 	}
1796 
1797 	if (globals.ringdev < 0) {
1798 		if (globals.outdev > -1) {
1799 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Invalid or no ring device configured, using output device as ring device\n");
1800 			globals.ringdev = globals.outdev;
1801 		}
1802 	}
1803 
1804 	/* streams and endpoints must be last, some initialization depend on globals defaults */
1805 	if ((streams = switch_xml_child(cfg, "streams"))) {
1806 		load_streams(streams);
1807 	}
1808 
1809 	if ((endpoints = switch_xml_child(cfg, "endpoints"))) {
1810 		load_endpoints(endpoints);
1811 	}
1812 
1813 
1814 	switch_xml_free(xml);
1815 
1816 	return status;
1817 }
1818 
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_shutdown)1819 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_shutdown)
1820 {
1821 
1822 	destroy_audio_streams();
1823 	destroy_codecs();
1824 
1825 	Pa_Terminate();
1826 	switch_core_hash_destroy(&globals.call_hash);
1827 	switch_core_hash_destroy(&globals.sh_streams);
1828 	switch_core_hash_destroy(&globals.endpoints);
1829 
1830 	switch_event_free_subclass(MY_EVENT_RINGING);
1831 	switch_event_free_subclass(MY_EVENT_MAKE_CALL);
1832 	switch_event_free_subclass(MY_EVENT_ERROR_AUDIO_DEV);
1833 	switch_event_free_subclass(MY_EVENT_CALL_HELD);
1834 	switch_event_free_subclass(MY_EVENT_CALL_RESUMED);
1835 
1836 
1837 	switch_safe_free(globals.dialplan);
1838 	switch_safe_free(globals.context);
1839 	switch_safe_free(globals.cid_name);
1840 	switch_safe_free(globals.cid_num);
1841 	switch_safe_free(globals.ring_file);
1842 	switch_safe_free(globals.hold_file);
1843 	switch_safe_free(globals.timer_name);
1844 
1845 	return SWITCH_STATUS_SUCCESS;
1846 }
1847 
get_dev_by_number(char * numstr,int in)1848 static int get_dev_by_number(char *numstr, int in)
1849 {
1850 	int numDevices = Pa_GetDeviceCount();
1851 	const PaDeviceInfo *pdi;
1852 	char *end_ptr;
1853 	int number;
1854 
1855 	number = (int) strtol(numstr, &end_ptr, 10);
1856 
1857 	if (end_ptr == numstr || number < 0) {
1858 		return -1;
1859 	}
1860 
1861 	if (number > -1 && number < numDevices && (pdi = Pa_GetDeviceInfo(number))) {
1862 		if (in && pdi->maxInputChannels) {
1863 			return number;
1864 		} else if (!in && pdi->maxOutputChannels) {
1865 			return number;
1866 		}
1867 	}
1868 
1869 	return -1;
1870 }
1871 
get_dev_by_name(char * name,int in)1872 static int get_dev_by_name(char *name, int in)
1873 {
1874 	int i;
1875 	int numDevices;
1876 	const PaDeviceInfo *pdi;
1877 	numDevices = Pa_GetDeviceCount();
1878 
1879 	if (numDevices < 0) {
1880 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices);
1881 		return -2;
1882 	}
1883 
1884 	for (i = 0; i < numDevices; i++) {
1885 		int match = 0;
1886 		pdi = Pa_GetDeviceInfo(i);
1887 
1888 		if (zstr(name)) {
1889 			match = 1;
1890 		} else if (pdi && pdi->name && strstr(pdi->name, name)) {
1891 			match = 1;
1892 		}
1893 
1894 		if (match) {
1895 			if (in && pdi->maxInputChannels) {
1896 				return i;
1897 			} else if (!in && pdi->maxOutputChannels) {
1898 				return i;
1899 			}
1900 		}
1901 	}
1902 
1903 	return -1;
1904 }
1905 
1906 
1907 /*******************************************************************/
PrintSupportedStandardSampleRates(const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters)1908 static void PrintSupportedStandardSampleRates(const PaStreamParameters * inputParameters, const PaStreamParameters * outputParameters)
1909 {
1910 	int i, printCount, cr = 7;
1911 	PaError err;
1912 	static double standardSampleRates[] = { 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
1913 		44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1
1914 	};
1915 
1916 	printCount = cr;
1917 	for (i = 0; standardSampleRates[i] > 0; i++) {
1918 		err = Pa_IsFormatSupported(inputParameters, outputParameters, standardSampleRates[i]);
1919 		if (err == paFormatIsSupported) {
1920 			if (printCount == cr) {
1921 				printCount = 0;
1922 				switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "\n\t%0.2f", standardSampleRates[i]);
1923 			} else {
1924 				switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, ", %0.2f", standardSampleRates[i]);
1925 			}
1926 			printCount++;
1927 		}
1928 	}
1929 	if (!printCount) {
1930 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, " None\n");
1931 	} else {
1932 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "\n");
1933 	}
1934 }
1935 
1936 /*******************************************************************/
play_dev(switch_stream_handle_t * stream,int outdev,char * file,const char * max_seconds,const char * no_close)1937 static switch_status_t play_dev(switch_stream_handle_t *stream, int outdev, char * file, const char * max_seconds, const char * no_close)
1938 {
1939 	switch_file_handle_t fh = { 0 };
1940 	int samples = 0;
1941 	int seconds = 5;
1942 	audio_stream_t * audio_stream;
1943 	int created_stream = 0;
1944 	int wrote = 0;
1945 	switch_size_t olen;
1946 	int16_t abuf[2048];
1947 
1948 
1949 	if (!strcasecmp(file, "ringtest")) {
1950 		file = globals.ring_file;
1951 	}
1952 	if (outdev == -1) {
1953 		stream->write_function(stream, "Invalid output audio device\n");
1954 		return SWITCH_STATUS_FALSE;
1955 	}
1956 	audio_stream = get_audio_stream(-1, outdev);
1957 
1958 	fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;
1959 
1960 	if (switch_core_file_open(&fh,	file,
1961 		globals.read_codec.implementation->number_of_channels,
1962 		globals.read_codec.implementation->actual_samples_per_second,
1963 		SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
1964 			stream->write_function(stream, "Cannot play requested file %s\n", file);
1965 			return SWITCH_STATUS_FALSE;
1966 	}
1967 
1968 	olen = globals.read_codec.implementation->samples_per_packet;
1969 
1970 	if (max_seconds) {
1971 		int i = atoi(max_seconds);
1972 		if (i >= 0) {
1973 			seconds = i;
1974 		}
1975 	}
1976 
1977 	if (globals.call_list) {
1978 		switch_mutex_lock(globals.pvt_lock);
1979 		if (!globals.main_stream) {
1980 			switch_mutex_unlock(globals.pvt_lock);
1981 			return SWITCH_STATUS_FALSE;
1982 		}
1983 
1984 		if ( switch_test_flag(globals.call_list, TFLAG_MASTER) && globals.main_stream->outdev == outdev) { /*so we are the active stream so we need to dupe it basically */
1985 			audio_stream = create_audio_stream(-1,outdev);
1986 			created_stream=1;
1987 		}
1988 		switch_mutex_unlock(globals.pvt_lock);
1989 	}
1990 
1991 	if (! audio_stream) {
1992 		stream->write_function(stream, "Failed to engage audio device\n");
1993 		return SWITCH_STATUS_FALSE;
1994 	}
1995 
1996 
1997 
1998 	samples = globals.read_codec.implementation->actual_samples_per_second * seconds;
1999 	globals.stream_in_use=1;
2000 	while (switch_core_file_read(&fh, abuf, &olen) == SWITCH_STATUS_SUCCESS) {
2001 		if (globals.destroying_streams ||  ! audio_stream->stream) {
2002 			break;
2003 		}
2004 
2005 		WriteAudioStream(audio_stream->stream, abuf, (long) olen, 0, &(audio_stream->write_timer));
2006 		wrote += (int) olen;
2007 		if (samples) {
2008 			samples -= (int) olen;
2009 			if (samples <= 0) {
2010 				break;
2011 			}
2012 		}
2013 		olen = globals.read_codec.implementation->samples_per_packet;
2014 	}
2015 	globals.stream_in_use = 0;
2016 
2017 	switch_core_file_close(&fh);
2018 	if (! globals.call_list && ( ! no_close || strcasecmp(no_close,  "no_close"))) {
2019 		destroy_audio_streams();
2020 	}
2021 
2022 	seconds = wrote / globals.read_codec.implementation->actual_samples_per_second;
2023 	stream->write_function(stream, "playback test [%s] %d second(s) %d samples @%dkhz",
2024 		file, seconds, wrote, globals.read_codec.implementation->actual_samples_per_second);
2025 	if (created_stream) { /*still need this as not added to the global pool */
2026 		destroy_actual_stream(audio_stream);
2027 	}
2028 	return SWITCH_STATUS_SUCCESS;
2029 }
devlist(char ** argv,int argc,switch_stream_handle_t * stream)2030 static switch_status_t devlist(char **argv, int argc, switch_stream_handle_t *stream)
2031 {
2032 	int i, numDevices, prev;
2033 	const PaDeviceInfo *deviceInfo;
2034 	const PaHostApiInfo *hostApiInfo;
2035 
2036 	numDevices = Pa_GetDeviceCount();
2037 
2038 	if (numDevices < 0) {
2039 		return SWITCH_STATUS_SUCCESS;
2040 	}
2041 
2042 	if (argv[0] && !strcasecmp(argv[0], "xml")) {
2043 		stream->write_function(stream, "<xml>\n\t<devices>\n");
2044 
2045 		for (i = 0; i < numDevices; i++) {
2046 			deviceInfo = Pa_GetDeviceInfo(i);
2047 			hostApiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
2048 			stream->write_function(stream, "\t\t<device id=\"%d\" name=\"%s\" hostapi=\"%s\" inputs=\"%d\" outputs=\"%d\" />\n", i, deviceInfo->name,
2049 								   hostApiInfo->name, deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels);
2050 		}
2051 
2052 		stream->write_function(stream, "\t</devices>\n\t<bindings>\n"
2053 							   "\t\t<ring device=\"%d\" />\n"
2054 							   "\t\t<input device=\"%d\" />\n"
2055 							   "\t\t<output device=\"%d\" />\n" "\t</bindings>\n</xml>\n", globals.ringdev, globals.indev, globals.outdev);
2056 	} else {
2057 
2058 		for (i = 0; i < numDevices; i++) {
2059 			deviceInfo = Pa_GetDeviceInfo(i);
2060 			hostApiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
2061 
2062 			stream->write_function(stream, "%d;%s(%s);%d;%d;", i, deviceInfo->name, hostApiInfo->name, deviceInfo->maxInputChannels,
2063 								   deviceInfo->maxOutputChannels);
2064 
2065 			prev = 0;
2066 			if (globals.ringdev == i) {
2067 				stream->write_function(stream, "r");
2068 				prev = 1;
2069 			}
2070 
2071 			if (globals.indev == i) {
2072 				if (prev) {
2073 					stream->write_function(stream, ",");
2074 				}
2075 				stream->write_function(stream, "i");
2076 				prev = 1;
2077 			}
2078 
2079 			if (globals.outdev == i) {
2080 				if (prev) {
2081 					stream->write_function(stream, ",");
2082 				}
2083 				stream->write_function(stream, "o");
2084 			}
2085 
2086 			stream->write_function(stream, "\n");
2087 
2088 		}
2089 	}
2090 
2091 	return SWITCH_STATUS_SUCCESS;
2092 }
2093 
dump_info(int verbose)2094 static int dump_info(int verbose)
2095 {
2096 	int i, numDevices, defaultDisplayed;
2097 	const PaDeviceInfo *deviceInfo;
2098 	PaStreamParameters inputParameters, outputParameters;
2099 	PaError err;
2100 	const char *line = "--------------------------------------------------------------------------------\n";
2101 
2102 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
2103 					  "PortAudio version number = %d\nPortAudio version text = '%s'\n", Pa_GetVersion(), Pa_GetVersionText());
2104 	if (globals.call_list) {
2105 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ERROR: Cannot use this command this while a call is in progress\n");
2106 		return 0;
2107 	}
2108 
2109 	if (verbose < 0) {
2110 		destroy_audio_streams();
2111 		destroy_codecs();
2112 		Pa_Terminate();
2113 		Pa_Initialize();
2114 		load_config();
2115 		verbose = 0;
2116 	}
2117 
2118 	numDevices = Pa_GetDeviceCount();
2119 	if (numDevices < 0) {
2120 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices);
2121 		err = numDevices;
2122 		goto error;
2123 	}
2124 
2125 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Number of devices = %d\n", numDevices);
2126 
2127 	if (!verbose) {
2128 		return 0;
2129 	}
2130 
2131 	for (i = 0; i < numDevices; i++) {
2132 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s", line);
2133 		deviceInfo = Pa_GetDeviceInfo(i);
2134 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Device #%d ", i);
2135 
2136 		/* Mark global and API specific default devices */
2137 		defaultDisplayed = 0;
2138 		if (i == Pa_GetDefaultInputDevice()) {
2139 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "**Default Input");
2140 			defaultDisplayed = 1;
2141 
2142 		} else if (i == Pa_GetHostApiInfo(deviceInfo->hostApi)->defaultInputDevice) {
2143 
2144 			const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
2145 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "**Default %s Input", hostInfo->name);
2146 			defaultDisplayed = 1;
2147 		}
2148 
2149 		if (i == Pa_GetDefaultOutputDevice()) {
2150 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "**Default Output");
2151 			defaultDisplayed = 1;
2152 
2153 		} else if (i == Pa_GetHostApiInfo(deviceInfo->hostApi)->defaultOutputDevice) {
2154 
2155 			const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
2156 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "**Default %s Output", hostInfo->name);
2157 			defaultDisplayed = 1;
2158 		}
2159 
2160 		if (defaultDisplayed) {
2161 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "** | ");
2162 		}
2163 		/* print device info fields */
2164 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Name: %s\n", deviceInfo->name);
2165 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Host: %s | ", Pa_GetHostApiInfo(deviceInfo->hostApi)->name);
2166 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "inputs: %d | ", deviceInfo->maxInputChannels);
2167 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "outputs: %d | ", deviceInfo->maxOutputChannels);
2168 
2169 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Default rate: %8.2f\n", deviceInfo->defaultSampleRate);
2170 
2171 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Default input latency: %.3f | ", deviceInfo->defaultLowInputLatency);
2172 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Default output latency: %.3f\n", deviceInfo->defaultLowOutputLatency);
2173 
2174 		/* poll for standard sample rates */
2175 		inputParameters.device = i;
2176 		inputParameters.channelCount = deviceInfo->maxInputChannels;
2177 		inputParameters.sampleFormat = paInt16;
2178 		inputParameters.suggestedLatency = deviceInfo->defaultLowInputLatency;	/* ignored by Pa_IsFormatSupported() */
2179 		inputParameters.hostApiSpecificStreamInfo = NULL;
2180 
2181 		outputParameters.device = i;
2182 		outputParameters.channelCount = deviceInfo->maxOutputChannels;
2183 		outputParameters.sampleFormat = paInt16;
2184 		outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency;	/* ignored by Pa_IsFormatSupported() */
2185 		outputParameters.hostApiSpecificStreamInfo = NULL;
2186 
2187 		if (inputParameters.channelCount > 0) {
2188 
2189 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "half-duplex 16 bit %d channel input rates:", inputParameters.channelCount);
2190 			PrintSupportedStandardSampleRates(&inputParameters, NULL);
2191 		}
2192 
2193 		if (outputParameters.channelCount > 0) {
2194 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "half-duplex 16 bit %d channel output rates:", outputParameters.channelCount);
2195 			PrintSupportedStandardSampleRates(NULL, &outputParameters);
2196 		}
2197 
2198 		if (inputParameters.channelCount > 0 && outputParameters.channelCount > 0) {
2199 
2200 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
2201 							  "full-duplex 16 bit %d channel input, %d channel output rates:", inputParameters.channelCount,
2202 							  outputParameters.channelCount);
2203 			PrintSupportedStandardSampleRates(&inputParameters, &outputParameters);
2204 		}
2205 	}
2206 
2207 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s", line);
2208 
2209 	return 0;
2210 
2211   error:
2212 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "An error occurred while using the portaudio stream\n");
2213 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Error number: %d\n", err);
2214 	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Error message: %s\n", Pa_GetErrorText(err));
2215 	return err;
2216 }
2217 
create_codecs(int restart)2218 static switch_status_t create_codecs(int restart)
2219 {
2220 	int sample_rate = globals.sample_rate;
2221 	int codec_ms = globals.codec_ms;
2222 
2223 	if (restart) {
2224 		destroy_codecs();
2225 	}
2226 	if (globals.codecs_inited) {
2227 		return SWITCH_STATUS_SUCCESS;
2228 	}
2229 
2230 	if (!switch_core_codec_ready(&globals.read_codec)) {
2231 		if (switch_core_codec_init(&globals.read_codec,
2232 								   "L16",
2233 								   NULL,
2234 								   NULL, sample_rate, codec_ms, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
2235 								   NULL) != SWITCH_STATUS_SUCCESS) {
2236 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
2237 			return SWITCH_STATUS_FALSE;
2238 		}
2239 	}
2240 
2241 	switch_assert(globals.read_codec.implementation);
2242 
2243 	if (!switch_core_codec_ready(&globals.write_codec)) {
2244 		if (switch_core_codec_init(&globals.write_codec,
2245 								   "L16",
2246 								   NULL,
2247 								   NULL,
2248 								   sample_rate, codec_ms, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
2249 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
2250 			switch_core_codec_destroy(&globals.read_codec);
2251 			return SWITCH_STATUS_FALSE;
2252 		}
2253 	}
2254 
2255 	if (!globals.read_timer.timer_interface) {
2256 		if (switch_core_timer_init(&globals.read_timer,
2257 								   globals.timer_name, codec_ms, globals.read_codec.implementation->samples_per_packet,
2258 								   module_pool) != SWITCH_STATUS_SUCCESS) {
2259 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "setup timer failed!\n");
2260 			switch_core_codec_destroy(&globals.read_codec);
2261 			switch_core_codec_destroy(&globals.write_codec);
2262 			return SWITCH_STATUS_FALSE;
2263 		}
2264 	}
2265 	if (!globals.readfile_timer.timer_interface) {
2266 		if (switch_core_timer_init(&globals.readfile_timer,
2267 								   globals.timer_name, codec_ms, globals.read_codec.implementation->samples_per_packet,
2268 								   module_pool) != SWITCH_STATUS_SUCCESS) {
2269 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "setup timer failed!\n");
2270 			switch_core_codec_destroy(&globals.read_codec);
2271 			switch_core_codec_destroy(&globals.write_codec);
2272 			return SWITCH_STATUS_FALSE;
2273 		}
2274 	}
2275 
2276 
2277 	if (!globals.hold_timer.timer_interface) {
2278 		if (switch_core_timer_init(&globals.hold_timer,
2279 								   globals.timer_name, codec_ms, globals.read_codec.implementation->samples_per_packet,
2280 								   module_pool) != SWITCH_STATUS_SUCCESS) {
2281 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "setup hold timer failed!\n");
2282 			switch_core_codec_destroy(&globals.read_codec);
2283 			switch_core_codec_destroy(&globals.write_codec);
2284 			switch_core_timer_destroy(&globals.read_timer);
2285 			switch_core_timer_destroy(&globals.readfile_timer);
2286 
2287 			return SWITCH_STATUS_FALSE;
2288 		}
2289 	}
2290 
2291 	globals.cng_frame.rate = globals.read_frame.rate = sample_rate;
2292 	globals.cng_frame.codec = globals.read_frame.codec = &globals.read_codec;
2293 
2294 	globals.codecs_inited=1;
2295 	return SWITCH_STATUS_SUCCESS;
2296 }
2297 
switch_audio_stream()2298 static switch_status_t switch_audio_stream()
2299 {
2300 	audio_stream_t *stream;
2301 	if (! globals.call_list) { /* If no active calls then it will automatically switch over on next call */
2302 		return SWITCH_STATUS_SUCCESS;
2303 	}
2304 	stream = get_audio_stream(globals.indev, globals.outdev);
2305 	if (stream == NULL) {
2306 		return SWITCH_STATUS_FALSE;
2307 	}
2308 
2309 	globals.main_stream = stream;//TODO: need locks around here??
2310 
2311 	return SWITCH_STATUS_SUCCESS;
2312 }
2313 
open_audio_stream(PABLIO_Stream ** stream,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters)2314 PaError open_audio_stream(PABLIO_Stream **stream, const PaStreamParameters * inputParameters, const PaStreamParameters * outputParameters)
2315 {
2316 	if (inputParameters->device != -1) {
2317 		return OpenAudioStream(stream, inputParameters, outputParameters, globals.sample_rate, paClipOff, globals.read_codec.implementation->samples_per_packet, globals.dual_streams);
2318 	}
2319 	return OpenAudioStream(stream, NULL, outputParameters, globals.sample_rate, paClipOff, globals.read_codec.implementation->samples_per_packet, 0);
2320 }
2321 
open_shared_audio_stream(shared_audio_stream_t * shstream,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters)2322 PaError open_shared_audio_stream(shared_audio_stream_t *shstream, const PaStreamParameters * inputParameters, const PaStreamParameters * outputParameters)
2323 {
2324 	PaError err;
2325 	if (inputParameters->device != -1) {
2326 		err = OpenAudioStream(&shstream->stream, inputParameters->device != -1 ? inputParameters : NULL,
2327 							outputParameters->device != -1 ? outputParameters : NULL, shstream->sample_rate,
2328 				paClipOff, STREAM_SAMPLES_PER_PACKET(shstream), globals.dual_streams);
2329 	} else {
2330 		err = OpenAudioStream(&shstream->stream, NULL, outputParameters, shstream->sample_rate,
2331 				paClipOff, STREAM_SAMPLES_PER_PACKET(shstream), 0);
2332 	}
2333 	if (err != paNoError) {
2334 		shstream->stream = NULL;
2335 	}
2336 	return err;
2337 }
2338 
create_shared_audio_stream(shared_audio_stream_t * shstream)2339 static int create_shared_audio_stream(shared_audio_stream_t *shstream)
2340 {
2341 	PaStreamParameters inputParameters, outputParameters;
2342 	PaError err;
2343 	switch_event_t *event;
2344 
2345 	inputParameters.device = shstream->indev;
2346 	if (shstream->indev != -1) {
2347 		inputParameters.channelCount = shstream->channels;
2348 		inputParameters.sampleFormat = SAMPLE_TYPE;
2349 		inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;
2350 		inputParameters.hostApiSpecificStreamInfo = NULL;
2351 	}
2352 	outputParameters.device = shstream->outdev;
2353 	if (shstream->outdev != -1) {
2354 		outputParameters.channelCount = shstream->channels;
2355 		outputParameters.sampleFormat = SAMPLE_TYPE;
2356 		outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
2357 		outputParameters.hostApiSpecificStreamInfo = NULL;
2358 	}
2359 
2360 	err = open_shared_audio_stream(shstream, &inputParameters, &outputParameters);
2361 	if (err != paNoError) {
2362 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
2363 						"Error opening audio device retrying (indev = %d, outdev = %d, error = %s)\n",
2364 						inputParameters.device, outputParameters.device, Pa_GetErrorText(err));
2365 		switch_yield(1000000);
2366 		err = open_shared_audio_stream(shstream, &inputParameters, &outputParameters);
2367 	}
2368 
2369 	if (err != paNoError) {
2370 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open audio device (indev = %d, outdev = %d, error = %s)\n",
2371 				inputParameters.device, outputParameters.device, Pa_GetErrorText(err));
2372 		if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_ERROR_AUDIO_DEV) == SWITCH_STATUS_SUCCESS) {
2373 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Reason", Pa_GetErrorText(err));
2374 			switch_event_fire(&event);
2375 		}
2376 		return -1;
2377 	}
2378 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created shared audio stream %s: %d channels %d\n",
2379 			shstream->name, shstream->sample_rate, shstream->channels);
2380 	return 0;
2381 }
2382 
destroy_shared_audio_stream(shared_audio_stream_t * shstream)2383 static int destroy_shared_audio_stream(shared_audio_stream_t *shstream)
2384 {
2385 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Destroying shared audio stream %s\n", shstream->name);
2386 	CloseAudioStream(shstream->stream);
2387 	shstream->stream = NULL;
2388 	return 0;
2389 }
2390 
create_audio_stream(int indev,int outdev)2391 static audio_stream_t *create_audio_stream(int indev, int outdev)
2392 {
2393 	PaStreamParameters inputParameters, outputParameters;
2394 	PaError err;
2395 	switch_event_t *event;
2396 	audio_stream_t *stream;
2397 
2398 	stream = malloc(sizeof(*stream));
2399 	if (stream == NULL) {
2400 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to alloc memory\n");
2401 		return NULL;
2402 	}
2403 	memset(stream, 0, sizeof(*stream));
2404 	stream->next = NULL;
2405 	stream->stream = NULL;
2406 	stream->indev = indev;
2407 	stream->outdev = outdev;
2408 	if (!stream->write_timer.timer_interface) {
2409 		if (switch_core_timer_init(&(stream->write_timer),
2410 								   globals.timer_name, globals.codec_ms, globals.read_codec.implementation->samples_per_packet,
2411 								   module_pool) != SWITCH_STATUS_SUCCESS) {
2412 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "setup timer failed!\n");
2413 			switch_safe_free(stream);
2414 			return NULL;
2415 		}
2416 	}
2417 
2418 	inputParameters.device = indev;
2419 	if (indev != -1) {
2420 		inputParameters.channelCount = 1;
2421 		inputParameters.sampleFormat = SAMPLE_TYPE;
2422 		inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;
2423 		inputParameters.hostApiSpecificStreamInfo = NULL;
2424 	}
2425 	outputParameters.device = outdev;
2426 
2427 	if (outdev != -1) {
2428 		outputParameters.channelCount = 1;
2429 		outputParameters.sampleFormat = SAMPLE_TYPE;
2430 		outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
2431 		outputParameters.hostApiSpecificStreamInfo = NULL;
2432 	}
2433 
2434 	err = open_audio_stream(&(stream->stream), &inputParameters, &outputParameters);
2435 	if (err != paNoError) {
2436 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening audio device retrying\n");
2437 		switch_yield(1000000);
2438 		err = open_audio_stream(&(stream->stream), &inputParameters, &outputParameters);
2439 	}
2440 
2441 	if (err != paNoError) {
2442 		switch_safe_free(stream);
2443 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open audio device\n");
2444 		if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_ERROR_AUDIO_DEV) == SWITCH_STATUS_SUCCESS) {
2445 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Reason", Pa_GetErrorText(err));
2446 			switch_event_fire(&event);
2447 		}
2448 		return NULL;
2449 	}
2450 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created audio stream: %d channels %d\n", globals.sample_rate, outputParameters.channelCount);
2451 	return stream;
2452 }
2453 
get_audio_stream(int indev,int outdev)2454 audio_stream_t *get_audio_stream(int indev, int outdev)
2455 {
2456 	audio_stream_t *stream = NULL;
2457 	if (outdev == -1) {
2458 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error invalid output audio device\n");
2459 		return NULL;
2460 	}
2461 	if (create_codecs(0) != SWITCH_STATUS_SUCCESS) {
2462 		return NULL;
2463 	}
2464 
2465 	stream = find_audio_stream(indev, outdev, 0);
2466 	if (stream != NULL) {
2467 		return stream;
2468 	}
2469 	stream = create_audio_stream(indev, outdev);
2470 	if (stream) {
2471 		add_stream(stream, 0);
2472 	}
2473 	return stream;
2474 }
2475 
dtmf_call(char ** argv,int argc,switch_stream_handle_t * stream)2476 static switch_status_t dtmf_call(char **argv, int argc, switch_stream_handle_t *stream)
2477 {
2478 	char *dtmf_str = argv[0];
2479 	switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0) };
2480 
2481 	if (zstr(dtmf_str)) {
2482 		stream->write_function(stream, "No DTMF Supplied!\n");
2483 	} else {
2484 		switch_mutex_lock(globals.pvt_lock);
2485 		if (globals.call_list) {
2486 			switch_channel_t *channel = switch_core_session_get_channel(globals.call_list->session);
2487 			char *p = dtmf_str;
2488 			while (p && *p) {
2489 				dtmf.digit = *p;
2490 				switch_channel_queue_dtmf(channel, &dtmf);
2491 				p++;
2492 			}
2493 		}
2494 		switch_mutex_unlock(globals.pvt_lock);
2495 	}
2496 
2497 	return SWITCH_STATUS_SUCCESS;
2498 }
2499 
list_shared_streams(char ** argv,int argc,switch_stream_handle_t * stream)2500 static switch_status_t list_shared_streams(char **argv, int argc, switch_stream_handle_t *stream)
2501 {
2502 	switch_hash_index_t *hi;
2503 	int cnt = 0;
2504 	for (hi = switch_core_hash_first(globals.sh_streams); hi; hi = switch_core_hash_next(&hi)) {
2505 		const void *var;
2506 		void *val;
2507 		shared_audio_stream_t *s = NULL;
2508 		switch_core_hash_this(hi, &var, NULL, &val);
2509 		s = val;
2510 		stream->write_function(stream, "%s> indev: %d, outdev: %d, sample-rate: %d, codec-ms: %d, channels: %d\n",
2511 				s->name, s->indev, s->outdev, s->sample_rate, s->codec_ms, s->channels);
2512 		cnt++;
2513 	}
2514 	stream->write_function(stream, "Total streams: %d\n", cnt);
2515 	return SWITCH_STATUS_SUCCESS;
2516 }
2517 
list_endpoints(char ** argv,int argc,switch_stream_handle_t * stream)2518 static switch_status_t list_endpoints(char **argv, int argc, switch_stream_handle_t *stream)
2519 {
2520 	switch_hash_index_t *hi;
2521 	int cnt = 0;
2522 	for (hi = switch_core_hash_first(globals.endpoints); hi; hi = switch_core_hash_next(&hi)) {
2523 		const void *var;
2524 		void *val;
2525 		audio_endpoint_t *e = NULL;
2526 		switch_core_hash_this(hi, &var, NULL, &val);
2527 		e = val;
2528 		stream->write_function(stream, "%s> instream: %s, outstream: %s\n",
2529 				e->name, e->in_stream ? e->in_stream->name : "(none)",
2530 				e->out_stream ? e->out_stream->name : "(none)");
2531 		cnt++;
2532 	}
2533 	stream->write_function(stream, "Total endpoints: %d\n", cnt);
2534 	return SWITCH_STATUS_SUCCESS;
2535 }
2536 
close_streams(char ** argv,int argc,switch_stream_handle_t * stream)2537 static switch_status_t close_streams(char **argv, int argc, switch_stream_handle_t *stream)
2538 {
2539 	if (globals.call_list) {
2540 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ERROR: Cannot use this command this while a call is in progress\n");
2541 		return SWITCH_STATUS_FALSE;
2542 	}
2543 	destroy_audio_streams();
2544 	stream->write_function(stream, "closestreams all open streams closed\n");
2545 	return SWITCH_STATUS_SUCCESS;
2546 }
2547 
set_indev(char ** argv,int argc,switch_stream_handle_t * stream)2548 static switch_status_t set_indev(char **argv, int argc, switch_stream_handle_t *stream)
2549 {
2550 	int devval;
2551 
2552 	if (globals.call_list && ! globals.live_stream_switch) {
2553 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ERROR: Cannot use this command this while a call is in progress\n");
2554 		return SWITCH_STATUS_FALSE;
2555 	}
2556 	if (*argv[0] == '#') {
2557 		devval = get_dev_by_number(argv[0] + 1, 1);
2558 	} else {
2559 		devval = get_dev_by_name(argv[0], 1);
2560 	}
2561 	if (devval < 0) {
2562 		stream->write_function(stream, "indev not set (invalid value)\n");
2563 		return SWITCH_STATUS_FALSE;
2564 	}
2565 	globals.indev = devval;
2566 	switch_audio_stream();
2567 	stream->write_function(stream, "indev set to %d\n", devval);
2568 	return SWITCH_STATUS_SUCCESS;
2569 }
2570 
set_outdev(char ** argv,int argc,switch_stream_handle_t * stream)2571 static switch_status_t set_outdev(char **argv, int argc, switch_stream_handle_t *stream)
2572 {
2573 	int devval;
2574 	if (globals.call_list && ! globals.live_stream_switch) {
2575 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ERROR: Cannot use this command this while a call is in progress\n");
2576 		return SWITCH_STATUS_FALSE;
2577 	}
2578 	if (*argv[0] == '#') {
2579 		devval = get_dev_by_number(argv[0] + 1, 0);
2580 	} else {
2581 		devval = get_dev_by_name(argv[0], 0);
2582 	}
2583 	if (devval < 0) {
2584 		stream->write_function(stream, "outdev not set (invalid value)\n");
2585 		return SWITCH_STATUS_FALSE;
2586 	}
2587 
2588 	globals.outdev = devval;
2589 	switch_audio_stream();
2590 	stream->write_function(stream, "outdev set to %d\n", devval);
2591 	return SWITCH_STATUS_SUCCESS;
2592 }
2593 
prepare_stream(char ** argv,int argc,switch_stream_handle_t * stream)2594 static switch_status_t prepare_stream(char **argv, int argc, switch_stream_handle_t *stream)
2595 {
2596 	int devval=-2,devval2=-1;
2597 	if (! strcmp(argv[0], "#-1")) {
2598 		devval = -1;
2599 	} else if (*argv[0] == '#') {
2600 		devval = get_dev_by_number(argv[0]+1, 1);
2601 	}
2602 	if (devval == -2) {
2603 		stream->write_function(stream, "preparestream not prepared as indev has (invalid value)\n");
2604 		return SWITCH_STATUS_FALSE;
2605 	}
2606 	if (*argv[1] == '#') {
2607 		devval2 = get_dev_by_number(argv[1]+1, 0);
2608 	}
2609 	if (devval2 == -1) {
2610 		stream->write_function(stream, "preparestream not prepared as outdev has (invalid value)\n");
2611 		return SWITCH_STATUS_FALSE;
2612 	}
2613 
2614 	if (! get_audio_stream(devval,devval2)) {
2615 		stream->write_function(stream, "preparestream not prepared received an invalid stream back\n");
2616 		return SWITCH_STATUS_FALSE;
2617 	}
2618 	stream->write_function(stream, "preparestream prepared indev: %d outdev: %d\n", devval, devval2);
2619 	return SWITCH_STATUS_SUCCESS;
2620 }
2621 
switch_stream(char ** argv,int argc,switch_stream_handle_t * stream)2622 static switch_status_t switch_stream(char **argv, int argc, switch_stream_handle_t *stream)
2623 {
2624 	int devval =-1, devval2 = -1;
2625 	if (globals.call_list && ! globals.live_stream_switch) {
2626 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ERROR: Cannot use this command this while a call is in progress\n");
2627 		return SWITCH_STATUS_FALSE;
2628 	}
2629 	if (*argv[0] == '#') {
2630 		devval = get_dev_by_number(argv[0]+1, 1);
2631 	}
2632 	if (devval == -1) {
2633 		stream->write_function(stream, "switchstream not prepared as indev has (invalid value)\n");
2634 		return SWITCH_STATUS_FALSE;
2635 	}
2636 	if (*argv[1] == '#') {
2637 		devval2 = get_dev_by_number(argv[1]+1, 0);
2638 	}
2639 	if (devval2 == -1) {
2640 		stream->write_function(stream, "switchstream not prepared as outdev has (invalid value)\n");
2641 		return SWITCH_STATUS_FALSE;
2642 	}
2643 	globals.indev = devval;
2644 	globals.outdev = devval2;
2645 	if (switch_audio_stream() != SWITCH_STATUS_SUCCESS) {
2646 		stream->write_function(stream, "switchstream was unable to switch\n");
2647 		return SWITCH_STATUS_FALSE;
2648 	}
2649 	stream->write_function(stream, "switchstream switched to indev: %d outdev: %d\n", devval, devval2);
2650 	return SWITCH_STATUS_SUCCESS;
2651 }
2652 
set_ringdev(char ** argv,int argc,switch_stream_handle_t * stream)2653 static switch_status_t set_ringdev(char **argv, int argc, switch_stream_handle_t *stream)
2654 {
2655 	int devval;
2656 	if (globals.call_list && ! globals.live_stream_switch) {
2657 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ERROR: Cannot use this command this while a call is in progress\n");
2658 		return SWITCH_STATUS_FALSE;
2659 	}
2660 	if (! strcmp(argv[0], "#-1")) {
2661 		globals.ring_stream = NULL;
2662 		globals.ringdev = -1;
2663 		stream->write_function(stream, "ringdev set to %d\n", globals.ringdev);
2664 		return SWITCH_STATUS_SUCCESS;
2665 	} else if (*argv[0] == '#') {
2666 		devval = get_dev_by_number(argv[0] + 1, 0);
2667 	} else {
2668 		devval = get_dev_by_name(argv[0], 0);
2669 	}
2670 	if (devval == -1) {
2671 		stream->write_function(stream, "ringdev not set as dev has (invalid value)\n");
2672 		return SWITCH_STATUS_FALSE;
2673 	}
2674 	globals.ringdev = devval;
2675 	stream->write_function(stream, "ringdev set to %d\n", globals.ringdev);
2676 	return SWITCH_STATUS_SUCCESS;
2677 }
2678 
looptest(char ** argv,int argc,switch_stream_handle_t * stream)2679 static switch_status_t looptest(char **argv, int argc, switch_stream_handle_t *stream)
2680 {
2681 	int samples = 0;
2682 	int success = 0;
2683 	int i;
2684 
2685 	if (globals.call_list) {
2686 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ERROR: Cannot use this command this while a call is in progress\n");
2687 		return SWITCH_STATUS_FALSE;
2688 	}
2689 	if (validate_main_audio_stream() != SWITCH_STATUS_SUCCESS) {
2690 		stream->write_function(stream, "looptest Failed to engage audio device\n");
2691 		return SWITCH_STATUS_FALSE;
2692 	}
2693 	globals.stream_in_use = 1;
2694 	for (i = 0; i < 400; i++) {
2695 		if (globals.destroying_streams ||  ! globals.main_stream->stream) {
2696 			break;
2697 		}
2698 		if ((samples = ReadAudioStream(globals.main_stream->stream, globals.read_frame.data, globals.read_codec.implementation->samples_per_packet, 0, &globals.read_timer))) {
2699 			WriteAudioStream(globals.main_stream->stream, globals.read_frame.data, (long) samples, 0, &(globals.main_stream->write_timer));
2700 			success = 1;
2701 		}
2702 		switch_yield(10000);
2703 	}
2704 	globals.stream_in_use = 0;
2705 
2706 	if (!success) {
2707 		stream->write_function(stream, "Failed to read any bytes from indev\n");
2708 		return SWITCH_STATUS_FALSE;
2709 	}
2710 	destroy_audio_streams();
2711 	stream->write_function(stream, "looptest complete\n");
2712 	return SWITCH_STATUS_SUCCESS;
2713 }
2714 
set_ringfile(char ** argv,int argc,switch_stream_handle_t * stream)2715 static switch_status_t set_ringfile(char **argv, int argc, switch_stream_handle_t *stream)
2716 {
2717 	if (! argv[0]) {
2718 		stream->write_function(stream, "%s", globals.ring_file);
2719 		return SWITCH_STATUS_SUCCESS;
2720 	}
2721 	if (create_codecs(0) == SWITCH_STATUS_SUCCESS) {
2722 		switch_file_handle_t fh = { 0 };
2723 		if (switch_core_file_open(&fh,
2724 								  argv[0],
2725 								  globals.read_codec.implementation->number_of_channels,
2726 								  globals.read_codec.implementation->actual_samples_per_second,
2727 								  SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) == SWITCH_STATUS_SUCCESS) {
2728 			switch_core_file_close(&fh);
2729 			set_global_ring_file(argv[0]);
2730 		} else {
2731 			stream->write_function(stream, "ringfile Unable to open ring file %s\n", argv[0]);
2732 			return SWITCH_STATUS_FALSE;
2733 		}
2734 	} else {
2735 		stream->write_function(stream, "ringfile Failed to init codecs device\n");
2736 		return SWITCH_STATUS_FALSE;
2737 	}
2738 	stream->write_function(stream, "ringfile set to %s", globals.ring_file);
2739 	return SWITCH_STATUS_SUCCESS;
2740 }
2741 
switch_call(char ** argv,int argc,switch_stream_handle_t * stream)2742 static switch_status_t switch_call(char **argv, int argc, switch_stream_handle_t *stream)
2743 {
2744 	private_t *tp, *tech_pvt = NULL;
2745 	char *callid = argv[0];
2746 	uint8_t one_call = 0;
2747 
2748 
2749 	switch_mutex_lock(globals.pvt_lock);
2750 	if (zstr(callid)) {
2751 		if (globals.call_list) {
2752 			if (globals.call_list->next) {
2753 				tech_pvt = globals.call_list->next;
2754 			} else {
2755 				tech_pvt = globals.call_list;
2756 				one_call = 1;
2757 			}
2758 		}
2759 	} else if (!strcasecmp(callid, "none")) {
2760 		for (tp = globals.call_list; tp; tp = tp->next) {
2761 			if (switch_test_flag(tp, TFLAG_MASTER))	{
2762 			switch_clear_flag_locked(tp, TFLAG_MASTER);
2763 				create_hold_event(tp,0);
2764 			}
2765 		}
2766 		stream->write_function(stream, "OK\n");
2767 		goto done;
2768 	} else {
2769 		tech_pvt = switch_core_hash_find(globals.call_hash, callid);
2770 	}
2771 
2772 	if (tech_pvt) {
2773 		if (tech_pvt == globals.call_list && !tech_pvt->next) {
2774 			one_call = 1;
2775 		}
2776 
2777 		if (!one_call) {
2778 			remove_pvt(tech_pvt);
2779 		}
2780 		add_pvt(tech_pvt, PA_MASTER);
2781 		create_hold_event(tech_pvt, 1);
2782 		stream->write_function(stream, "OK\n");
2783 	} else {
2784 		stream->write_function(stream, "NO SUCH CALL\n");
2785 	}
2786 
2787   done:
2788 	switch_mutex_unlock(globals.pvt_lock);
2789 
2790 	return SWITCH_STATUS_SUCCESS;
2791 }
2792 
hangup_call(char ** argv,int argc,switch_stream_handle_t * stream)2793 static switch_status_t hangup_call(char **argv, int argc, switch_stream_handle_t *stream)
2794 {
2795 	private_t *tech_pvt;
2796 	char *callid = argv[0];
2797 
2798 	switch_mutex_lock(globals.pvt_lock);
2799 	if (zstr(callid)) {
2800 		tech_pvt = globals.call_list;
2801 	} else {
2802 		tech_pvt = switch_core_hash_find(globals.call_hash, callid);
2803 	}
2804 
2805 	if (tech_pvt) {
2806 		switch_channel_hangup(switch_core_session_get_channel(tech_pvt->session), SWITCH_CAUSE_NORMAL_CLEARING);
2807 		stream->write_function(stream, "OK\n");
2808 	} else {
2809 		stream->write_function(stream, "NO SUCH CALL\n");
2810 	}
2811 	switch_mutex_unlock(globals.pvt_lock);
2812 
2813 	return SWITCH_STATUS_SUCCESS;
2814 }
2815 
answer_call(char ** argv,int argc,switch_stream_handle_t * stream)2816 static switch_status_t answer_call(char **argv, int argc, switch_stream_handle_t *stream)
2817 {
2818 	private_t *tp;
2819 	int x = 0;
2820 	char *callid = argv[0];
2821 
2822 	switch_mutex_lock(globals.pvt_lock);
2823 
2824 	if (!zstr(callid)) {
2825 		if ((tp = switch_core_hash_find(globals.call_hash, callid))) {
2826 			if (switch_test_flag(tp, TFLAG_ANSWER)) {
2827 				stream->write_function(stream, "CALL ALREADY ANSWERED\n");
2828 			} else {
2829 				switch_channel_t *channel = switch_core_session_get_channel(tp->session);
2830 				switch_set_flag_locked(tp, TFLAG_ANSWER);
2831 				if (tp != globals.call_list) {
2832 					remove_pvt(tp);
2833 				}
2834 				add_pvt(tp, PA_MASTER);
2835 				switch_channel_mark_answered(channel);
2836 			}
2837 		} else {
2838 			stream->write_function(stream, "NO SUCH CALL\n");
2839 		}
2840 
2841 		goto done;
2842 	}
2843 
2844 	for (tp = globals.call_list; tp; tp = tp->next) {
2845 		if (!switch_test_flag(tp, TFLAG_ANSWER)) {
2846 			switch_channel_t *channel = switch_core_session_get_channel(tp->session);
2847 			switch_set_flag_locked(tp, TFLAG_ANSWER);
2848 			add_pvt(tp, PA_MASTER);
2849 			switch_channel_mark_answered(channel);
2850 			x++;
2851 			break;
2852 		}
2853 	}
2854   done:
2855 	switch_mutex_unlock(globals.pvt_lock);
2856 	stream->write_function(stream, "Answered %d channels.\n", x);
2857 
2858 	return SWITCH_STATUS_SUCCESS;
2859 }
2860 
do_flags(char ** argv,int argc,switch_stream_handle_t * stream)2861 static switch_status_t do_flags(char **argv, int argc, switch_stream_handle_t *stream)
2862 {
2863 	char *action = argv[0];
2864 	char *flag_str;
2865 	GFLAGS flags = GFLAG_NONE;
2866 	char *p;
2867 	int x = 0;
2868 
2869 	if (argc < 2) {
2870 		goto desc;
2871 	}
2872 
2873 	for (x = 1; x < argc; x++) {
2874 		flag_str = argv[x];
2875 		for (p = flag_str; *p; p++) {
2876 			*p = (char) tolower(*p);
2877 		}
2878 
2879 		if (strstr(flag_str, "ear")) {
2880 			flags |= GFLAG_EAR;
2881 		}
2882 		if (strstr(flag_str, "mouth")) {
2883 			flags |= GFLAG_MOUTH;
2884 		}
2885 	}
2886 
2887 	if (!strcasecmp(action, "on")) {
2888 		if (flags & GFLAG_EAR) {
2889 			switch_set_flag((&globals), GFLAG_EAR);
2890 		}
2891 		if (flags & GFLAG_MOUTH) {
2892 			switch_set_flag((&globals), GFLAG_MOUTH);
2893 		}
2894 	} else if (!strcasecmp(action, "off")) {
2895 		if (flags & GFLAG_EAR) {
2896 			switch_clear_flag((&globals), GFLAG_EAR);
2897 		}
2898 		if (flags & GFLAG_MOUTH) {
2899 			switch_clear_flag((&globals), GFLAG_MOUTH);
2900 		}
2901 	} else {
2902 		goto bad;
2903 	}
2904 
2905   desc:
2906 	x = 0;
2907 	stream->write_function(stream, "FLAGS: ");
2908 	if (switch_test_flag((&globals), GFLAG_EAR)) {
2909 		stream->write_function(stream, "ear");
2910 		x++;
2911 	}
2912 	if (switch_test_flag((&globals), GFLAG_MOUTH)) {
2913 		stream->write_function(stream, "%smouth", x ? "|" : "");
2914 		x++;
2915 	}
2916 	if (!x) {
2917 		stream->write_function(stream, "none");
2918 	}
2919 
2920 	goto done;
2921 
2922   bad:
2923 	stream->write_function(stream, "Usage: flags [on|off] <flags>\n");
2924   done:
2925 	return SWITCH_STATUS_SUCCESS;
2926 }
2927 
list_calls(char ** argv,int argc,switch_stream_handle_t * stream)2928 static switch_status_t list_calls(char **argv, int argc, switch_stream_handle_t *stream)
2929 {
2930 	private_t *tp;
2931 	int x = 0;
2932 	const char *cid_name = "n/a";
2933 	const char *cid_num = "n/a";
2934 
2935 	switch_mutex_lock(globals.pvt_lock);
2936 	for (tp = globals.call_list; tp; tp = tp->next) {
2937 		switch_channel_t *channel;
2938 		switch_caller_profile_t *profile;
2939 		x++;
2940 		channel = switch_core_session_get_channel(tp->session);
2941 
2942 		if ((profile = switch_channel_get_caller_profile(channel))) {
2943 			if (profile->originatee_caller_profile) {
2944 				cid_name = "Outbound Call";
2945 				cid_num = profile->originatee_caller_profile->destination_number;
2946 			} else {
2947 				cid_name = profile->caller_id_name;
2948 				cid_num = profile->caller_id_number;
2949 			}
2950 		}
2951 
2952 		stream->write_function(stream, "%s %s [%s (%s)] %s\n", tp->call_id, switch_channel_get_name(channel),
2953 							   cid_name, cid_num, switch_test_flag(tp, TFLAG_MASTER) ? "active" : "hold");
2954 	}
2955 	switch_mutex_unlock(globals.pvt_lock);
2956 
2957 	stream->write_function(stream, "\n%d call%s\n", x, x == 1 ? "" : "s");
2958 
2959 	return SWITCH_STATUS_SUCCESS;
2960 }
2961 
place_call(char ** argv,int argc,switch_stream_handle_t * stream)2962 static switch_status_t place_call(char **argv, int argc, switch_stream_handle_t *stream)
2963 {
2964 	switch_core_session_t *session;
2965 	switch_status_t status = SWITCH_STATUS_SUCCESS;
2966 	char *dest = NULL;
2967 
2968 	if (zstr(argv[0])) {
2969 		stream->write_function(stream, "FAIL:Usage: call <dest>\n");
2970 		return SWITCH_STATUS_SUCCESS;
2971 	}
2972 	dest = argv[0];
2973 
2974 	if ((session = switch_core_session_request(portaudio_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL)) != 0) {
2975 		private_t *tech_pvt;
2976 		switch_channel_t *channel;
2977 		char *dialplan = globals.dialplan;
2978 		char *context = globals.context;
2979 		char *cid_name = globals.cid_name;
2980 		char *cid_num = globals.cid_num;
2981 		char ip[25] = "0.0.0.0";
2982 
2983 		switch_core_session_add_stream(session, NULL);
2984 		if ((tech_pvt = (private_t *) switch_core_session_alloc(session, sizeof(private_t))) != 0) {
2985 			memset(tech_pvt, 0, sizeof(*tech_pvt));
2986 			switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
2987 			channel = switch_core_session_get_channel(session);
2988 			switch_core_session_set_private(session, tech_pvt);
2989 			tech_pvt->session = session;
2990 		} else {
2991 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
2992 			switch_core_session_destroy(&session);
2993 			return SWITCH_STATUS_MEMERR;
2994 		}
2995 
2996 		if (!zstr(argv[1])) {
2997 			dialplan = argv[1];
2998 		}
2999 
3000 		if (!zstr(argv[2])) {
3001 			cid_num = argv[2];
3002 		}
3003 
3004 		if (!zstr(argv[3])) {
3005 			cid_name = argv[3];
3006 		}
3007 
3008 		if (!zstr(argv[4])) {
3009 			tech_pvt->sample_rate = atoi(argv[4]);
3010 		}
3011 
3012 		if (!zstr(argv[5])) {
3013 			tech_pvt->codec_ms = atoi(argv[5]);
3014 		}
3015 
3016 		switch_find_local_ip(ip, sizeof(ip), NULL, AF_INET);
3017 
3018 		if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
3019 																  NULL, dialplan, cid_name, cid_num, ip, NULL, NULL, NULL, modname, context, dest)) != 0) {
3020 			char name[128];
3021 			switch_snprintf(name, sizeof(name), "portaudio/%s",
3022 							tech_pvt->caller_profile->destination_number ? tech_pvt->caller_profile->destination_number : modname);
3023 			switch_channel_set_name(channel, name);
3024 
3025 			switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
3026 		}
3027 		tech_pvt->session = session;
3028 		if ((status = validate_main_audio_stream()) == SWITCH_STATUS_SUCCESS) {
3029 			switch_set_flag_locked(tech_pvt, TFLAG_ANSWER);
3030 			switch_channel_mark_answered(channel);
3031 			switch_channel_set_state(channel, CS_INIT);
3032 			if (switch_core_session_thread_launch(tech_pvt->session) != SWITCH_STATUS_SUCCESS) {
3033 				switch_event_t *event;
3034 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error spawning thread\n");
3035 				switch_core_session_destroy(&session);
3036 				stream->write_function(stream, "FAIL:Thread Error!\n");
3037 				if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_MAKE_CALL) == SWITCH_STATUS_SUCCESS) {
3038 					char buf[512];
3039 					switch_channel_event_set_data(channel, event);
3040 					switch_snprintf(buf, sizeof(buf), "Thread error!.\n");
3041 					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "error", buf);
3042 					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fail", "true");
3043 					switch_event_fire(&event);
3044 				}
3045 			} else {
3046 				switch_event_t *event;
3047 				add_pvt(tech_pvt, PA_MASTER);
3048 				stream->write_function(stream, "SUCCESS:%s:%s\n", tech_pvt->call_id, switch_core_session_get_uuid(tech_pvt->session));
3049 				if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_MAKE_CALL) == SWITCH_STATUS_SUCCESS) {
3050 					switch_channel_event_set_data(channel, event);
3051 					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fail", "false");
3052 					switch_event_fire(&event);
3053 				}
3054 			}
3055 		} else {
3056 			switch_event_t *event;
3057 			switch_core_session_destroy(&session);
3058 			stream->write_function(stream, "FAIL:Device Error!\n");
3059 			if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_MAKE_CALL) == SWITCH_STATUS_SUCCESS) {
3060 				char buf[512];
3061 				switch_channel_event_set_data(channel, event);
3062 				switch_snprintf(buf, sizeof(buf), "Device fail.\n");
3063 				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "error", buf);
3064 				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fail", "true");
3065 				switch_event_fire(&event);
3066 			}
3067 		}
3068 	}
3069 
3070 	return SWITCH_STATUS_SUCCESS;
3071 }
3072 
SWITCH_STANDARD_API(pa_cmd)3073 SWITCH_STANDARD_API(pa_cmd)
3074 {
3075 	char *argv[1024] = { 0 };
3076 	int argc = 0;
3077 	char *mycmd = NULL;
3078 	switch_status_t status = SWITCH_STATUS_SUCCESS;
3079 	pa_command_t func = NULL;
3080 	int devval;
3081 	int lead = 1;
3082 	char *wcmd = NULL, *action = NULL;
3083 	char cmd_buf[1024] = "";
3084 	char *http = NULL;
3085 
3086 	const char *usage_string = "USAGE:\n"
3087 		"--------------------------------------------------------------------------------\n"
3088 		"pa help\n"
3089 		"pa dump\n"
3090 		"pa rescan\n"
3091 		"pa call <dest> [<dialplan> <cid_name> <cid_num>]\n"
3092 		"pa answer [<call_id>]\n"
3093 		"pa hangup [<call_id>]\n"
3094 		"pa list\n"
3095 		"pa switch [<call_id>|none]\n"
3096 		"pa dtmf <digit string>\n"
3097 		"pa flags [on|off] [ear] [mouth]\n"
3098 		"pa devlist [xml]\n"
3099 		"pa indev #<num>|<partial name>\n"
3100 		"pa outdev #<num>|<partial name>\n"
3101 		"pa preparestream #<indev_num> #<outdev_num>\n"
3102 		"pa switchstream #<indev_num> #<outdev_num>\n"
3103 		"pa closestreams\n"
3104 		"pa ringdev #<num>|<partial name>\n"
3105 		"pa play [ringtest|<filename>] [seconds] [no_close]\n"
3106 		"pa playdev #<num> [ringtest|<filename>] [seconds] [no_close]\n"
3107 		"pa ringfile [filename]\n"
3108 		"pa looptest\n"
3109 		"pa shstreams\n"
3110 		"pa endpoints\n"
3111 		"--------------------------------------------------------------------------------\n";
3112 
3113 
3114 	if (stream->param_event) {
3115 		http = switch_event_get_header(stream->param_event, "http-host");
3116 	}
3117 
3118 	if (http) {
3119 		stream->write_function(stream, "Content-type: text/html\n\n");
3120 
3121 		wcmd = switch_str_nil(switch_event_get_header(stream->param_event, "wcmd"));
3122 		action = switch_event_get_header(stream->param_event, "action");
3123 
3124 		if (action) {
3125 			if (strlen(action) == 1) {
3126 				switch_snprintf(cmd_buf, sizeof(cmd_buf), "dtmf %s", action);
3127 				cmd = cmd_buf;
3128 			} else if (!strcmp(action, "mute")) {
3129 				switch_snprintf(cmd_buf, sizeof(cmd_buf), "flags off mouth");
3130 				cmd = cmd_buf;
3131 			} else if (!strcmp(action, "unmute")) {
3132 				switch_snprintf(cmd_buf, sizeof(cmd_buf), "flags on mouth");
3133 				cmd = cmd_buf;
3134 			} else if (!strcmp(action, "switch")) {
3135 				switch_snprintf(cmd_buf, sizeof(cmd_buf), "switch %s", wcmd);
3136 				cmd = cmd_buf;
3137 			} else if (!strcmp(action, "call")) {
3138 				switch_snprintf(cmd_buf, sizeof(cmd_buf), "call %s", wcmd);
3139 				cmd = cmd_buf;
3140 			} else if (!strcmp(action, "hangup") || !strcmp(action, "list") || !strcmp(action, "devlist") || !strcmp(action, "answer")) {
3141 				cmd = action;
3142 			}
3143 		}
3144 
3145 		if (zstr(cmd)) {
3146 			goto done;
3147 		}
3148 
3149 	} else {
3150 
3151 		if (zstr(cmd)) {
3152 			stream->write_function(stream, "%s", usage_string);
3153 			goto done;
3154 		}
3155 	}
3156 
3157 	if (!(mycmd = strdup(cmd))) {
3158 		status = SWITCH_STATUS_MEMERR;
3159 		goto done;
3160 	}
3161 
3162 	if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
3163 		stream->write_function(stream, "%s", usage_string);
3164 		goto done;
3165 	}
3166 
3167 	if (!argv[0]) {
3168 		stream->write_function(stream, "Unknown Command\n");
3169 		goto done;
3170 	}
3171 
3172 	if (!strcasecmp(argv[0], "call")) {
3173 		func = place_call;
3174 	} else if (!strcasecmp(argv[0], "help")) {
3175 		stream->write_function(stream, "%s", usage_string);
3176 		goto done;
3177 	} else if (!strcasecmp(argv[0], "devlist")) {
3178 		func = devlist;
3179 	} else if (!strcasecmp(argv[0], "rescan")) {
3180 
3181 		if (globals.call_list) {
3182 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ERROR: Cannot use this command this while a call is in progress\n");
3183 			goto done;
3184 		}
3185 
3186 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Looking for new devices.\n");
3187 		dump_info(-1);
3188 		goto done;
3189 	} else if (!strcasecmp(argv[0], "dump")) {
3190 		dump_info(1);
3191 		goto done;
3192 	} else if (!strcasecmp(argv[0], "list")) {
3193 		func = list_calls;
3194 	} else if (!strcasecmp(argv[0], "flags")) {
3195 		func = do_flags;
3196 	} else if (!strcasecmp(argv[0], "hangup")) {
3197 		func = hangup_call;
3198 	} else if (!strcasecmp(argv[0], "answer")) {
3199 		func = answer_call;
3200 	} else if (!strcasecmp(argv[0], "switch")) {
3201 		func = switch_call;
3202 	} else if (!strcasecmp(argv[0], "dtmf")) {
3203 		func = dtmf_call;
3204 	} else if (!strcasecmp(argv[0], "closestreams")) {
3205 		func = close_streams;
3206 	} else if (argv[1] && !strcmp(argv[0], "indev")) {
3207 		func = set_indev;
3208 	} else if (argv[1] && !strcmp(argv[0], "outdev")) {
3209 		func = set_outdev;
3210 	} else if (argv[1] && argv[2] && !strcmp(argv[0], "preparestream")) {
3211 		func = prepare_stream;
3212 	} else if (argv[1] && argv[2] && !strcmp(argv[0], "switchstream")) {
3213 		func = switch_stream;
3214 	} else if (argv[1] && !strcmp(argv[0], "ringdev")) {
3215 		func = set_ringdev;
3216 	} else if ((argv[1] && !strcmp(argv[0], "play"))) {
3217 		if (validate_main_audio_stream() == SWITCH_STATUS_SUCCESS) {
3218 			play_dev(stream, globals.main_stream ? globals.main_stream->outdev : -1,argv[1],argv[2], argv[3]);
3219 		}else{
3220 			stream->write_function(stream, "Failed to engage audio device\n");
3221 		}
3222 		goto done;
3223 	} else if ((argv[1] && argv[2] && !strcmp(argv[0], "playdev"))) {
3224 		if (*argv[1] == '#') {
3225 			devval = get_dev_by_number(argv[1] + 1, 0);
3226 		} else {
3227 			devval = -1;
3228 		}
3229 		play_dev(stream, devval,argv[2],argv[3],argv[4]);
3230 		goto done;
3231 	} else if (!strcasecmp(argv[0], "looptest")) {
3232 		func = looptest;
3233 	} else if (!strcasecmp(argv[0], "ringfile")) {
3234 		func = set_ringfile;
3235 	} else if (!strcasecmp(argv[0], "shstreams")) {
3236 		func = list_shared_streams;
3237 	} else if (!strcasecmp(argv[0], "endpoints")) {
3238 		func = list_endpoints;
3239 	} else {
3240 		stream->write_function(stream, "Unknown Command or not enough args [%s]\n", argv[0]);
3241 	}
3242 
3243 
3244 	if (func) {
3245 		if (http) {
3246 			stream->write_function(stream, "<pre>");
3247 		}
3248 
3249 		switch_mutex_lock(globals.pa_mutex);
3250 		func(&argv[lead], argc - lead, stream);
3251 		status = SWITCH_STATUS_SUCCESS; /*if func was defined we want to always return success as the command was found */
3252 		switch_mutex_unlock(globals.pa_mutex);
3253 
3254 		if (http) {
3255 			stream->write_function(stream, "\n\n</pre>");
3256 		}
3257 	}
3258 
3259   done:
3260 	if (http) {
3261 		stream->write_function(stream,
3262 							   "<br><br><table align=center><tr><td><center><form method=post>\n"
3263 							   "<input type=text name=wcmd size=40><br><br>\n"
3264 							   "<input name=action type=submit value=\"call\"> "
3265 							   "<input name=action type=submit value=\"hangup\"> "
3266 							   "<input name=action type=submit value=\"list\"> "
3267 							   "<input name=action type=submit value=\"switch\"> "
3268 							   "<input name=action type=submit value=\"mute\"> "
3269 							   "<input name=action type=submit value=\"unmute\"> "
3270 							   "<input name=action type=submit value=\"indev\"> "
3271 							   "<input name=action type=submit value=\"outdev\"> "
3272 							   "<input name=action type=submit value=\"devlist\"> <br> "
3273 							   "<input name=action type=submit value=\"preparestream\"> "
3274 							   "<input name=action type=submit value=\"switchstream\"> "
3275 							   "<input name=action type=submit value=\"closestreams\"> "
3276 							   "<input name=action type=submit value=\"ringdev\"> "
3277 							   "<input name=action type=submit value=\"play\"> "
3278 							   "<input name=action type=submit value=\"playdev\"> "
3279 							   "<input name=action type=submit value=\"answer\"> <br><br>"
3280 							   "<table border=1>\n"
3281 							   "<tr><td><input name=action type=submit value=\"1\"></td>"
3282 							   "<td><input name=action type=submit value=\"2\"></td>"
3283 							   "<td><input name=action type=submit value=\"3\"></td>\n"
3284 							   "<td><input name=action type=submit value=\"A\"></td></tr>\n"
3285 							   "<tr><td><input name=action type=submit value=\"4\"></td>"
3286 							   "<td><input name=action type=submit value=\"5\"></td>"
3287 							   "<td><input name=action type=submit value=\"6\"></td>\n"
3288 							   "<td><input name=action type=submit value=\"B\"></td></tr>\n"
3289 							   "<tr><td><input name=action type=submit value=\"7\"></td>"
3290 							   "<td><input name=action type=submit value=\"8\"></td>"
3291 							   "<td><input name=action type=submit value=\"9\"></td>\n"
3292 							   "<td><input name=action type=submit value=\"C\"></td></tr>\n"
3293 							   "<tr><td><input name=action type=submit value=\"*\"></td>"
3294 							   "<td><input name=action type=submit value=\"0\"></td>"
3295 							   "<td><input name=action type=submit value=\"#\"></td>\n"
3296 							   "<td><input name=action type=submit value=\"D\"></td></tr>\n" "</table>" "</form><br></center></td></tr></table>\n");
3297 	}
3298 
3299 	switch_safe_free(mycmd);
3300 	return status;
3301 }
3302 
3303 
3304 /* For Emacs:
3305  * Local Variables:
3306  * mode:c
3307  * indent-tabs-mode:t
3308  * tab-width:4
3309  * c-basic-offset:4
3310  * End:
3311  * For VIM:
3312  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
3313  */
3314