[commit] r5662 - freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio
Author: cseket Date: Fri Aug 24 13:50:56 2007 New Revision: 5662 Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/ (props changed) freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/Makefile freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/mod_portaudio.c freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pa_ringbuffer.c freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pa_ringbuffer.h freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pablio.c freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pablio.h Log: merge from trunk and try to fix MODENDP-20 Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/Makefile ============================================================================== --- freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/Makefile (original) +++ freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/Makefile Fri Aug 24 13:50:56 2007 @@ -1,22 +1,29 @@ -CFLAGS += -I. -LDFLAGS += -lportaudio -L$(PREFIX) -MYOBJS = pablio.o pa_ringbuffer.o +BASE=../../../.. -all: depends $(MODNAME).$(DYNAMIC_LIB_EXTEN) +PA_DIR=$(BASE)/libs/portaudio -depends: - MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) install portaudio --prefix=$(PREFIX) --with-pic -%.o: %.c - $(CC) -fPIC $(CFLAGS) -c -o $@ $< +PALA=$(PA_DIR)/lib/libportaudio.la +LOCAL_CFLAGS=-I. -I$(PA_DIR)/include -D__EXTENSION__=1 -$(MODNAME).$(DYNAMIC_LIB_EXTEN): $(MODNAME).c $(MYOBJS) - $(CC) $(CFLAGS) -fPIC -c $(MODNAME).c -o $(MODNAME).o - $(CC) $(SOLINK) -o $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(MODNAME).o $(MYOBJS) $(LDFLAGS) +LOCAL_INSERT_LDFLAGS=if test $$osarch = "Darwin" ; then echo "-framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon" ; fi ; +LOCAL_LIBADD=$(PALA) +LOCAL_OBJS=pablio.o pa_ringbuffer.o +LOCAL_SOURCES=pablio.c pa_ringbuffer.c +PX_DIR=$(BASE)/libs/portmixer +PXA=$(PX_DIR)/libportmixer.a +LOCAL_CFLAGS+=-I$(PX_DIR)/include +LOCAL_LIBADD+=$(PXA) -clean: - rm -fr *.$(DYNAMIC_LIB_EXTEN) *.o *~ +include $(BASE)/build/modmake.rules -install: - cp -f $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(PREFIX)/mod +$(PALA): $(PA_DIR) $(PA_DIR)/.update + cd $(PA_DIR) && $(MAKE) + $(TOUCH_TARGET) + +$(PXA): $(PX_DIR) $(PX_DIR)/.update + cd $(PX_DIR) && $(MAKE) + $(TOUCH_TARGET) + +$(LOCAL_OBJS): $(LOCAL_SOURCES) Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/mod_portaudio.c ============================================================================== --- freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/mod_portaudio.c (original) +++ freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/mod_portaudio.c Fri Aug 24 13:50:56 2007 @@ -6,7 +6,7 @@ * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at + * the License. You may obtain a copy of the License ` * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, @@ -29,32 +29,34 @@ * mod_portaudio.c -- PortAudio Endpoint Module * */ -#include <switch.h> +#include "switch.h" #include <stdio.h> #include <stdlib.h> #include <math.h> #include "pablio.h" #include <string.h> +#include <portmixer.h> #define MY_EVENT_RINGING "portaudio::ringing" -static const char modname[] = "mod_portaudio"; +SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load); +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_shutdown); +SWITCH_MODULE_DEFINITION(mod_portaudio, mod_portaudio_load, mod_portaudio_shutdown, NULL); static switch_memory_pool_t *module_pool = NULL; -//static int running = 1; +static switch_endpoint_interface_t *channel_endpoint_interface; #define SAMPLE_TYPE paInt16 -//#define SAMPLE_TYPE paFloat32 -typedef short SAMPLE; +typedef int16_t SAMPLE; -typedef switch_status_t (*pa_command_t)(char **argv, int argc, switch_stream_handle_t *stream); +typedef switch_status_t (*pa_command_t) (char **argv, int argc, switch_stream_handle_t *stream); typedef enum { - GFLAG_NONE = 0, - GFLAG_EAR = (1 << 0), - GFLAG_MOUTH = (1 << 1), - GFLAG_RING = (1 << 2) + GFLAG_NONE = 0, + GFLAG_EAR = (1 << 0), + GFLAG_MOUTH = (1 << 1), + GFLAG_RING = (1 << 2) } GFLAGS; typedef enum { @@ -75,17 +77,16 @@ switch_core_session_t *session; switch_caller_profile_t *caller_profile; char call_id[50]; - int sample_rate; - int codec_ms; + int sample_rate; + int codec_ms; switch_mutex_t *flag_mutex; - char *hold_file; - switch_file_handle_t fh; - switch_file_handle_t *hfh; + char *hold_file; + switch_file_handle_t fh; + switch_file_handle_t *hfh; switch_frame_t hold_frame; - unsigned char holdbuf[SWITCH_RECCOMMENDED_BUFFER_SIZE]; + unsigned char holdbuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; switch_codec_t write_codec; - switch_timer_t timer; - struct private_object *next; + struct private_object *next; }; typedef struct private_object private_t; @@ -96,9 +97,9 @@ char *cid_name; char *cid_num; char *dialplan; - char *ring_file; - char *hold_file; - char *timer_name; + char *ring_file; + char *hold_file; + char *timer_name; int ringdev; int indev; int outdev; @@ -114,12 +115,14 @@ switch_codec_t read_codec; switch_codec_t write_codec; switch_frame_t read_frame; - switch_frame_t cng_frame; - unsigned char databuf[SWITCH_RECCOMMENDED_BUFFER_SIZE]; - unsigned char cngbuf[SWITCH_RECCOMMENDED_BUFFER_SIZE]; - private_t *call_list; - int ring_interval; - GFLAGS flags; + switch_frame_t cng_frame; + unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; + unsigned char cngbuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; + private_t *call_list; + int ring_interval; + GFLAGS flags; + switch_timer_t timer; + PxMixer *mixer; } globals; @@ -128,126 +131,125 @@ SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan) -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_cid_name, globals.cid_name) -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_cid_num, globals.cid_num) -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_ring_file, globals.ring_file) -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_hold_file, globals.hold_file) -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_timer_name, globals.timer_name) - + SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_cid_name, globals.cid_name) + SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_cid_num, globals.cid_num) + SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_ring_file, globals.ring_file) + SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_hold_file, globals.hold_file) + SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_timer_name, globals.timer_name) #define is_master(t) switch_test_flag(t, TFLAG_MASTER) -static void add_pvt(private_t *tech_pvt, int master); -static void remove_pvt(private_t *tech_pvt); -static switch_status_t channel_on_init(switch_core_session_t *session); -static switch_status_t channel_on_hangup(switch_core_session_t *session); -static switch_status_t channel_on_ring(switch_core_session_t *session); -static switch_status_t channel_on_loopback(switch_core_session_t *session); -static switch_status_t channel_on_transmit(switch_core_session_t *session); -static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, - switch_caller_profile_t *outbound_profile, - switch_core_session_t **new_session, switch_memory_pool_t **pool); -static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, - switch_io_flag_t flags, int stream_id); -static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, - switch_io_flag_t flags, int stream_id); -static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig); -static switch_status_t engage_device(int samplerate, int codec_ms); -static switch_status_t engage_ring_device(int sample_rate, int channels); -static void deactivate_ring_device(void); -static int dump_info(void); -static switch_status_t load_config(void); -static int get_dev_by_name(char *name, int in); -static int get_dev_by_number(int number, int in); -static switch_status_t pa_cmd(char *dest, switch_core_session_t *session, switch_stream_handle_t *stream); -static switch_status_t padep(char *dest, switch_core_session_t *session, switch_stream_handle_t *stream); - + static void add_pvt(private_t * tech_pvt, int master); + static void remove_pvt(private_t * tech_pvt); + static switch_status_t channel_on_init(switch_core_session_t *session); + static switch_status_t channel_on_hangup(switch_core_session_t *session); + static switch_status_t channel_on_ring(switch_core_session_t *session); + static switch_status_t channel_on_loopback(switch_core_session_t *session); + static switch_status_t channel_on_transmit(switch_core_session_t *session); + static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, switch_memory_pool_t **pool); + static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id); + static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id); + static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig); + static switch_status_t engage_device(int samplerate, int codec_ms); + static switch_status_t engage_ring_device(int sample_rate, int channels); + static void deactivate_ring_device(void); + static int dump_info(void); + static switch_status_t load_config(void); + static int get_dev_by_name(char *name, int in); + static int get_dev_by_number(int number, int in); + static switch_status_t pa_cmd(const char *dest, switch_core_session_t *session, switch_stream_handle_t *stream); /* State methods they get called when the state changes to the specific state returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it. */ -static switch_status_t channel_on_init(switch_core_session_t *session) + static switch_status_t channel_on_init(switch_core_session_t *session) { switch_channel_t *channel; private_t *tech_pvt = NULL; switch_time_t last; int waitsec = globals.ring_interval * 1000000; - switch_file_handle_t fh = {0}; - char *val, *ring_file = NULL, *hold_file = NULL; - int16_t abuf[2048]; + switch_file_handle_t fh = { 0 }; + char *val, *ring_file = NULL, *hold_file = NULL; + int16_t abuf[2048]; - tech_pvt = switch_core_session_get_private(session); + tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); channel = switch_core_session_get_channel(session); assert(channel != NULL); - + last = switch_time_now() - waitsec; - if ((val = switch_channel_get_variable(channel, "pa_hold_file"))) { - hold_file = val; - } else { - hold_file = globals.hold_file; - } - - if (hold_file) { - tech_pvt->hold_file = switch_core_session_strdup(session, hold_file); - } + + if ((val = switch_channel_get_variable(channel, "pa_hold_file"))) { + hold_file = val; + } else { + hold_file = globals.hold_file; + } + + if (hold_file) { + tech_pvt->hold_file = switch_core_session_strdup(session, hold_file); + } if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL INIT %d %d\n", switch_channel_get_name(channel), - switch_channel_get_state(channel), switch_test_flag(tech_pvt, TFLAG_ANSWER)); - - - - if (engage_device(tech_pvt->sample_rate, tech_pvt->codec_ms) != SWITCH_STATUS_SUCCESS) { - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - return SWITCH_STATUS_FALSE; - } - - if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - add_pvt(tech_pvt, PA_SLAVE); - - ring_file = globals.ring_file; - if ((val = switch_channel_get_variable(channel, "pa_ring_file"))) { - ring_file = val; - } - - if (switch_test_flag((&globals), GFLAG_RING)) { - ring_file = NULL; - } - switch_set_flag_locked((&globals), GFLAG_RING); - if (ring_file) { - if (switch_core_file_open(&fh, - ring_file, - SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, - NULL) == SWITCH_STATUS_SUCCESS) { - - if (engage_ring_device(fh.samplerate, fh.channels) != SWITCH_STATUS_SUCCESS) { - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Ring Error!\n"); - switch_core_file_close(&fh); - return SWITCH_STATUS_GENERR; - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot open %s, disabling ring file!\n", ring_file); - ring_file = NULL; - } - } - } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL INIT %d %d\n", + switch_channel_get_name(channel), switch_channel_get_state(channel), switch_test_flag(tech_pvt, TFLAG_ANSWER)); + + + + if (engage_device(tech_pvt->sample_rate, tech_pvt->codec_ms) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return SWITCH_STATUS_FALSE; + } + + if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { + add_pvt(tech_pvt, PA_SLAVE); + + ring_file = globals.ring_file; + if ((val = switch_channel_get_variable(channel, "pa_ring_file"))) { + ring_file = val; + } + + if (switch_test_flag((&globals), GFLAG_RING)) { + ring_file = NULL; + } + switch_set_flag_locked((&globals), GFLAG_RING); + if (ring_file) { + if (switch_core_file_open(&fh, + ring_file, + globals.read_codec.implementation->number_of_channels, + globals.read_codec.implementation->samples_per_second, + SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) == SWITCH_STATUS_SUCCESS) { + + if (engage_ring_device(fh.samplerate, fh.channels) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Ring Error!\n"); + switch_core_file_close(&fh); + return SWITCH_STATUS_GENERR; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot open %s, disabling ring file!\n", ring_file); + ring_file = NULL; + } + } + } switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING); switch_channel_mark_ring_ready(channel); - + while (switch_channel_get_state(channel) == CS_INIT && !switch_test_flag(tech_pvt, TFLAG_ANSWER)) { + switch_size_t olen = globals.timer.samples; + if (switch_time_now() - last >= waitsec) { char buf[512]; switch_event_t *event; - + snprintf(buf, sizeof(buf), "BRRRRING! BRRRRING! call %s\n", tech_pvt->call_id); if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_RINGING) == SWITCH_STATUS_SUCCESS) { @@ -256,49 +258,46 @@ switch_channel_event_set_data(channel, event); switch_event_fire(&event); } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s\n", buf); last = switch_time_now(); - if (ring_file) { - unsigned int pos = 0; - switch_core_file_seek(&fh, &pos, 0, SEEK_SET); - for (;;) { - switch_size_t olen = 1024; - switch_core_file_read(&fh, abuf, &olen); - if (olen == 0) { - break; - } - WriteAudioStream(globals.ring_stream, abuf, (long)olen); - } - } - } - - switch_yield(globals.read_codec.implementation->microseconds_per_frame); - - } - switch_clear_flag_locked((&globals), GFLAG_RING); - } - - if (ring_file) { - deactivate_ring_device(); - switch_core_file_close(&fh); - switch_core_codec_destroy(&tech_pvt->write_codec); - switch_core_timer_destroy(&tech_pvt->timer); - } + } + + if (ring_file) { + if (switch_core_timer_next(&globals.timer) != SWITCH_STATUS_SUCCESS) { + switch_core_file_close(&fh); + break; + } + switch_core_file_read(&fh, abuf, &olen); + if (olen == 0) { + unsigned int pos = 0; + switch_core_file_seek(&fh, &pos, 0, SEEK_SET); + } + if (globals.ring_stream) { + WriteAudioStream(globals.ring_stream, abuf, (long) olen, &globals.timer); + } + } + } + switch_clear_flag_locked((&globals), GFLAG_RING); + } + + if (ring_file) { + deactivate_ring_device(); + switch_core_file_close(&fh); + } if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - if (!switch_test_flag(tech_pvt, TFLAG_ANSWER)) { - switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER); - return SWITCH_STATUS_SUCCESS; - } + if (!switch_test_flag(tech_pvt, TFLAG_ANSWER)) { + switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER); + return SWITCH_STATUS_SUCCESS; + } } - switch_set_flag_locked(tech_pvt, TFLAG_IO); - - /* Move Channel's State Machine to RING */ - switch_channel_set_state(channel, CS_RING); - - return SWITCH_STATUS_SUCCESS; + switch_set_flag_locked(tech_pvt, TFLAG_IO); + + /* Move Channel's State Machine to RING */ + switch_channel_set_state(channel, CS_RING); + + return SWITCH_STATUS_SUCCESS; } @@ -344,6 +343,11 @@ globals.audio_stream = NULL; } switch_mutex_unlock(globals.device_lock); + if (globals.mixer) { + Px_CloseMixer(globals.mixer); + globals.mixer = NULL; + } + } @@ -359,72 +363,72 @@ -static void add_pvt(private_t *tech_pvt, int master) +static void add_pvt(private_t * tech_pvt, int master) { - private_t *tp; - uint8_t in_list = 0; + private_t *tp; + uint8_t in_list = 0; + + switch_mutex_lock(globals.pvt_lock); + + if (switch_strlen_zero(tech_pvt->call_id)) { + snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", ++globals.call_id); + switch_core_hash_insert(globals.call_hash, tech_pvt->call_id, tech_pvt); + switch_core_session_set_read_codec(tech_pvt->session, &globals.read_codec); + switch_core_session_set_write_codec(tech_pvt->session, &globals.write_codec); + } + + for (tp = globals.call_list; tp; tp = tp->next) { + if (tp == tech_pvt) { + in_list = 1; + } + if (master) { + switch_clear_flag_locked(tp, TFLAG_MASTER); + } + } - switch_mutex_lock(globals.pvt_lock); - if (switch_strlen_zero(tech_pvt->call_id)) { - snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", ++globals.call_id); - switch_core_hash_insert(globals.call_hash, tech_pvt->call_id, tech_pvt); - switch_core_session_set_read_codec(tech_pvt->session, &globals.read_codec); - switch_core_session_set_write_codec(tech_pvt->session, &globals.write_codec); - } - - for (tp = globals.call_list; tp; tp = tp->next) { - if (tp == tech_pvt) { - in_list = 1; - } - if (master) { - switch_clear_flag_locked(tp, TFLAG_MASTER); - } - } - - - if (master) { - if (!in_list) { - tech_pvt->next = globals.call_list; - globals.call_list = tech_pvt; - } - switch_set_flag_locked(tech_pvt, TFLAG_MASTER); - - } else if (!in_list) { - for (tp = globals.call_list; tp && tp->next; tp = tp->next); - if (tp) { - tp->next = tech_pvt; - } else { - globals.call_list = tech_pvt; - } - } + if (master) { + if (!in_list) { + tech_pvt->next = globals.call_list; + globals.call_list = tech_pvt; + } + switch_set_flag_locked(tech_pvt, TFLAG_MASTER); + + } else if (!in_list) { + for (tp = globals.call_list; tp && tp->next; tp = tp->next); + if (tp) { + tp->next = tech_pvt; + } else { + globals.call_list = tech_pvt; + } + } switch_mutex_unlock(globals.pvt_lock); } -static void remove_pvt(private_t *tech_pvt) +static void remove_pvt(private_t * tech_pvt) { - private_t *tp, *last = NULL; + private_t *tp, *last = NULL; switch_mutex_lock(globals.pvt_lock); - for (tp = globals.call_list; tp; tp = tp->next) { - switch_clear_flag_locked(tp, TFLAG_MASTER); - if (tp == tech_pvt) { - if (last) { - last->next = tp->next; - } else { - globals.call_list = tp->next; - } - } - last = tp; - } - - if (globals.call_list) { - switch_set_flag_locked(globals.call_list, TFLAG_MASTER); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No more channels, deactivating audio\n"); - deactivate_audio_device(); - } + for (tp = globals.call_list; tp; tp = tp->next) { + switch_clear_flag_locked(tp, TFLAG_MASTER); + if (tp == tech_pvt) { + if (last) { + last->next = tp->next; + } else { + globals.call_list = tp->next; + } + } + last = tp; + } + + if (globals.call_list) { + switch_set_flag_locked(globals.call_list, TFLAG_MASTER); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No more channels, deactivating audio\n"); + deactivate_audio_device(); + } switch_mutex_unlock(globals.pvt_lock); } @@ -440,17 +444,17 @@ tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); - remove_pvt(tech_pvt); + remove_pvt(tech_pvt); switch_clear_flag_locked(tech_pvt, TFLAG_IO); switch_set_flag_locked(tech_pvt, TFLAG_HUP); switch_core_hash_delete(globals.call_hash, tech_pvt->call_id); - if (tech_pvt->hfh) { - tech_pvt->hfh = NULL; - switch_core_file_close(&tech_pvt->fh); - } + if (tech_pvt->hfh) { + tech_pvt->hfh = NULL; + switch_core_file_close(&tech_pvt->fh); + } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel)); @@ -468,14 +472,14 @@ tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); - switch (sig) { - case SWITCH_SIG_KILL: - switch_set_flag_locked(tech_pvt, TFLAG_HUP); - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - break; - default: - break; - } + switch (sig) { + case SWITCH_SIG_KILL: + switch_set_flag_locked(tech_pvt, TFLAG_HUP); + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + break; + default: + break; + } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL KILL\n", switch_channel_get_name(channel)); @@ -538,8 +542,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, - switch_io_flag_t flags, int stream_id) +static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; @@ -553,109 +556,90 @@ assert(tech_pvt != NULL); if (!globals.audio_stream) { - return SWITCH_STATUS_FALSE; - } + return SWITCH_STATUS_FALSE; + } + + if (switch_test_flag(tech_pvt, TFLAG_HUP)) { + return SWITCH_STATUS_FALSE; + } + + if (!switch_test_flag(tech_pvt, TFLAG_IO)) { + goto cng; + } - if (switch_test_flag(tech_pvt, TFLAG_HUP)) { - return SWITCH_STATUS_FALSE; - } - - if (!switch_test_flag(tech_pvt, TFLAG_IO)) { - goto cng; - } - - if (!is_master(tech_pvt)) { - if (tech_pvt->hold_file) { - if (!tech_pvt->hfh) { - int codec_ms = tech_pvt->codec_ms ? tech_pvt->codec_ms : globals.codec_ms; - int sample_rate = tech_pvt->sample_rate ? tech_pvt->sample_rate : globals.sample_rate; - - if (switch_core_codec_init(&tech_pvt->write_codec, - "L16", - NULL, - sample_rate, - codec_ms, - 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, - NULL, - switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); - switch_core_codec_destroy(&globals.read_codec); - tech_pvt->hold_file = NULL; - goto cng; - } - - if (switch_core_file_open(&tech_pvt->fh, - tech_pvt->hold_file, - SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, - switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_core_codec_destroy(&tech_pvt->write_codec); - tech_pvt->hold_file = NULL; - goto cng; - } - - if (switch_core_timer_init(&tech_pvt->timer, - globals.timer_name, - codec_ms, - globals.read_codec.implementation->samples_per_frame, - switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "setup timer failed!\n"); - switch_core_file_close(&tech_pvt->fh); - switch_core_codec_destroy(&tech_pvt->write_codec); - goto cng; - } - - tech_pvt->hfh = &tech_pvt->fh; - tech_pvt->hold_frame.data = tech_pvt->holdbuf; - tech_pvt->hold_frame.buflen = sizeof(tech_pvt->holdbuf); - tech_pvt->hold_frame.rate = sample_rate; - tech_pvt->hold_frame.codec = &tech_pvt->write_codec; - } - - goto hold; - } - cng: - switch_yield(globals.read_codec.implementation->microseconds_per_frame); - *frame = &globals.cng_frame; + if (!is_master(tech_pvt)) { + if (tech_pvt->hold_file) { + if (!tech_pvt->hfh) { + int sample_rate = tech_pvt->sample_rate ? tech_pvt->sample_rate : globals.sample_rate; + if (switch_core_file_open(&tech_pvt->fh, + tech_pvt->hold_file, + globals.read_codec.implementation->number_of_channels, + globals.read_codec.implementation->samples_per_second, + SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, + switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + tech_pvt->hold_file = NULL; + goto cng; + } + + tech_pvt->hfh = &tech_pvt->fh; + tech_pvt->hold_frame.data = tech_pvt->holdbuf; + tech_pvt->hold_frame.buflen = sizeof(tech_pvt->holdbuf); + tech_pvt->hold_frame.rate = sample_rate; + tech_pvt->hold_frame.codec = &globals.write_codec; + } + + goto hold; + } + cng: + switch_yield(globals.read_codec.implementation->microseconds_per_frame); + *frame = &globals.cng_frame; return SWITCH_STATUS_SUCCESS; - hold: + hold: - { - switch_size_t olen = globals.read_codec.implementation->samples_per_frame; - if (switch_core_timer_next(&tech_pvt->timer) != SWITCH_STATUS_SUCCESS) { - switch_core_file_close(&tech_pvt->fh); - switch_core_codec_destroy(&tech_pvt->write_codec); - goto cng; + { + switch_size_t olen = globals.read_codec.implementation->samples_per_frame; + if (switch_core_timer_next(&globals.timer) != SWITCH_STATUS_SUCCESS) { + switch_core_file_close(&tech_pvt->fh); + goto cng; + } + switch_core_file_read(tech_pvt->hfh, tech_pvt->hold_frame.data, &olen); + + if (olen == 0) { + unsigned int pos = 0; + switch_core_file_seek(tech_pvt->hfh, &pos, 0, SEEK_SET); + goto cng; } - switch_core_file_read(tech_pvt->hfh, tech_pvt->hold_frame.data, &olen); - - if (olen == 0) { - unsigned int pos = 0; - switch_core_file_seek(tech_pvt->hfh, &pos, 0, SEEK_SET); - goto cng; - } - - - tech_pvt->hold_frame.datalen = (uint32_t)(olen * sizeof(int16_t)); - tech_pvt->hold_frame.samples = (uint32_t)olen; - *frame = &tech_pvt->hold_frame; - - } - return SWITCH_STATUS_SUCCESS; - } + + tech_pvt->hold_frame.datalen = (uint32_t) (olen * sizeof(int16_t)); + tech_pvt->hold_frame.samples = (uint32_t) olen; + tech_pvt->hold_frame.timestamp = globals.timer.samplecount; + *frame = &tech_pvt->hold_frame; + + } + + return SWITCH_STATUS_SUCCESS; + } switch_mutex_lock(globals.device_lock); - if ((samples = ReadAudioStream(globals.audio_stream, globals.read_frame.data, globals.read_codec.implementation->samples_per_frame)) != 0) { + if ((samples = ReadAudioStream(globals.audio_stream, globals.read_frame.data, + globals.read_codec.implementation->samples_per_frame, + &globals.timer)) == 0) { + switch_mutex_unlock(globals.device_lock); + goto cng; + } else { globals.read_frame.datalen = samples * 2; globals.read_frame.samples = samples; + + switch_core_timer_check(&globals.timer); + globals.read_frame.timestamp = globals.timer.samplecount; *frame = &globals.read_frame; - if (!switch_test_flag((&globals), GFLAG_MOUTH)) { - memset(globals.read_frame.data, 255, globals.read_frame.datalen); - } + if (!switch_test_flag((&globals), GFLAG_MOUTH)) { + memset(globals.read_frame.data, 255, globals.read_frame.datalen); + } status = SWITCH_STATUS_SUCCESS; } @@ -664,8 +648,7 @@ return status; } -static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, - switch_io_flag_t flags, int stream_id) +static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; @@ -677,21 +660,22 @@ assert(tech_pvt != NULL); if (!globals.audio_stream) { - return SWITCH_STATUS_FALSE; - } + return SWITCH_STATUS_FALSE; + } - if (switch_test_flag(tech_pvt, TFLAG_HUP)) { - return SWITCH_STATUS_FALSE; - } - - if (!is_master(tech_pvt) || !switch_test_flag(tech_pvt, TFLAG_IO)) { - return SWITCH_STATUS_SUCCESS; - } + if (switch_test_flag(tech_pvt, TFLAG_HUP)) { + return SWITCH_STATUS_FALSE; + } + + if (!is_master(tech_pvt) || !switch_test_flag(tech_pvt, TFLAG_IO)) { + return SWITCH_STATUS_SUCCESS; + } if (globals.audio_stream) { - if (switch_test_flag((&globals), GFLAG_EAR)) { - WriteAudioStream(globals.audio_stream, (short *) frame->data, (int) (frame->datalen / sizeof(SAMPLE))); - } + if (switch_test_flag((&globals), GFLAG_EAR)) { + WriteAudioStream(globals.audio_stream, (short *) frame->data, (int) (frame->datalen / sizeof(SAMPLE)), + &globals.timer); + } status = SWITCH_STATUS_SUCCESS; } @@ -717,16 +701,19 @@ { switch_channel_t *channel; private_t *tech_pvt; - + channel = switch_core_session_get_channel(session); assert(channel != NULL); - + tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); switch (msg->message_id) { - case SWITCH_MESSAGE_INDICATE_PROGRESS: + case SWITCH_MESSAGE_INDICATE_ANSWER: + channel_answer_channel(session); + break; + case SWITCH_MESSAGE_INDICATE_PROGRESS: { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Engage Early Media\n"); switch_set_flag_locked(tech_pvt, TFLAG_IO); @@ -737,55 +724,7 @@ return SWITCH_STATUS_SUCCESS; } -static switch_api_interface_t send_dtmf_interface = { - /*.interface_name */ "padtmf", - /*.desc */ "DEPRICATED (see 'pa')", - /*.function */ padep, - /*.syntax */ "DEPRICATED (see 'pa')", - /*.next */ NULL -}; - -static switch_api_interface_t answer_call_interface = { - /*.interface_name */ "paoffhook", - /*.desc */ "DEPRICATED (see 'pa')", - /*.function */ padep, - /*.syntax */ "DEPRICATED (see 'pa')", - /*.next */ &send_dtmf_interface -}; - -static switch_api_interface_t channel_info_interface = { - /*.interface_name */ "painfo", - /*.desc */ "DEPRICATED (see 'pa')", - /*.function */ padep, - /*.syntax */ "DEPRICATED (see 'pa')", - /*.next */ &answer_call_interface -}; - -static switch_api_interface_t channel_hup_interface = { - /*.interface_name */ "pahup", - /*.desc */ "DEPRICATED (see 'pa')", - /*.function */ padep, - /*.syntax */ "DEPRICATED (see 'pa')", - /*.next */ &channel_info_interface -}; - -static switch_api_interface_t channel_call_interface = { - /*.interface_name */ "pacall", - /*.desc */ "DEPRICATED (see 'pa')", - /*.function */ padep, - /*.syntax */ "DEPRICATED (see 'pa')", - /*.next */ &channel_hup_interface -}; - -static switch_api_interface_t channel_api_interface = { - /*.interface_name */ "pa", - /*.desc */ "PortAudio", - /*.function */ pa_cmd, - /*.syntax */ "<command> [<args>]", - /*.next */ &channel_call_interface -}; - -static const switch_state_handler_table_t channel_event_handlers = { +static switch_state_handler_table_t channel_event_handlers = { /*.on_init */ channel_on_init, /*.on_ring */ channel_on_ring, /*.on_execute */ channel_on_execute, @@ -794,56 +733,38 @@ /*.on_transmit */ channel_on_transmit }; -static const switch_io_routines_t channel_io_routines = { +static switch_io_routines_t channel_io_routines = { /*.outgoing_channel */ channel_outgoing_channel, - /*.answer_channel */ channel_answer_channel, /*.read_frame */ channel_read_frame, /*.write_frame */ channel_write_frame, /*.kill_channel */ channel_kill_channel, /*.waitfor_read */ channel_waitfor_read, /*.waitfor_write */ channel_waitfor_write, /*.send_dtmf */ channel_send_dtmf, - /*.receive_message*/ channel_receive_message -}; - -static const switch_endpoint_interface_t channel_endpoint_interface = { - /*.interface_name */ "portaudio", - /*.io_routines */ &channel_io_routines, - /*.event_handlers */ &channel_event_handlers, - /*.private */ NULL, - /*.next */ NULL -}; - -static const switch_loadable_module_interface_t channel_module_interface = { - /*.module_name */ modname, - /*.endpoint_interface */ &channel_endpoint_interface, - /*.timer_interface */ NULL, - /*.dialplan_interface */ NULL, - /*.codec_interface */ NULL, - /*.application_interface */ NULL, - /*.api_interface */ &channel_api_interface + /*.receive_message */ channel_receive_message }; /* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines that allocate memory or you will have 1 channel with memory allocated from another channel's pool! */ -static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_caller_profile_t *outbound_profile, +static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, + switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session, switch_memory_pool_t **pool) { - if ((*new_session = switch_core_session_request(&channel_endpoint_interface, pool)) != 0) { + if ((*new_session = switch_core_session_request(channel_endpoint_interface, pool)) != 0) { private_t *tech_pvt; switch_channel_t *channel; switch_caller_profile_t *caller_profile; switch_core_session_add_stream(*new_session, NULL); if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) { - memset(tech_pvt, 0, sizeof(*tech_pvt)); + memset(tech_pvt, 0, sizeof(*tech_pvt)); switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(*new_session)); channel = switch_core_session_get_channel(*new_session); switch_core_session_set_private(*new_session, tech_pvt); tech_pvt->session = *new_session; - globals.flags = GFLAG_EAR | GFLAG_MOUTH; + globals.flags = GFLAG_EAR | GFLAG_MOUTH; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n"); switch_core_session_destroy(new_session); @@ -852,9 +773,9 @@ if (outbound_profile) { char name[128]; - char *id = !switch_strlen_zero(outbound_profile->caller_id_number) ? outbound_profile->caller_id_number : "na"; + char *id = !switch_strlen_zero(outbound_profile->caller_id_number) ? outbound_profile->caller_id_number : "na"; snprintf(name, sizeof(name), "PortAudio/%s", id); - + switch_channel_set_name(channel, name); caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); @@ -877,30 +798,28 @@ } -SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename) +SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load) { + switch_status_t status; + switch_api_interface_t *api_interface; - switch_status_t status; - - if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n"); - return SWITCH_STATUS_TERM; - } + module_pool = pool; Pa_Initialize(); if (dump_info()) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't find any audio devices!\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't find any audio devices!\n"); return SWITCH_STATUS_TERM; - } + } if ((status = load_config()) != SWITCH_STATUS_SUCCESS) { - return status; - } + return status; + } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Input Device: %d, Output Device: %d, Ring Device: %d Sample Rate: %d MS: %d\n", - globals.indev, globals.outdev, globals.ringdev, globals.sample_rate, globals.codec_ms); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Input Device: %d, Output Device: %d, Ring Device: %d Sample Rate: %d MS: %d\n", globals.indev, + globals.outdev, globals.ringdev, globals.sample_rate, globals.codec_ms); switch_core_hash_init(&globals.call_hash, module_pool); @@ -920,10 +839,16 @@ globals.cng_frame.data = globals.cngbuf; globals.cng_frame.buflen = sizeof(globals.cngbuf); globals.cng_frame.datalen = sizeof(globals.cngbuf); - switch_set_flag((&globals.cng_frame), SFF_CNG); + switch_set_flag((&globals.cng_frame), SFF_CNG); /* connect my internal structure to the blank pointer passed to me */ - *module_interface = &channel_module_interface; + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + channel_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE); + channel_endpoint_interface->interface_name = "portaudio"; + channel_endpoint_interface->io_routines = &channel_io_routines; + channel_endpoint_interface->state_handler = &channel_event_handlers; + + SWITCH_ADD_API(api_interface, "pa", "PortAudio", pa_cmd, "<command> [<args>]"); /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; @@ -934,7 +859,7 @@ { char *cf = "portaudio.conf"; switch_xml_t cfg, xml, settings, param; - switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_status_t status = SWITCH_STATUS_SUCCESS; if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf); @@ -942,7 +867,7 @@ } memset(&globals, 0, sizeof(globals)); - globals.indev = globals.outdev = globals.ringdev = -1; + globals.indev = globals.outdev = globals.ringdev = -1; if ((settings = switch_xml_child(cfg, "settings"))) { for (param = switch_xml_child(settings, "param"); param; param = param->next) { @@ -952,7 +877,7 @@ if (!strcmp(var, "debug")) { globals.debug = atoi(val); } else if (!strcmp(var, "ring-interval")) { - globals.ring_interval = atoi(val); + globals.ring_interval = atoi(val); } else if (!strcmp(var, "ring-file")) { set_global_ring_file(val); } else if (!strcmp(var, "hold-file")) { @@ -987,7 +912,7 @@ } else { globals.ringdev = get_dev_by_name(val, 0); } - } + } } } @@ -1006,44 +931,44 @@ if (!globals.ring_interval) { globals.ring_interval = 5; } - - if (!globals.timer_name) { - set_global_timer_name("soft"); - } - - if (globals.indev < 0) { - globals.indev = get_dev_by_name(NULL, 1); - if (globals.indev > -1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Switching to default input device!\n"); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find an input device!\n"); - status = SWITCH_STATUS_GENERR; - } - } - - if (globals.outdev < 0) { - globals.outdev = get_dev_by_name(NULL, 0); - if (globals.outdev > -1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Switching to default output device!\n"); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find an input device!\n"); - status = SWITCH_STATUS_GENERR; - } - } - - if (globals.ringdev < 0) { - if (globals.outdev > -1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid ring device configured using output device!\n"); - globals.ringdev = globals.outdev; - } - } + + if (!globals.timer_name) { + set_global_timer_name("soft"); + } + + if (globals.indev < 0) { + globals.indev = get_dev_by_name(NULL, 1); + if (globals.indev > -1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Switching to default input device!\n"); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find an input device!\n"); + status = SWITCH_STATUS_GENERR; + } + } + + if (globals.outdev < 0) { + globals.outdev = get_dev_by_name(NULL, 0); + if (globals.outdev > -1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Switching to default output device!\n"); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find an input device!\n"); + status = SWITCH_STATUS_GENERR; + } + } + + if (globals.ringdev < 0) { + if (globals.outdev > -1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid ring device configured using output device!\n"); + globals.ringdev = globals.outdev; + } + } switch_xml_free(xml); return status; } -SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void) +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_shutdown) { if (globals.read_codec.implementation) { switch_core_codec_destroy(&globals.read_codec); @@ -1053,6 +978,7 @@ switch_core_codec_destroy(&globals.write_codec); } + switch_core_timer_destroy(&globals.timer); Pa_Terminate(); return SWITCH_STATUS_SUCCESS; @@ -1061,18 +987,18 @@ static int get_dev_by_number(int number, int in) { - int numDevices = Pa_GetDeviceCount(); + int numDevices = Pa_GetDeviceCount(); const PaDeviceInfo *pdi; - if (number > -1 && number < numDevices && (pdi = Pa_GetDeviceInfo(number))) { - if (in && pdi->maxInputChannels) { - return number; - } else if (!in && pdi->maxOutputChannels) { - return number; - } - } - - return -1; + if (number > -1 && number < numDevices && (pdi = Pa_GetDeviceInfo(number))) { + if (in && pdi->maxInputChannels) { + return number; + } else if (!in && pdi->maxOutputChannels) { + return number; + } + } + + return -1; } static int get_dev_by_name(char *name, int in) @@ -1088,15 +1014,15 @@ } for (i = 0; i < numDevices; i++) { - int match = 0; + int match = 0; pdi = Pa_GetDeviceInfo(i); - + if (switch_strlen_zero(name)) { - match = 1; - } else if (strstr(pdi->name, name)) { - match = 1; - } - + match = 1; + } else if (strstr(pdi->name, name)) { + match = 1; + } + if (match) { if (in && pdi->maxInputChannels) { return i; @@ -1106,248 +1032,253 @@ } } - if (switch_strlen_zero(name)) { - return -1; - } + if (switch_strlen_zero(name)) { + return -1; + } return get_dev_by_name(NULL, in); } /*******************************************************************/ -static void PrintSupportedStandardSampleRates(const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters) +static void PrintSupportedStandardSampleRates(const PaStreamParameters * inputParameters, const PaStreamParameters * outputParameters) { - int i, printCount, cr = 7; - PaError err; - static double standardSampleRates[] = { 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, - 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1}; - - printCount = cr; - for(i=0; standardSampleRates[i] > 0; i++) { - err = Pa_IsFormatSupported(inputParameters, outputParameters, standardSampleRates[i]); - if (err == paFormatIsSupported) { - if (printCount == cr) { - printCount = 0; - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "\n\t%0.2f", standardSampleRates[i]); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, ", %0.2f", standardSampleRates[i]); - } - printCount++; - } - } - if (!printCount) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, " None\n"); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "\n"); - } + int i, printCount, cr = 7; + PaError err; + static double standardSampleRates[] = { 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, + 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 + }; + + printCount = cr; + for (i = 0; standardSampleRates[i] > 0; i++) { + err = Pa_IsFormatSupported(inputParameters, outputParameters, standardSampleRates[i]); + if (err == paFormatIsSupported) { + if (printCount == cr) { + printCount = 0; + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "\n\t%0.2f", standardSampleRates[i]); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, ", %0.2f", standardSampleRates[i]); + } + printCount++; + } + } + if (!printCount) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, " None\n"); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "\n"); + } } + /*******************************************************************/ static switch_status_t devlist(char **argv, int argc, switch_stream_handle_t *stream) { - int i, numDevices; - const PaDeviceInfo *deviceInfo; - - numDevices = Pa_GetDeviceCount(); - if (numDevices < 0) { + int i, numDevices; + const PaDeviceInfo *deviceInfo; + + numDevices = Pa_GetDeviceCount(); + if (numDevices < 0) { return SWITCH_STATUS_SUCCESS; - } - for(i=0; i<numDevices; i++) { - deviceInfo = Pa_GetDeviceInfo(i); - stream->write_function(stream, "%d;%s;%d;%d\n", i, deviceInfo->name, deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels); + } + for (i = 0; i < numDevices; i++) { + deviceInfo = Pa_GetDeviceInfo(i); + stream->write_function(stream, "%d;%s;%d;%d\n", i, deviceInfo->name, deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels); } - return SWITCH_STATUS_SUCCESS; + return SWITCH_STATUS_SUCCESS; } static int dump_info(void) { - int i, numDevices, defaultDisplayed; - const PaDeviceInfo *deviceInfo; - PaStreamParameters inputParameters, outputParameters; - PaError err; - const char *line = "--------------------------------------------------------------------------------\n"; - + int i, numDevices, defaultDisplayed; + const PaDeviceInfo *deviceInfo; + PaStreamParameters inputParameters, outputParameters; + PaError err; + const char *line = "--------------------------------------------------------------------------------\n"; + - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "PortAudio version number = %d\nPortAudio version text = '%s'\n", - Pa_GetVersion(), Pa_GetVersionText()); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "PortAudio version number = %d\nPortAudio version text = '%s'\n", Pa_GetVersion(), Pa_GetVersionText()); if (globals.audio_stream) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "ERROR: Cannot use this command this while a call is in progress\n"); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "ERROR: Cannot use this command this while a call is in progress\n"); return 0; } - - numDevices = Pa_GetDeviceCount(); - if (numDevices < 0) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices); - err = numDevices; - goto error; - } - - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Number of devices = %d\n", numDevices); - for(i=0; i<numDevices; i++) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "%s", line); - deviceInfo = Pa_GetDeviceInfo(i); - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Device #%d ", i); - - /* Mark global and API specific default devices */ - defaultDisplayed = 0; - if (i == Pa_GetDefaultInputDevice()) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "**Default Input"); - defaultDisplayed = 1; - - } else if (i == Pa_GetHostApiInfo(deviceInfo->hostApi)->defaultInputDevice) { - - const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "**Default %s Input", hostInfo->name); - defaultDisplayed = 1; - } - - if (i == Pa_GetDefaultOutputDevice()) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "**Default Output"); - defaultDisplayed = 1; - - } else if (i == Pa_GetHostApiInfo(deviceInfo->hostApi)->defaultOutputDevice) { - - const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "**Default %s Output", hostInfo->name); - defaultDisplayed = 1; - } - - if (defaultDisplayed) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "** | "); - } - /* print device info fields */ - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Name: %s\n", deviceInfo->name); - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Host: %s | ", Pa_GetHostApiInfo(deviceInfo->hostApi)->name); - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "inputs: %d | ", deviceInfo->maxInputChannels ); - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "outputs: %d | ", deviceInfo->maxOutputChannels ); - - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Default rate: %8.2f\n", deviceInfo->defaultSampleRate); - - /* poll for standard sample rates */ - inputParameters.device = i; - inputParameters.channelCount = deviceInfo->maxInputChannels; - inputParameters.sampleFormat = paInt16; - inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ - inputParameters.hostApiSpecificStreamInfo = NULL; - - outputParameters.device = i; - outputParameters.channelCount = deviceInfo->maxOutputChannels; - outputParameters.sampleFormat = paInt16; - outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ - outputParameters.hostApiSpecificStreamInfo = NULL; - - if (inputParameters.channelCount > 0) { - - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "half-duplex 16 bit %d channel input rates:", - inputParameters.channelCount); - PrintSupportedStandardSampleRates(&inputParameters, NULL); - } - - if (outputParameters.channelCount > 0) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "half-duplex 16 bit %d channel output rates:", - outputParameters.channelCount); - PrintSupportedStandardSampleRates(NULL, &outputParameters); - } - - if (inputParameters.channelCount > 0 && outputParameters.channelCount > 0) { - - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "full-duplex 16 bit %d channel input, %d channel output rates:", - inputParameters.channelCount, outputParameters.channelCount); - PrintSupportedStandardSampleRates(&inputParameters, &outputParameters); - } - } - - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "%s", line); - - return 0; - - error: - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "An error occured while using the portaudio stream\n"); - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Error number: %d\n", err); - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Error message: %s\n", Pa_GetErrorText(err)); - return err; + + numDevices = Pa_GetDeviceCount(); + if (numDevices < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices); + err = numDevices; + goto error; + } + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Number of devices = %d\n", numDevices); + for (i = 0; i < numDevices; i++) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "%s", line); + deviceInfo = Pa_GetDeviceInfo(i); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Device #%d ", i); + + /* Mark global and API specific default devices */ + defaultDisplayed = 0; + if (i == Pa_GetDefaultInputDevice()) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "**Default Input"); + defaultDisplayed = 1; + + } else if (i == Pa_GetHostApiInfo(deviceInfo->hostApi)->defaultInputDevice) { + + const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "**Default %s Input", hostInfo->name); + defaultDisplayed = 1; + } + + if (i == Pa_GetDefaultOutputDevice()) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "**Default Output"); + defaultDisplayed = 1; + + } else if (i == Pa_GetHostApiInfo(deviceInfo->hostApi)->defaultOutputDevice) { + + const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "**Default %s Output", hostInfo->name); + defaultDisplayed = 1; + } + + if (defaultDisplayed) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "** | "); + } + /* print device info fields */ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Name: %s\n", deviceInfo->name); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Host: %s | ", Pa_GetHostApiInfo(deviceInfo->hostApi)->name); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "inputs: %d | ", deviceInfo->maxInputChannels); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "outputs: %d | ", deviceInfo->maxOutputChannels); + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Default rate: %8.2f\n", deviceInfo->defaultSampleRate); + + /* poll for standard sample rates */ + inputParameters.device = i; + inputParameters.channelCount = deviceInfo->maxInputChannels; + inputParameters.sampleFormat = paInt16; + inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ + inputParameters.hostApiSpecificStreamInfo = NULL; + + outputParameters.device = i; + outputParameters.channelCount = deviceInfo->maxOutputChannels; + outputParameters.sampleFormat = paInt16; + outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ + outputParameters.hostApiSpecificStreamInfo = NULL; + + if (inputParameters.channelCount > 0) { + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "half-duplex 16 bit %d channel input rates:", inputParameters.channelCount); + PrintSupportedStandardSampleRates(&inputParameters, NULL); + } + + if (outputParameters.channelCount > 0) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "half-duplex 16 bit %d channel output rates:", outputParameters.channelCount); + PrintSupportedStandardSampleRates(NULL, &outputParameters); + } + + if (inputParameters.channelCount > 0 && outputParameters.channelCount > 0) { + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, + "full-duplex 16 bit %d channel input, %d channel output rates:", inputParameters.channelCount, + outputParameters.channelCount); + PrintSupportedStandardSampleRates(&inputParameters, &outputParameters); + } + } + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "%s", line); + + return 0; + + error: + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "An error occured while using the portaudio stream\n"); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Error number: %d\n", err); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Error message: %s\n", Pa_GetErrorText(err)); + return err; } static switch_status_t engage_device(int sample_rate, int codec_ms) { - PaStreamParameters inputParameters, outputParameters; + PaStreamParameters inputParameters, outputParameters; PaError err; - if (!globals.audio_stream) { - if (!sample_rate) { - sample_rate = globals.sample_rate; - } - if (!codec_ms) { - codec_ms = globals.codec_ms; - } - - if (switch_core_codec_init(&globals.read_codec, - "L16", - NULL, - sample_rate, - codec_ms, - 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, - NULL, - NULL) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); - return SWITCH_STATUS_FALSE; - } else { - if (switch_core_codec_init(&globals.write_codec, - "L16", - NULL, - sample_rate, - codec_ms, - 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, - NULL, - NULL) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); - switch_core_codec_destroy(&globals.read_codec); - return SWITCH_STATUS_FALSE; - } - } - - globals.read_frame.rate = sample_rate; - globals.read_frame.codec = &globals.read_codec; - - - - switch_mutex_lock(globals.device_lock); - /* LOCKED ***************************************************************************************************/ - inputParameters.device = globals.indev; - inputParameters.channelCount = 1; - inputParameters.sampleFormat = SAMPLE_TYPE; - inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency; - inputParameters.hostApiSpecificStreamInfo = NULL; - - outputParameters.device = globals.outdev; - outputParameters.channelCount = 1; - outputParameters.sampleFormat = SAMPLE_TYPE; - outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; - err = OpenAudioStream(&globals.audio_stream, &inputParameters, &outputParameters, sample_rate, paClipOff); - /* UNLOCKED **************************************************************************************************/ - switch_mutex_unlock(globals.device_lock); - - - if (err != paNoError) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open audio device!\n"); - switch_core_codec_destroy(&globals.read_codec); - switch_core_codec_destroy(&globals.write_codec); - - return SWITCH_STATUS_FALSE; - } - } + if (!globals.audio_stream) { + if (!sample_rate) { + sample_rate = globals.sample_rate; + } + if (!codec_ms) { + codec_ms = globals.codec_ms; + } + + if (switch_core_codec_init(&globals.read_codec, + "L16", + NULL, sample_rate, codec_ms, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, + NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + return SWITCH_STATUS_FALSE; + } else { + if (switch_core_codec_init(&globals.write_codec, + "L16", + NULL, + sample_rate, codec_ms, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, + NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + switch_core_codec_destroy(&globals.read_codec); + return SWITCH_STATUS_FALSE; + } + } + + if (switch_core_timer_init(&globals.timer, + globals.timer_name, codec_ms, globals.read_codec.implementation->samples_per_frame, + module_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "setup timer failed!\n"); + switch_core_codec_destroy(&globals.read_codec); + switch_core_codec_destroy(&globals.write_codec); + return SWITCH_STATUS_FALSE; + } + + globals.read_frame.rate = sample_rate; + globals.read_frame.codec = &globals.read_codec; - return SWITCH_STATUS_SUCCESS; + + + switch_mutex_lock(globals.device_lock); + /* LOCKED ************************************************************************************************** */ + inputParameters.device = globals.indev; + inputParameters.channelCount = 1; + inputParameters.sampleFormat = SAMPLE_TYPE; + inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + + outputParameters.device = globals.outdev; + outputParameters.channelCount = 1; + outputParameters.sampleFormat = SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + err = OpenAudioStream(&globals.audio_stream, &inputParameters, &outputParameters, sample_rate, paClipOff, + globals.read_codec.implementation->samples_per_frame); + /* UNLOCKED ************************************************************************************************* */ + switch_mutex_unlock(globals.device_lock); + + globals.mixer = Px_OpenMixer(&globals.audio_stream, 0); + + + if (err != paNoError) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open audio device!\n"); + switch_core_codec_destroy(&globals.read_codec); + switch_core_codec_destroy(&globals.write_codec); + + return SWITCH_STATUS_FALSE; + } + } + + + + return SWITCH_STATUS_SUCCESS; } @@ -1355,35 +1286,35 @@ static switch_status_t engage_ring_device(int sample_rate, int channels) { - //int codec_ms = 20; - PaStreamParameters outputParameters; + PaStreamParameters outputParameters; PaError err; - if (!globals.ring_stream) { - if (!sample_rate) { - sample_rate = globals.sample_rate; - } - - switch_mutex_lock(globals.device_lock); - /* LOCKED ***************************************************************************************************/ - outputParameters.device = globals.ringdev; - outputParameters.channelCount = channels; - outputParameters.sampleFormat = SAMPLE_TYPE; - outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; - err = OpenAudioStream(&globals.ring_stream, NULL, &outputParameters, sample_rate, paClipOff); - /* UNLOCKED **************************************************************************************************/ - switch_mutex_unlock(globals.device_lock); - - - if (err != paNoError) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open ring device!\n"); - return SWITCH_STATUS_FALSE; - } - } + if (!globals.ring_stream) { + if (!sample_rate) { + sample_rate = globals.sample_rate; + } + + switch_mutex_lock(globals.device_lock); + /* LOCKED ************************************************************************************************** */ + outputParameters.device = globals.ringdev; + outputParameters.channelCount = channels; + outputParameters.sampleFormat = SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + err = OpenAudioStream(&globals.ring_stream, NULL, &outputParameters, sample_rate, paClipOff, + globals.read_codec.implementation->samples_per_frame); + /* UNLOCKED ************************************************************************************************* */ + switch_mutex_unlock(globals.device_lock); + + + if (err != paNoError) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open ring device!\n"); + return SWITCH_STATUS_FALSE; + } + } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Engage ring device! rate: %d channels %d\n", sample_rate, channels); - return SWITCH_STATUS_SUCCESS; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Engage ring device! rate: %d channels %d\n", sample_rate, channels); + return SWITCH_STATUS_SUCCESS; } @@ -1391,64 +1322,64 @@ static switch_status_t dtmf_call(char **argv, int argc, switch_stream_handle_t *stream) { - char *dtmf = argv[0]; + char *dtmf = argv[0]; - if (switch_strlen_zero(dtmf)) { - stream->write_function(stream, "No DTMF Supplied!\n"); - } else { - switch_mutex_lock(globals.pvt_lock); - if (globals.call_list) { - switch_channel_t *channel = switch_core_session_get_channel(globals.call_list->session); - switch_channel_queue_dtmf(channel, dtmf); - } - switch_mutex_unlock(globals.pvt_lock); - } + if (switch_strlen_zero(dtmf)) { + stream->write_function(stream, "No DTMF Supplied!\n"); + } else { + switch_mutex_lock(globals.pvt_lock); + if (globals.call_list) { + switch_channel_t *channel = switch_core_session_get_channel(globals.call_list->session); + switch_channel_queue_dtmf(channel, dtmf); + } + switch_mutex_unlock(globals.pvt_lock); + } - return SWITCH_STATUS_SUCCESS; + return SWITCH_STATUS_SUCCESS; } static switch_status_t switch_call(char **argv, int argc, switch_stream_handle_t *stream) { - private_t *tp,*tech_pvt = NULL; - char *callid = argv[0]; - uint8_t one_call = 0; - - switch_mutex_lock(globals.pvt_lock); - if (switch_strlen_zero(callid)) { - if (globals.call_list) { - if (globals.call_list->next) { - tech_pvt = globals.call_list->next; - } else { - tech_pvt = globals.call_list; - one_call = 1; - } - } - } else if (!strcasecmp(callid, "none")) { - for (tp = globals.call_list; tp; tp = tp->next) { - switch_clear_flag_locked(tp, TFLAG_MASTER); - } - stream->write_function(stream, "OK\n"); - goto done; - } else { - tech_pvt = switch_core_hash_find(globals.call_hash, callid); - } + private_t *tp, *tech_pvt = NULL; + char *callid = argv[0]; + uint8_t one_call = 0; + + switch_mutex_lock(globals.pvt_lock); + if (switch_strlen_zero(callid)) { + if (globals.call_list) { + if (globals.call_list->next) { + tech_pvt = globals.call_list->next; + } else { + tech_pvt = globals.call_list; + one_call = 1; + } + } + } else if (!strcasecmp(callid, "none")) { + for (tp = globals.call_list; tp; tp = tp->next) { + switch_clear_flag_locked(tp, TFLAG_MASTER); + } + stream->write_function(stream, "OK\n"); + goto done; + } else { + tech_pvt = switch_core_hash_find(globals.call_hash, callid); + } if (tech_pvt) { - if (tech_pvt == globals.call_list && !tech_pvt->next) { - one_call = 1; - } - - if (!one_call) { - remove_pvt(tech_pvt); - } - add_pvt(tech_pvt, PA_MASTER); - stream->write_function(stream, "OK\n"); + if (tech_pvt == globals.call_list && !tech_pvt->next) { + one_call = 1; + } + + if (!one_call) { + remove_pvt(tech_pvt); + } + add_pvt(tech_pvt, PA_MASTER); + stream->write_function(stream, "OK\n"); } else { stream->write_function(stream, "NO SUCH CALL\n"); } - done: - switch_mutex_unlock(globals.pvt_lock); + done: + switch_mutex_unlock(globals.pvt_lock); return SWITCH_STATUS_SUCCESS; @@ -1456,23 +1387,23 @@ static switch_status_t hangup_call(char **argv, int argc, switch_stream_handle_t *stream) { - private_t *tech_pvt; - char *callid = argv[0]; - - switch_mutex_lock(globals.pvt_lock); - if (switch_strlen_zero(callid)) { - tech_pvt = globals.call_list; - } else { - tech_pvt = switch_core_hash_find(globals.call_hash, callid); - } + private_t *tech_pvt; + char *callid = argv[0]; + + switch_mutex_lock(globals.pvt_lock); + if (switch_strlen_zero(callid)) { + tech_pvt = globals.call_list; + } else { + tech_pvt = switch_core_hash_find(globals.call_hash, callid); + } if (tech_pvt) { - switch_set_flag_locked(tech_pvt, TFLAG_HUP); + switch_channel_hangup(switch_core_session_get_channel(tech_pvt->session), SWITCH_CAUSE_NORMAL_CLEARING); stream->write_function(stream, "OK\n"); } else { stream->write_function(stream, "NO SUCH CALL\n"); } - switch_mutex_unlock(globals.pvt_lock); + switch_mutex_unlock(globals.pvt_lock); return SWITCH_STATUS_SUCCESS; @@ -1480,43 +1411,43 @@ static switch_status_t answer_call(char **argv, int argc, switch_stream_handle_t *stream) { - private_t *tp; - int x = 0; - char *callid = argv[0]; - - switch_mutex_lock(globals.pvt_lock); - - if (!switch_strlen_zero(callid)) { - if ((tp = switch_core_hash_find(globals.call_hash, callid))) { - if (switch_test_flag(tp, TFLAG_ANSWER)) { - stream->write_function(stream, "CALL ALREADY ANSWERED\n"); - } else { - switch_channel_t *channel = switch_core_session_get_channel(tp->session); - switch_set_flag_locked(tp, TFLAG_ANSWER); - switch_channel_answer(channel); - add_pvt(tp, PA_MASTER); - } - } else { - stream->write_function(stream, "NO SUCH CALL\n"); - } - - goto done; - } - - for (tp = globals.call_list; tp; tp = tp->next) { - if (!switch_test_flag(tp, TFLAG_ANSWER)) { - switch_channel_t *channel = switch_core_session_get_channel(tp->session); - switch_set_flag_locked(tp, TFLAG_ANSWER); - switch_channel_answer(channel); - add_pvt(tp, PA_MASTER); - x++; - break; - } - } - done: - switch_mutex_unlock(globals.pvt_lock); + private_t *tp; + int x = 0; + char *callid = argv[0]; + + switch_mutex_lock(globals.pvt_lock); + + if (!switch_strlen_zero(callid)) { + if ((tp = switch_core_hash_find(globals.call_hash, callid))) { + if (switch_test_flag(tp, TFLAG_ANSWER)) { + stream->write_function(stream, "CALL ALREADY ANSWERED\n"); + } else { + switch_channel_t *channel = switch_core_session_get_channel(tp->session); + switch_set_flag_locked(tp, TFLAG_ANSWER); + switch_channel_answer(channel); + add_pvt(tp, PA_MASTER); + } + } else { + stream->write_function(stream, "NO SUCH CALL\n"); + } - stream->write_function(stream, "Answered %d channels.\n", x); + goto done; + } + + for (tp = globals.call_list; tp; tp = tp->next) { + if (!switch_test_flag(tp, TFLAG_ANSWER)) { + switch_channel_t *channel = switch_core_session_get_channel(tp->session); + switch_set_flag_locked(tp, TFLAG_ANSWER); + switch_channel_answer(channel); + add_pvt(tp, PA_MASTER); + x++; + break; + } + } + done: + switch_mutex_unlock(globals.pvt_lock); + + stream->write_function(stream, "Answered %d channels.\n", x); return SWITCH_STATUS_SUCCESS; @@ -1525,113 +1456,110 @@ static switch_status_t do_flags(char **argv, int argc, switch_stream_handle_t *stream) { - char *action = argv[0]; - char *flag_str = argv[1]; - GFLAGS flags = GFLAG_NONE; - char *p; - int x = 0; - - if (argc < 2) { - goto desc; - } - - for (x = 1; x < argc; x++) { - flag_str = argv[x]; - for(p = flag_str; *p; p++) { - *p = (char)tolower(*p); - } - - if (strstr(flag_str, "ear")) { - flags |= GFLAG_EAR; - } - if (strstr(flag_str, "mouth")) { - flags |= GFLAG_MOUTH; - } - } - - if (!strcasecmp(action, "on")) { - if (flags & GFLAG_EAR) { - switch_set_flag((&globals), GFLAG_EAR); - } - if (flags & GFLAG_MOUTH) { - switch_set_flag((&globals), GFLAG_MOUTH); - } - } else if (!strcasecmp(action, "off")) { - if (flags & GFLAG_EAR) { - switch_clear_flag((&globals), GFLAG_EAR); - } - if (flags & GFLAG_MOUTH) { - switch_clear_flag((&globals), GFLAG_MOUTH); - } - } else { - goto bad; - } - - desc: - x = 0; - stream->write_function(stream, "FLAGS: "); - if (switch_test_flag((&globals), GFLAG_EAR)) { - stream->write_function(stream, "ear"); - x++; - } - if (switch_test_flag((&globals), GFLAG_MOUTH)) { - stream->write_function(stream, "%smouth", x ? "|" : ""); - x++; - } - if (!x) { - stream->write_function(stream, "none"); - } - - goto done; - - bad: - stream->write_function(stream, "Usage: flags [on|off] <flags>\n"); - done: - return SWITCH_STATUS_SUCCESS; + char *action = argv[0]; + char *flag_str = argv[1]; + GFLAGS flags = GFLAG_NONE; + char *p; + int x = 0; + + if (argc < 2) { + goto desc; + } + + for (x = 1; x < argc; x++) { + flag_str = argv[x]; + for (p = flag_str; *p; p++) { + *p = (char) tolower(*p); + } + + if (strstr(flag_str, "ear")) { + flags |= GFLAG_EAR; + } + if (strstr(flag_str, "mouth")) { + flags |= GFLAG_MOUTH; + } + } + + if (!strcasecmp(action, "on")) { + if (flags & GFLAG_EAR) { + switch_set_flag((&globals), GFLAG_EAR); + } + if (flags & GFLAG_MOUTH) { + switch_set_flag((&globals), GFLAG_MOUTH); + } + } else if (!strcasecmp(action, "off")) { + if (flags & GFLAG_EAR) { + switch_clear_flag((&globals), GFLAG_EAR); + } + if (flags & GFLAG_MOUTH) { + switch_clear_flag((&globals), GFLAG_MOUTH); + } + } else { + goto bad; + } + + desc: + x = 0; + stream->write_function(stream, "FLAGS: "); + if (switch_test_flag((&globals), GFLAG_EAR)) { + stream->write_function(stream, "ear"); + x++; + } + if (switch_test_flag((&globals), GFLAG_MOUTH)) { + stream->write_function(stream, "%smouth", x ? "|" : ""); + x++; + } + if (!x) { + stream->write_function(stream, "none"); + } + + goto done; + + bad: + stream->write_function(stream, "Usage: flags [on|off] <flags>\n"); + done: + return SWITCH_STATUS_SUCCESS; } static switch_status_t list_calls(char **argv, int argc, switch_stream_handle_t *stream) { - private_t *tp; - int x = 0; - char *cid_name = "n/a"; - char *cid_num = "n/a"; - - switch_mutex_lock(globals.pvt_lock); - for (tp = globals.call_list; tp; tp = tp->next) { + private_t *tp; + int x = 0; + char *cid_name = "n/a"; + char *cid_num = "n/a"; + + switch_mutex_lock(globals.pvt_lock); + for (tp = globals.call_list; tp; tp = tp->next) { switch_channel_t *channel; - switch_caller_profile_t *profile; - x++; - channel = switch_core_session_get_channel(tp->session); - - if ((profile = switch_channel_get_caller_profile(channel))) { - if (profile->originatee_caller_profile) { - cid_name = "Outbound Call"; - cid_num = profile->originatee_caller_profile->destination_number; - } else { - cid_name = profile->caller_id_name; - cid_num = profile->caller_id_number; - } - } - - stream->write_function(stream, "%s %s [%s (%s)] %s\n", tp->call_id, switch_channel_get_name(channel), - cid_name, - cid_num, - switch_test_flag(tp, TFLAG_MASTER) ? "active" : "hold" - ); - } - switch_mutex_unlock(globals.pvt_lock); + switch_caller_profile_t *profile; + x++; + channel = switch_core_session_get_channel(tp->session); + + if ((profile = switch_channel_get_caller_profile(channel))) { + if (profile->originatee_caller_profile) { + cid_name = "Outbound Call"; + cid_num = profile->originatee_caller_profile->destination_number; + } else { + cid_name = profile->caller_id_name; + cid_num = profile->caller_id_number; + } + } + + stream->write_function(stream, "%s %s [%s (%s)] %s\n", tp->call_id, switch_channel_get_name(channel), + cid_name, cid_num, switch_test_flag(tp, TFLAG_MASTER) ? "active" : "hold"); + } + switch_mutex_unlock(globals.pvt_lock); - stream->write_function(stream, "\n%d call%s\n", x, x == 1 ? "" : "s"); + stream->write_function(stream, "\n%d call%s\n", x, x == 1 ? "" : "s"); - return SWITCH_STATUS_SUCCESS; + return SWITCH_STATUS_SUCCESS; } static switch_status_t place_call(char **argv, int argc, switch_stream_handle_t *stream) { switch_core_session_t *session; switch_status_t status = SWITCH_STATUS_SUCCESS; - char *dest = NULL; + char *dest = NULL; if (!argv[0]) { stream->write_function(stream, "FAIL:Usage: call <dest>\n"); @@ -1639,12 +1567,12 @@ } dest = argv[0]; - if ((session = switch_core_session_request(&channel_endpoint_interface, NULL)) != 0) { + if ((session = switch_core_session_request(channel_endpoint_interface, NULL)) != 0) { private_t *tech_pvt; switch_channel_t *channel; - char *dialplan = globals.dialplan; - char *cid_name = globals.cid_name; - char *cid_num = globals.cid_num; + char *dialplan = globals.dialplan; + char *cid_name = globals.cid_name; + char *cid_num = globals.cid_num; switch_core_session_add_stream(session, NULL); if ((tech_pvt = (private_t *) switch_core_session_alloc(session, sizeof(private_t))) != 0) { @@ -1653,7 +1581,7 @@ channel = switch_core_session_get_channel(session); switch_core_session_set_private(session, tech_pvt); tech_pvt->session = session; - globals.flags = GFLAG_EAR | GFLAG_MOUTH; + globals.flags = GFLAG_EAR | GFLAG_MOUTH; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n"); switch_core_session_destroy(&session); @@ -1661,31 +1589,29 @@ } if (!switch_strlen_zero(argv[1])) { - dialplan = argv[1]; - } + dialplan = argv[1]; + } - if (!switch_strlen_zero(argv[2])) { - cid_num = argv[2]; - } - - if (!switch_strlen_zero(argv[3])) { - cid_name = argv[3]; - } - - if (!switch_strlen_zero(argv[4])) { - tech_pvt->sample_rate = atoi(argv[4]); - } - - if (!switch_strlen_zero(argv[4])) { - tech_pvt->codec_ms = atoi(argv[5]); - } + if (!switch_strlen_zero(argv[2])) { + cid_num = argv[2]; + } + + if (!switch_strlen_zero(argv[3])) { + cid_name = argv[3]; + } + + if (!switch_strlen_zero(argv[4])) { + tech_pvt->sample_rate = atoi(argv[4]); + } + + if (!switch_strlen_zero(argv[4])) { + tech_pvt->codec_ms = atoi(argv[5]); + } if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), NULL, - dialplan, - cid_name, - cid_num, - NULL, NULL, NULL, NULL, (char *)modname, NULL, dest)) != 0) { + dialplan, cid_name, cid_num, NULL, NULL, NULL, NULL, (char *) modname, NULL, + dest)) != 0) { char name[128]; snprintf(name, sizeof(name), "PortAudio/%s", tech_pvt->caller_profile->destination_number ? tech_pvt->caller_profile->destination_number : modname); @@ -1695,14 +1621,19 @@ } tech_pvt->session = session; if ((status = engage_device(tech_pvt->sample_rate, tech_pvt->codec_ms)) == SWITCH_STATUS_SUCCESS) { - switch_set_flag_locked(tech_pvt, TFLAG_ANSWER); - switch_channel_mark_answered(channel); + switch_set_flag_locked(tech_pvt, TFLAG_ANSWER); + switch_channel_mark_answered(channel); switch_channel_set_state(channel, CS_INIT); - switch_core_session_thread_launch(tech_pvt->session); - add_pvt(tech_pvt, PA_MASTER); - stream->write_function(stream, "SUCCESS:%s:%s\n", tech_pvt->call_id, switch_core_session_get_uuid(tech_pvt->session)); + if (switch_core_session_thread_launch(tech_pvt->session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n"); + switch_core_session_destroy(&session); + stream->write_function(stream, "FAIL:Thread Error!\n"); + } else { + add_pvt(tech_pvt, PA_MASTER); + stream->write_function(stream, "SUCCESS:%s:%s\n", tech_pvt->call_id, switch_core_session_get_uuid(tech_pvt->session)); + } } else { - switch_core_session_destroy(&session); + switch_core_session_destroy(&session); stream->write_function(stream, "FAIL:Device Error!\n"); } } @@ -1710,74 +1641,131 @@ return SWITCH_STATUS_SUCCESS; } -static switch_status_t padep(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +static switch_status_t set_volume(char **argv, int argc, switch_stream_handle_t *stream) { - stream->write_function(stream, "This command no longer exists (try 'pa help')\n"); - return SWITCH_STATUS_SUCCESS; + PxVolume volume; + switch_mutex_lock(globals.device_lock); + if (!switch_strlen_zero(argv[1])) { + volume = (PxVolume) atof(argv[1]); + Px_SetMasterVolume( globals.mixer, volume ); + } + switch_mutex_unlock(globals.device_lock); + return SWITCH_STATUS_SUCCESS; } -static switch_status_t pa_cmd(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream) +SWITCH_STANDARD_API(pa_cmd) { - char *argv[1024] = {0}; - int argc = 0; - char *mycmd = NULL, *devname = NULL; - switch_status_t status = SWITCH_STATUS_SUCCESS; - pa_command_t func = NULL; - int lead = 1, devval = 0; - const char *usage_string = "USAGE:\n" - "--------------------------------------------------------------------------------\n" - "pa help\n" - "pa dump\n" - "pa call <dest> [<dialplan> <cid_name> <cid_num> <rate>]\n" - "pa answer [<call_id>]\n" - "pa hangup [<call_id>]\n" - "pa list\n" - "pa switch [<call_id>|none]\n" - "pa dtmf <digit string>\n" - "pa flags [on|off] [ear] [mouth]\n" + char *argv[1024] = { 0 }; + int argc = 0; + char *mycmd = NULL, *devname = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + pa_command_t func = NULL; + int lead = 1, devval = 0; + char *wcmd = NULL, *action = NULL; + char cmd_buf[1024] = ""; + char *http = NULL; + + const char *usage_string = "USAGE:\n" + "--------------------------------------------------------------------------------\n" + "pa help\n" + "pa dump\n" + "pa call <dest> [<dialplan> <cid_name> <cid_num> <rate>]\n" + "pa answer [<call_id>]\n" + "pa hangup [<call_id>]\n" + "pa list\n" + "pa switch [<call_id>|none]\n" + "pa dtmf <digit string>\n" + "pa flags [on|off] [ear] [mouth]\n" "pa devlist\n" "pa indev [#<num>|<partial name>\n" "pa outdev [#<num>|<partial name>\n" "pa ringdev [#<num>|<partial name>\n" - "--------------------------------------------------------------------------------\n"; + "pa setvolume <volume between 0.0 and 1.0>\n" + "--------------------------------------------------------------------------------\n"; + + if (stream->event) { + http = switch_event_get_header(stream->event, "http-host"); + } + + + if (http) { +#if 0 + switch_event_header_t *hp; + stream->write_function(stream, "<pre>"); + for (hp = stream->event->headers; hp; hp = hp->next) { + stream->write_function(stream, "[%s]=[%s]\n", hp->name, hp->value); + } + stream->write_function(stream, "</pre>"); +#endif + + wcmd = switch_str_nil(switch_event_get_header(stream->event, "wcmd")); + action = switch_event_get_header(stream->event, "action"); - if (switch_strlen_zero(cmd)) { - stream->write_function(stream, "%s", usage_string); - goto done; - } - - if (!(mycmd = strdup(cmd))) { - status = SWITCH_STATUS_MEMERR; - goto done; - } - - if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { - stream->write_function(stream, "%s", usage_string); - goto done; - } - - if (!strcasecmp(argv[0], "call")) { - func = place_call; - } else if (!strcasecmp(argv[0], "help")) { - stream->write_function(stream, "%s", usage_string); - goto done; - } else if (!strcasecmp(argv[0], "devlist")) { + if (action) { + if (strlen(action) == 1) { + snprintf(cmd_buf, sizeof(cmd_buf), "dtmf %s", action); + cmd = cmd_buf; + } else if (!strcmp(action, "mute")) { + snprintf(cmd_buf, sizeof(cmd_buf), "flags off mouth"); + cmd = cmd_buf; + } else if (!strcmp(action, "unmute")) { + snprintf(cmd_buf, sizeof(cmd_buf), "flags on mouth"); + cmd = cmd_buf; + } else if (!strcmp(action, "switch")) { + snprintf(cmd_buf, sizeof(cmd_buf), "switch %s", wcmd); + cmd = cmd_buf; + } else if (!strcmp(action, "call")) { + snprintf(cmd_buf, sizeof(cmd_buf), "call %s", wcmd); + cmd = cmd_buf; + } else if (!strcmp(action, "hangup") || !strcmp(action, "list") || !strcmp(action, "answer")) { + cmd = action; + } + } + + if (switch_strlen_zero(cmd)) { + goto done; + } + + } else { + + if (switch_strlen_zero(cmd)) { + stream->write_function(stream, "%s", usage_string); + goto done; + } + } + + if (!(mycmd = strdup(cmd))) { + status = SWITCH_STATUS_MEMERR; + goto done; + } + + if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { + stream->write_function(stream, "%s", usage_string); + goto done; + } + + if (!strcasecmp(argv[0], "call")) { + func = place_call; + } else if (!strcasecmp(argv[0], "help")) { + stream->write_function(stream, "%s", usage_string); + goto done; + } else if (!strcasecmp(argv[0], "devlist")) { func = devlist; - } else if (!strcasecmp(argv[0], "dump")) { - dump_info(); - goto done; - } else if (!strcasecmp(argv[0], "list")) { - func = list_calls; - } else if (!strcasecmp(argv[0], "flags")) { - func = do_flags; - } else if (!strcasecmp(argv[0], "hangup")) { - func = hangup_call; - } else if (!strcasecmp(argv[0], "answer")) { - func = answer_call; - } else if (!strcasecmp(argv[0], "switch")) { - func = switch_call; - } else if (!strcasecmp(argv[0], "dtmf")) { - func = dtmf_call; + } else if (!strcasecmp(argv[0], "dump")) { + dump_info(); + goto done; + } else if (!strcasecmp(argv[0], "list")) { + func = list_calls; + } else if (!strcasecmp(argv[0], "flags")) { + func = do_flags; + } else if (!strcasecmp(argv[0], "hangup")) { + func = hangup_call; + } else if (!strcasecmp(argv[0], "answer")) { + func = answer_call; + } else if (!strcasecmp(argv[0], "switch")) { + func = switch_call; + } else if (!strcasecmp(argv[0], "dtmf")) { + func = dtmf_call; } else if (argv[1] && !strcmp(argv[0], "indev")) { if (*argv[1] == '#') { devval = get_dev_by_number(atoi(argv[1] + 1), 1); @@ -1795,7 +1783,7 @@ devval = get_dev_by_name(argv[1], 0); } devname = "outdev"; - if (devval > 0) { + if (devval > 0) { globals.outdev = devval; } } else if (argv[1] && !strcmp(argv[0], "ringdev")) { @@ -1807,12 +1795,20 @@ devname = "ringdev"; if (devval > 0) { globals.ringdev = devval; + } + } else if (!strcasecmp(argv[0], "setvolume")) { + func = set_volume; + } + + if (func) { + if (http) { + stream->write_function(stream, "<pre>"); } - } - - if (func) { - status = func(&argv[lead], argc - lead, stream); - } else { + status = func(&argv[lead], argc - lead, stream); + if (http) { + stream->write_function(stream, "\n\n</pre>"); + } + } else { if (devname) { if (devval > 0) { stream->write_function(stream, "%s set to %d\n", devname, devval); @@ -1822,13 +1818,52 @@ } else { stream->write_function(stream, "Unknown Command [%s]\n", argv[0]); } - } + } + + done: - done: + if (http) { - switch_safe_free(mycmd); + stream->write_function(stream, + "<br><br><table align=center><tr><td><center><form method=post>\n" + "<input type=text name=wcmd size=40><br><br>\n" + + "<input name=action type=submit value=\"call\"> " + "<input name=action type=submit value=\"hangup\"> " + "<input name=action type=submit value=\"list\"> " + "<input name=action type=submit value=\"switch\"> " + "<input name=action type=submit value=\"mute\"> " + "<input name=action type=submit value=\"unmute\"> " + "<input name=action type=submit value=\"answer\"> <br><br>" + "<table border=1>\n" + "<tr><td><input name=action type=submit value=\"1\"></td>" + "<td><input name=action type=submit value=\"2\"></td>" + "<td><input name=action type=submit value=\"3\"></td>\n" + "<td><input name=action type=submit value=\"A\"></td></tr>\n" + + "<tr><td><input name=action type=submit value=\"4\"></td>" + "<td><input name=action type=submit value=\"5\"></td>" + "<td><input name=action type=submit value=\"6\"></td>\n" + "<td><input name=action type=submit value=\"B\"></td></tr>\n" + + "<tr><td><input name=action type=submit value=\"7\"></td>" + "<td><input name=action type=submit value=\"8\"></td>" + "<td><input name=action type=submit value=\"9\"></td>\n" + "<td><input name=action type=submit value=\"C\"></td></tr>\n" + + "<tr><td><input name=action type=submit value=\"*\"></td>" + "<td><input name=action type=submit value=\"0\"></td>" + "<td><input name=action type=submit value=\"#\"></td>\n" + "<td><input name=action type=submit value=\"D\"></td></tr>\n" + "</table>" + + "</form><br></center></td></tr></table>\n" + ); + } - return status; + switch_safe_free(mycmd); + + return status; } Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pa_ringbuffer.c ============================================================================== --- freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pa_ringbuffer.c (original) +++ freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pa_ringbuffer.c Fri Aug 24 13:50:56 2007 @@ -81,24 +81,25 @@ # define PaUtil_WriteMemoryBarrier() #else -#if defined(__APPLE__) //|| defined(__FreeBSD__) +#if defined(__APPLE__) //|| defined(__FreeBSD__) # include <libkern/OSAtomic.h> - /* Here are the memory barrier functions. Mac OS X and FreeBSD only provide - full memory barriers, so the three types of barriers are the same. */ + /* Here are the memory barrier functions. Mac OS X and FreeBSD only provide + full memory barriers, so the three types of barriers are the same. */ # define PaUtil_FullMemoryBarrier() OSMemoryBarrier() # define PaUtil_ReadMemoryBarrier() OSMemoryBarrier() # define PaUtil_WriteMemoryBarrier() OSMemoryBarrier() #elif defined(__GNUC__) - /* GCC understands volatile asm and "memory" to mean it - * should not reorder memory read/writes */ + + /* GCC understands volatile asm and "memory" to mean it + * should not reorder memory read/writes */ # if defined( __PPC__ ) -# define PaUtil_FullMemoryBarrier() asm volatile("sync":::"memory") -# define PaUtil_ReadMemoryBarrier() asm volatile("sync":::"memory") -# define PaUtil_WriteMemoryBarrier() asm volatile("sync":::"memory") +# define PaUtil_FullMemoryBarrier() __asm__ volatile("sync":::"memory") +# define PaUtil_ReadMemoryBarrier() __asm__ volatile("sync":::"memory") +# define PaUtil_WriteMemoryBarrier() __asm__ volatile("sync":::"memory") # elif defined( __i386__ ) || defined( __i486__ ) || defined( __i586__ ) || defined( __i686__ ) || defined(__x86_64__) -# define PaUtil_FullMemoryBarrier() asm volatile("mfence":::"memory") -# define PaUtil_ReadMemoryBarrier() asm volatile("lfence":::"memory") -# define PaUtil_WriteMemoryBarrier() asm volatile("sfence":::"memory") +# define PaUtil_FullMemoryBarrier() __asm__ volatile("mfence":::"memory") +# define PaUtil_ReadMemoryBarrier() __asm__ volatile("lfence":::"memory") +# define PaUtil_WriteMemoryBarrier() __asm__ volatile("sfence":::"memory") # else # define PaUtil_FullMemoryBarrier() # define PaUtil_ReadMemoryBarrier() @@ -122,37 +123,39 @@ * Initialize FIFO. * numBytes must be power of 2, returns -1 if not. */ -long PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, long numBytes, void *dataPtr ) +long PaUtil_InitializeRingBuffer(PaUtilRingBuffer * rbuf, long numBytes, void *dataPtr) { - if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */ - rbuf->bufferSize = numBytes; - rbuf->buffer = (char *)dataPtr; - PaUtil_FlushRingBuffer( rbuf ); - rbuf->bigMask = (numBytes*2)-1; - rbuf->smallMask = (numBytes)-1; - return 0; + if (((numBytes - 1) & numBytes) != 0) + return -1; /* Not Power of two. */ + rbuf->bufferSize = numBytes; + rbuf->buffer = (char *) dataPtr; + PaUtil_FlushRingBuffer(rbuf); + rbuf->bigMask = (numBytes * 2) - 1; + rbuf->smallMask = (numBytes) - 1; + return 0; } /*************************************************************************** ** Return number of bytes available for reading. */ -long PaUtil_GetRingBufferReadAvailable( PaUtilRingBuffer *rbuf ) +long PaUtil_GetRingBufferReadAvailable(PaUtilRingBuffer * rbuf) { - PaUtil_ReadMemoryBarrier(); - return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask ); + PaUtil_ReadMemoryBarrier(); + return ((rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask); } + /*************************************************************************** ** Return number of bytes available for writing. */ -long PaUtil_GetRingBufferWriteAvailable( PaUtilRingBuffer *rbuf ) +long PaUtil_GetRingBufferWriteAvailable(PaUtilRingBuffer * rbuf) { - /* Since we are calling PaUtil_GetRingBufferReadAvailable, we don't need an aditional MB */ - return ( rbuf->bufferSize - PaUtil_GetRingBufferReadAvailable(rbuf)); + /* Since we are calling PaUtil_GetRingBufferReadAvailable, we don't need an aditional MB */ + return (rbuf->bufferSize - PaUtil_GetRingBufferReadAvailable(rbuf)); } /*************************************************************************** ** Clear buffer. Should only be called when buffer is NOT being read. */ -void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf ) +void PaUtil_FlushRingBuffer(PaUtilRingBuffer * rbuf) { - rbuf->writeIndex = rbuf->readIndex = 0; + rbuf->writeIndex = rbuf->readIndex = 0; } /*************************************************************************** @@ -161,42 +164,38 @@ ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ -long PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, long numBytes, - void **dataPtr1, long *sizePtr1, - void **dataPtr2, long *sizePtr2 ) -{ - long index; - long available = PaUtil_GetRingBufferWriteAvailable( rbuf ); - if( numBytes > available ) numBytes = available; - /* Check to see if write is not contiguous. */ - index = rbuf->writeIndex & rbuf->smallMask; - if( (index + numBytes) > rbuf->bufferSize ) - { - /* Write data in two blocks that wrap the buffer. */ - long firstHalf = rbuf->bufferSize - index; - *dataPtr1 = &rbuf->buffer[index]; - *sizePtr1 = firstHalf; - *dataPtr2 = &rbuf->buffer[0]; - *sizePtr2 = numBytes - firstHalf; - } - else - { - *dataPtr1 = &rbuf->buffer[index]; - *sizePtr1 = numBytes; - *dataPtr2 = NULL; - *sizePtr2 = 0; - } - return numBytes; +long PaUtil_GetRingBufferWriteRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2) +{ + long index; + long available = PaUtil_GetRingBufferWriteAvailable(rbuf); + if (numBytes > available) + numBytes = available; + /* Check to see if write is not contiguous. */ + index = rbuf->writeIndex & rbuf->smallMask; + if ((index + numBytes) > rbuf->bufferSize) { + /* Write data in two blocks that wrap the buffer. */ + long firstHalf = rbuf->bufferSize - index; + *dataPtr1 = &rbuf->buffer[index]; + *sizePtr1 = firstHalf; + *dataPtr2 = &rbuf->buffer[0]; + *sizePtr2 = numBytes - firstHalf; + } else { + *dataPtr1 = &rbuf->buffer[index]; + *sizePtr1 = numBytes; + *dataPtr2 = NULL; + *sizePtr2 = 0; + } + return numBytes; } /*************************************************************************** */ -long PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, long numBytes ) +long PaUtil_AdvanceRingBufferWriteIndex(PaUtilRingBuffer * rbuf, long numBytes) { - /* we need to ensure that previous writes are seen before we update the write index */ - PaUtil_WriteMemoryBarrier(); - return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask; + /* we need to ensure that previous writes are seen before we update the write index */ + PaUtil_WriteMemoryBarrier(); + return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask; } /*************************************************************************** @@ -205,81 +204,72 @@ ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ -long PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, long numBytes, - void **dataPtr1, long *sizePtr1, - void **dataPtr2, long *sizePtr2 ) -{ - long index; - long available = PaUtil_GetRingBufferReadAvailable( rbuf ); - if( numBytes > available ) numBytes = available; - /* Check to see if read is not contiguous. */ - index = rbuf->readIndex & rbuf->smallMask; - if( (index + numBytes) > rbuf->bufferSize ) - { - /* Write data in two blocks that wrap the buffer. */ - long firstHalf = rbuf->bufferSize - index; - *dataPtr1 = &rbuf->buffer[index]; - *sizePtr1 = firstHalf; - *dataPtr2 = &rbuf->buffer[0]; - *sizePtr2 = numBytes - firstHalf; - } - else - { - *dataPtr1 = &rbuf->buffer[index]; - *sizePtr1 = numBytes; - *dataPtr2 = NULL; - *sizePtr2 = 0; - } - return numBytes; +long PaUtil_GetRingBufferReadRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2) +{ + long index; + long available = PaUtil_GetRingBufferReadAvailable(rbuf); + if (numBytes > available) + numBytes = available; + /* Check to see if read is not contiguous. */ + index = rbuf->readIndex & rbuf->smallMask; + if ((index + numBytes) > rbuf->bufferSize) { + /* Write data in two blocks that wrap the buffer. */ + long firstHalf = rbuf->bufferSize - index; + *dataPtr1 = &rbuf->buffer[index]; + *sizePtr1 = firstHalf; + *dataPtr2 = &rbuf->buffer[0]; + *sizePtr2 = numBytes - firstHalf; + } else { + *dataPtr1 = &rbuf->buffer[index]; + *sizePtr1 = numBytes; + *dataPtr2 = NULL; + *sizePtr2 = 0; + } + return numBytes; } + /*************************************************************************** */ -long PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, long numBytes ) +long PaUtil_AdvanceRingBufferReadIndex(PaUtilRingBuffer * rbuf, long numBytes) { - /* we need to ensure that previous writes are always seen before updating the index. */ - PaUtil_WriteMemoryBarrier(); - return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask; + /* we need to ensure that previous writes are always seen before updating the index. */ + PaUtil_WriteMemoryBarrier(); + return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask; } /*************************************************************************** ** Return bytes written. */ -long PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, long numBytes ) +long PaUtil_WriteRingBuffer(PaUtilRingBuffer * rbuf, const void *data, long numBytes) { - long size1, size2, numWritten; - void *data1, *data2; - numWritten = PaUtil_GetRingBufferWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); - if( size2 > 0 ) - { - - memcpy( data1, data, size1 ); - data = ((char *)data) + size1; - memcpy( data2, data, size2 ); - } - else - { - memcpy( data1, data, size1 ); - } - PaUtil_AdvanceRingBufferWriteIndex( rbuf, numWritten ); - return numWritten; + long size1, size2, numWritten; + void *data1, *data2; + numWritten = PaUtil_GetRingBufferWriteRegions(rbuf, numBytes, &data1, &size1, &data2, &size2); + if (size2 > 0) { + + memcpy(data1, data, size1); + data = ((char *) data) + size1; + memcpy(data2, data, size2); + } else { + memcpy(data1, data, size1); + } + PaUtil_AdvanceRingBufferWriteIndex(rbuf, numWritten); + return numWritten; } /*************************************************************************** ** Return bytes read. */ -long PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, long numBytes ) +long PaUtil_ReadRingBuffer(PaUtilRingBuffer * rbuf, void *data, long numBytes) { - long size1, size2, numRead; - void *data1, *data2; - numRead = PaUtil_GetRingBufferReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); - if( size2 > 0 ) - { - memcpy( data, data1, size1 ); - data = ((char *)data) + size1; - memcpy( data, data2, size2 ); - } - else - { - memcpy( data, data1, size1 ); - } - PaUtil_AdvanceRingBufferReadIndex( rbuf, numRead ); - return numRead; + long size1, size2, numRead; + void *data1, *data2; + numRead = PaUtil_GetRingBufferReadRegions(rbuf, numBytes, &data1, &size1, &data2, &size2); + if (size2 > 0) { + memcpy(data, data1, size1); + data = ((char *) data) + size1; + memcpy(data, data2, size2); + } else { + memcpy(data, data1, size1); + } + PaUtil_AdvanceRingBufferReadIndex(rbuf, numRead); + return numRead; } Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pa_ringbuffer.h ============================================================================== --- freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pa_ringbuffer.h (original) +++ freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pa_ringbuffer.h Fri Aug 24 13:50:56 2007 @@ -51,19 +51,17 @@ */ #ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -typedef struct PaUtilRingBuffer -{ - long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by PaUtil_InitRingBuffer. */ - long writeIndex; /* Index of next writable byte. Set by PaUtil_AdvanceRingBufferWriteIndex. */ - long readIndex; /* Index of next readable byte. Set by PaUtil_AdvanceRingBufferReadIndex. */ - long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */ - long smallMask; /* Used for fitting indices to buffer. */ - char *buffer; -}PaUtilRingBuffer; +extern "C" { +#endif /* __cplusplus */ + + typedef struct PaUtilRingBuffer { + long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by PaUtil_InitRingBuffer. */ + long writeIndex; /* Index of next writable byte. Set by PaUtil_AdvanceRingBufferWriteIndex. */ + long readIndex; /* Index of next readable byte. Set by PaUtil_AdvanceRingBufferReadIndex. */ + long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */ + long smallMask; /* Used for fitting indices to buffer. */ + char *buffer; + } PaUtilRingBuffer; /** Initialize Ring Buffer. @@ -76,13 +74,13 @@ @return -1 if numBytes is not a power of 2, otherwise 0. */ -long PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, long numBytes, void *dataPtr ); + long PaUtil_InitializeRingBuffer(PaUtilRingBuffer * rbuf, long numBytes, void *dataPtr); /** Clear buffer. Should only be called when buffer is NOT being read. @param rbuf The ring buffer. */ -void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf ); + void PaUtil_FlushRingBuffer(PaUtilRingBuffer * rbuf); /** Retrieve the number of bytes available in the ring buffer for writing. @@ -90,7 +88,7 @@ @return The number of bytes available for writing. */ -long PaUtil_GetRingBufferWriteAvailable( PaUtilRingBuffer *rbuf ); + long PaUtil_GetRingBufferWriteAvailable(PaUtilRingBuffer * rbuf); /** Retrieve the number of bytes available in the ring buffer for reading. @@ -98,7 +96,7 @@ @return The number of bytes available for reading. */ -long PaUtil_GetRingBufferReadAvailable( PaUtilRingBuffer *rbuf ); + long PaUtil_GetRingBufferReadAvailable(PaUtilRingBuffer * rbuf); /** Write data to the ring buffer. @@ -110,7 +108,7 @@ @return The number of bytes written. */ -long PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, long numBytes ); + long PaUtil_WriteRingBuffer(PaUtilRingBuffer * rbuf, const void *data, long numBytes); /** Read data from the ring buffer. @@ -122,7 +120,7 @@ @return The number of bytes read. */ -long PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, long numBytes ); + long PaUtil_ReadRingBuffer(PaUtilRingBuffer * rbuf, void *data, long numBytes); /** Get address of region(s) to which we can write data. @@ -144,9 +142,7 @@ @return The room available to be written or numBytes, whichever is smaller. */ -long PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, long numBytes, - void **dataPtr1, long *sizePtr1, - void **dataPtr2, long *sizePtr2 ); + long PaUtil_GetRingBufferWriteRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2); /** Advance the write index to the next location to be written. @@ -156,7 +152,7 @@ @return The new position. */ -long PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, long numBytes ); + long PaUtil_AdvanceRingBufferWriteIndex(PaUtilRingBuffer * rbuf, long numBytes); /** Get address of region(s) from which we can write data. @@ -178,9 +174,7 @@ @return The number of bytes available for reading. */ -long PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, long numBytes, - void **dataPtr1, long *sizePtr1, - void **dataPtr2, long *sizePtr2 ); + long PaUtil_GetRingBufferReadRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2); /** Advance the read index to the next location to be read. @@ -190,9 +184,9 @@ @return The new position. */ -long PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, long numBytes ); + long PaUtil_AdvanceRingBufferReadIndex(PaUtilRingBuffer * rbuf, long numBytes); #ifdef __cplusplus } -#endif /* __cplusplus */ -#endif /* PA_RINGBUFFER_H */ +#endif /* __cplusplus */ +#endif /* PA_RINGBUFFER_H */ Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pablio.c ============================================================================== --- freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pablio.c (original) +++ freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pablio.c Fri Aug 24 13:50:56 2007 @@ -40,6 +40,7 @@ * license above. */ +#include <switch.h> #include <stdio.h> #include <stdlib.h> #include <math.h> @@ -49,176 +50,181 @@ #include <string.h> #include <time.h> -/************************************************************************/ -/******** Constants *****************************************************/ -/************************************************************************/ - -#define FRAMES_PER_BUFFER (256) /************************************************************************/ /******** Prototypes ****************************************************/ /************************************************************************/ -static int blockingIOCallback( const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ); -static PaError PABLIO_InitFIFO( PaUtilRingBuffer *rbuf, long numFrames, long bytesPerFrame ); -static PaError PABLIO_TermFIFO( PaUtilRingBuffer *rbuf ); +static int blockingIOCallback(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData); +static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames, long bytesPerFrame); +static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf); /************************************************************************/ /******** Functions *****************************************************/ /************************************************************************/ /* Called from PortAudio. - * Read and write data only if there is room in FIFOs. + * Read and write data */ -static int blockingIOCallback( const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ) +static int blockingIOCallback(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData) { - PABLIO_Stream *data = (PABLIO_Stream*)userData; - long numBytes = data->bytesPerFrame * framesPerBuffer; - - /* This may get called with NULL inputBuffer during initial setup. */ - if( inputBuffer != NULL ) - { - PaUtil_WriteRingBuffer( &data->inFIFO, inputBuffer, numBytes ); - } - if( outputBuffer != NULL ) - { - int i; - int numRead = PaUtil_ReadRingBuffer( &data->outFIFO, outputBuffer, numBytes ); - /* Zero out remainder of buffer if we run out of data. */ - for( i=numRead; i<numBytes; i++ ) - { - ((char *)outputBuffer)[i] = 0; - } - } + PABLIO_Stream *data = (PABLIO_Stream *) userData; + long numBytes = data->bytesPerFrame * framesPerBuffer; + + /* This may get called with NULL inputBuffer during initial setup. */ + if (inputBuffer != NULL) { + if (PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes) != numBytes) { + PaUtil_FlushRingBuffer(&data->inFIFO); + PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes); + } + } + if (outputBuffer != NULL) { + int i; + int numRead = PaUtil_ReadRingBuffer(&data->outFIFO, outputBuffer, numBytes); + /* Zero out remainder of buffer if we run out of data. */ + for (i = numRead; i < numBytes; i++) { + ((char *) outputBuffer)[i] = 0; + } + } - return 0; + return 0; } /* Allocate buffer. */ -static PaError PABLIO_InitFIFO( PaUtilRingBuffer *rbuf, long numFrames, long bytesPerFrame ) +static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames, long bytesPerFrame) { - long numBytes = numFrames * bytesPerFrame; - char *buffer = (char *) malloc( numBytes ); - if( buffer == NULL ) return paInsufficientMemory; - memset( buffer, 0, numBytes ); - return (PaError) PaUtil_InitializeRingBuffer( rbuf, numBytes, buffer ); + long numBytes = numFrames * bytesPerFrame; + char *buffer = (char *) malloc(numBytes); + if (buffer == NULL) + return paInsufficientMemory; + memset(buffer, 0, numBytes); + return (PaError) PaUtil_InitializeRingBuffer(rbuf, numBytes, buffer); } /* Free buffer. */ -static PaError PABLIO_TermFIFO( PaUtilRingBuffer *rbuf ) +static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf) { - if( rbuf->buffer ) free( rbuf->buffer ); - rbuf->buffer = NULL; - return paNoError; + if (rbuf->buffer) + free(rbuf->buffer); + rbuf->buffer = NULL; + return paNoError; } /************************************************************ * Write data to ring buffer. * Will not return until all the data has been written. */ -long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) +long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer) { - long bytesWritten; - char *p = (char *) data; - long numBytes = aStream->bytesPerFrame * numFrames; - while( numBytes > 0) - { - bytesWritten = PaUtil_WriteRingBuffer( &aStream->outFIFO, p, numBytes ); - numBytes -= bytesWritten; - p += bytesWritten; - if( numBytes > 0) Pa_Sleep(10); - } - return numFrames; + long bytesWritten; + char *p = (char *) data; + long numBytes = aStream->bytesPerFrame * numFrames; + + while (numBytes > 0) { + bytesWritten = PaUtil_WriteRingBuffer(&aStream->outFIFO, p, numBytes); + numBytes -= bytesWritten; + p += bytesWritten; + if (numBytes > 0) { + if (switch_core_timer_check(timer) == SWITCH_STATUS_SUCCESS) { + PaUtil_FlushRingBuffer(&aStream->outFIFO); + return 0; + } + switch_yield(1000); + } + } + return numFrames; } /************************************************************ * Read data from ring buffer. * Will not return until all the data has been read. */ -long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) +long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer) { - long bytesRead; - char *p = (char *) data; - long numBytes = aStream->bytesPerFrame * numFrames; - - while( numBytes > 0) - { - bytesRead = PaUtil_ReadRingBuffer( &aStream->inFIFO, p, numBytes ); - numBytes -= bytesRead; - p += bytesRead; - if( numBytes > 0) Pa_Sleep(10); - } - return numFrames; + long bytesRead; + char *p = (char *) data; + long numBytes = aStream->bytesPerFrame * numFrames; + + while (numBytes > 0) { + bytesRead = PaUtil_ReadRingBuffer(&aStream->inFIFO, p, numBytes); + numBytes -= bytesRead; + if (numBytes > 0) { + if (switch_core_timer_check(timer) == SWITCH_STATUS_SUCCESS) { + PaUtil_FlushRingBuffer(&aStream->inFIFO); + return 0; + } + switch_yield(1000); + } + } + return numFrames; } /************************************************************ * Return the number of frames that could be written to the stream without * having to wait. */ -long GetAudioStreamWriteable( PABLIO_Stream *aStream ) +long GetAudioStreamWriteable(PABLIO_Stream * aStream) { - int bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); - return bytesEmpty / aStream->bytesPerFrame; + int bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO); + return bytesEmpty / aStream->bytesPerFrame; } /************************************************************ * Return the number of frames that are available to be read from the * stream without having to wait. */ -long GetAudioStreamReadable( PABLIO_Stream *aStream ) +long GetAudioStreamReadable(PABLIO_Stream * aStream) { - int bytesFull = PaUtil_GetRingBufferReadAvailable( &aStream->inFIFO ); - return bytesFull / aStream->bytesPerFrame; + int bytesFull = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO); + return bytesFull / aStream->bytesPerFrame; } -/************************************************************/ -static unsigned long RoundUpToNextPowerOf2( unsigned long n ) +/***********************************************************/ +static unsigned long RoundUpToNextPowerOf2(unsigned long n) { - long numBits = 0; - if( ((n-1) & n) == 0) return n; /* Already Power of two. */ - while( n > 0 ) - { - n= n>>1; - numBits++; - } - return (1<<numBits); + long numBits = 0; + if (((n - 1) & n) == 0) + return n; + while (n > 0) { + n = n >> 1; + numBits++; + } + return (1 << numBits); } + + /************************************************************ * Opens a PortAudio stream with default characteristics. * Allocates PABLIO_Stream structure. * */ -PaError OpenAudioStream( PABLIO_Stream **rwblPtr, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - PaStreamFlags streamFlags) +PaError OpenAudioStream(PABLIO_Stream ** rwblPtr, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + PaStreamFlags streamFlags, + long samples_per_frame) { - long bytesPerSample; - PaError err; - PABLIO_Stream *aStream; - long minNumBuffers; - long numFrames; - long numBytes; + long bytesPerSample = 2; + PaError err; + PABLIO_Stream *aStream; + long numFrames; + //long numBytes; int channels = 1; - /* Allocate PABLIO_Stream structure for caller. */ - aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) ); - if( aStream == NULL ) return paInsufficientMemory; - memset( aStream, 0, sizeof(PABLIO_Stream) ); - - /* Initialize PortAudio */ - err = Pa_Initialize(); - if( err != paNoError ) goto error; + /* Allocate PABLIO_Stream structure for caller. */ + aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream)); + if (aStream == NULL) + return paInsufficientMemory; + memset(aStream, 0, sizeof(PABLIO_Stream)); + + /* Initialize PortAudio */ + err = Pa_Initialize(); + if (err != paNoError) + goto error; if (inputParameters) { channels = inputParameters->channelCount; @@ -226,81 +232,74 @@ channels = outputParameters->channelCount; } - numFrames = 4 * FRAMES_PER_BUFFER; - numFrames = RoundUpToNextPowerOf2( numFrames ); - - bytesPerSample = 2; - aStream->samplesPerFrame = channels; - aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame; + numFrames = RoundUpToNextPowerOf2(samples_per_frame * 5); + aStream->bytesPerFrame = bytesPerSample; - /* Initialize Ring Buffers */ + /* Initialize Ring Buffers */ if (inputParameters) { - err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame ); - if( err != paNoError ) goto error; + err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->bytesPerFrame); + if (err != paNoError) + goto error; } if (outputParameters) { - err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame ); - if( err != paNoError ) goto error; + err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->bytesPerFrame); + if (err != paNoError) + goto error; } /* Make Write FIFO appear full initially. */ - numBytes = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); - PaUtil_AdvanceRingBufferWriteIndex( &aStream->outFIFO, numBytes ); - + //numBytes = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO); + //PaUtil_AdvanceRingBufferWriteIndex(&aStream->outFIFO, numBytes); + - /* Open a PortAudio stream that we will use to communicate with the underlying - * audio drivers. */ - err = Pa_OpenStream( - &aStream->stream, - inputParameters, - outputParameters, - sampleRate, - FRAMES_PER_BUFFER, - streamFlags, - blockingIOCallback, - aStream ); - if( err != paNoError ) goto error; - - err = Pa_StartStream( aStream->stream ); - if( err != paNoError ) goto error; - *rwblPtr = aStream; - return paNoError; - -error: - CloseAudioStream( aStream ); - *rwblPtr = NULL; - return err; + /* Open a PortAudio stream that we will use to communicate with the underlying + * audio drivers. */ + err = Pa_OpenStream(&aStream->stream, inputParameters, outputParameters, sampleRate, samples_per_frame, streamFlags, blockingIOCallback, aStream); + + if (err != paNoError) + goto error; + + err = Pa_StartStream(aStream->stream); + if (err != paNoError) + goto error; + *rwblPtr = aStream; + return paNoError; + + error: + CloseAudioStream(aStream); + *rwblPtr = NULL; + return err; } /************************************************************/ -PaError CloseAudioStream( PABLIO_Stream *aStream ) +PaError CloseAudioStream(PABLIO_Stream * aStream) { - PaError err; - int bytesEmpty; - int byteSize = aStream->outFIFO.bufferSize; - - /* If we are writing data, make sure we play everything written. */ - if( byteSize > 0 ) - { - bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); - while( bytesEmpty < byteSize ) - { - Pa_Sleep( 10 ); - bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); - } - } - - err = Pa_StopStream( aStream->stream ); - if( err != paNoError ) goto error; - err = Pa_CloseStream( aStream->stream ); - if( err != paNoError ) goto error; - Pa_Terminate(); - -error: - PABLIO_TermFIFO( &aStream->inFIFO ); - PABLIO_TermFIFO( &aStream->outFIFO ); - free( aStream ); - return err; + PaError err; + int bytesEmpty; + int byteSize = aStream->outFIFO.bufferSize; + + /* If we are writing data, make sure we play everything written. */ + if (byteSize > 0) { + bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO); + while (bytesEmpty < byteSize) { + Pa_Sleep(10); + bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO); + } + } + + err = Pa_StopStream(aStream->stream); + if (err != paNoError) + goto error; + err = Pa_CloseStream(aStream->stream); + if (err != paNoError) + goto error; + Pa_Terminate(); + + error: + PABLIO_TermFIFO(&aStream->inFIFO); + PABLIO_TermFIFO(&aStream->outFIFO); + free(aStream); + return err; } Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pablio.h ============================================================================== --- freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pablio.h (original) +++ freeswitch/branches/cseket/src/mod/endpoints/mod_portaudio/pablio.h Fri Aug 24 13:50:56 2007 @@ -2,9 +2,8 @@ #define _PABLIO_H #ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ +extern "C" { +#endif /* __cplusplus */ /* * $Id: pablio.h 1083 2006-08-23 07:30:49Z rossb $ @@ -57,15 +56,12 @@ #include <string.h> -typedef struct -{ - PaUtilRingBuffer inFIFO; - PaUtilRingBuffer outFIFO; - PaStream *stream; - int bytesPerFrame; - int samplesPerFrame; -} -PABLIO_Stream; + typedef struct { + PaUtilRingBuffer inFIFO; + PaUtilRingBuffer outFIFO; + PaStream *stream; + int bytesPerFrame; + } PABLIO_Stream; /* Values for flags for OpenAudioStream(). */ #define PABLIO_READ (1<<0) @@ -78,25 +74,25 @@ * Write data to ring buffer. * Will not return until all the data has been written. */ -long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); + long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer); /************************************************************ * Read data from ring buffer. * Will not return until all the data has been read. */ -long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); + long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer); /************************************************************ * Return the number of frames that could be written to the stream without * having to wait. */ -long GetAudioStreamWriteable( PABLIO_Stream *aStream ); + long GetAudioStreamWriteable(PABLIO_Stream * aStream); /************************************************************ * Return the number of frames that are available to be read from the * stream without having to wait. */ -long GetAudioStreamReadable( PABLIO_Stream *aStream ); + long GetAudioStreamReadable(PABLIO_Stream * aStream); /************************************************************ * Opens a PortAudio stream with default characteristics. @@ -106,15 +102,13 @@ * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE, * and either PABLIO_MONO or PABLIO_STEREO */ -PaError OpenAudioStream( PABLIO_Stream **rwblPtr, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - PaStreamCallbackFlags statusFlags); + PaError OpenAudioStream(PABLIO_Stream ** rwblPtr, + const PaStreamParameters * inputParameters, + const PaStreamParameters * outputParameters, double sampleRate, PaStreamCallbackFlags statusFlags, long samples_per_frame); -PaError CloseAudioStream( PABLIO_Stream *aStream ); + PaError CloseAudioStream(PABLIO_Stream * aStream); #ifdef __cplusplus } -#endif /* __cplusplus */ -#endif /* _PABLIO_H */ +#endif /* __cplusplus */ +#endif /* _PABLIO_H */
participants (1)
-
Freeswitch SVN