From df43e51ca5b893fcaaaf50ba8d98051b2d6a3fb2 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 17 Mar 2011 21:46:52 -0400 Subject: [PATCH 001/163] initial reworking for mod_portaudio multiple enpoint support --- conf/autoload_configs/portaudio.conf.xml | 33 ++++++++++++++++--- .../endpoints/mod_portaudio/mod_portaudio.c | 28 ++++++++++++++++ src/mod/endpoints/mod_portaudio/pablio.h | 24 +++++++------- 3 files changed, 70 insertions(+), 15 deletions(-) diff --git a/conf/autoload_configs/portaudio.conf.xml b/conf/autoload_configs/portaudio.conf.xml index 1f758de896..7389bf49cd 100644 --- a/conf/autoload_configs/portaudio.conf.xml +++ b/conf/autoload_configs/portaudio.conf.xml @@ -5,12 +5,14 @@ or the device number prefixed with # eg "#1" (or blank for default) --> - + - + + - + + @@ -29,7 +31,30 @@ - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index baa33d456e..d02a3ead07 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -106,6 +106,34 @@ struct audio_stream { }; typedef struct audio_stream audio_stream_t; +typedef struct _pa_shared_device { + /*! Sampling rate */ + int sample_rate; + /*! */ + int codec_ms; + /*! Device number */ + int devno; + /*! Running stream (if a stream is already running for devno) */ + audio_stream_t *stream; + /*! The actual portaudio device number */ + /*! It's a shared device after all */ + switch_mutex_t *mutex; +} pa_shared_device_t; + +typedef struct _pa_endpoint { + /*! Input device for this endpoint */ + pa_shared_device_t *indev; + + /*! Output device for this endpoint */ + pa_shared_device_t *outdev; + + /*! Channel index within the input device stream */ + int inchan; + + /*! Channel index within the input device stream */ + int outchan; +} pa_endpoint_t; + static struct { int debug; int port; diff --git a/src/mod/endpoints/mod_portaudio/pablio.h b/src/mod/endpoints/mod_portaudio/pablio.h index 0bd3c41e46..6d99d2f012 100644 --- a/src/mod/endpoints/mod_portaudio/pablio.h +++ b/src/mod/endpoints/mod_portaudio/pablio.h @@ -56,17 +56,19 @@ extern "C" { #include - typedef struct { - PaUtilRingBuffer inFIFO; - PaUtilRingBuffer outFIFO; - PaStream *istream; - PaStream *ostream; - PaStream *iostream; - int bytesPerFrame; - int do_dual; - int has_in; - int has_out; - } PABLIO_Stream; +#define MAX_IO_CHANNELS 2 +typedef struct { + PaStream *istream; + PaStream *ostream; + PaStream *iostream; + int bytesPerFrame; + int do_dual; + int has_in; + int has_out; + PaUtilRingBuffer inFIFOs[2] + PaUtilRingBuffer outFIFOs[2] + int channelCount; +} PABLIO_Stream; /* Values for flags for OpenAudioStream(). */ #define PABLIO_READ (1<<0) From b05965c88d3f429abea24f76e2fbad1ddf311db5 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sat, 19 Mar 2011 13:24:02 -0400 Subject: [PATCH 002/163] mod_portaudio: update to support multiple io buffers --- .../endpoints/mod_portaudio/mod_portaudio.c | 39 ++++++++----------- src/mod/endpoints/mod_portaudio/pablio.c | 36 ++++++++--------- src/mod/endpoints/mod_portaudio/pablio.h | 4 +- 3 files changed, 37 insertions(+), 42 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index d02a3ead07..b7140e987c 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -98,41 +98,36 @@ struct private_object { typedef struct private_object private_t; struct audio_stream { + /*! Sampling rate */ + int sample_rate; + /*! Buffer packetization (and therefore timing) */ + int codec_ms; + /*! The PA input device */ int indev; + /*! The PA output device */ int outdev; + /*! The io stream helper to buffer audio */ PABLIO_Stream *stream; + /*! How often to write */ switch_timer_t write_timer; + /*! Next stream */ struct audio_stream *next; }; typedef struct audio_stream audio_stream_t; -typedef struct _pa_shared_device { - /*! Sampling rate */ - int sample_rate; - /*! */ - int codec_ms; - /*! Device number */ - int devno; - /*! Running stream (if a stream is already running for devno) */ - audio_stream_t *stream; - /*! The actual portaudio device number */ - /*! It's a shared device after all */ - switch_mutex_t *mutex; -} pa_shared_device_t; +typedef struct audio_endpoint { + /*! Input stream for this endpoint */ + audio_stream_t *in_stream; -typedef struct _pa_endpoint { - /*! Input device for this endpoint */ - pa_shared_device_t *indev; + /*! Output stream for this endpoint */ + audio_stream_t *out_stream; - /*! Output device for this endpoint */ - pa_shared_device_t *outdev; - - /*! Channel index within the input device stream */ + /*! Channel index within the input stream where we get the audio for this endpoint */ int inchan; - /*! Channel index within the input device stream */ + /*! Channel index within the output stream where we get the audio for this endpoint */ int outchan; -} pa_endpoint_t; +} audio_endpoint_t; static struct { int debug; diff --git a/src/mod/endpoints/mod_portaudio/pablio.c b/src/mod/endpoints/mod_portaudio/pablio.c index b994d21c2a..e65851a61e 100644 --- a/src/mod/endpoints/mod_portaudio/pablio.c +++ b/src/mod/endpoints/mod_portaudio/pablio.c @@ -83,9 +83,9 @@ static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer, /* 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 (PaUtil_WriteRingBuffer(&data->inFIFOs[0], inputBuffer, numBytes) != numBytes) { + PaUtil_FlushRingBuffer(&data->inFIFOs[0]); + PaUtil_WriteRingBuffer(&data->inFIFOs[0], inputBuffer, numBytes); } } @@ -100,7 +100,7 @@ static int oblockingIOCallback(const void *inputBuffer, void *outputBuffer, if (outputBuffer != NULL) { int i; - int numRead = PaUtil_ReadRingBuffer(&data->outFIFO, outputBuffer, numBytes); + int numRead = PaUtil_ReadRingBuffer(&data->outFIFOs[0], outputBuffer, numBytes); /* Zero out remainder of buffer if we run out of data. */ for (i = numRead; i < numBytes; i++) { ((char *) outputBuffer)[i] = 0; @@ -151,12 +151,12 @@ long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switc switch_core_timer_next(timer); - bytesWritten = PaUtil_WriteRingBuffer(&aStream->outFIFO, p, numBytes); + bytesWritten = PaUtil_WriteRingBuffer(&aStream->outFIFOs[0], p, numBytes); numBytes -= bytesWritten; p += bytesWritten; if (numBytes > 0) { - PaUtil_FlushRingBuffer(&aStream->outFIFO); + PaUtil_FlushRingBuffer(&aStream->outFIFOs[0]); return 0; } return numFrames; @@ -177,17 +177,17 @@ long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch while (totalBytes < neededBytes && --max > 0) { - avail = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO); + avail = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFOs[0]); //printf("AVAILABLE BYTES %ld pass %d\n", avail, 5000 - max); if (avail >= neededBytes * 6) { - PaUtil_FlushRingBuffer(&aStream->inFIFO); + PaUtil_FlushRingBuffer(&aStream->inFIFOs[0]); avail = 0; } else { bytesRead = 0; if (totalBytes < neededBytes && avail >= neededBytes) { - bytesRead = PaUtil_ReadRingBuffer(&aStream->inFIFO, p, neededBytes); + bytesRead = PaUtil_ReadRingBuffer(&aStream->inFIFOs[0], p, neededBytes); totalBytes += bytesRead; } @@ -208,7 +208,7 @@ long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch */ long GetAudioStreamWriteable(PABLIO_Stream * aStream) { - int bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO); + int bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[0]); return bytesEmpty / aStream->bytesPerFrame; } @@ -218,7 +218,7 @@ long GetAudioStreamWriteable(PABLIO_Stream * aStream) */ long GetAudioStreamReadable(PABLIO_Stream * aStream) { - int bytesFull = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO); + int bytesFull = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFOs[0]); return bytesFull / aStream->bytesPerFrame; } @@ -274,7 +274,7 @@ PaError OpenAudioStream(PABLIO_Stream ** rwblPtr, /* Initialize Ring Buffers */ if (inputParameters) { - err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->bytesPerFrame); + err = PABLIO_InitFIFO(&aStream->inFIFOs[0], numFrames, aStream->bytesPerFrame); if (err != paNoError) { goto error; } @@ -282,7 +282,7 @@ PaError OpenAudioStream(PABLIO_Stream ** rwblPtr, } if (outputParameters) { - err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->bytesPerFrame); + err = PABLIO_InitFIFO(&aStream->outFIFOs[0], numFrames, aStream->bytesPerFrame); if (err != paNoError) { goto error; } @@ -355,15 +355,15 @@ PaError CloseAudioStream(PABLIO_Stream * aStream) int byteSize; - byteSize = aStream->outFIFO.bufferSize; + byteSize = aStream->outFIFOs[0].bufferSize; if (aStream->has_out) { /* If we are writing data, make sure we play everything written. */ if (byteSize > 0) { - bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO); + bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[0]); while (bytesEmpty < byteSize) { Pa_Sleep(10); - bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO); + bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[0]); } } } @@ -399,11 +399,11 @@ PaError CloseAudioStream(PABLIO_Stream * aStream) } if (aStream->has_in) { - PABLIO_TermFIFO(&aStream->inFIFO); + PABLIO_TermFIFO(&aStream->inFIFOs[0]); } if (aStream->has_out) { - PABLIO_TermFIFO(&aStream->outFIFO); + PABLIO_TermFIFO(&aStream->outFIFOs[0]); } free(aStream); diff --git a/src/mod/endpoints/mod_portaudio/pablio.h b/src/mod/endpoints/mod_portaudio/pablio.h index 6d99d2f012..a30863bbd4 100644 --- a/src/mod/endpoints/mod_portaudio/pablio.h +++ b/src/mod/endpoints/mod_portaudio/pablio.h @@ -65,8 +65,8 @@ typedef struct { int do_dual; int has_in; int has_out; - PaUtilRingBuffer inFIFOs[2] - PaUtilRingBuffer outFIFOs[2] + PaUtilRingBuffer inFIFOs[2]; + PaUtilRingBuffer outFIFOs[2]; int channelCount; } PABLIO_Stream; From 5e4911ff25b753a41eac58598981c58b80bd838c Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sat, 19 Mar 2011 15:06:43 -0400 Subject: [PATCH 003/163] mod_portaudio: added XML parsing and CLI commands for configuration of streams --- .../endpoints/mod_portaudio/mod_portaudio.c | 164 ++++++++++++++++-- src/mod/endpoints/mod_portaudio/pablio.h | 4 +- 2 files changed, 154 insertions(+), 14 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index b7140e987c..76f609f7b1 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -45,6 +45,8 @@ #define MY_EVENT_ERROR_AUDIO_DEV "portaudio::audio_dev_error" #define SWITCH_PA_CALL_ID_VARIABLE "pa_call_id" +#define MIN_STREAM_SAMPLE_RATE 8000 + SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_shutdown); //SWITCH_MODULE_RUNTIME_FUNCTION(mod_portaudio_runtime); @@ -98,6 +100,18 @@ struct private_object { typedef struct private_object private_t; struct audio_stream { + int indev; + int outdev; + PABLIO_Stream *stream; + switch_timer_t write_timer; + struct audio_stream *next; +}; +typedef struct audio_stream audio_stream_t; + +/* Audio stream that can be shared across endpoints */ +typedef struct _shared_audio_stream_t { + /*! Friendly name for this stream */ + char name[255]; /*! Sampling rate */ int sample_rate; /*! Buffer packetization (and therefore timing) */ @@ -106,21 +120,24 @@ struct audio_stream { int indev; /*! The PA output device */ int outdev; + /*! How many channels to create (for both indev and outdev) */ + int channels; /*! The io stream helper to buffer audio */ PABLIO_Stream *stream; /*! How often to write */ switch_timer_t write_timer; - /*! Next stream */ - struct audio_stream *next; -}; -typedef struct audio_stream audio_stream_t; +} shared_audio_stream_t; + +/* Endpoint that can be called via portaudio/endpoint/ */ +typedef struct _audio_endpoint { + /*! Friendly name for this endpoint */ + char name[255]; -typedef struct audio_endpoint { /*! Input stream for this endpoint */ - audio_stream_t *in_stream; + shared_audio_stream_t *in_stream; /*! Output stream for this endpoint */ - audio_stream_t *out_stream; + shared_audio_stream_t *out_stream; /*! Channel index within the input stream where we get the audio for this endpoint */ int inchan; @@ -161,6 +178,10 @@ static struct { unsigned char cngbuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; private_t *call_list; audio_stream_t *stream_list; + /*! Streams that can be used by multiple endpoints at the same time */ + switch_hash_t *sh_streams; + /*! Endpoints configured */ + switch_hash_t *endpoints; int ring_interval; GFLAGS flags; switch_timer_t read_timer; @@ -266,7 +287,7 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) if (hold_file) { tech_pvt->hold_file = switch_core_session_strdup(session, hold_file); } - if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { + if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { if (validate_main_audio_stream() != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); return SWITCH_STATUS_FALSE; @@ -994,12 +1015,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load) memset(&globals, 0, sizeof(globals)); switch_core_hash_init(&globals.call_hash, module_pool); + switch_core_hash_init(&globals.sh_streams, module_pool); + switch_core_hash_init(&globals.endpoints, module_pool); switch_mutex_init(&globals.device_lock, SWITCH_MUTEX_NESTED, module_pool); switch_mutex_init(&globals.pvt_lock, SWITCH_MUTEX_NESTED, module_pool); switch_mutex_init(&globals.streams_lock, SWITCH_MUTEX_NESTED, module_pool); switch_mutex_init(&globals.flag_mutex, SWITCH_MUTEX_NESTED, module_pool); switch_mutex_init(&globals.pa_mutex, SWITCH_MUTEX_NESTED, module_pool); - globals.codecs_inited=0; + globals.codecs_inited = 0; globals.read_frame.data = globals.databuf; globals.read_frame.buflen = sizeof(globals.databuf); globals.cng_frame.data = globals.cngbuf; @@ -1078,16 +1101,106 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load) switch_console_set_complete("add pa play"); switch_console_set_complete("add pa playdev"); switch_console_set_complete("add pa looptest"); + switch_console_set_complete("add pa shstreams"); /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; } +static int check_device(char *devstr, int check_input) +{ + int devval; + if (devstr[0] == '#') { + devval = get_dev_by_number(devstr + 1, check_input); + } else { + devval = get_dev_by_name(devstr, check_input); + } + return devval; +} + +static switch_status_t load_streams(switch_xml_t streams) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_xml_t param, mystream; + for (mystream = switch_xml_child(streams, "stream"); mystream; mystream = mystream->next) { + shared_audio_stream_t *stream = NULL; + int devval = -1; + char *stream_name = (char *) switch_xml_attr_soft(mystream, "name"); + + /* check if that stream name is not already used */ + stream = switch_core_hash_find(globals.sh_streams, stream_name); + if (stream) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "A stream with name '%s' already exists\n", stream_name); + continue; + } + + stream = switch_core_alloc(module_pool, sizeof(*stream)); + if (!stream) { + continue; + } + stream->indev = -1; + stream->outdev = -1; + switch_snprintf(stream->name, sizeof(stream->name), "%s", stream_name); + for (param = switch_xml_child(mystream, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parsing stream '%s' parameter %s = %s\n", stream_name, var, val); + if (!strcmp(var, "indev")) { + devval = check_device(val, 1); + if (devval < 0) { + stream->indev = -1; + continue; + } + stream->indev = devval; + } else if (!strcmp(var, "outdev")) { + devval = check_device(val, 0); + if (devval < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Invalid outdev specified for stream '%s'\n", stream_name); + stream->outdev = -1; + continue; + } + stream->outdev = devval; + } else if (!strcmp(var, "sample-rate")) { + stream->sample_rate = atoi(val); + if (stream->sample_rate < MIN_STREAM_SAMPLE_RATE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Invalid sample rate specified for stream '%s', forcing to 8000\n", stream_name); + stream->sample_rate = MIN_STREAM_SAMPLE_RATE; + } + } else if (!strcmp(var, "codec-ms")) { + int tmp = atoi(val); + if (switch_check_interval(stream->sample_rate, tmp)) { + stream->codec_ms = tmp; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "codec-ms must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL); + } + } else if (!strcmp(var, "channels")) { + stream->channels = atoi(val); + if (stream->channels < 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Invalid number of channels specified for stream '%s', forcing to 1\n", stream_name); + stream->channels = 1; + } + } + } + if (stream->indev < 0 && stream->outdev < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "You need at least one device for stream '%s'\n", stream_name); + continue; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, + "Created stream '%s', sample-rate = %d, codec-ms = %d\n", stream->name, stream->sample_rate, stream->codec_ms); + switch_core_hash_insert(globals.sh_streams, stream->name, stream); + } + return status; +} static switch_status_t load_config(void) { char *cf = "portaudio.conf"; - switch_xml_t cfg, xml, settings, param; + switch_xml_t cfg, xml, settings, streams, param; switch_status_t status = SWITCH_STATUS_SUCCESS; if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { @@ -1182,6 +1295,10 @@ static switch_status_t load_config(void) } } + if ((streams = switch_xml_child(cfg, "streams"))) { + load_streams(streams); + } + if (!globals.dialplan) { set_global_dialplan("XML"); } @@ -1246,6 +1363,8 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_shutdown) Pa_Terminate(); switch_core_hash_destroy(&globals.call_hash); + switch_core_hash_destroy(&globals.sh_streams); + switch_core_hash_destroy(&globals.endpoints); switch_event_free_subclass(MY_EVENT_RINGING); switch_event_free_subclass(MY_EVENT_MAKE_CALL); @@ -1744,12 +1863,12 @@ static audio_stream_t *create_audio_stream(int indev, int outdev) switch_event_t *event; audio_stream_t *stream; - stream = malloc(sizeof(audio_stream_t)); + stream = malloc(sizeof(*stream)); if (stream == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to alloc memory\n"); return NULL; } - memset(stream, 0, sizeof(audio_stream_t)); + memset(stream, 0, sizeof(*stream)); stream->next = NULL; stream->stream = NULL; stream->indev = indev; @@ -1840,6 +1959,24 @@ static switch_status_t dtmf_call(char **argv, int argc, switch_stream_handle_t * return SWITCH_STATUS_SUCCESS; } +static switch_status_t list_shared_streams(char **argv, int argc, switch_stream_handle_t *stream) +{ + switch_hash_index_t *hi; + int cnt = 0; + for (hi = switch_hash_first(NULL, globals.sh_streams); hi; hi = switch_hash_next(hi)) { + const void *var; + void *val; + shared_audio_stream_t *s = NULL; + switch_hash_this(hi, &var, NULL, &val); + s = val; + stream->write_function(stream, "%s> outdev: %d, indev: %d, sample-rate: %d, codec-ms: %d, channels: %d\n", + s->name, s->indev, s->outdev, s->sample_rate, s->codec_ms, s->channels); + cnt++; + } + stream->write_function(stream, "Total streams: %d\n", cnt); + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t close_streams(char **argv, int argc, switch_stream_handle_t *stream) { if (globals.call_list) { @@ -2409,6 +2546,7 @@ SWITCH_STANDARD_API(pa_cmd) "pa playdev # [ringtest|] [seconds] [no_close]\n" "pa ringfile [filename]\n" "pa looptest\n" + "pa shstreams\n" "--------------------------------------------------------------------------------\n"; @@ -2533,6 +2671,8 @@ SWITCH_STANDARD_API(pa_cmd) func = looptest; } else if (!strcasecmp(argv[0], "ringfile")) { func = set_ringfile; + } else if (!strcasecmp(argv[0], "shstreams")) { + func = list_shared_streams; } else { stream->write_function(stream, "Unknown Command or not enough args [%s]\n", argv[0]); } diff --git a/src/mod/endpoints/mod_portaudio/pablio.h b/src/mod/endpoints/mod_portaudio/pablio.h index a30863bbd4..d2d6bf8101 100644 --- a/src/mod/endpoints/mod_portaudio/pablio.h +++ b/src/mod/endpoints/mod_portaudio/pablio.h @@ -65,8 +65,8 @@ typedef struct { int do_dual; int has_in; int has_out; - PaUtilRingBuffer inFIFOs[2]; - PaUtilRingBuffer outFIFOs[2]; + PaUtilRingBuffer inFIFOs[MAX_IO_CHANNELS]; + PaUtilRingBuffer outFIFOs[MAX_IO_CHANNELS]; int channelCount; } PABLIO_Stream; From e4b24e841cf1c77baf0c2baf38e291e1974287ed Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sat, 19 Mar 2011 16:01:11 -0400 Subject: [PATCH 004/163] mod_portaudio: XML parsing of endpoints --- .../endpoints/mod_portaudio/mod_portaudio.c | 163 +++++++++++++++++- 1 file changed, 160 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 76f609f7b1..249f681fea 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -24,6 +24,7 @@ * Contributor(s): * * Anthony Minessale II + * Moises Silva (Multiple endpoints work sponsored by Comrex Corporation) * * * mod_portaudio.c -- PortAudio Endpoint Module @@ -1102,6 +1103,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load) switch_console_set_complete("add pa playdev"); switch_console_set_complete("add pa looptest"); switch_console_set_complete("add pa shstreams"); + switch_console_set_complete("add pa endpoints"); /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; @@ -1122,11 +1124,17 @@ static switch_status_t load_streams(switch_xml_t streams) { switch_status_t status = SWITCH_STATUS_SUCCESS; switch_xml_t param, mystream; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading streams ...\n"); for (mystream = switch_xml_child(streams, "stream"); mystream; mystream = mystream->next) { shared_audio_stream_t *stream = NULL; int devval = -1; char *stream_name = (char *) switch_xml_attr_soft(mystream, "name"); + if (!stream_name) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing stream name attribute, skipping ...\n"); + continue; + } + /* check if that stream name is not already used */ stream = switch_core_hash_find(globals.sh_streams, stream_name); if (stream) { @@ -1140,6 +1148,7 @@ static switch_status_t load_streams(switch_xml_t streams) } stream->indev = -1; stream->outdev = -1; + stream->sample_rate = globals.sample_rate; switch_snprintf(stream->name, sizeof(stream->name), "%s", stream_name); for (param = switch_xml_child(mystream, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); @@ -1148,6 +1157,8 @@ static switch_status_t load_streams(switch_xml_t streams) if (!strcmp(var, "indev")) { devval = check_device(val, 1); if (devval < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Invalid indev specified for stream '%s'\n", stream_name); stream->indev = -1; continue; } @@ -1178,7 +1189,7 @@ static switch_status_t load_streams(switch_xml_t streams) } } else if (!strcmp(var, "channels")) { stream->channels = atoi(val); - if (stream->channels < 1) { + if (stream->channels < 1 || stream->channels > MAX_IO_CHANNELS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid number of channels specified for stream '%s', forcing to 1\n", stream_name); stream->channels = 1; @@ -1197,10 +1208,130 @@ static switch_status_t load_streams(switch_xml_t streams) return status; } +static int check_stream_compat(shared_audio_stream_t *in_stream, shared_audio_stream_t *out_stream) +{ + if (!in_stream || !out_stream) { + /* nothing to be compatible with */ + return 0; + } + if (in_stream->sample_rate != out_stream->sample_rate) { + return -1; + } + if (in_stream->codec_ms != out_stream->codec_ms) { + return -1; + } + return 0; +} + +static shared_audio_stream_t *check_stream(char *streamstr, int check_input, int *chanindex) +{ + shared_audio_stream_t *stream = NULL; + int cnum = 0; + char stream_name[255]; + char *chan = NULL; + + *chanindex = -1; + + switch_snprintf(stream_name, sizeof(stream_name), "%s", streamstr); + + chan = strchr(stream_name, ':'); + if (!chan) { + return NULL; + } + *chan = 0; + chan++; + cnum = atoi(chan); + + stream = switch_core_hash_find(globals.sh_streams, stream_name); + if (!stream) { + return NULL; + } + + if (cnum < 0 || cnum > stream->channels) { + return NULL; + } + + *chanindex = cnum; + + return stream; +} + +static switch_status_t load_endpoints(switch_xml_t endpoints) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_xml_t param, myendpoint; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading endpoints ...\n"); + for (myendpoint = switch_xml_child(endpoints, "endpoint"); myendpoint; myendpoint = myendpoint->next) { + audio_endpoint_t *endpoint = NULL; + shared_audio_stream_t *stream = NULL; + char *endpoint_name = (char *) switch_xml_attr_soft(myendpoint, "name"); + + if (!endpoint_name) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing endpoint name attribute, skipping ...\n"); + continue; + } + + /* check if that endpoint name is not already used */ + endpoint = switch_core_hash_find(globals.endpoints, endpoint_name); + if (endpoint) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "An endpoint with name '%s' already exists\n", endpoint_name); + continue; + } + + endpoint = switch_core_alloc(module_pool, sizeof(*endpoint)); + if (!endpoint) { + continue; + } + endpoint->inchan = -1; + endpoint->outchan = -1; + switch_snprintf(endpoint->name, sizeof(endpoint->name), "%s", endpoint_name); + for (param = switch_xml_child(myendpoint, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parsing endpoint '%s' parameter %s = %s\n", endpoint_name, var, val); + if (!strcmp(var, "instream")) { + stream = check_stream(val, 1, &endpoint->inchan) ; + if (!stream) { + endpoint->in_stream = NULL; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Invalid instream specified for endpoint '%s'\n", endpoint_name); + continue; + } + endpoint->in_stream = stream; + } else if (!strcmp(var, "outstream")) { + stream = check_stream(val, 0, &endpoint->outchan); + if (!stream) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Invalid outstream specified for endpoint '%s'\n", endpoint_name); + endpoint->out_stream = NULL; + continue; + } + endpoint->out_stream = stream; + } + } + if (!endpoint->in_stream && !endpoint->out_stream) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "You need at least one stream for endpoint '%s'\n", endpoint_name); + continue; + } + if (check_stream_compat(endpoint->in_stream, endpoint->out_stream)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Incomatible input and output streams for endpoint '%s'\n", endpoint_name); + continue; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, + "Created endpoint '%s', instream = %s, outstream = %s\n", endpoint->name, + endpoint->in_stream ? endpoint->in_stream->name : "(none)", + endpoint->out_stream ? endpoint->out_stream->name : "(none)"); + switch_core_hash_insert(globals.endpoints, endpoint->name, endpoint); + } + return status; +} + static switch_status_t load_config(void) { char *cf = "portaudio.conf"; - switch_xml_t cfg, xml, settings, streams, param; + switch_xml_t cfg, xml, settings, streams, endpoints, param; switch_status_t status = SWITCH_STATUS_SUCCESS; if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { @@ -1299,6 +1430,10 @@ static switch_status_t load_config(void) load_streams(streams); } + if ((endpoints = switch_xml_child(cfg, "endpoints"))) { + load_endpoints(endpoints); + } + if (!globals.dialplan) { set_global_dialplan("XML"); } @@ -1969,7 +2104,7 @@ static switch_status_t list_shared_streams(char **argv, int argc, switch_stream_ shared_audio_stream_t *s = NULL; switch_hash_this(hi, &var, NULL, &val); s = val; - stream->write_function(stream, "%s> outdev: %d, indev: %d, sample-rate: %d, codec-ms: %d, channels: %d\n", + stream->write_function(stream, "%s> indev: %d, outdev: %d, sample-rate: %d, codec-ms: %d, channels: %d\n", s->name, s->indev, s->outdev, s->sample_rate, s->codec_ms, s->channels); cnt++; } @@ -1977,6 +2112,25 @@ static switch_status_t list_shared_streams(char **argv, int argc, switch_stream_ return SWITCH_STATUS_SUCCESS; } +static switch_status_t list_endpoints(char **argv, int argc, switch_stream_handle_t *stream) +{ + switch_hash_index_t *hi; + int cnt = 0; + for (hi = switch_hash_first(NULL, globals.endpoints); hi; hi = switch_hash_next(hi)) { + const void *var; + void *val; + audio_endpoint_t *e = NULL; + switch_hash_this(hi, &var, NULL, &val); + e = val; + stream->write_function(stream, "%s> instream: %s, outstream: %s\n", + e->name, e->in_stream ? e->in_stream->name : "(none)", + e->out_stream ? e->out_stream->name : "(none)"); + cnt++; + } + stream->write_function(stream, "Total endpoints: %d\n", cnt); + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t close_streams(char **argv, int argc, switch_stream_handle_t *stream) { if (globals.call_list) { @@ -2547,6 +2701,7 @@ SWITCH_STANDARD_API(pa_cmd) "pa ringfile [filename]\n" "pa looptest\n" "pa shstreams\n" + "pa endpoints\n" "--------------------------------------------------------------------------------\n"; @@ -2673,6 +2828,8 @@ SWITCH_STANDARD_API(pa_cmd) func = set_ringfile; } else if (!strcasecmp(argv[0], "shstreams")) { func = list_shared_streams; + } else if (!strcasecmp(argv[0], "endpoints")) { + func = list_endpoints; } else { stream->write_function(stream, "Unknown Command or not enough args [%s]\n", argv[0]); } From 877b4cf53bc89d1ace7007176ec0f94472b3873a Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sat, 19 Mar 2011 19:23:11 -0400 Subject: [PATCH 005/163] mod_portaudio: create the actual shared stream --- .../endpoints/mod_portaudio/mod_portaudio.c | 330 ++++++++++++++---- src/mod/endpoints/mod_portaudio/pablio.c | 1 + 2 files changed, 269 insertions(+), 62 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 249f681fea..ec5d2f357c 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -47,6 +47,7 @@ #define SWITCH_PA_CALL_ID_VARIABLE "pa_call_id" #define MIN_STREAM_SAMPLE_RATE 8000 +#define STREAM_SAMPLES_PER_PACKET(stream) ((stream->codec_ms * stream->sample_rate) / 1000) SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_shutdown); @@ -82,24 +83,6 @@ typedef enum { TFLAG_AUTO_ANSWER = (1 << 10) } TFLAGS; -struct private_object { - unsigned int flags; - switch_core_session_t *session; - switch_caller_profile_t *caller_profile; - char call_id[50]; - int sample_rate; - int codec_ms; - switch_mutex_t *flag_mutex; - char *hold_file; - switch_file_handle_t fh; - switch_file_handle_t *hfh; - switch_frame_t hold_frame; - unsigned char holdbuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; - struct private_object *next; -}; - -typedef struct private_object private_t; - struct audio_stream { int indev; int outdev; @@ -119,16 +102,21 @@ typedef struct _shared_audio_stream_t { int codec_ms; /*! The PA input device */ int indev; + /*! Input channels being used */ + uint8_t inchan_used[MAX_IO_CHANNELS]; /*! The PA output device */ int outdev; + /*! Output channels being used */ + uint8_t outchan_used[MAX_IO_CHANNELS]; /*! How many channels to create (for both indev and outdev) */ int channels; /*! The io stream helper to buffer audio */ PABLIO_Stream *stream; - /*! How often to write */ - switch_timer_t write_timer; + /* It can be shared after all :-) */ + switch_mutex_t *mutex; } shared_audio_stream_t; +typedef struct private_object private_t; /* Endpoint that can be called via portaudio/endpoint/ */ typedef struct _audio_endpoint { /*! Friendly name for this endpoint */ @@ -145,8 +133,35 @@ typedef struct _audio_endpoint { /*! Channel index within the output stream where we get the audio for this endpoint */ int outchan; + + /*! Associated private information if involved in a call */ + private_t *master; + + /*! For timed writes */ + switch_timer_t write_timer; + + /*! Let's be safe */ + switch_mutex_t *mutex; } audio_endpoint_t; +struct private_object { + unsigned int flags; + switch_core_session_t *session; + switch_caller_profile_t *caller_profile; + char call_id[50]; + int sample_rate; + int codec_ms; + switch_mutex_t *flag_mutex; + char *hold_file; + switch_file_handle_t fh; + switch_file_handle_t *hfh; + switch_frame_t hold_frame; + unsigned char holdbuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; + audio_endpoint_t *audio_endpoint; + struct private_object *next; +}; + + static struct { int debug; int port; @@ -434,6 +449,7 @@ static audio_stream_t* find_audio_stream(int indev, int outdev, int already_lock } return NULL; } + static void destroy_audio_streams() { int close_wait = 4; @@ -447,6 +463,7 @@ static void destroy_audio_streams() } globals.destroying_streams = 0; } + static switch_status_t validate_main_audio_stream() { if (globals.read_timer.timer_interface) { @@ -949,6 +966,80 @@ switch_io_routines_t portaudio_io_routines = { /*.receive_message */ channel_receive_message }; +static int create_shared_audio_stream(shared_audio_stream_t *stream); +static int destroy_shared_audio_stream(shared_audio_stream_t *stream); +static int take_stream_channel(shared_audio_stream_t *stream, int index, int input) +{ + int rc = 0; + if (!stream) { + return rc; + } + + switch_mutex_lock(stream->mutex); + + if (!stream->stream && create_shared_audio_stream(stream)) { + rc = -1; + goto done; + } + + if (input) { + if (stream->inchan_used[index]) { + rc = -1; + goto done; + } + stream->inchan_used[index] = 1; + } else { + if (!input && stream->outchan_used[index]) { + rc = -1; + goto done; + } + stream->outchan_used[index] = 1; + } + +done: + switch_mutex_unlock(stream->mutex); + return rc; +} + +static int release_stream_channel(shared_audio_stream_t *stream, int index, int input) +{ + int i = 0; + int destroy_stream = 1; + int rc = 0; + + if (!stream) { + return rc; + } + + switch_mutex_lock(stream->mutex); + + if (input) { + if (stream->inchan_used[index]) { + rc = -1; + goto done; + } + stream->inchan_used[index] = 1; + } else { + if (!input && stream->outchan_used[index]) { + rc = -1; + goto done; + } + stream->outchan_used[index] = 1; + } + + for (i = 0; i < stream->channels; i++) { + if (stream->inchan_used[i] || stream->outchan_used[i]) { + destroy_stream = 0; + } + } + if (destroy_stream) { + destroy_shared_audio_stream(stream); + } +done: + switch_mutex_unlock(stream->mutex); + return rc; +} + /* 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! */ @@ -957,51 +1048,93 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause) { + char name[128]; + const char *id = NULL; + private_t *tech_pvt = NULL; + switch_channel_t *channel = NULL; + switch_caller_profile_t *caller_profile = NULL; + switch_call_cause_t retcause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; - if ((*new_session = switch_core_session_request(portaudio_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, flags, 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)); - 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; - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "Hey where is my memory pool?\n"); - switch_core_session_destroy(new_session); - return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; - } - - if (outbound_profile) { - char name[128]; - const char *id = !zstr(outbound_profile->caller_id_number) ? outbound_profile->caller_id_number : "na"; - switch_snprintf(name, sizeof(name), "portaudio/%s", id); - - switch_channel_set_name(channel, name); - - caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); - switch_channel_set_caller_profile(channel, caller_profile); - tech_pvt->caller_profile = caller_profile; - if (outbound_profile->destination_number && !strcasecmp(outbound_profile->destination_number, "auto_answer")) { - switch_set_flag(tech_pvt, TFLAG_AUTO_ANSWER); - } - - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_ERROR, "Doh! no caller profile\n"); - switch_core_session_destroy(new_session); - return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; - } - - switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND); - switch_channel_set_state(channel, CS_INIT); - return SWITCH_CAUSE_SUCCESS; + if (!outbound_profile) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n"); + return retcause; } - return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + if (!(*new_session = switch_core_session_request(portaudio_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, flags, pool))) { + return retcause; + } + + 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)); + 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; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "Hey where is my memory pool?\n"); + switch_core_session_destroy(new_session); + return retcause; + } + + if (outbound_profile->destination_number && !strncasecmp(outbound_profile->destination_number, "endpoint", sizeof("endpoint"))) { + audio_endpoint_t *endpoint = NULL; + char *endpoint_name = switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number); + endpoint_name = strchr(endpoint_name, '/'); + if (!endpoint_name) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "No portaudio endpoint specified\n"); + goto error; + } + endpoint = switch_core_hash_find(globals.endpoints, endpoint_name); + if (!endpoint) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "Invalid portaudio endpoint %s\n", endpoint_name); + goto error; + } + /* check that there is no call there yet */ + switch_mutex_lock(endpoint->mutex); + if (endpoint->master) { + switch_mutex_unlock(endpoint->mutex); + retcause = SWITCH_CAUSE_USER_BUSY; + goto error; + } + /* try to acquire the stream */ + if (take_stream_channel(endpoint->in_stream, endpoint->inchan, 1)) { + switch_mutex_unlock(endpoint->mutex); + retcause = SWITCH_CAUSE_USER_BUSY; + goto error; + } + if (take_stream_channel(endpoint->out_stream, endpoint->outchan, 0)) { + release_stream_channel(endpoint->in_stream, endpoint->inchan, 1); + switch_mutex_unlock(endpoint->mutex); + retcause = SWITCH_CAUSE_USER_BUSY; + goto error; + } + switch_snprintf(name, sizeof(name), "portaudio/endpoint-%s", endpoint_name); + switch_set_flag(tech_pvt, TFLAG_AUTO_ANSWER); + endpoint->master = tech_pvt; + tech_pvt->audio_endpoint = endpoint; + switch_mutex_unlock(endpoint->mutex); + } else { + id = !zstr(outbound_profile->caller_id_number) ? outbound_profile->caller_id_number : "na"; + switch_snprintf(name, sizeof(name), "portaudio/%s", id); + if (outbound_profile->destination_number && !strcasecmp(outbound_profile->destination_number, "auto_answer")) { + switch_set_flag(tech_pvt, TFLAG_AUTO_ANSWER); + } + } + switch_channel_set_name(channel, name); + caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); + switch_channel_set_caller_profile(channel, caller_profile); + tech_pvt->caller_profile = caller_profile; + + switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND); + switch_channel_set_state(channel, CS_INIT); + return SWITCH_CAUSE_SUCCESS; + +error: + if (new_session && *new_session) { + switch_core_session_destroy(new_session); + } + return retcause; } @@ -1146,6 +1279,7 @@ static switch_status_t load_streams(switch_xml_t streams) if (!stream) { continue; } + switch_mutex_init(&stream->mutex, SWITCH_MUTEX_NESTED, module_pool); stream->indev = -1; stream->outdev = -1; stream->sample_rate = globals.sample_rate; @@ -1250,6 +1384,14 @@ static shared_audio_stream_t *check_stream(char *streamstr, int check_input, int if (cnum < 0 || cnum > stream->channels) { return NULL; } + + if (check_input && stream->indev < 0) { + return NULL; + } + + if (!check_input && stream->outdev < 0) { + return NULL; + } *chanindex = cnum; @@ -1282,6 +1424,7 @@ static switch_status_t load_endpoints(switch_xml_t endpoints) if (!endpoint) { continue; } + switch_mutex_init(&endpoint->mutex, SWITCH_MUTEX_NESTED, module_pool); endpoint->inchan = -1; endpoint->outchan = -1; switch_snprintf(endpoint->name, sizeof(endpoint->name), "%s", endpoint_name); @@ -1983,6 +2126,7 @@ static switch_status_t switch_audio_stream() return SWITCH_STATUS_SUCCESS; } + PaError open_audio_stream(PABLIO_Stream **stream, const PaStreamParameters * inputParameters, const PaStreamParameters * outputParameters) { if (inputParameters->device != -1) { @@ -1991,6 +2135,68 @@ PaError open_audio_stream(PABLIO_Stream **stream, const PaStreamParameters * inp return OpenAudioStream(stream, NULL, outputParameters, globals.sample_rate, paClipOff, globals.read_codec.implementation->samples_per_packet, 0); } +PaError open_shared_audio_stream(shared_audio_stream_t *shstream, const PaStreamParameters * inputParameters, const PaStreamParameters * outputParameters) +{ + PaError err; + if (inputParameters->device != -1) { + err = OpenAudioStream(&shstream->stream, inputParameters, outputParameters, shstream->sample_rate, + paClipOff, STREAM_SAMPLES_PER_PACKET(shstream), globals.dual_streams); + } else { + err = OpenAudioStream(&shstream->stream, NULL, outputParameters, shstream->sample_rate, + paClipOff, STREAM_SAMPLES_PER_PACKET(shstream), 0); + } + if (err != paNoError) { + shstream->stream = NULL; + } + return err; +} + +static int create_shared_audio_stream(shared_audio_stream_t *shstream) +{ + PaStreamParameters inputParameters, outputParameters; + PaError err; + switch_event_t *event; + + inputParameters.device = shstream->indev; + if (shstream->indev != -1) { + inputParameters.channelCount = shstream->channels; + inputParameters.sampleFormat = SAMPLE_TYPE; + inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + } + outputParameters.device = shstream->outdev; + outputParameters.channelCount = shstream->channels; + outputParameters.sampleFormat = SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = open_shared_audio_stream(shstream, &inputParameters, &outputParameters); + if (err != paNoError) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening audio device retrying\n"); + switch_yield(1000000); + err = open_shared_audio_stream(shstream, &inputParameters, &outputParameters); + } + + if (err != paNoError) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open audio device\n"); + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_ERROR_AUDIO_DEV) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Reason", Pa_GetErrorText(err)); + switch_event_fire(&event); + } + return -1; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created audio stream: %d channels %d\n", + shstream->sample_rate, shstream->channels); + return 0; +} + +static int destroy_shared_audio_stream(shared_audio_stream_t *shstream) +{ + CloseAudioStream(shstream->stream); + shstream->stream = NULL; + return 0; +} + static audio_stream_t *create_audio_stream(int indev, int outdev) { PaStreamParameters inputParameters, outputParameters; diff --git a/src/mod/endpoints/mod_portaudio/pablio.c b/src/mod/endpoints/mod_portaudio/pablio.c index e65851a61e..29fcc583ed 100644 --- a/src/mod/endpoints/mod_portaudio/pablio.c +++ b/src/mod/endpoints/mod_portaudio/pablio.c @@ -411,3 +411,4 @@ PaError CloseAudioStream(PABLIO_Stream * aStream) return paNoError; } + From fbce9061a35acf3b4950f0064fa134c085d2e6ad Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sat, 19 Mar 2011 19:55:12 -0400 Subject: [PATCH 006/163] mod_portaudio: implement endpoint reads --- .../endpoints/mod_portaudio/mod_portaudio.c | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index ec5d2f357c..3f5702f3ce 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -137,9 +137,13 @@ typedef struct _audio_endpoint { /*! Associated private information if involved in a call */ private_t *master; - /*! For timed writes */ + /*! For timed read and writes */ + switch_timer_t read_timer; switch_timer_t write_timer; + /* We need our own read frame */ + switch_frame_t read_frame; + /*! Let's be safe */ switch_mutex_t *mutex; } audio_endpoint_t; @@ -725,11 +729,21 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session) return SWITCH_STATUS_SUCCESS; } +static int release_stream_channel(shared_audio_stream_t *stream, int index, int input); static switch_status_t channel_on_hangup(switch_core_session_t *session) { private_t *tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); + if (tech_pvt->audio_endpoint) { + audio_endpoint_t *endpoint = tech_pvt->audio_endpoint; + switch_mutex_lock(endpoint->mutex); + /* release the stream channels */ + release_stream_channel(endpoint->in_stream, endpoint->inchan, 1); + release_stream_channel(endpoint->out_stream, endpoint->outchan, 0); + switch_mutex_unlock(endpoint->mutex); + } + switch_mutex_lock(globals.pa_mutex); switch_core_hash_delete(globals.call_hash, tech_pvt->call_id); switch_mutex_unlock(globals.pa_mutex); @@ -789,12 +803,40 @@ static switch_status_t channel_send_dtmf(switch_core_session_t *session, const s return SWITCH_STATUS_SUCCESS; } +static switch_status_t channel_endpoint_read(audio_endpoint_t *endpoint, switch_frame_t **frame) +{ + int samples = 0; + + if (!endpoint->in_stream) { + *frame = &globals.cng_frame; + return SWITCH_STATUS_SUCCESS; + } + + samples = ReadAudioStream(endpoint->in_stream->stream, + endpoint->read_frame.data, STREAM_SAMPLES_PER_PACKET(endpoint->in_stream), + &endpoint->read_timer); + + if (!samples) { + *frame = &globals.cng_frame; + return SWITCH_STATUS_SUCCESS; + } + + endpoint->read_frame.datalen = (samples * sizeof(int16_t)); + endpoint->read_frame.samples = samples; + *frame = &endpoint->read_frame; + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) { private_t *tech_pvt = switch_core_session_get_private(session); int samples = 0; switch_status_t status = SWITCH_STATUS_FALSE; switch_assert(tech_pvt != NULL); + + if (tech_pvt->audio_endpoint) { + return channel_endpoint_read(tech_pvt->audio_endpoint, frame); + } if (!globals.main_stream) { goto normal_return; @@ -1462,6 +1504,21 @@ static switch_status_t load_endpoints(switch_xml_t endpoints) "Incomatible input and output streams for endpoint '%s'\n", endpoint_name); continue; } + + if (switch_core_timer_init(&endpoint->read_timer, + globals.timer_name, endpoint->in_stream->codec_ms, + STREAM_SAMPLES_PER_PACKET(endpoint->in_stream), module_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint_name); + continue; + } + + if (switch_core_timer_init(&endpoint->write_timer, + globals.timer_name, endpoint->out_stream->codec_ms, + STREAM_SAMPLES_PER_PACKET(endpoint->in_stream), module_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint_name); + continue; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created endpoint '%s', instream = %s, outstream = %s\n", endpoint->name, endpoint->in_stream ? endpoint->in_stream->name : "(none)", From 739ff9d35a956e6014b8cbf71b1bc94a06777827 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sat, 19 Mar 2011 20:09:18 -0400 Subject: [PATCH 007/163] mod_portaudio: implement endpoint writes and multiplex read/writes in pablio streams --- .../endpoints/mod_portaudio/mod_portaudio.c | 30 ++++++++++++++----- src/mod/endpoints/mod_portaudio/pablio.c | 22 +++++++------- src/mod/endpoints/mod_portaudio/pablio.h | 18 +++++------ 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 3f5702f3ce..68e914ac70 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -389,7 +389,7 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) if (globals.ring_stream && (! switch_test_flag(globals.call_list, TFLAG_MASTER) || ( !globals.no_ring_during_call && globals.main_stream != globals.ring_stream)) ) { //if there is a ring stream and not an active call or if there is an active call and we are allowed to ring during it AND the ring stream is not the main stream - WriteAudioStream(globals.ring_stream->stream, abuf, (long) olen, &globals.ring_stream->write_timer); + WriteAudioStream(globals.ring_stream->stream, abuf, (long) olen, 0, &globals.ring_stream->write_timer); } } else { switch_yield(10000); @@ -814,7 +814,7 @@ static switch_status_t channel_endpoint_read(audio_endpoint_t *endpoint, switch_ samples = ReadAudioStream(endpoint->in_stream->stream, endpoint->read_frame.data, STREAM_SAMPLES_PER_PACKET(endpoint->in_stream), - &endpoint->read_timer); + endpoint->inchan, &endpoint->read_timer); if (!samples) { *frame = &globals.cng_frame; @@ -900,7 +900,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch } switch_mutex_lock(globals.device_lock); - samples = ReadAudioStream(globals.main_stream->stream, globals.read_frame.data, globals.read_codec.implementation->samples_per_packet, &globals.read_timer); + samples = ReadAudioStream(globals.main_stream->stream, globals.read_frame.data, globals.read_codec.implementation->samples_per_packet, 0, &globals.read_timer); switch_mutex_unlock(globals.device_lock); if (samples) { @@ -931,12 +931,28 @@ normal_return: } +static switch_status_t channel_endpoint_write(audio_endpoint_t *endpoint, switch_frame_t *frame) +{ + if (!endpoint->out_stream) { + switch_core_timer_next(&endpoint->write_timer); + return SWITCH_STATUS_SUCCESS; + } + WriteAudioStream(endpoint->out_stream->stream, (short *)frame->data, + (int)(frame->datalen / sizeof(SAMPLE)), + endpoint->outchan, &(endpoint->write_timer)); + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) { switch_status_t status = SWITCH_STATUS_FALSE; private_t *tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); + if (tech_pvt->audio_endpoint) { + return channel_endpoint_write(tech_pvt->audio_endpoint, frame); + } + if (!globals.main_stream) { return SWITCH_STATUS_FALSE; } @@ -951,7 +967,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc if (globals.main_stream) { if (switch_test_flag((&globals), GFLAG_EAR)) { - WriteAudioStream(globals.main_stream->stream, (short *) frame->data, (int) (frame->datalen / sizeof(SAMPLE)), &(globals.main_stream->write_timer)); + WriteAudioStream(globals.main_stream->stream, (short *) frame->data, (int) (frame->datalen / sizeof(SAMPLE)), 0, &(globals.main_stream->write_timer)); } status = SWITCH_STATUS_SUCCESS; } @@ -1876,7 +1892,7 @@ static switch_status_t play_dev(switch_stream_handle_t *stream, int outdev, char break; } - WriteAudioStream(audio_stream->stream, abuf, (long) olen, &(audio_stream->write_timer)); + WriteAudioStream(audio_stream->stream, abuf, (long) olen, 0, &(audio_stream->write_timer)); wrote += (int) olen; if (samples) { samples -= (int) olen; @@ -2555,8 +2571,8 @@ static switch_status_t looptest(char **argv, int argc, switch_stream_handle_t *s if (globals.destroying_streams || ! globals.main_stream->stream) { break; } - if ((samples = ReadAudioStream(globals.main_stream->stream, globals.read_frame.data, globals.read_codec.implementation->samples_per_packet, &globals.read_timer))) { - WriteAudioStream(globals.main_stream->stream, globals.read_frame.data, (long) samples, &(globals.main_stream->write_timer)); + if ((samples = ReadAudioStream(globals.main_stream->stream, globals.read_frame.data, globals.read_codec.implementation->samples_per_packet, 0, &globals.read_timer))) { + WriteAudioStream(globals.main_stream->stream, globals.read_frame.data, (long) samples, 0, &(globals.main_stream->write_timer)); success = 1; } switch_yield(10000); diff --git a/src/mod/endpoints/mod_portaudio/pablio.c b/src/mod/endpoints/mod_portaudio/pablio.c index 29fcc583ed..7070eaedac 100644 --- a/src/mod/endpoints/mod_portaudio/pablio.c +++ b/src/mod/endpoints/mod_portaudio/pablio.c @@ -143,7 +143,7 @@ static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf) * Write data to ring buffer. * Will not return until all the data has been written. */ -long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer) +long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, int chan, switch_timer_t *timer) { long bytesWritten; char *p = (char *) data; @@ -151,12 +151,12 @@ long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switc switch_core_timer_next(timer); - bytesWritten = PaUtil_WriteRingBuffer(&aStream->outFIFOs[0], p, numBytes); + bytesWritten = PaUtil_WriteRingBuffer(&aStream->outFIFOs[chan], p, numBytes); numBytes -= bytesWritten; p += bytesWritten; if (numBytes > 0) { - PaUtil_FlushRingBuffer(&aStream->outFIFOs[0]); + PaUtil_FlushRingBuffer(&aStream->outFIFOs[chan]); return 0; } return numFrames; @@ -166,7 +166,7 @@ long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switc * Read data from ring buffer. * Will not return until all the data has been read. */ -long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer) +long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, int chan, switch_timer_t *timer) { long bytesRead = 0; char *p = (char *) data; @@ -177,17 +177,17 @@ long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch while (totalBytes < neededBytes && --max > 0) { - avail = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFOs[0]); + avail = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFOs[chan]); //printf("AVAILABLE BYTES %ld pass %d\n", avail, 5000 - max); if (avail >= neededBytes * 6) { - PaUtil_FlushRingBuffer(&aStream->inFIFOs[0]); + PaUtil_FlushRingBuffer(&aStream->inFIFOs[chan]); avail = 0; } else { bytesRead = 0; if (totalBytes < neededBytes && avail >= neededBytes) { - bytesRead = PaUtil_ReadRingBuffer(&aStream->inFIFOs[0], p, neededBytes); + bytesRead = PaUtil_ReadRingBuffer(&aStream->inFIFOs[chan], p, neededBytes); totalBytes += bytesRead; } @@ -206,9 +206,9 @@ long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch * 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 chan) { - int bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[0]); + int bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[chan]); return bytesEmpty / aStream->bytesPerFrame; } @@ -216,9 +216,9 @@ 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, int chan) { - int bytesFull = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFOs[0]); + int bytesFull = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFOs[chan]); return bytesFull / aStream->bytesPerFrame; } diff --git a/src/mod/endpoints/mod_portaudio/pablio.h b/src/mod/endpoints/mod_portaudio/pablio.h index d2d6bf8101..859aabb513 100644 --- a/src/mod/endpoints/mod_portaudio/pablio.h +++ b/src/mod/endpoints/mod_portaudio/pablio.h @@ -81,25 +81,25 @@ typedef struct { * Write data to ring buffer. * Will not return until all the data has been written. */ - long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer); +long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, int chan, 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, switch_timer_t *timer); +long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, int chan, 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, int chan); /************************************************************ * 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 chan); /************************************************************ * Opens a PortAudio stream with default characteristics. @@ -109,12 +109,12 @@ typedef struct { * 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, long samples_per_packet, int do_dual); +PaError OpenAudioStream(PABLIO_Stream ** rwblPtr, + const PaStreamParameters * inputParameters, + const PaStreamParameters * outputParameters, + double sampleRate, PaStreamCallbackFlags statusFlags, long samples_per_packet, int do_dual); - PaError CloseAudioStream(PABLIO_Stream * aStream); +PaError CloseAudioStream(PABLIO_Stream * aStream); #ifdef __cplusplus } From 3814eb13df334f588dc23a159311a9f878902367 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sat, 19 Mar 2011 23:43:40 -0400 Subject: [PATCH 008/163] mod_portaudio: initialize read/write endpoint timers per call fix pablio multiplexing --- .../endpoints/mod_portaudio/mod_portaudio.c | 63 +++++++++------ src/mod/endpoints/mod_portaudio/pablio.c | 79 +++++++++++++------ src/mod/endpoints/mod_portaudio/pablio.h | 11 +++ 3 files changed, 106 insertions(+), 47 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 68e914ac70..3e726cfb18 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -1136,6 +1136,8 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi } if (outbound_profile->destination_number && !strncasecmp(outbound_profile->destination_number, "endpoint", sizeof("endpoint"))) { + int timer_ms = -1; + int samples_per_packet = -1; audio_endpoint_t *endpoint = NULL; char *endpoint_name = switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number); endpoint_name = strchr(endpoint_name, '/'); @@ -1155,6 +1157,34 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi retcause = SWITCH_CAUSE_USER_BUSY; goto error; } + + timer_ms = endpoint->in_stream ? endpoint->in_stream->codec_ms : endpoint->out_stream->codec_ms; + samples_per_packet = endpoint->in_stream ? + STREAM_SAMPLES_PER_PACKET(endpoint->in_stream) : STREAM_SAMPLES_PER_PACKET(endpoint->out_stream); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Setting up timer for endpoint '%s' with %dms and %d samples per packet\n", endpoint->name, timer_ms, samples_per_packet); + + /* only setup read timer if we'll be reading */ + if (endpoint->in_stream && switch_core_timer_init(&endpoint->read_timer, + globals.timer_name, timer_ms, + samples_per_packet, module_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint->name); + switch_mutex_unlock(endpoint->mutex); + goto error; + } + + /* The write timer must be setup regardless */ + if (switch_core_timer_init(&endpoint->write_timer, + globals.timer_name, timer_ms, + samples_per_packet, module_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint->name); + if (endpoint->in_stream) { + switch_core_timer_destroy(&endpoint->read_timer); + } + switch_mutex_unlock(endpoint->mutex); + goto error; + } + /* try to acquire the stream */ if (take_stream_channel(endpoint->in_stream, endpoint->inchan, 1)) { switch_mutex_unlock(endpoint->mutex); @@ -1520,21 +1550,6 @@ static switch_status_t load_endpoints(switch_xml_t endpoints) "Incomatible input and output streams for endpoint '%s'\n", endpoint_name); continue; } - - if (switch_core_timer_init(&endpoint->read_timer, - globals.timer_name, endpoint->in_stream->codec_ms, - STREAM_SAMPLES_PER_PACKET(endpoint->in_stream), module_pool) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint_name); - continue; - } - - if (switch_core_timer_init(&endpoint->write_timer, - globals.timer_name, endpoint->out_stream->codec_ms, - STREAM_SAMPLES_PER_PACKET(endpoint->in_stream), module_pool) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint_name); - continue; - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created endpoint '%s', instream = %s, outstream = %s\n", endpoint->name, endpoint->in_stream ? endpoint->in_stream->name : "(none)", @@ -1642,14 +1657,6 @@ static switch_status_t load_config(void) } } - if ((streams = switch_xml_child(cfg, "streams"))) { - load_streams(streams); - } - - if ((endpoints = switch_xml_child(cfg, "endpoints"))) { - load_endpoints(endpoints); - } - if (!globals.dialplan) { set_global_dialplan("XML"); } @@ -1701,6 +1708,16 @@ static switch_status_t load_config(void) } } + /* streams and endpoints must be last, some initialization depend on globals defaults */ + if ((streams = switch_xml_child(cfg, "streams"))) { + load_streams(streams); + } + + if ((endpoints = switch_xml_child(cfg, "endpoints"))) { + load_endpoints(endpoints); + } + + switch_xml_free(xml); return status; diff --git a/src/mod/endpoints/mod_portaudio/pablio.c b/src/mod/endpoints/mod_portaudio/pablio.c index 7070eaedac..6423dc762d 100644 --- a/src/mod/endpoints/mod_portaudio/pablio.c +++ b/src/mod/endpoints/mod_portaudio/pablio.c @@ -78,14 +78,23 @@ static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf); static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData) { + int c = 0, i = 0, j = 0; PABLIO_Stream *data = (PABLIO_Stream *) userData; long numBytes = data->bytesPerFrame * framesPerBuffer; + const int16_t *inputSamples = inputBuffer; + int16_t *chanSamples = (int16_t*)data->iobuff; /* This may get called with NULL inputBuffer during initial setup. */ if (inputBuffer != NULL) { - if (PaUtil_WriteRingBuffer(&data->inFIFOs[0], inputBuffer, numBytes) != numBytes) { - PaUtil_FlushRingBuffer(&data->inFIFOs[0]); - PaUtil_WriteRingBuffer(&data->inFIFOs[0], inputBuffer, numBytes); + /* retrieve the data for each channel and put it in the ring buffer */ + for (c = 0; c < data->channelCount; c++) { + for (i = 0, j = c; i < framesPerBuffer; j += data->channelCount, i++) { + chanSamples[i] = inputSamples[j]; + } + if (PaUtil_WriteRingBuffer(&data->inFIFOs[c], chanSamples, numBytes) != numBytes) { + PaUtil_FlushRingBuffer(&data->inFIFOs[c]); + PaUtil_WriteRingBuffer(&data->inFIFOs[c], inputBuffer, numBytes); + } } } @@ -97,13 +106,21 @@ static int oblockingIOCallback(const void *inputBuffer, void *outputBuffer, { PABLIO_Stream *data = (PABLIO_Stream *) userData; long numBytes = data->bytesPerFrame * framesPerBuffer; + int16_t *outputSamples = outputBuffer; + int16_t *chanSamples = (short *)data->iobuff; + int c = 0, i = 0, j = 0; if (outputBuffer != NULL) { - int i; - int numRead = PaUtil_ReadRingBuffer(&data->outFIFOs[0], outputBuffer, numBytes); - /* Zero out remainder of buffer if we run out of data. */ - for (i = numRead; i < numBytes; i++) { - ((char *) outputBuffer)[i] = 0; + for (c = 0; c < data->channelCount; c++) { + int numRead = PaUtil_ReadRingBuffer(&data->outFIFOs[c], chanSamples, numBytes); + numRead = numRead / sizeof(int16_t); + for (i = 0, j = c; i < framesPerBuffer; j += data->channelCount, i++) { + if (i < numRead) { + outputSamples[j] = chanSamples[i]; + } else { + outputSamples[j] = 0; + } + } } } @@ -251,6 +268,7 @@ PaError OpenAudioStream(PABLIO_Stream ** rwblPtr, PABLIO_Stream *aStream; long numFrames; //long numBytes; + int c = 0; int channels = 1; if (!(inputParameters || outputParameters)) { @@ -270,21 +288,26 @@ PaError OpenAudioStream(PABLIO_Stream ** rwblPtr, numFrames = RoundUpToNextPowerOf2(samples_per_packet * 5); aStream->bytesPerFrame = bytesPerSample; + aStream->channelCount = channels; /* Initialize Ring Buffers */ if (inputParameters) { - err = PABLIO_InitFIFO(&aStream->inFIFOs[0], numFrames, aStream->bytesPerFrame); - if (err != paNoError) { - goto error; + for (c = 0; c < channels; c++) { + err = PABLIO_InitFIFO(&aStream->inFIFOs[c], numFrames, aStream->bytesPerFrame); + if (err != paNoError) { + goto error; + } } aStream->has_in = 1; } if (outputParameters) { - err = PABLIO_InitFIFO(&aStream->outFIFOs[0], numFrames, aStream->bytesPerFrame); - if (err != paNoError) { - goto error; + for (c = 0; c < channels; c++) { + err = PABLIO_InitFIFO(&aStream->outFIFOs[c], numFrames, aStream->bytesPerFrame); + if (err != paNoError) { + goto error; + } } aStream->has_out = 1; } @@ -353,17 +376,21 @@ PaError CloseAudioStream(PABLIO_Stream * aStream) { int bytesEmpty; int byteSize; + int c = 0; - byteSize = aStream->outFIFOs[0].bufferSize; - if (aStream->has_out) { - /* If we are writing data, make sure we play everything written. */ - if (byteSize > 0) { - bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[0]); - while (bytesEmpty < byteSize) { - Pa_Sleep(10); - bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[0]); + + for (c = 0; c < aStream->channelCount; c++) { + byteSize = aStream->outFIFOs[c].bufferSize; + + /* If we are writing data, make sure we play everything written. */ + if (byteSize > 0) { + bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[c]); + while (bytesEmpty < byteSize) { + Pa_Sleep(10); + bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[c]); + } } } } @@ -399,11 +426,15 @@ PaError CloseAudioStream(PABLIO_Stream * aStream) } if (aStream->has_in) { - PABLIO_TermFIFO(&aStream->inFIFOs[0]); + for (c = 0; c < aStream->channelCount; c++) { + PABLIO_TermFIFO(&aStream->inFIFOs[c]); + } } if (aStream->has_out) { - PABLIO_TermFIFO(&aStream->outFIFOs[0]); + for (c = 0; c < aStream->channelCount; c++) { + PABLIO_TermFIFO(&aStream->outFIFOs[c]); + } } free(aStream); diff --git a/src/mod/endpoints/mod_portaudio/pablio.h b/src/mod/endpoints/mod_portaudio/pablio.h index 859aabb513..435e4b0ca7 100644 --- a/src/mod/endpoints/mod_portaudio/pablio.h +++ b/src/mod/endpoints/mod_portaudio/pablio.h @@ -56,7 +56,17 @@ extern "C" { #include +/*! Maximum number of channels per stream */ #define MAX_IO_CHANNELS 2 + +/*! Maximum numer of milliseconds per packet */ +#define MAX_IO_MS 100 + +/*! Maximum sampling rate (48Khz) */ +#define MAX_SAMPLING_RATE 48000 + +/* Maximum size of a read */ +#define MAX_IO_BUFFER (((MAX_IO_MS * MAX_SAMPLING_RATE)/1000)*sizeof(int16_t)) typedef struct { PaStream *istream; PaStream *ostream; @@ -68,6 +78,7 @@ typedef struct { PaUtilRingBuffer inFIFOs[MAX_IO_CHANNELS]; PaUtilRingBuffer outFIFOs[MAX_IO_CHANNELS]; int channelCount; + char iobuff[MAX_IO_BUFFER]; } PABLIO_Stream; /* Values for flags for OpenAudioStream(). */ From dc98b03b4cda0267bb78aea6247baffad603dae1 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 20 Mar 2011 01:16:55 -0400 Subject: [PATCH 009/163] mod_portaudio: set read/write codec to L16 --- .../endpoints/mod_portaudio/mod_portaudio.c | 108 ++++++++++++------ 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 3e726cfb18..07b7018004 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -144,6 +144,10 @@ typedef struct _audio_endpoint { /* We need our own read frame */ switch_frame_t read_frame; + /* Needed codecs for the core to read/write in the proper format */ + switch_codec_t read_codec; + switch_codec_t write_codec; + /*! Let's be safe */ switch_mutex_t *mutex; } audio_endpoint_t; @@ -308,7 +312,7 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) tech_pvt->hold_file = switch_core_session_strdup(session, hold_file); } if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - if (validate_main_audio_stream() != SWITCH_STATUS_SUCCESS) { + if (!tech_pvt->audio_endpoint && validate_main_audio_stream() != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); return SWITCH_STATUS_FALSE; } @@ -345,7 +349,9 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) } } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Testing autoanswer\n"); if (switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "autoanswer\n"); switch_mutex_lock(globals.pvt_lock); add_pvt(tech_pvt, PA_MASTER); switch_channel_mark_answered(channel); @@ -353,6 +359,7 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) switch_mutex_unlock(globals.pvt_lock); switch_yield(1000000); } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No autoanswer\n"); switch_channel_mark_ring_ready(channel); } @@ -639,6 +646,7 @@ static void add_pvt(private_t *tech_pvt, int master) switch_mutex_lock(globals.pvt_lock); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "call is '%s'\n", tech_pvt->call_id); if (*tech_pvt->call_id == '\0') { switch_mutex_lock(globals.pa_mutex); switch_snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", ++globals.call_id); @@ -647,6 +655,7 @@ static void add_pvt(private_t *tech_pvt, int master) switch_core_session_set_read_codec(tech_pvt->session, &globals.read_codec); switch_core_session_set_write_codec(tech_pvt->session, &globals.write_codec); switch_mutex_unlock(globals.pa_mutex); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Added call %s\n", tech_pvt->call_id); } for (tp = globals.call_list; tp; tp = tp->next) { @@ -738,9 +747,12 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) if (tech_pvt->audio_endpoint) { audio_endpoint_t *endpoint = tech_pvt->audio_endpoint; switch_mutex_lock(endpoint->mutex); - /* release the stream channels */ release_stream_channel(endpoint->in_stream, endpoint->inchan, 1); release_stream_channel(endpoint->out_stream, endpoint->outchan, 0); + switch_core_timer_destroy(&endpoint->read_timer); + switch_core_timer_destroy(&endpoint->write_timer); + switch_core_codec_destroy(&endpoint->read_codec); + switch_core_codec_destroy(&endpoint->write_codec); switch_mutex_unlock(endpoint->mutex); } @@ -823,6 +835,7 @@ static switch_status_t channel_endpoint_read(audio_endpoint_t *endpoint, switch_ endpoint->read_frame.datalen = (samples * sizeof(int16_t)); endpoint->read_frame.samples = samples; + endpoint->read_frame.codec = &endpoint->read_codec; *frame = &endpoint->read_frame; return SWITCH_STATUS_SUCCESS; } @@ -1072,17 +1085,9 @@ static int release_stream_channel(shared_audio_stream_t *stream, int index, int switch_mutex_lock(stream->mutex); if (input) { - if (stream->inchan_used[index]) { - rc = -1; - goto done; - } - stream->inchan_used[index] = 1; + stream->inchan_used[index] = 0; } else { - if (!input && stream->outchan_used[index]) { - rc = -1; - goto done; - } - stream->outchan_used[index] = 1; + stream->outchan_used[index] = 0; } for (i = 0; i < stream->channels; i++) { @@ -1093,7 +1098,7 @@ static int release_stream_channel(shared_audio_stream_t *stream, int index, int if (destroy_stream) { destroy_shared_audio_stream(stream); } -done: + switch_mutex_unlock(stream->mutex); return rc; } @@ -1112,6 +1117,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi switch_channel_t *channel = NULL; switch_caller_profile_t *caller_profile = NULL; switch_call_cause_t retcause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + int codec_ms = -1; + int samples_per_packet = -1; + int sample_rate = 0; + audio_endpoint_t *endpoint = NULL; + char *endpoint_name = NULL; if (!outbound_profile) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n"); @@ -1135,65 +1145,75 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi return retcause; } - if (outbound_profile->destination_number && !strncasecmp(outbound_profile->destination_number, "endpoint", sizeof("endpoint"))) { - int timer_ms = -1; - int samples_per_packet = -1; - audio_endpoint_t *endpoint = NULL; - char *endpoint_name = switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "dest: %s\n", outbound_profile ? outbound_profile->destination_number : ""); + if (outbound_profile->destination_number && !strncasecmp(outbound_profile->destination_number, "endpoint", sizeof("endpoint")-1)) { + codec_ms = -1; + samples_per_packet = -1; + endpoint = NULL; + endpoint_name = switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number); endpoint_name = strchr(endpoint_name, '/'); if (!endpoint_name) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "No portaudio endpoint specified\n"); goto error; } + endpoint_name++; endpoint = switch_core_hash_find(globals.endpoints, endpoint_name); if (!endpoint) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "Invalid portaudio endpoint %s\n", endpoint_name); goto error; } - /* check that there is no call there yet */ + switch_mutex_lock(endpoint->mutex); + if (endpoint->master) { - switch_mutex_unlock(endpoint->mutex); + /* someone already has this endpoint */ retcause = SWITCH_CAUSE_USER_BUSY; goto error; } - timer_ms = endpoint->in_stream ? endpoint->in_stream->codec_ms : endpoint->out_stream->codec_ms; + codec_ms = endpoint->in_stream ? endpoint->in_stream->codec_ms : endpoint->out_stream->codec_ms; samples_per_packet = endpoint->in_stream ? STREAM_SAMPLES_PER_PACKET(endpoint->in_stream) : STREAM_SAMPLES_PER_PACKET(endpoint->out_stream); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, - "Setting up timer for endpoint '%s' with %dms and %d samples per packet\n", endpoint->name, timer_ms, samples_per_packet); + sample_rate = endpoint->in_stream ? endpoint->in_stream->sample_rate : endpoint->out_stream->sample_rate; - /* only setup read timer if we'll be reading */ - if (endpoint->in_stream && switch_core_timer_init(&endpoint->read_timer, - globals.timer_name, timer_ms, + if (switch_core_timer_init(&endpoint->read_timer, + globals.timer_name, codec_ms, samples_per_packet, module_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint->name); - switch_mutex_unlock(endpoint->mutex); goto error; } /* The write timer must be setup regardless */ if (switch_core_timer_init(&endpoint->write_timer, - globals.timer_name, timer_ms, + globals.timer_name, codec_ms, samples_per_packet, module_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to setup read timer for endpoint '%s'!\n", endpoint->name); - if (endpoint->in_stream) { - switch_core_timer_destroy(&endpoint->read_timer); - } - switch_mutex_unlock(endpoint->mutex); goto error; } + if (switch_core_codec_init(&endpoint->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"); + goto error; + } + + if (switch_core_codec_init(&endpoint->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"); + goto error; + } + switch_core_session_set_read_codec(tech_pvt->session, &endpoint->read_codec); + switch_core_session_set_write_codec(tech_pvt->session, &endpoint->write_codec); + /* try to acquire the stream */ if (take_stream_channel(endpoint->in_stream, endpoint->inchan, 1)) { - switch_mutex_unlock(endpoint->mutex); retcause = SWITCH_CAUSE_USER_BUSY; goto error; } if (take_stream_channel(endpoint->out_stream, endpoint->outchan, 0)) { release_stream_channel(endpoint->in_stream, endpoint->inchan, 1); - switch_mutex_unlock(endpoint->mutex); retcause = SWITCH_CAUSE_USER_BUSY; goto error; } @@ -1219,6 +1239,21 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi return SWITCH_CAUSE_SUCCESS; error: + if (endpoint) { + if (endpoint->read_timer.interval) { + switch_core_timer_destroy(&endpoint->read_timer); + } + if (endpoint->write_timer.interval) { + switch_core_timer_destroy(&endpoint->write_timer); + } + if (endpoint->read_codec.codec_interface) { + switch_core_codec_destroy(&endpoint->read_codec); + } + if (endpoint->write_codec.codec_interface) { + switch_core_codec_destroy(&endpoint->write_codec); + } + switch_mutex_unlock(endpoint->mutex); + } if (new_session && *new_session) { switch_core_session_destroy(new_session); } @@ -2275,13 +2310,14 @@ static int create_shared_audio_stream(shared_audio_stream_t *shstream) } return -1; } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created audio stream: %d channels %d\n", - shstream->sample_rate, shstream->channels); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created shared audio stream %s: %d channels %d\n", + shstream->name, shstream->sample_rate, shstream->channels); return 0; } static int destroy_shared_audio_stream(shared_audio_stream_t *shstream) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Destroying shared audio stream %s\n", shstream->name); CloseAudioStream(shstream->stream); shstream->stream = NULL; return 0; From 667507bda98c76090d9be802735a275f8fc2c039 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 20 Mar 2011 01:33:08 -0400 Subject: [PATCH 010/163] mod_portaudio: release the endpoint on hangup --- src/mod/endpoints/mod_portaudio/mod_portaudio.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 07b7018004..98833d9d86 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -746,13 +746,19 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) if (tech_pvt->audio_endpoint) { audio_endpoint_t *endpoint = tech_pvt->audio_endpoint; + + tech_pvt->audio_endpoint = NULL; + switch_mutex_lock(endpoint->mutex); + release_stream_channel(endpoint->in_stream, endpoint->inchan, 1); release_stream_channel(endpoint->out_stream, endpoint->outchan, 0); switch_core_timer_destroy(&endpoint->read_timer); switch_core_timer_destroy(&endpoint->write_timer); switch_core_codec_destroy(&endpoint->read_codec); switch_core_codec_destroy(&endpoint->write_codec); + endpoint->master = NULL; + switch_mutex_unlock(endpoint->mutex); } From 43551c6503c1b3fcd464e3d8993319ba194f5ac4 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 20 Mar 2011 01:57:35 -0400 Subject: [PATCH 011/163] mod_portaudio: do not set the global codec for endpoints --- src/mod/endpoints/mod_portaudio/mod_portaudio.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 98833d9d86..74ba9a76fb 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -349,9 +349,7 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) } } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Testing autoanswer\n"); if (switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "autoanswer\n"); switch_mutex_lock(globals.pvt_lock); add_pvt(tech_pvt, PA_MASTER); switch_channel_mark_answered(channel); @@ -359,7 +357,6 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) switch_mutex_unlock(globals.pvt_lock); switch_yield(1000000); } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No autoanswer\n"); switch_channel_mark_ring_ready(channel); } @@ -646,16 +643,17 @@ static void add_pvt(private_t *tech_pvt, int master) switch_mutex_lock(globals.pvt_lock); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "call is '%s'\n", tech_pvt->call_id); if (*tech_pvt->call_id == '\0') { switch_mutex_lock(globals.pa_mutex); switch_snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", ++globals.call_id); switch_channel_set_variable(switch_core_session_get_channel(tech_pvt->session), SWITCH_PA_CALL_ID_VARIABLE, tech_pvt->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); + if (!tech_pvt->audio_endpoint) { + switch_core_session_set_read_codec(tech_pvt->session, &globals.read_codec); + switch_core_session_set_write_codec(tech_pvt->session, &globals.write_codec); + } switch_mutex_unlock(globals.pa_mutex); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Added call %s\n", tech_pvt->call_id); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Added call %s\n", tech_pvt->call_id); } for (tp = globals.call_list; tp; tp = tp->next) { @@ -664,7 +662,7 @@ static void add_pvt(private_t *tech_pvt, int master) } if (master && switch_test_flag(tp, TFLAG_MASTER) ) { switch_clear_flag_locked(tp, TFLAG_MASTER); - create_hold_event(tp,0); + create_hold_event(tp, 0); } } @@ -1151,7 +1149,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi return retcause; } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "dest: %s\n", outbound_profile ? outbound_profile->destination_number : ""); if (outbound_profile->destination_number && !strncasecmp(outbound_profile->destination_number, "endpoint", sizeof("endpoint")-1)) { codec_ms = -1; samples_per_packet = -1; From e7a58ab233aafcf754aea32f482c3655a049d0ee Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 20 Mar 2011 02:04:19 -0400 Subject: [PATCH 012/163] mod_portaudio: use the read timer for endpoints --- src/mod/endpoints/mod_portaudio/mod_portaudio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 74ba9a76fb..e27d24b190 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -824,6 +824,7 @@ static switch_status_t channel_endpoint_read(audio_endpoint_t *endpoint, switch_ int samples = 0; if (!endpoint->in_stream) { + switch_core_timer_next(&endpoint->read_timer); *frame = &globals.cng_frame; return SWITCH_STATUS_SUCCESS; } @@ -833,6 +834,7 @@ static switch_status_t channel_endpoint_read(audio_endpoint_t *endpoint, switch_ endpoint->inchan, &endpoint->read_timer); if (!samples) { + switch_core_timer_next(&endpoint->read_timer); *frame = &globals.cng_frame; return SWITCH_STATUS_SUCCESS; } From dbe4a4850a890105355a9cdf578bf02a01ecde86 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 20 Mar 2011 02:36:46 -0400 Subject: [PATCH 013/163] mod_portaudio: do not destroy codec and timers if there is a call in progress! --- .../endpoints/mod_portaudio/mod_portaudio.c | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index e27d24b190..291cc00c4a 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -1245,17 +1245,19 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi error: if (endpoint) { - if (endpoint->read_timer.interval) { - switch_core_timer_destroy(&endpoint->read_timer); - } - if (endpoint->write_timer.interval) { - switch_core_timer_destroy(&endpoint->write_timer); - } - if (endpoint->read_codec.codec_interface) { - switch_core_codec_destroy(&endpoint->read_codec); - } - if (endpoint->write_codec.codec_interface) { - switch_core_codec_destroy(&endpoint->write_codec); + if (!endpoint->master) { + if (endpoint->read_timer.interval) { + switch_core_timer_destroy(&endpoint->read_timer); + } + if (endpoint->write_timer.interval) { + switch_core_timer_destroy(&endpoint->write_timer); + } + if (endpoint->read_codec.codec_interface) { + switch_core_codec_destroy(&endpoint->read_codec); + } + if (endpoint->write_codec.codec_interface) { + switch_core_codec_destroy(&endpoint->write_codec); + } } switch_mutex_unlock(endpoint->mutex); } From e335a876cf388ec8ba425f7975d2b519368c9777 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 20 Mar 2011 03:11:13 -0400 Subject: [PATCH 014/163] mod_portaudio: fix endpoint reads --- src/mod/endpoints/mod_portaudio/mod_portaudio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 291cc00c4a..046c5293b0 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -143,6 +143,7 @@ typedef struct _audio_endpoint { /* We need our own read frame */ switch_frame_t read_frame; + unsigned char read_buf[SWITCH_RECOMMENDED_BUFFER_SIZE]; /* Needed codecs for the core to read/write in the proper format */ switch_codec_t read_codec; @@ -829,6 +830,7 @@ static switch_status_t channel_endpoint_read(audio_endpoint_t *endpoint, switch_ return SWITCH_STATUS_SUCCESS; } + endpoint->read_frame.data = endpoint->read_buf; samples = ReadAudioStream(endpoint->in_stream->stream, endpoint->read_frame.data, STREAM_SAMPLES_PER_PACKET(endpoint->in_stream), endpoint->inchan, &endpoint->read_timer); From 1509aa6371d915d111248a208ddc775c5eb97d7f Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 20 Mar 2011 03:26:01 -0400 Subject: [PATCH 015/163] mod_portaudio: update config --- conf/autoload_configs/portaudio.conf.xml | 43 ++++++++++++++++++------ 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/conf/autoload_configs/portaudio.conf.xml b/conf/autoload_configs/portaudio.conf.xml index 7389bf49cd..8de36de4a4 100644 --- a/conf/autoload_configs/portaudio.conf.xml +++ b/conf/autoload_configs/portaudio.conf.xml @@ -36,22 +36,45 @@ - - + + + + + + + - - - - + + + + + + + + + + - - + + + + - - + + + + + + + From 10ff1f43866ab6bc6ebbd2aec87dc53eea9bad93 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 20 Mar 2011 19:54:14 -0400 Subject: [PATCH 016/163] mod_portaudio: more endpoints in sample config --- conf/autoload_configs/portaudio.conf.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/conf/autoload_configs/portaudio.conf.xml b/conf/autoload_configs/portaudio.conf.xml index 8de36de4a4..8a5c9b2b42 100644 --- a/conf/autoload_configs/portaudio.conf.xml +++ b/conf/autoload_configs/portaudio.conf.xml @@ -72,6 +72,24 @@ + + + + + + + + + + + + + + + + + + From 07d574a662b6b12a0e2efbf5c984be9801a3e0f5 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 20 Mar 2011 21:45:51 -0400 Subject: [PATCH 017/163] mod_portaudio: use default global configuration when configuring streams add tons of comments to default portaudio.conf.xml for streams and endpoints --- conf/autoload_configs/portaudio.conf.xml | 148 ++++++++++++++++-- .../endpoints/mod_portaudio/mod_portaudio.c | 2 + 2 files changed, 136 insertions(+), 14 deletions(-) diff --git a/conf/autoload_configs/portaudio.conf.xml b/conf/autoload_configs/portaudio.conf.xml index 8a5c9b2b42..70fd596880 100644 --- a/conf/autoload_configs/portaudio.conf.xml +++ b/conf/autoload_configs/portaudio.conf.xml @@ -36,65 +36,185 @@ + + + + - + + + + + + + + + + + - + + + + + + - + + + + + + + + + + - + + + + + - - - - - diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 046c5293b0..21e912e968 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -1415,6 +1415,8 @@ static switch_status_t load_streams(switch_xml_t streams) stream->indev = -1; stream->outdev = -1; stream->sample_rate = globals.sample_rate; + stream->codec_ms = globals.codec_ms; + stream->channels = 1; switch_snprintf(stream->name, sizeof(stream->name), "%s", stream_name); for (param = switch_xml_child(mystream, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); From de05a6510805cfb6bfa12d9cc16fb0be219cfbc2 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sat, 30 Apr 2011 08:33:32 -0400 Subject: [PATCH 018/163] set the maximum buffer length and source members for frames returned from portaudio endpoints --- src/mod/endpoints/mod_portaudio/mod_portaudio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 21e912e968..577da2d131 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -831,6 +831,8 @@ static switch_status_t channel_endpoint_read(audio_endpoint_t *endpoint, switch_ } endpoint->read_frame.data = endpoint->read_buf; + endpoint->read_frame.buflen = sizeof(endpoint->read_buf); + endpoint->read_frame.source = __FILE__; samples = ReadAudioStream(endpoint->in_stream->stream, endpoint->read_frame.data, STREAM_SAMPLES_PER_PACKET(endpoint->in_stream), endpoint->inchan, &endpoint->read_timer); From b2d696b3fdab3738dd333a07ea3e9ad86d98b907 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 9 May 2011 00:45:31 -0400 Subject: [PATCH 019/163] make endpoint auto-answer configurable via {endpoint_answer=yes|no} in the dial string do not warn about ring device since is acceptable to not have one --- src/mod/endpoints/mod_portaudio/mod_portaudio.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 577da2d131..643daab445 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -1132,6 +1132,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi int sample_rate = 0; audio_endpoint_t *endpoint = NULL; char *endpoint_name = NULL; + const char *endpoint_answer = NULL; if (!outbound_profile) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n"); @@ -1227,7 +1228,13 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi goto error; } switch_snprintf(name, sizeof(name), "portaudio/endpoint-%s", endpoint_name); - switch_set_flag(tech_pvt, TFLAG_AUTO_ANSWER); + if (var_event && (endpoint_answer = (switch_event_get_header(var_event, "endpoint_answer")))) { + if (switch_true(endpoint_answer)) { + switch_set_flag(tech_pvt, TFLAG_AUTO_ANSWER); + } + } else { + switch_set_flag(tech_pvt, TFLAG_AUTO_ANSWER); + } endpoint->master = tech_pvt; tech_pvt->audio_endpoint = endpoint; switch_mutex_unlock(endpoint->mutex); @@ -1751,7 +1758,7 @@ static switch_status_t load_config(void) if (globals.ringdev < 0) { if (globals.outdev > -1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid ring device configured using output device\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No ring device configured, using output device\n"); globals.ringdev = globals.outdev; } } From 45fb1725b0687ce1ab7d4bce5ff61c44bdfd6afd Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 9 May 2011 01:25:24 -0400 Subject: [PATCH 020/163] added uuid_outgoing_answer to answer outgoing channels (ie portaudio endpoints) --- .../applications/mod_commands/mod_commands.c | 29 +++++++++++++++++++ .../endpoints/mod_portaudio/mod_portaudio.c | 8 +++++ 2 files changed, 37 insertions(+) diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index a6df087cb0..4a3502b35b 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -2047,6 +2047,34 @@ SWITCH_STANDARD_API(kill_function) return SWITCH_STATUS_SUCCESS; } +#define OUTGOING_ANSWER_SYNTAX "" +SWITCH_STANDARD_API(outgoing_answer_function) +{ + switch_core_session_t *asession = NULL; + char *mycmd = NULL; + + if (zstr(cmd) || !(mycmd = strdup(cmd))) { + stream->write_function(stream, "-USAGE: %s\n", OUTGOING_ANSWER_SYNTAX); + return SWITCH_STATUS_SUCCESS; + } + + if (zstr(mycmd) || !(asession = switch_core_session_locate(mycmd))) { + stream->write_function(stream, "-ERR No Such Channel!\n"); + } else { + switch_channel_t *channel = switch_core_session_get_channel(asession); + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + switch_channel_mark_answered(channel); + stream->write_function(stream, "+OK\n"); + } else { + stream->write_function(stream, "-ERR Not an outbound channel!\n"); + } + switch_core_session_rwunlock(session); + } + + switch_safe_free(mycmd); + return SWITCH_STATUS_SUCCESS; +} + #define PREPROCESS_SYNTAX "<>" SWITCH_STANDARD_API(preprocess_function) { @@ -5063,6 +5091,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "uuid_getvar", "uuid_getvar", uuid_getvar_function, GETVAR_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_hold", "hold", uuid_hold_function, HOLD_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_kill", "Kill Channel", kill_function, KILL_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "uuid_outgoing_answer", "Answer Outgoing Channel", outgoing_answer_function, OUTGOING_ANSWER_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_limit_release", "Release limit resource", uuid_limit_release_function, LIMIT_RELEASE_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_loglevel", "set loglevel on session", uuid_loglevel, UUID_LOGLEVEL_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_media", "media", uuid_media_function, MEDIA_SYNTAX); diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 643daab445..079c5af8a2 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -319,8 +319,15 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) } if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND) && !switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) { + add_pvt(tech_pvt, PA_SLAVE); + /* endpoints do not ring (yet) */ + if (tech_pvt->audio_endpoint) { + ring_file = NULL; + goto endpoint_noring; + } + ring_file = globals.ring_file; if ((val = switch_channel_get_variable(channel, "pa_ring_file"))) { ring_file = val; @@ -349,6 +356,7 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) } } } +endpoint_noring: if (switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) { switch_mutex_lock(globals.pvt_lock); From 72f2ffce5d8a9ebd0cfdc08b804496b18e773166 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 9 May 2011 01:57:01 -0400 Subject: [PATCH 021/163] mod_portaudio: check for CF_ANSWERED too --- .../endpoints/mod_portaudio/mod_portaudio.c | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 079c5af8a2..7c9a3a9841 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -318,16 +318,12 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) return SWITCH_STATUS_FALSE; } - if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND) && !switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) { + if (!tech_pvt->audio_endpoint && + switch_test_flag(tech_pvt, TFLAG_OUTBOUND) && + !switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) { add_pvt(tech_pvt, PA_SLAVE); - /* endpoints do not ring (yet) */ - if (tech_pvt->audio_endpoint) { - ring_file = NULL; - goto endpoint_noring; - } - ring_file = globals.ring_file; if ((val = switch_channel_get_variable(channel, "pa_ring_file"))) { ring_file = val; @@ -356,20 +352,23 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) } } } -endpoint_noring: - if (switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) { + if (tech_pvt->audio_endpoint || switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) { switch_mutex_lock(globals.pvt_lock); add_pvt(tech_pvt, PA_MASTER); - switch_channel_mark_answered(channel); - switch_set_flag(tech_pvt, TFLAG_ANSWER); + if (switch_test_flag(tech_pvt, TFLAG_AUTO_ANSWER)) { + switch_channel_mark_answered(channel); + switch_set_flag(tech_pvt, TFLAG_ANSWER); + } switch_mutex_unlock(globals.pvt_lock); switch_yield(1000000); } else { switch_channel_mark_ring_ready(channel); } - while (switch_channel_get_state(channel) == CS_ROUTING && !switch_test_flag(tech_pvt, TFLAG_ANSWER)) { + while (switch_channel_get_state(channel) == CS_ROUTING && + !switch_channel_test_flag(channel, CF_ANSWERED) && + !switch_test_flag(tech_pvt, TFLAG_ANSWER)) { switch_size_t olen = globals.readfile_timer.samples; if (switch_micro_time_now() - last >= waitsec) { @@ -416,10 +415,12 @@ endpoint_noring: } if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - if (!switch_test_flag(tech_pvt, TFLAG_ANSWER)) { + if (!switch_test_flag(tech_pvt, TFLAG_ANSWER) && + !switch_channel_test_flag(channel, CF_ANSWERED)) { switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER); return SWITCH_STATUS_SUCCESS; } + switch_set_flag(tech_pvt, TFLAG_ANSWER); } switch_set_flag_locked(tech_pvt, TFLAG_IO); From 690b3b5b72ef75a82d65b8f73003e4462f4c5caa Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 9 May 2011 02:32:31 -0400 Subject: [PATCH 022/163] add uuid completion to uuid_outgoing_answer fix segfault due to typo in uuid_outgoing_answer --- src/mod/applications/mod_commands/mod_commands.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 4a3502b35b..ae84463868 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -2050,7 +2050,7 @@ SWITCH_STANDARD_API(kill_function) #define OUTGOING_ANSWER_SYNTAX "" SWITCH_STANDARD_API(outgoing_answer_function) { - switch_core_session_t *asession = NULL; + switch_core_session_t *outgoing_session = NULL; char *mycmd = NULL; if (zstr(cmd) || !(mycmd = strdup(cmd))) { @@ -2058,17 +2058,17 @@ SWITCH_STANDARD_API(outgoing_answer_function) return SWITCH_STATUS_SUCCESS; } - if (zstr(mycmd) || !(asession = switch_core_session_locate(mycmd))) { + if (zstr(mycmd) || !(outgoing_session = switch_core_session_locate(mycmd))) { stream->write_function(stream, "-ERR No Such Channel!\n"); } else { - switch_channel_t *channel = switch_core_session_get_channel(asession); + switch_channel_t *channel = switch_core_session_get_channel(outgoing_session); if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { switch_channel_mark_answered(channel); stream->write_function(stream, "+OK\n"); } else { stream->write_function(stream, "-ERR Not an outbound channel!\n"); } - switch_core_session_rwunlock(session); + switch_core_session_rwunlock(outgoing_session); } switch_safe_free(mycmd); @@ -5210,6 +5210,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add uuid_hold ::console::list_uuid"); switch_console_set_complete("add uuid_jitterbuffer ::console::list_uuid"); switch_console_set_complete("add uuid_kill ::console::list_uuid"); + switch_console_set_complete("add uuid_outgoing_answer ::console::list_uuid"); switch_console_set_complete("add uuid_limit_release ::console::list_uuid"); switch_console_set_complete("add uuid_loglevel ::console::list_uuid console"); switch_console_set_complete("add uuid_loglevel ::console::list_uuid alert"); From 792149f32af962dc545d4e2b8b1342ec402a8971 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Wed, 18 May 2011 20:55:51 -0400 Subject: [PATCH 023/163] mod_portaudio: fix shared stream output device validation/initialization that caused segfault and portaudio errors --- .../endpoints/mod_portaudio/mod_portaudio.c | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 7c9a3a9841..44df30ad71 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -2293,7 +2293,8 @@ PaError open_shared_audio_stream(shared_audio_stream_t *shstream, const PaStream { PaError err; if (inputParameters->device != -1) { - err = OpenAudioStream(&shstream->stream, inputParameters, outputParameters, shstream->sample_rate, + err = OpenAudioStream(&shstream->stream, inputParameters->device != -1 ? inputParameters : NULL, + outputParameters->device != -1 ? outputParameters : NULL, shstream->sample_rate, paClipOff, STREAM_SAMPLES_PER_PACKET(shstream), globals.dual_streams); } else { err = OpenAudioStream(&shstream->stream, NULL, outputParameters, shstream->sample_rate, @@ -2319,20 +2320,25 @@ static int create_shared_audio_stream(shared_audio_stream_t *shstream) inputParameters.hostApiSpecificStreamInfo = NULL; } outputParameters.device = shstream->outdev; - outputParameters.channelCount = shstream->channels; - outputParameters.sampleFormat = SAMPLE_TYPE; - outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; + if (shstream->outdev != -1) { + outputParameters.channelCount = shstream->channels; + outputParameters.sampleFormat = SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + } err = open_shared_audio_stream(shstream, &inputParameters, &outputParameters); if (err != paNoError) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening audio device retrying\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Error opening audio device retrying (indev = %d, outdev = %d, error = %s)\n", + inputParameters.device, outputParameters.device, Pa_GetErrorText(err)); switch_yield(1000000); err = open_shared_audio_stream(shstream, &inputParameters, &outputParameters); } if (err != paNoError) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open audio device\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open audio device (indev = %d, outdev = %d, error = %s)\n", + inputParameters.device, outputParameters.device, Pa_GetErrorText(err)); if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_ERROR_AUDIO_DEV) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Reason", Pa_GetErrorText(err)); switch_event_fire(&event); From 267d9cbc3adcb291eadfc4647ef3797876e4a2e1 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 20 May 2011 02:28:42 -0400 Subject: [PATCH 024/163] mod_portaudio: few more checks on write --- src/mod/endpoints/mod_portaudio/mod_portaudio.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 44df30ad71..743a6568fb 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -969,6 +969,15 @@ static switch_status_t channel_endpoint_write(audio_endpoint_t *endpoint, switch switch_core_timer_next(&endpoint->write_timer); return SWITCH_STATUS_SUCCESS; } + if (!endpoint->master) { + return SWITCH_STATUS_SUCCESS; + } + if (switch_test_flag(endpoint->master, TFLAG_HUP)) { + return SWITCH_STATUS_FALSE; + } + if (!switch_test_flag(endpoint->master, TFLAG_IO)) { + return SWITCH_STATUS_SUCCESS; + } WriteAudioStream(endpoint->out_stream->stream, (short *)frame->data, (int)(frame->datalen / sizeof(SAMPLE)), endpoint->outchan, &(endpoint->write_timer)); From 765908f356916bf248c71dae6c395c16276db0a5 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Sun, 22 May 2011 19:10:52 -0500 Subject: [PATCH 025/163] FS-3152 --resolve dup_dest was being overwritten by switch_split_user_domain --- src/mod/endpoints/mod_sofia/sofia_presence.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 3259808d4d..6c7c0cf648 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -195,15 +195,9 @@ switch_status_t sofia_presence_chat_send(const char *proto, const char *from, co } - if (dst->route_uri) { - remote_host = strdup(dst->route_uri); - if (!zstr(remote_host)) { - switch_split_user_domain(remote_host, NULL, &remote_ip); - } - } - - if (zstr(remote_ip)) { - switch_split_user_domain(dup_dest, NULL, &remote_ip); + remote_host = strdup(dup_dest); + if (!zstr(remote_host)) { + switch_split_user_domain(remote_host, NULL, &remote_ip); } if (!zstr(remote_ip) && sofia_glue_check_nat(profile, remote_ip)) { From 34a008d2d76fc61d183d4da4d3fa22f9ac28e25d Mon Sep 17 00:00:00 2001 From: Brian West Date: Mon, 23 May 2011 10:56:22 -0500 Subject: [PATCH 026/163] swigall --- .../languages/mod_managed/freeswitch_wrap.cxx | 178 ++++++++++++++++++ src/mod/languages/mod_managed/managed/swig.cs | 153 +++++++++++++++ 2 files changed, 331 insertions(+) diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.cxx index d1c0dfcb31..f2aebaf078 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.cxx @@ -5710,6 +5710,35 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_switch_app_log_arg_get(void * jarg1) { } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_app_log_stamp_set(void * jarg1, void * jarg2) { + switch_app_log *arg1 = (switch_app_log *) 0 ; + switch_time_t arg2 ; + switch_time_t *argp2 ; + + arg1 = (switch_app_log *)jarg1; + argp2 = (switch_time_t *)jarg2; + if (!argp2) { + SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null switch_time_t", 0); + return ; + } + arg2 = *argp2; + if (arg1) (arg1)->stamp = arg2; + +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_switch_app_log_stamp_get(void * jarg1) { + void * jresult ; + switch_app_log *arg1 = (switch_app_log *) 0 ; + switch_time_t result; + + arg1 = (switch_app_log *)jarg1; + result = ((arg1)->stamp); + jresult = new switch_time_t((switch_time_t &)result); + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_app_log_next_set(void * jarg1, void * jarg2) { switch_app_log *arg1 = (switch_app_log *) 0 ; switch_app_log *arg2 = (switch_app_log *) 0 ; @@ -6926,6 +6955,30 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_add_state_handler(void * jarg1) { } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_curl_count(void * jarg1) { + int jresult ; + int *arg1 = (int *) 0 ; + int result; + + arg1 = (int *)jarg1; + result = (int)switch_core_curl_count(arg1); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_ssl_count(void * jarg1) { + int jresult ; + int *arg1 = (int *) 0 ; + int result; + + arg1 = (int *)jarg1; + result = (int)switch_core_ssl_count(arg1); + jresult = result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_core_remove_state_handler(void * jarg1) { switch_state_handler_table_t *arg1 = (switch_state_handler_table_t *) 0 ; @@ -13455,6 +13508,108 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_split_user_domain(char * jarg1, void * } +SWIGEXPORT void SWIGSTDCALL CSharp_profile_node_t_var_set(void * jarg1, char * jarg2) { + profile_node_t *arg1 = (profile_node_t *) 0 ; + char *arg2 = (char *) 0 ; + + arg1 = (profile_node_t *)jarg1; + arg2 = (char *)jarg2; + { + if (arg1->var) delete [] arg1->var; + if (arg2) { + arg1->var = (char *) (new char[strlen((const char *)arg2)+1]); + strcpy((char *)arg1->var, (const char *)arg2); + } else { + arg1->var = 0; + } + } +} + + +SWIGEXPORT char * SWIGSTDCALL CSharp_profile_node_t_var_get(void * jarg1) { + char * jresult ; + profile_node_t *arg1 = (profile_node_t *) 0 ; + char *result = 0 ; + + arg1 = (profile_node_t *)jarg1; + result = (char *) ((arg1)->var); + jresult = SWIG_csharp_string_callback((const char *)result); + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_profile_node_t_val_set(void * jarg1, char * jarg2) { + profile_node_t *arg1 = (profile_node_t *) 0 ; + char *arg2 = (char *) 0 ; + + arg1 = (profile_node_t *)jarg1; + arg2 = (char *)jarg2; + { + if (arg1->val) delete [] arg1->val; + if (arg2) { + arg1->val = (char *) (new char[strlen((const char *)arg2)+1]); + strcpy((char *)arg1->val, (const char *)arg2); + } else { + arg1->val = 0; + } + } +} + + +SWIGEXPORT char * SWIGSTDCALL CSharp_profile_node_t_val_get(void * jarg1) { + char * jresult ; + profile_node_t *arg1 = (profile_node_t *) 0 ; + char *result = 0 ; + + arg1 = (profile_node_t *)jarg1; + result = (char *) ((arg1)->val); + jresult = SWIG_csharp_string_callback((const char *)result); + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_profile_node_t_next_set(void * jarg1, void * jarg2) { + profile_node_t *arg1 = (profile_node_t *) 0 ; + profile_node_s *arg2 = (profile_node_s *) 0 ; + + arg1 = (profile_node_t *)jarg1; + arg2 = (profile_node_s *)jarg2; + if (arg1) (arg1)->next = arg2; + +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_profile_node_t_next_get(void * jarg1) { + void * jresult ; + profile_node_t *arg1 = (profile_node_t *) 0 ; + profile_node_s *result = 0 ; + + arg1 = (profile_node_t *)jarg1; + result = (profile_node_s *) ((arg1)->next); + jresult = (void *)result; + return jresult; +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_new_profile_node_t() { + void * jresult ; + profile_node_t *result = 0 ; + + result = (profile_node_t *)new profile_node_t(); + jresult = (void *)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_delete_profile_node_t(void * jarg1) { + profile_node_t *arg1 = (profile_node_t *) 0 ; + + arg1 = (profile_node_t *)jarg1; + delete arg1; + +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_caller_profile_username_set(void * jarg1, char * jarg2) { switch_caller_profile *arg1 = (switch_caller_profile *) 0 ; char *arg2 = (char *) 0 ; @@ -14336,6 +14491,29 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_caller_profile_direction_get(void * jar } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_caller_profile_soft_set(void * jarg1, void * jarg2) { + switch_caller_profile *arg1 = (switch_caller_profile *) 0 ; + profile_node_t *arg2 = (profile_node_t *) 0 ; + + arg1 = (switch_caller_profile *)jarg1; + arg2 = (profile_node_t *)jarg2; + if (arg1) (arg1)->soft = arg2; + +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_switch_caller_profile_soft_get(void * jarg1) { + void * jresult ; + switch_caller_profile *arg1 = (switch_caller_profile *) 0 ; + profile_node_t *result = 0 ; + + arg1 = (switch_caller_profile *)jarg1; + result = (profile_node_t *) ((arg1)->soft); + jresult = (void *)result; + return jresult; +} + + SWIGEXPORT void * SWIGSTDCALL CSharp_new_switch_caller_profile() { void * jresult ; switch_caller_profile *result = 0 ; diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs index d06e9881d4..33e754b8b7 100644 --- a/src/mod/languages/mod_managed/managed/swig.cs +++ b/src/mod/languages/mod_managed/managed/swig.cs @@ -1151,6 +1151,16 @@ public class freeswitch { return ret; } + public static int switch_core_curl_count(SWIGTYPE_p_int val) { + int ret = freeswitchPINVOKE.switch_core_curl_count(SWIGTYPE_p_int.getCPtr(val)); + return ret; + } + + public static int switch_core_ssl_count(SWIGTYPE_p_int val) { + int ret = freeswitchPINVOKE.switch_core_ssl_count(SWIGTYPE_p_int.getCPtr(val)); + return ret; + } + public static void switch_core_remove_state_handler(switch_state_handler_table state_handler) { freeswitchPINVOKE.switch_core_remove_state_handler(switch_state_handler_table.getCPtr(state_handler)); } @@ -7272,6 +7282,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_app_log_arg_get")] public static extern string switch_app_log_arg_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_app_log_stamp_set")] + public static extern void switch_app_log_stamp_set(HandleRef jarg1, HandleRef jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_app_log_stamp_get")] + public static extern IntPtr switch_app_log_stamp_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_app_log_next_set")] public static extern void switch_app_log_next_set(HandleRef jarg1, HandleRef jarg2); @@ -7566,6 +7582,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_core_add_state_handler")] public static extern int switch_core_add_state_handler(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_curl_count")] + public static extern int switch_core_curl_count(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_ssl_count")] + public static extern int switch_core_ssl_count(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_remove_state_handler")] public static extern void switch_core_remove_state_handler(HandleRef jarg1); @@ -9009,6 +9031,30 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_split_user_domain")] public static extern int switch_split_user_domain(string jarg1, ref string jarg2, ref string jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_profile_node_t_var_set")] + public static extern void profile_node_t_var_set(HandleRef jarg1, string jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_profile_node_t_var_get")] + public static extern string profile_node_t_var_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_profile_node_t_val_set")] + public static extern void profile_node_t_val_set(HandleRef jarg1, string jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_profile_node_t_val_get")] + public static extern string profile_node_t_val_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_profile_node_t_next_set")] + public static extern void profile_node_t_next_set(HandleRef jarg1, HandleRef jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_profile_node_t_next_get")] + public static extern IntPtr profile_node_t_next_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_new_profile_node_t")] + public static extern IntPtr new_profile_node_t(); + + [DllImport("mod_managed", EntryPoint="CSharp_delete_profile_node_t")] + public static extern void delete_profile_node_t(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_caller_profile_username_set")] public static extern void switch_caller_profile_username_set(HandleRef jarg1, string jarg2); @@ -9213,6 +9259,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_caller_profile_direction_get")] public static extern int switch_caller_profile_direction_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_caller_profile_soft_set")] + public static extern void switch_caller_profile_soft_set(HandleRef jarg1, HandleRef jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_caller_profile_soft_get")] + public static extern IntPtr switch_caller_profile_soft_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_new_switch_caller_profile")] public static extern IntPtr new_switch_caller_profile(); @@ -14456,6 +14508,84 @@ public partial class ManagedSession : CoreSession { namespace FreeSWITCH.Native { +using System; +using System.Runtime.InteropServices; + +public class profile_node_t : IDisposable { + private HandleRef swigCPtr; + protected bool swigCMemOwn; + + internal profile_node_t(IntPtr cPtr, bool cMemoryOwn) { + swigCMemOwn = cMemoryOwn; + swigCPtr = new HandleRef(this, cPtr); + } + + internal static HandleRef getCPtr(profile_node_t obj) { + return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr; + } + + ~profile_node_t() { + Dispose(); + } + + public virtual void Dispose() { + lock(this) { + if(swigCPtr.Handle != IntPtr.Zero && swigCMemOwn) { + swigCMemOwn = false; + freeswitchPINVOKE.delete_profile_node_t(swigCPtr); + } + swigCPtr = new HandleRef(null, IntPtr.Zero); + GC.SuppressFinalize(this); + } + } + + public string var { + set { + freeswitchPINVOKE.profile_node_t_var_set(swigCPtr, value); + } + get { + string ret = freeswitchPINVOKE.profile_node_t_var_get(swigCPtr); + return ret; + } + } + + public string val { + set { + freeswitchPINVOKE.profile_node_t_val_set(swigCPtr, value); + } + get { + string ret = freeswitchPINVOKE.profile_node_t_val_get(swigCPtr); + return ret; + } + } + + public profile_node_t next { + set { + freeswitchPINVOKE.profile_node_t_next_set(swigCPtr, profile_node_t.getCPtr(value)); + } + get { + IntPtr cPtr = freeswitchPINVOKE.profile_node_t_next_get(swigCPtr); + profile_node_t ret = (cPtr == IntPtr.Zero) ? null : new profile_node_t(cPtr, false); + return ret; + } + } + + public profile_node_t() : this(freeswitchPINVOKE.new_profile_node_t(), true) { + } + +} + +} +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.35 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +namespace FreeSWITCH.Native { + [System.Flags] public enum session_flag_t { S_HUP = (1 << 0), S_FREE = (1 << 1), @@ -19936,6 +20066,18 @@ public class switch_app_log : IDisposable { } } + public SWIGTYPE_p_switch_time_t stamp { + set { + freeswitchPINVOKE.switch_app_log_stamp_set(swigCPtr, SWIGTYPE_p_switch_time_t.getCPtr(value)); + if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); + } + get { + SWIGTYPE_p_switch_time_t ret = new SWIGTYPE_p_switch_time_t(freeswitchPINVOKE.switch_app_log_stamp_get(swigCPtr), true); + if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + } + public switch_app_log next { set { freeswitchPINVOKE.switch_app_log_next_set(swigCPtr, switch_app_log.getCPtr(value)); @@ -21775,6 +21917,17 @@ public class switch_caller_profile : IDisposable { } } + public profile_node_t soft { + set { + freeswitchPINVOKE.switch_caller_profile_soft_set(swigCPtr, profile_node_t.getCPtr(value)); + } + get { + IntPtr cPtr = freeswitchPINVOKE.switch_caller_profile_soft_get(swigCPtr); + profile_node_t ret = (cPtr == IntPtr.Zero) ? null : new profile_node_t(cPtr, false); + return ret; + } + } + public switch_caller_profile() : this(freeswitchPINVOKE.new_switch_caller_profile(), true) { } From 62c81afef0e2d13979daf08c85a87c3d56c2f5b8 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 23 May 2011 12:23:30 -0500 Subject: [PATCH 027/163] init ssl locks in sofia --- src/mod/endpoints/mod_sofia/mod_sofia.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index c9ea6790b7..c258e62dd7 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -37,6 +37,8 @@ /*************************************************************************************************************************************************************/ #include "mod_sofia.h" #include "sofia-sip/sip_extra.h" +#include + SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown); SWITCH_MODULE_DEFINITION(mod_sofia, mod_sofia_load, mod_sofia_shutdown, NULL); @@ -4951,6 +4953,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) switch_management_interface_t *management_interface; struct in_addr in; + switch_ssl_init_ssl_locks(); + memset(&mod_sofia_globals, 0, sizeof(mod_sofia_globals)); mod_sofia_globals.destroy_private.destroy_nh = 1; mod_sofia_globals.destroy_private.is_static = 1; @@ -5154,6 +5158,8 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown) switch_core_hash_destroy(&mod_sofia_globals.gateway_hash); switch_mutex_unlock(mod_sofia_globals.hash_mutex); + switch_ssl_destroy_ssl_locks(); + return SWITCH_STATUS_SUCCESS; } From 50e54364e3458efa2deceb9aa6dbf95cdc72a4e4 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 23 May 2011 13:20:33 -0500 Subject: [PATCH 028/163] FS-3308 --resolve --- src/switch_apr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/switch_apr.c b/src/switch_apr.c index 495e0605a8..fe7442b57f 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -697,10 +697,10 @@ SWITCH_DECLARE(switch_status_t) switch_socket_send(switch_socket_t *sock, const switch_size_t req = *len, wrote = 0, need = *len; int to_count = 0; - while ((wrote < req && status == SWITCH_STATUS_SUCCESS) || (need == 0 && status == SWITCH_STATUS_BREAK) || status == 730035) { + while ((wrote < req && status == SWITCH_STATUS_SUCCESS) || (need == 0 && status == SWITCH_STATUS_BREAK) || status == 730035 || status == 35) { need = req - wrote; status = apr_socket_send(sock, buf + wrote, &need); - if (status == SWITCH_STATUS_BREAK || status == 730035) { + if (status == SWITCH_STATUS_BREAK || status == 730035 || status == 35) { if (++to_count > 10000000) { status = SWITCH_STATUS_FALSE; break; From 8bbfcd9c7ffb57cae9efa21453b8e1ce4ae1c849 Mon Sep 17 00:00:00 2001 From: Michael S Collins Date: Mon, 23 May 2011 14:39:04 -0700 Subject: [PATCH 029/163] Update ChangeLog through May 22 --- docs/ChangeLog | 55 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/docs/ChangeLog b/docs/ChangeLog index b4e93ab05c..379a1045f8 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -43,6 +43,10 @@ freeswitch (1.0.7) config: add default to conf to demonstrate min-idle-cpu (r:b8b7266a) config: change min/max enforcements to >= instead of > (r:0d5fcf65) config: Add README_IMPORTANT.txt to default configuration (r:6cd5ce72) + config: Talking clock dialplan example (Thanks AviMarcus) (r:ffb4a3ae) + config: fix talking clock regexes (need ^ and $ so they don't match only 917x) (r:8529ba33) + config: Update phrase_en.xml to reflect 1.0.16 sounds version (r:7499dfb2) + config: bump en sounds version to 1.0.16 (r:50ce2cae) core: Add RTCP support (FSRTP-14) core: handle some errors on missing db handle conditions core: add ... and shutdown as a fail-safe when no modules are loaded @@ -245,6 +249,18 @@ freeswitch (1.0.7) core: enable optimal defaults on linux kernels that can support newer features. (r:0b51aca3) core: Lower NAT port mapping disabled log msg from WARNING to INFO (r:973a850d) core: Change the structure of the phrases/language system. Previously it was fxml->phrases->macros->language->macro. Changed it so fxml->languages->language->phrases->macros->macro You can have sub macros and allow you to call it login@voicemail. Change the sound-path to sound-prefix to make it constistant with the rest of freeswitch. Also allow to set a sound-prefix to a macros, so you can override it for a specific file set. You can set say-modules="en" or whatever in the