From df43e51ca5b893fcaaaf50ba8d98051b2d6a3fb2 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 17 Mar 2011 21:46:52 -0400 Subject: [PATCH 01/64] 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 02/64] 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 03/64] 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 04/64] 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 05/64] 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 06/64] 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 07/64] 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 08/64] 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 09/64] 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 10/64] 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 11/64] 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 12/64] 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 13/64] 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 14/64] 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 15/64] 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 16/64] 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 17/64] 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 18/64] 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 19/64] 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 20/64] 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 21/64] 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 22/64] 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 23/64] 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 24/64] 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 294a57fbcbaaaff3c6401d3e9c1523e3dfa9f0e8 Mon Sep 17 00:00:00 2001 From: System Administrator Date: Wed, 25 May 2011 23:16:24 -0400 Subject: [PATCH 25/64] allow -1 as silence generation divisor to specify only zeroes silence --- src/include/switch_ivr.h | 6 ++++++ src/switch_ivr.c | 8 +++++++- src/switch_ivr_originate.c | 4 +--- src/switch_resample.c | 5 +++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 9b353f3ded..6df047e9cc 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -62,6 +62,12 @@ SWITCH_BEGIN_EXTERN_C struct switch_unicast_conninfo { }; typedef struct switch_unicast_conninfo switch_unicast_conninfo_t; +#define SWITCH_IVR_VERIFY_SILENCE_DIVISOR(divisor) \ + do { \ + if ((divisor) <= 0 && (divisor) != -1) { \ + divisor = 400; \ + } \ + } while(0); /** * @defgroup switch_ivr IVR Library diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 5a082763b2..81be1893f1 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -154,7 +154,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session, return SWITCH_STATUS_SUCCESS; } - if (ms > 100 && (var = switch_channel_get_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE)) && (sval = atoi(var))) { + var = switch_channel_get_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE); + if (var) { + sval = atoi(var); + SWITCH_IVR_VERIFY_SILENCE_DIVISOR(sval); + } + + if (ms > 100 && sval) { switch_core_session_get_read_impl(session, &imp); if (switch_core_codec_init(&codec, diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 92137ea5d8..33951d5a97 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -910,9 +910,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t ringback.silence = atoi(p); } } - if (ringback.silence <= 0) { - ringback.silence = 400; - } + SWITCH_IVR_VERIFY_SILENCE_DIVISOR(ringback.silence); } else { switch_buffer_create_dynamic(&ringback.audio_buffer, 512, 1024, 0); switch_buffer_set_loops(ringback.audio_buffer, -1); diff --git a/src/switch_resample.c b/src/switch_resample.c index 9c7f9b95d2..7355384915 100644 --- a/src/switch_resample.c +++ b/src/switch_resample.c @@ -190,6 +190,11 @@ SWITCH_DECLARE(void) switch_generate_sln_silence(int16_t *data, uint32_t samples assert(divisor); + if (divisor == (uint32_t)-1) { + memset(data, 0, sizeof(*data)); + return; + } + for (i = 0; i < samples; i++, sum_rnd = 0) { for (x = 0; x < 6; x++) { rnd2 = rnd2 * 31821U + 13849U; From 65b231f5a4450b903c0975ab1c8c6d470c0ab67f Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 26 May 2011 00:21:59 -0400 Subject: [PATCH 26/64] restore default config valus for portaudio.conf.xml --- conf/autoload_configs/portaudio.conf.xml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/conf/autoload_configs/portaudio.conf.xml b/conf/autoload_configs/portaudio.conf.xml index 70fd596880..02c21ef449 100644 --- a/conf/autoload_configs/portaudio.conf.xml +++ b/conf/autoload_configs/portaudio.conf.xml @@ -5,14 +5,12 @@ or the device number prefixed with # eg "#1" (or blank for default) --> - + - - + - - + @@ -31,8 +29,7 @@ - - + From ba76388cb2b198e3a96783efe5de5b566fbabd05 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 26 May 2011 02:23:34 -0400 Subject: [PATCH 27/64] fix missing ringback silence calculation spot in switch_ivr_originate --- src/switch_ivr_originate.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 264263a2e6..78b553601b 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1201,9 +1201,7 @@ static switch_status_t setup_ringback(originate_global_t *oglobals, originate_st ringback->silence = atoi(c); } } - if (ringback->silence <= 0) { - ringback->silence = 400; - } + SWITCH_IVR_VERIFY_SILENCE_DIVISOR(ringback->silence); } else { switch_buffer_create_dynamic(&ringback->audio_buffer, 512, 1024, 0); switch_buffer_set_loops(ringback->audio_buffer, -1); From 3a918f3333be90172df2a039815d1358a220c59a Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 26 May 2011 17:41:17 -0400 Subject: [PATCH 28/64] mod_sangoma_codec: do not use the provided session void* to store the rtp port --- src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c index 52782ad983..322da31272 100644 --- a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c +++ b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c @@ -224,7 +224,7 @@ static int sangoma_create_rtp_port(void *usr_priv, uint32_t host_ip, uint32_t *p switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "New allocated port %d for IP %s/%d.%d.%d.%d\n", rtp_port, local_ip, SNGTC_NIPV4(host_ip)); *p_rtp_port = rtp_port; - *rtp_fd = (void *)(long)rtp_port; + *rtp_fd = NULL; return 0; } @@ -259,6 +259,9 @@ static int sangoma_create_rtp(void *usr_priv, sngtc_codec_request_leg_t *codec_r switch_port_t rtp_port; struct sangoma_transcoding_session *sess = usr_priv; + rtp_port = codec_req_leg->host_udp_port; + *rtp_fd = NULL; + /* * We *MUST* use a new pool * Do not use the session pool since the session may go away while the RTP socket should linger around @@ -271,11 +274,6 @@ static int sangoma_create_rtp(void *usr_priv, sngtc_codec_request_leg_t *codec_r return -1; } - rtp_port = (switch_port_t)(long)*rtp_fd; - *rtp_fd = NULL; - - codec_req_leg->host_udp_port = rtp_port; - local_ip_addr.s_addr = htonl(codec_req_leg->host_ip); switch_inet_ntop(AF_INET, &local_ip_addr, local_ip, sizeof(local_ip)); sngtc_codec_ipv4_hex_to_str(codec_reply_leg->codec_ip, codec_ip); From 8035d498eaec367b14136476b9541de9cba04540 Mon Sep 17 00:00:00 2001 From: Stefan Knoblich Date: Fri, 27 May 2011 10:58:51 +0200 Subject: [PATCH 29/64] ftmod_zt: Add ZT_EVENT_ABORT event handling and update ZT_EVENT_OVERRUN error message. ZT_EVENT_ABORT and ZT_EVENT_OVERRUN are HDLC events. Signed-off-by: Stefan Knoblich --- libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c index 9c01b41299..b77fde0ffa 100644 --- a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c +++ b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c @@ -1066,16 +1066,20 @@ static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, break; case ZT_EVENT_BADFCS: { - ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Bad frame checksum (ZT_EVENT_BADFCS)!\n"); - /* What else could we do? */ - *event_id = FTDM_OOB_NOOP; + ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Bad frame checksum (ZT_EVENT_BADFCS)\n"); + *event_id = FTDM_OOB_NOOP; /* What else could we do? */ } break; case ZT_EVENT_OVERRUN: { - ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Driver overrun! (ZT_EVENT_OVERRUN)\n"); - /* What else could we do? */ - *event_id = FTDM_OOB_NOOP; + ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "HDLC frame overrun (ZT_EVENT_OVERRUN)\n"); + *event_id = FTDM_OOB_NOOP; /* What else could we do? */ + } + break; + case ZT_EVENT_ABORT: + { + ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "HDLC abort frame received (ZT_EVENT_ABORT)\n"); + *event_id = FTDM_OOB_NOOP; /* What else could we do? */ } break; case ZT_EVENT_NONE: From e03d900c23789038c4f5bc62fc8c58c9e616932d Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 27 May 2011 09:38:54 -0500 Subject: [PATCH 30/64] FS-3300 --resolve --- src/mod/endpoints/mod_sofia/mod_sofia.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 99c00424dc..fbff334ab2 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -4634,7 +4634,7 @@ static void general_event_handler(switch_event_t *event) id = switch_mprintf("sip:%s@%s", user, host); switch_assert(id); - + for (m = list->head; m; m = m->next) { contact = sofia_glue_get_url_from_contact(m->val, 0); @@ -4647,10 +4647,9 @@ static void general_event_handler(switch_event_t *event) nua_message(nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_IF(!zstr(subject), SIPTAG_SUBJECT_STR(subject)), TAG_END()); - - - free(id); } + + free(id); switch_console_free_matches(&list); sofia_glue_release_profile(profile); From 01d0250ee6569ceba108e24c6ffd67d89e4f9833 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 27 May 2011 09:49:02 -0500 Subject: [PATCH 31/64] FS-1986 --resolve Come To ClueCon 2011 http://www.cluecon.com --- src/mod/applications/mod_dptools/mod_dptools.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index e0b8e0aa93..c98e632f94 100755 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -2529,8 +2529,7 @@ SWITCH_STANDARD_APP(audio_bridge_function) char *tof_data = NULL; char *tof_array[4] = { 0 }; //int tof_arrayc = 0; - const char *continue_on_fail = NULL, *failure_causes = NULL, - *v_campon = NULL, *v_campon_retries, *v_campon_sleep, *v_campon_timeout, *v_campon_fallback_exten = NULL; + const char *v_campon = NULL, *v_campon_retries, *v_campon_sleep, *v_campon_timeout, *v_campon_fallback_exten = NULL; switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING; int campon_retries = 100, campon_timeout = 10, campon_sleep = 10, tmp, camping = 0, fail = 0, thread_started = 0; struct camping_stake stake = { 0 }; @@ -2544,15 +2543,11 @@ SWITCH_STANDARD_APP(audio_bridge_function) return; } - continue_on_fail = switch_channel_get_variable(caller_channel, "continue_on_fail"); - transfer_on_fail = switch_channel_get_variable(caller_channel, "transfer_on_fail"); tof_data = switch_core_session_strdup(session, transfer_on_fail); switch_split(tof_data, ' ', tof_array); transfer_on_fail = tof_array[0]; - failure_causes = switch_channel_get_variable(caller_channel, "failure_causes"); - if ((v_campon = switch_channel_get_variable(caller_channel, "campon")) && switch_true(v_campon)) { const char *cid_name = NULL; const char *cid_number = NULL; @@ -2693,6 +2688,11 @@ SWITCH_STANDARD_APP(audio_bridge_function) EXCEPTION... ATTENDED_TRANSFER never is a reason to continue....... */ if (cause != SWITCH_CAUSE_ATTENDED_TRANSFER) { + const char *continue_on_fail = NULL, *failure_causes = NULL; + + continue_on_fail = switch_channel_get_variable(caller_channel, "continue_on_fail"); + failure_causes = switch_channel_get_variable(caller_channel, "failure_causes"); + if (continue_on_fail || failure_causes) { const char *cause_str; char cause_num[35] = ""; From 0ac088e32c029462e502d625ddc653aa660ff3c2 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 27 May 2011 09:51:05 -0500 Subject: [PATCH 32/64] FS-3313 --resolve Come To ClueCon 2011 http://www.cluecon.com --- src/mod/endpoints/mod_sofia/sofia.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index be24a00d98..329db32582 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1326,6 +1326,10 @@ void *SWITCH_THREAD_FUNC sofia_profile_worker_thread_run(switch_thread_t *thread (statements == 0 || (statements <= 1024 && (switch_micro_time_now() - last_commit)/1000 < profile->trans_timeout)))) { switch_interval_time_t sleepy_time = !statements ? 1000000 : switch_micro_time_now() - last_commit - profile->trans_timeout*1000; + + if (sleepy_time < 1000 || sleepy_time > 1000000) { + sleepy_time = 1000; + } if (sql || (switch_queue_pop_timeout(profile->sql_queue, &pop, sleepy_time) == SWITCH_STATUS_SUCCESS && pop)) { switch_size_t newlen; From 9d756ecc777ca2158ca384bd28fddfc064d6e91a Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Fri, 27 May 2011 12:24:48 -0400 Subject: [PATCH 33/64] FS-3320 --resolve --- libs/esl/src/esl_event.c | 3 +-- src/switch_event.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libs/esl/src/esl_event.c b/libs/esl/src/esl_event.c index 8280f3e892..28723928e3 100644 --- a/libs/esl/src/esl_event.c +++ b/libs/esl/src/esl_event.c @@ -365,7 +365,6 @@ ESL_DECLARE(int) esl_event_add_array(esl_event_t *event, const char *var, const { char *data; char **array; - int idx; int max = 0; int len; const char *p; @@ -395,7 +394,7 @@ ESL_DECLARE(int) esl_event_add_array(esl_event_t *event, const char *var, const esl_assert(array); memset(array, 0, len); - idx = esl_separate_string_string(data, "|:", array, max); + esl_separate_string_string(data, "|:", array, max); for(i = 0; i < max; i++) { esl_event_add_header_string(event, ESL_STACK_PUSH, var, array[i]); diff --git a/src/switch_event.c b/src/switch_event.c index 79881e69ae..f362bb112b 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -856,7 +856,6 @@ SWITCH_DECLARE(int) switch_event_add_array(switch_event_t *event, const char *va { char *data; char **array; - int idx; int max = 0; int len; const char *p; @@ -887,7 +886,7 @@ SWITCH_DECLARE(int) switch_event_add_array(switch_event_t *event, const char *va array = malloc(len); memset(array, 0, len); - idx = switch_separate_string_string(data, "|:", array, max); + switch_separate_string_string(data, "|:", array, max); for(i = 0; i < max; i++) { switch_event_add_header_string(event, SWITCH_STACK_PUSH, var, array[i]); From 42f10a48c3529d5700ab610b90874aba33fe5b6d Mon Sep 17 00:00:00 2001 From: Michael S Collins Date: Fri, 27 May 2011 09:55:50 -0700 Subject: [PATCH 34/64] Add ivr/ subdir to conf/lang/en/en.xml --- conf/lang/en/en.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/lang/en/en.xml b/conf/lang/en/en.xml index 1e23dc5d7b..2ccd513823 100644 --- a/conf/lang/en/en.xml +++ b/conf/lang/en/en.xml @@ -6,6 +6,7 @@ + From d1169d6e974ad097f209af87773f30108c4a19e7 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 27 May 2011 18:09:06 -0400 Subject: [PATCH 35/64] mod_portaudio_stream: update to specify the channel index --- src/mod/formats/mod_portaudio_stream/mod_portaudio_stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/formats/mod_portaudio_stream/mod_portaudio_stream.c b/src/mod/formats/mod_portaudio_stream/mod_portaudio_stream.c index 1ad1645554..b7e49e9e24 100644 --- a/src/mod/formats/mod_portaudio_stream/mod_portaudio_stream.c +++ b/src/mod/formats/mod_portaudio_stream/mod_portaudio_stream.c @@ -285,7 +285,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void samples = 0; switch_mutex_lock(source->device_lock); samples = ReadAudioStream(source->audio_stream, source->databuf, - source->read_codec.implementation->samples_per_packet, &source->timer); + source->read_codec.implementation->samples_per_packet, 0, &source->timer); switch_mutex_unlock(source->device_lock); From a405b779c97b0599b4f6653ce6112bda005f6d19 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 27 May 2011 19:14:00 -0500 Subject: [PATCH 36/64] FS-3319 --resolve --- src/mod/applications/mod_fsv/mod_fsv.c | 90 ++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 5 deletions(-) diff --git a/src/mod/applications/mod_fsv/mod_fsv.c b/src/mod/applications/mod_fsv/mod_fsv.c index 7b59796d99..a4c8969621 100644 --- a/src/mod/applications/mod_fsv/mod_fsv.c +++ b/src/mod/applications/mod_fsv/mod_fsv.c @@ -51,6 +51,7 @@ struct record_helper { switch_mutex_t *mutex; int fd; int up; + switch_size_t shared_ts; }; static void *SWITCH_THREAD_FUNC record_video_thread(switch_thread_t *thread, void *obj) @@ -63,7 +64,7 @@ static void *SWITCH_THREAD_FUNC record_video_thread(switch_thread_t *thread, voi int bytes; eh->up = 1; - while (switch_channel_ready(channel)) { + while (switch_channel_ready(channel) && eh->up) { status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); if (!SWITCH_READ_ACCEPTABLE(status)) { @@ -108,11 +109,13 @@ SWITCH_STANDARD_APP(record_fsv_function) switch_mutex_t *mutex = NULL; switch_codec_t codec, *vid_codec; switch_codec_implementation_t read_impl = { 0 }; + switch_dtmf_t dtmf = { 0 }; int count = 0, sanity = 30; switch_core_session_get_read_impl(session, &read_impl); switch_channel_answer(channel); + switch_channel_set_variable(channel, SWITCH_PLAYBACK_TERMINATOR_USED, ""); while (switch_channel_up(channel) && !switch_channel_test_flag(channel, CF_VIDEO)) { switch_yield(10000); @@ -125,6 +128,7 @@ SWITCH_STANDARD_APP(record_fsv_function) if (!--sanity) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s timeout waiting for video.\n", switch_channel_get_name(channel)); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "Got timeout while waiting for video"); return; } } @@ -132,11 +136,13 @@ SWITCH_STANDARD_APP(record_fsv_function) if (!switch_channel_ready(channel)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "%s not ready.\n", switch_channel_get_name(channel)); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "Channel not ready"); return; } if ((fd = open((char *) data, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR)) < 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error opening file %s\n", (char *) data); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "Got error while opening file"); return; } @@ -150,6 +156,7 @@ SWITCH_STANDARD_APP(record_fsv_function) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Activation Success\n"); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Audio Codec Activation Fail\n"); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "Audio codec activation failed"); goto end; } @@ -170,6 +177,7 @@ SWITCH_STANDARD_APP(record_fsv_function) h.audio_ptime = read_impl.microseconds_per_packet / 1000; if (write(fd, &h, sizeof(h)) != sizeof(h)) { + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "File write failed"); goto end; } @@ -186,9 +194,37 @@ SWITCH_STANDARD_APP(record_fsv_function) while (switch_channel_ready(channel)) { - status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); + status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_SINGLE_READ, 0); + + if (switch_channel_test_flag(channel, CF_BREAK)) { + switch_channel_clear_flag(channel, CF_BREAK); + eh.up = 0; + break; + } + + switch_ivr_parse_all_events(session); + + //check for dtmf interrupts + if (switch_channel_has_dtmf(channel)) { + const char * terminators = switch_channel_get_variable(channel, SWITCH_PLAYBACK_TERMINATORS_VARIABLE); + switch_channel_dequeue_dtmf(channel, &dtmf); + + if (terminators && !strcasecmp(terminators, "none")) + { + terminators = NULL; + } + + if (terminators && strchr(terminators, dtmf.digit)) { + + char sbuf[2] = {dtmf.digit, '\0'}; + switch_channel_set_variable(channel, SWITCH_PLAYBACK_TERMINATOR_USED, sbuf); + eh.up = 0; + break; + } + } if (!SWITCH_READ_ACCEPTABLE(status)) { + eh.up = 0; break; } @@ -213,12 +249,15 @@ SWITCH_STANDARD_APP(record_fsv_function) } break; } - + if (mutex) { switch_mutex_unlock(mutex); } + + switch_core_session_write_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0); } + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "OK"); end: @@ -239,7 +278,7 @@ SWITCH_STANDARD_APP(play_fsv_function) switch_frame_t write_frame = { 0 }, vid_frame = { 0}; int fd = -1; - int bytes; + int bytes; switch_codec_t codec = { 0 }, vid_codec = { 0}, *read_vid_codec; unsigned char *aud_buffer; @@ -248,24 +287,32 @@ SWITCH_STANDARD_APP(play_fsv_function) uint32_t ts = 0, last = 0; switch_timer_t timer = { 0 }; switch_payload_t pt = 0; + switch_dtmf_t dtmf = { 0 }; + switch_frame_t *read_frame; switch_codec_implementation_t read_impl = { 0 }; + switch_core_session_get_read_impl(session, &read_impl); aud_buffer = switch_core_session_alloc(session, SWITCH_RECOMMENDED_BUFFER_SIZE); vid_buffer = switch_core_session_alloc(session, SWITCH_RECOMMENDED_BUFFER_SIZE); + switch_channel_set_variable(channel, SWITCH_PLAYBACK_TERMINATOR_USED, ""); + if ((fd = open((char *) data, O_RDONLY | O_BINARY)) < 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error opening file %s\n", (char *) data); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "Got error while opening file"); return; } if (read(fd, &h, sizeof(h)) != sizeof(h)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error reading file header\n"); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "Got error reading file header"); goto end; } if (h.version != VERSION) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "File version does not match!\n"); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "File version does not match!"); goto end; } @@ -290,6 +337,7 @@ SWITCH_STANDARD_APP(play_fsv_function) if (switch_core_timer_init(&timer, "soft", read_impl.microseconds_per_packet / 1000, read_impl.samples_per_packet, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Timer Activation Fail\n"); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "Timer activation failed!"); goto end; } @@ -303,6 +351,7 @@ SWITCH_STANDARD_APP(play_fsv_function) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Activation Success\n"); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Audio Codec Activation Fail\n"); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "Audio codec activation failed"); goto end; } @@ -316,6 +365,7 @@ SWITCH_STANDARD_APP(play_fsv_function) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video Codec Activation Success\n"); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Video Codec Activation Fail\n"); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "Video codec activation failed"); goto end; } switch_core_session_set_read_codec(session, &codec); @@ -353,15 +403,45 @@ SWITCH_STANDARD_APP(play_fsv_function) if (bytes > (int) write_frame.buflen) { bytes = write_frame.buflen; } + if ((write_frame.datalen = read(fd, write_frame.data, bytes)) <= 0) { break; } switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0); switch_core_timer_next(&timer); - } + switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); + + if (switch_channel_test_flag(channel, CF_BREAK)) { + switch_channel_clear_flag(channel, CF_BREAK); + break; + } + + switch_ivr_parse_all_events(session); + + //check for dtmf interrupts + if (switch_channel_has_dtmf(channel)) { + const char * terminators = switch_channel_get_variable(channel, SWITCH_PLAYBACK_TERMINATORS_VARIABLE); + switch_channel_dequeue_dtmf(channel, &dtmf); + + if (terminators && !strcasecmp(terminators, "none")) + { + terminators = NULL; + } + + if (terminators && strchr(terminators, dtmf.digit)) { + + char sbuf[2] = {dtmf.digit, '\0'}; + switch_channel_set_variable(channel, SWITCH_PLAYBACK_TERMINATOR_USED, sbuf); + break; + } + } + } + } + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "OK"); + end: if (timer.interval) { From dc028b36483b4d595e7339c4e48f8ac6baebfa7c Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 27 May 2011 20:39:12 -0500 Subject: [PATCH 37/64] FS-3046 --resolve --- src/switch_ivr.c | 58 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/switch_ivr.c b/src/switch_ivr.c index b1c54c3df1..92eb97ef12 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -750,34 +750,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session, unsigned char *abuf = NULL; switch_codec_implementation_t imp = { 0 }; - if ((var = switch_channel_get_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE)) && (sval = atoi(var))) { - switch_core_session_get_read_impl(session, &imp); - - if (switch_core_codec_init(&codec, - "L16", - NULL, - imp.samples_per_second, - imp.microseconds_per_packet / 1000, - imp.number_of_channels, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, - switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec Error L16@%uhz %u channels %dms\n", - imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000); - return SWITCH_STATUS_FALSE; - } - - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Codec Activated L16@%uhz %u channels %dms\n", - imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000); - - write_frame.codec = &codec; - switch_zmalloc(abuf, SWITCH_RECOMMENDED_BUFFER_SIZE); - write_frame.data = abuf; - write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE; - write_frame.datalen = imp.decoded_bytes_per_packet; - write_frame.samples = write_frame.datalen / sizeof(int16_t); - } - if (switch_channel_test_flag(channel, CF_RECOVERED) && switch_channel_test_flag(channel, CF_CONTROLLED)) { switch_channel_clear_flag(channel, CF_CONTROLLED); } @@ -821,6 +793,34 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session, switch_core_session_get_read_impl(session, &read_impl); rate = read_impl.actual_samples_per_second; bpf = read_impl.decoded_bytes_per_packet; + + if ((var = switch_channel_get_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE)) && (sval = atoi(var))) { + switch_core_session_get_read_impl(session, &imp); + + if (switch_core_codec_init(&codec, + "L16", + NULL, + imp.samples_per_second, + imp.microseconds_per_packet / 1000, + imp.number_of_channels, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, + switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec Error L16@%uhz %u channels %dms\n", + imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000); + return SWITCH_STATUS_FALSE; + } + + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Codec Activated L16@%uhz %u channels %dms\n", + imp.samples_per_second, imp.number_of_channels, imp.microseconds_per_packet / 1000); + + write_frame.codec = &codec; + switch_zmalloc(abuf, SWITCH_RECOMMENDED_BUFFER_SIZE); + write_frame.data = abuf; + write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE; + write_frame.datalen = imp.decoded_bytes_per_packet; + write_frame.samples = write_frame.datalen / sizeof(int16_t); + } } if (rate) { @@ -845,7 +845,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session, break; } - if (write_frame.data) { + if (rate && write_frame.data && sval) { switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, sval); switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0); } From 9e12983f3e9e0d3f821f987125176c4bfc001055 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 27 May 2011 20:41:31 -0500 Subject: [PATCH 38/64] FS-3100 --resolve --- src/mod/endpoints/mod_sofia/sofia.c | 43 ++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 329db32582..f881d6f734 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -5672,6 +5672,8 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_channel_set_variable(channel_a, SOFIA_REPLACES_HEADER, rep); if ((b_private = nua_handle_magic(bnh))) { + int deny_refer_requests = 0; + if (!(b_session = switch_core_session_locate(b_private->uuid))) { goto done; } @@ -5689,7 +5691,46 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t br_b = NULL; } - if (switch_channel_test_flag(channel_b, CF_ORIGINATOR)) { + if (channel_a && switch_true(switch_channel_get_variable(channel_a, "deny_refer_requests"))) { + deny_refer_requests = 1; + } + + if (!deny_refer_requests && channel_b && switch_true(switch_channel_get_variable(channel_b, "deny_refer_requests"))) { + deny_refer_requests = 1; + } + + if (!deny_refer_requests && br_a) { + switch_core_session_t *a_session; + if ((a_session = switch_core_session_locate(br_a))) { + switch_channel_t *a_channel = switch_core_session_get_channel(a_session); + + if (a_channel && switch_true(switch_channel_get_variable(a_channel, "deny_refer_requests"))) { + deny_refer_requests = 1; + } + switch_core_session_rwunlock(a_session); + } + } + + if (!deny_refer_requests && br_b) { + switch_core_session_t *b_session; + if ((b_session = switch_core_session_locate(br_b))) { + switch_channel_t *b_channel = switch_core_session_get_channel(b_session); + + if (b_channel && switch_true(switch_channel_get_variable(b_channel, "deny_refer_requests"))) { + deny_refer_requests = 1; + } + switch_core_session_rwunlock(b_session); + } + } + + if (deny_refer_requests) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Denying Attended Transfer, variable [deny_refer_requests] was set to true\n"); + + nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), + NUTAG_SUBSTATE(nua_substate_terminated), + SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END()); + + } else if (switch_channel_test_flag(channel_b, CF_ORIGINATOR)) { switch_core_session_t *a_session; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, From 4480abc911663e79ab15d5fe2e2cb8b2986fd618 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 27 May 2011 21:46:28 -0500 Subject: [PATCH 39/64] fix compiler warning --- src/include/switch_ivr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 13c5a7ce51..288751d850 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -63,11 +63,11 @@ SWITCH_BEGIN_EXTERN_C struct switch_unicast_conninfo { typedef struct switch_unicast_conninfo switch_unicast_conninfo_t; #define SWITCH_IVR_VERIFY_SILENCE_DIVISOR(divisor) \ - do { \ + { \ if ((divisor) <= 0 && (divisor) != -1) { \ divisor = 400; \ } \ - } while(0); + } /** * @defgroup switch_ivr IVR Library From 6a38dce2b8fb92a203ac5ed6f78eb2e529f729d7 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Sun, 29 May 2011 09:46:02 -0500 Subject: [PATCH 40/64] trivial compiler warnings --- src/mod/endpoints/mod_sofia/mod_sofia.c | 6 +++--- src/mod/endpoints/mod_sofia/mod_sofia.h | 4 ++-- src/mod/endpoints/mod_sofia/sofia_glue.c | 16 ++++++++-------- src/mod/endpoints/mod_sofia/sofia_reg.c | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index fbff334ab2..16a24df9bd 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1345,7 +1345,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_JITTER_BUFFER: { if (switch_rtp_ready(tech_pvt->rtp_session)) { - int len, maxlen = 0, qlen = 0, maxqlen = 50, max_drift = 0; + int len = 0, maxlen = 0, qlen = 0, maxqlen = 50, max_drift = 0; if (msg->string_arg) { char *p, *q; @@ -1626,7 +1626,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi ip = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE); port = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE); if (ip && port) { - sofia_glue_set_local_sdp(tech_pvt, ip, atoi(port), msg->string_arg, 1); + sofia_glue_set_local_sdp(tech_pvt, ip, (switch_port_t)atoi(port), msg->string_arg, 1); } if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { @@ -1666,7 +1666,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi port = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE); switch_core_session_rwunlock(other_session); if (ip && port) { - sofia_glue_set_local_sdp(tech_pvt, ip, atoi(port), NULL, 1); + sofia_glue_set_local_sdp(tech_pvt, ip, (switch_port_t)atoi(port), NULL, 1); } } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 65404050e4..8e1c43d1df 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -795,7 +795,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f void sofia_glue_deactivate_rtp(private_object_t *tech_pvt); -void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32_t port, const char *sr, int force); +void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch_port_t port, const char *sr, int force); void sofia_glue_tech_prepare_codecs(private_object_t *tech_pvt); @@ -1065,6 +1065,6 @@ void sofia_glue_proxy_codec(switch_core_session_t *session, const char *r_sdp); switch_status_t sofia_glue_sdp_map(const char *r_sdp, switch_event_t **fmtp, switch_event_t **pt); void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl); void sofia_glue_check_dtmf_type(private_object_t *tech_pvt); -void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str); +void sofia_glue_parse_rtp_bugs(switch_rtp_bug_flag_t *flag_pole, const char *str); char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, sofia_nat_parse_t *np); void sofia_glue_pause_jitterbuffer(switch_core_session_t *session, switch_bool_t on); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 8af77a17d7..e1b4ac7011 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -358,7 +358,7 @@ void sofia_glue_check_dtmf_type(private_object_t *tech_pvt) } -void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32_t port, const char *sr, int force) +void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch_port_t port, const char *sr, int force) { char buf[2048]; int ptime = 0; @@ -3579,7 +3579,7 @@ static void add_audio_codec(sdp_rtpmap_t *map, int ptime, char *buf, switch_size codec_ms = switch_default_ptime(map->rm_encoding, map->rm_pt); } - map_bit_rate = switch_known_bitrate(map->rm_pt); + map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt); if (!ptime && !strcasecmp(map->rm_encoding, "g723")) { ptime = codec_ms = 30; @@ -4649,7 +4649,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s codec_ms = switch_default_ptime(rm_encoding, map->rm_pt); } - map_bit_rate = switch_known_bitrate(map->rm_pt); + map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt); if (!ptime && !strcasecmp(map->rm_encoding, "g723")) { ptime = codec_ms = 30; @@ -4765,7 +4765,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port); switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip); switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp); - tech_pvt->audio_recv_pt = map->rm_pt; + tech_pvt->audio_recv_pt = (switch_payload_t)map->rm_pt; if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && !sofia_test_flag(tech_pvt, TFLAG_REINVITE)) { sofia_glue_get_offered_pt(tech_pvt, mimp, &tech_pvt->audio_recv_pt); @@ -4889,7 +4889,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s switch_channel_set_variable(tech_pvt->channel, "sip_video_pt", tmp); sofia_glue_check_video_codecs(tech_pvt); - tech_pvt->video_recv_pt = map->rm_pt; + tech_pvt->video_recv_pt = (switch_payload_t)map->rm_pt; if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { sofia_glue_get_offered_pt(tech_pvt, mimp, &tech_pvt->video_recv_pt); @@ -5458,13 +5458,13 @@ static int recover_callback(void *pArg, int argc, char **argv, char **columnName if (switch_rtp_ready(tech_pvt->rtp_session)) { if ((tmp = switch_channel_get_variable(channel, "sip_audio_recv_pt"))) { - switch_rtp_set_recv_pt(tech_pvt->rtp_session, atoi(tmp)); + switch_rtp_set_recv_pt(tech_pvt->rtp_session, (switch_payload_t)atoi(tmp)); } } if (switch_rtp_ready(tech_pvt->video_rtp_session)) { if ((tmp = switch_channel_get_variable(channel, "sip_video_recv_pt"))) { - switch_rtp_set_recv_pt(tech_pvt->rtp_session, atoi(tmp)); + switch_rtp_set_recv_pt(tech_pvt->rtp_session, (switch_payload_t)atoi(tmp)); } } @@ -6415,7 +6415,7 @@ void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const } -void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str) +void sofia_glue_parse_rtp_bugs(switch_rtp_bug_flag_t *flag_pole, const char *str) { if (switch_stristr("clear", str)) { diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index c757a9e43e..fa837eb830 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -1050,7 +1050,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand } if (authorization) { - char *v_contact_str; + char *v_contact_str = NULL; const char *username = "unknown"; const char *realm = reg_host; if ((auth_res = sofia_reg_parse_auth(profile, authorization, sip, sip->sip_request->rq_method_name, From d193789a2cb6a5b706952fd0e0ad7f0794c2914d Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Mon, 30 May 2011 00:07:32 -0500 Subject: [PATCH 41/64] fix several problems discovered with code analysis --- src/include/switch_utils.h | 6 +++--- src/switch_core_session.c | 8 ++++++-- src/switch_utils.c | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 88c13379b3..f798e92386 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -793,9 +793,9 @@ SWITCH_DECLARE(int) switch_split_user_domain(char *in, char **user, char **domai /* malloc or DIE macros */ #ifdef NDEBUG -#define switch_malloc(ptr, len) (void)( (!!(ptr = malloc(len))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%s", __FILE__, __LINE__),abort(), 0), ptr ) -#define switch_zmalloc(ptr, len) (void)( (!!(ptr = calloc(1, (len)))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%s", __FILE__, __LINE__),abort(), 0), ptr) -#define switch_strdup(ptr, s) (void)( (!!(ptr = strdup(s))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%s", __FILE__, __LINE__),abort(), 0), ptr) +#define switch_malloc(ptr, len) (void)( (!!(ptr = malloc(len))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%d", __FILE__, __LINE__),abort(), 0), ptr ) +#define switch_zmalloc(ptr, len) (void)( (!!(ptr = calloc(1, (len)))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%d", __FILE__, __LINE__),abort(), 0), ptr) +#define switch_strdup(ptr, s) (void)( (!!(ptr = strdup(s))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%d", __FILE__, __LINE__),abort(), 0), ptr) #else #if (_MSC_VER >= 1500) // VC9+ #define switch_malloc(ptr, len) (void)(assert(((ptr) = malloc((len)))),ptr);__analysis_assume( ptr ) diff --git a/src/switch_core_session.c b/src/switch_core_session.c index ade22d2f32..ea07a7805e 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -616,6 +616,10 @@ static const char *message_names[] = { "APPLICATION_EXEC_COMPLETE", "PHONE_EVENT", "T38_DESCRIPTION" + "UDPTL_MODE", + "CLEAR_PROGRESS", + "JITTER_BUFFER", + "RECOVERY_REFRESH", "INVALID" }; @@ -644,8 +648,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_perform_receive_message(swit message->_line = line; } - if (message->message_id > SWITCH_MESSAGE_INVALID) { - message->message_id = SWITCH_MESSAGE_INVALID; + if (message->message_id > SWITCH_MESSAGE_INVALID-1) { + message->message_id = SWITCH_MESSAGE_INVALID-1; } switch_log_printf(SWITCH_CHANNEL_ID_LOG, message->_file, message->_func, message->_line, diff --git a/src/switch_utils.c b/src/switch_utils.c index 99d1d98275..906a02eba6 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -2669,7 +2669,7 @@ SWITCH_DECLARE(switch_bool_t) switch_dow_cmp(const char *exp, int val) /* Save the previous token and move to the next one */ range_start = prev; } else if (cur == DOW_ERR) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse error for [%s] at position %td (%.6s)\n", exp, p - exp, p); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse error for [%s] at position %ld (%.6s)\n", exp, (long) (p - exp), p); break; } else { /* Valid day found */ From 7822db8aa6c5c4dd344abc1108b11e18a4580fd6 Mon Sep 17 00:00:00 2001 From: Michal Bielicki - cypromis Date: Mon, 30 May 2011 16:05:07 +0200 Subject: [PATCH 42/64] added mod_cdr_sqlite to Debian build --- debian/changelog | 6 ++++++ debian/freeswitch.install | 1 + debian/rules | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 35a8787d38..abfe17e081 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +freeswitch (1.0.head-git.master.20110530.1-1) unstable; urgency=low + + * added mod_cdr_sqlite + + -- Michal Bielicki Mon, 30 May 2011 16:02:02 +0200 + freeswitch (1.0.head-git.master.20110402.1-1) unstable; urgency=low * Added Hebrew lang package diff --git a/debian/freeswitch.install b/debian/freeswitch.install index 72ded2c48c..a54895e631 100644 --- a/debian/freeswitch.install +++ b/debian/freeswitch.install @@ -155,6 +155,7 @@ opt/freeswitch/mod/mod_skinny.so* opt/freeswitch/mod/mod_skypopen.so* opt/freeswitch/mod/mod_sndfile.so* opt/freeswitch/mod/mod_snom.so* +opt/freeswitch/mod/mod_sqlite.so* opt/freeswitch/mod/mod_sofia.so* opt/freeswitch/mod/mod_spandsp.so* opt/freeswitch/mod/mod_speex.so* diff --git a/debian/rules b/debian/rules index d6b1915c88..2227a76552 100755 --- a/debian/rules +++ b/debian/rules @@ -23,7 +23,7 @@ export CODECS_MODULES= codecs/mod_bv codecs/mod_h26x codecs/mod_speex codecs/mod export DIALPLANS_MODULES= dialplans/mod_dialplan_asterisk dialplans/mod_dialplan_directory dialplans/mod_dialplan_xml export ENDPOINTS_MODULES= endpoints/mod_dingaling endpoints/mod_portaudio endpoints/mod_sofia endpoints/mod_loopback \ ../../libs/freetdm/mod_freetdm endpoints/mod_skypopen endpoints/mod_skinny -export EVENT_HANDLERS_MODULES=event_handlers/mod_event_multicast event_handlers/mod_event_socket event_handlers/mod_cdr_csv +export EVENT_HANDLERS_MODULES=event_handlers/mod_event_multicast event_handlers/mod_event_socket event_handlers/mod_cdr_csv event_handlers/mod_cdr_sqlite export FORMATS_MODULES= formats/mod_local_stream formats/mod_native_file formats/mod_portaudio_stream \ formats/mod_shout formats/mod_sndfile formats/mod_tone_stream export LANGUAGES_MODULES=languages/mod_spidermonkey languages/mod_perl languages/mod_lua languages/mod_python From 16c23f787cf9736ab720ce2b448926dbae488c1e Mon Sep 17 00:00:00 2001 From: Michal Bielicki - cypromis Date: Mon, 30 May 2011 16:55:24 +0200 Subject: [PATCH 43/64] typo --- debian/freeswitch.install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/freeswitch.install b/debian/freeswitch.install index a54895e631..a72200294f 100644 --- a/debian/freeswitch.install +++ b/debian/freeswitch.install @@ -155,7 +155,7 @@ opt/freeswitch/mod/mod_skinny.so* opt/freeswitch/mod/mod_skypopen.so* opt/freeswitch/mod/mod_sndfile.so* opt/freeswitch/mod/mod_snom.so* -opt/freeswitch/mod/mod_sqlite.so* +opt/freeswitch/mod/mod_cdr_sqlite.so* opt/freeswitch/mod/mod_sofia.so* opt/freeswitch/mod/mod_spandsp.so* opt/freeswitch/mod/mod_speex.so* From 43a5af7df6089a258e7c2a143c2982ec0f8accbb Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 30 May 2011 12:26:21 -0400 Subject: [PATCH 44/64] mod_sangoma_codec: Update max ms loop limit --- src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c index 322da31272..6da0ca0b17 100644 --- a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c +++ b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c @@ -1269,10 +1269,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sangoma_codec_load) * At this point there is an empty shell codec interface registered, but not yet implementations */ SWITCH_ADD_CODEC(codec_interface, g_codec_map[c].fs_name); - /* Now add as many codec implementations as needed, just up to 40ms for now */ + /* Now add as many codec implementations as needed, just up to 200ms for now */ if (g_codec_map[c].autoinit) { int ms = 0; - for (i = 1; i <= 4; i++) { + for (i = 1; i <= 20; i++) { ms = i * 10; if (g_codec_map[c].maxms < ms) { break; From 37064511e491b8270a15a3ef9bb9352156d03542 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 31 May 2011 09:53:39 -0500 Subject: [PATCH 45/64] fix bug from the *cough* FRICKING MAILING LIST WHERE IT SHOULD NOT HAVE BEEN REPORTED FROM *cough* --- libs/esl/src/esl_event.c | 7 +++++++ src/switch_channel.c | 8 ++++++-- src/switch_event.c | 9 ++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/libs/esl/src/esl_event.c b/libs/esl/src/esl_event.c index 28723928e3..7aa12a8cd6 100644 --- a/libs/esl/src/esl_event.c +++ b/libs/esl/src/esl_event.c @@ -478,6 +478,13 @@ static esl_status_t esl_event_base_add_header(esl_event_t *event, esl_stack_t st if (!header) { + + if (esl_strlen_zero(data)) { + esl_event_del_header(event, header_name); + FREE(data); + goto end; + } + if (esl_test_flag(event, ESL_EF_UNIQ_HEADERS)) { esl_event_del_header(event, header_name); } diff --git a/src/switch_channel.c b/src/switch_channel.c index d31b75e478..ebddafb236 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -1032,7 +1032,9 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_var_check(switch_cha switch_mutex_lock(channel->profile_mutex); if (channel->variables && !zstr(varname)) { - if (!zstr(value)) { + if (zstr(value)) { + switch_event_del_header(channel->variables, varname); + } else { int ok = 1; if (var_check) { @@ -1061,7 +1063,9 @@ SWITCH_DECLARE(switch_status_t) switch_channel_add_variable_var_check(switch_cha switch_mutex_lock(channel->profile_mutex); if (channel->variables && !zstr(varname)) { - if (!zstr(value)) { + if (zstr(value)) { + switch_event_del_header(channel->variables, varname); + } else { int ok = 1; if (var_check) { diff --git a/src/switch_event.c b/src/switch_event.c index f362bb112b..b1f5762887 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -916,7 +916,7 @@ static switch_status_t switch_event_base_add_header(switch_event_t *event, switc } header_name = real_header_name; } - + if (index_ptr || (stack & SWITCH_STACK_PUSH) || (stack & SWITCH_STACK_UNSHIFT)) { if (!(header = switch_event_get_header_ptr(event, header_name)) && index_ptr) { @@ -970,6 +970,13 @@ static switch_status_t switch_event_base_add_header(switch_event_t *event, switc if (!header) { + + if (zstr(data)) { + switch_event_del_header(event, header_name); + FREE(data); + goto end; + } + if (switch_test_flag(event, EF_UNIQ_HEADERS)) { switch_event_del_header(event, header_name); } From 0419c4e0f32e144ff741cc4181126e9adab64c90 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 31 May 2011 10:40:34 -0500 Subject: [PATCH 46/64] add append flag to mod_shout --- src/mod/formats/mod_shout/mod_shout.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mod/formats/mod_shout/mod_shout.c b/src/mod/formats/mod_shout/mod_shout.c index a4134db943..4ac6790933 100644 --- a/src/mod/formats/mod_shout/mod_shout.c +++ b/src/mod/formats/mod_shout/mod_shout.c @@ -655,9 +655,6 @@ static switch_status_t shout_file_open(switch_file_handle_t *handle, const char } } else if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { - if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Appending to MP3 not supported.\n"); - } if (!(context->gfp = lame_init())) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate lame\n"); goto error; @@ -781,8 +778,13 @@ static switch_status_t shout_file_open(switch_file_handle_t *handle, const char } } else { + const char *mask = "wb+"; + + if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) { + mask = "ab+"; + } /* lame being lame and all has FILE * coded into it's API for some functions so we gotta use it */ - if (!(context->fp = fopen(path, "wb+"))) { + if (!(context->fp = fopen(path, mask))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path); goto error; } From e2da3bea0c0f88a86df5768267150f6cf017252f Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 31 May 2011 13:01:28 -0500 Subject: [PATCH 47/64] add code to pass recording bugs on to other legs when executing an attended transfer, needs testing and possible follup commits before using --- src/include/switch_core.h | 1 + src/mod/endpoints/mod_sofia/sofia.c | 21 ++++++++++++++++ src/switch_core_media_bug.c | 39 +++++++++++++++++++++++++++++ src/switch_ivr_async.c | 1 + 4 files changed, 62 insertions(+) diff --git a/src/include/switch_core.h b/src/include/switch_core.h index ee890a80c9..681fbf4dc6 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -248,6 +248,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_close(_Inout_ switch_media SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all(_In_ switch_core_session_t *session); SWITCH_DECLARE(switch_status_t) switch_core_media_bug_enumerate(switch_core_session_t *session, switch_stream_handle_t *stream); +SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session); /*! \brief Read a frame from the bug diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index f881d6f734..dda5588cc7 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -4975,6 +4975,14 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, char *br_a = b_private->uuid; if (br_b) { + switch_core_session_t *tmp; + + if (switch_true(switch_channel_get_variable(channel, "recording_follow_transfer")) && + (tmp = switch_core_session_locate(br_a))) { + switch_core_media_bug_transfer_recordings(session, tmp); + switch_core_session_rwunlock(tmp); + } + switch_ivr_uuid_bridge(br_a, br_b); switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); @@ -5478,6 +5486,11 @@ void *SWITCH_THREAD_FUNC nightmare_xfer_thread_run(switch_thread_t *thread, void if ((status = switch_ivr_originate(NULL, &tsession, &cause, nhelper->exten_with_params, timeout, NULL, NULL, NULL, switch_channel_get_caller_profile(channel_a), nhelper->vars, SOF_NONE, NULL)) == SWITCH_STATUS_SUCCESS) { if (switch_channel_up(channel_a)) { + + if (switch_true(switch_channel_get_variable(channel_a, "recording_follow_transfer"))) { + switch_core_media_bug_transfer_recordings(session, a_session); + } + tuuid_str = switch_core_session_get_uuid(tsession); switch_ivr_uuid_bridge(nhelper->bridge_to_uuid, tuuid_str); switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); @@ -5828,6 +5841,14 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_core_session_rwunlock(tmp); } + + if (switch_true(switch_channel_get_variable(channel_a, "recording_follow_transfer")) && + (tmp = switch_core_session_locate(br_a))) { + switch_core_media_bug_transfer_recordings(session, tmp); + switch_core_session_rwunlock(tmp); + } + + switch_ivr_uuid_bridge(br_b, br_a); switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), diff --git a/src/switch_core_media_bug.c b/src/switch_core_media_bug.c index 5cc28a3c88..c8a17cfd91 100644 --- a/src/switch_core_media_bug.c +++ b/src/switch_core_media_bug.c @@ -392,6 +392,45 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_flush_all(switch_core_sess return SWITCH_STATUS_FALSE; } +SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session) +{ + switch_media_bug_t *bp; + char *list[100] = { 0 }; + int stop_times[100] = { 0 }; + int i = 0, x = 0; + + if (orig_session->bugs) { + switch_channel_t *new_channel = switch_core_session_get_channel(new_session); + const char *save = switch_channel_get_variable(new_channel, "record_append"); + + switch_thread_rwlock_wrlock(orig_session->bug_rwlock); + + switch_channel_set_variable(new_channel, "record_append", "true"); + + for (bp = orig_session->bugs; bp; bp = bp->next) { + if (!strcmp(bp->function, "session_record")) { + list[x] = switch_core_session_strdup(new_session, bp->target); + if (bp->stop_time > 0) { + stop_times[x] = bp->stop_time - switch_epoch_time_now(NULL); + } + x++; + } + } + + switch_thread_rwlock_unlock(orig_session->bug_rwlock); + + for(i = 0; i < x; i++) { + switch_ivr_stop_record_session(orig_session, list[i]); + switch_ivr_record_session(new_session, list[i], stop_times[i], NULL); + } + + switch_channel_set_variable(new_channel, "record_append", save); + + } + + return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; +} + SWITCH_DECLARE(switch_status_t) switch_core_media_bug_enumerate(switch_core_session_t *session, switch_stream_handle_t *stream) { switch_media_bug_t *bp; diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index ed69799d26..955fdee14c 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -1638,6 +1638,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t return SWITCH_STATUS_SUCCESS; } + typedef struct { SpeexPreprocessState *read_st; SpeexPreprocessState *write_st; From bb614c5a0817348ecccc3bab022cb57ca24b4980 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 31 May 2011 13:10:37 -0500 Subject: [PATCH 48/64] followup 1 --- src/mod/endpoints/mod_sofia/sofia.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index dda5588cc7..c9468872aa 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -4377,6 +4377,11 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status if (sofia_test_pflag(profile, PFLAG_MANUAL_REDIRECT)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Redirect: Transfering to %s %s %s\n", p_contact->m_url->url_user, sip_redirect_dialplan, sip_redirect_context); + + if (switch_true(switch_channel_get_variable(channel, "recording_follow_transfer"))) { + switch_core_media_bug_transfer_recordings(session, a_session); + } + switch_ivr_session_transfer(a_session, p_contact->m_url->url_user, sip_redirect_dialplan, sip_redirect_context); switch_channel_hangup(channel, SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION); } else if ((!strcmp(profile->sipip, p_contact->m_url->url_host)) @@ -4384,6 +4389,11 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status || (switch_xml_locate_domain(p_contact->m_url->url_host, NULL, &root, &domain) == SWITCH_STATUS_SUCCESS)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Redirect: Transfering to %s\n", p_contact->m_url->url_user); + + if (switch_true(switch_channel_get_variable(channel, "recording_follow_transfer"))) { + switch_core_media_bug_transfer_recordings(session, a_session); + } + switch_ivr_session_transfer(a_session, p_contact->m_url->url_user, NULL, NULL); switch_channel_hangup(channel, SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION); switch_xml_free(root); @@ -5848,6 +5858,13 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_core_session_rwunlock(tmp); } + + if (switch_true(switch_channel_get_variable(channel_b, "recording_follow_transfer")) && + (tmp = switch_core_session_locate(br_b))) { + switch_core_media_bug_transfer_recordings(b_session, tmp); + switch_core_session_rwunlock(tmp); + } + switch_ivr_uuid_bridge(br_b, br_a); switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); From 17e2cbb380ff7f2c1578e032996cd2f4e7b03695 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 31 May 2011 13:18:35 -0500 Subject: [PATCH 49/64] followup 2 --- src/switch_core_media_bug.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/switch_core_media_bug.c b/src/switch_core_media_bug.c index c8a17cfd91..b211022b28 100644 --- a/src/switch_core_media_bug.c +++ b/src/switch_core_media_bug.c @@ -420,6 +420,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_recordings(switch switch_thread_rwlock_unlock(orig_session->bug_rwlock); for(i = 0; i < x; i++) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(orig_session), SWITCH_LOG_DEBUG, "Transfering %s from %s to %s\n", list[i], + switch_core_session_get_name(orig_session), switch_core_session_get_name(new_session)); switch_ivr_stop_record_session(orig_session, list[i]); switch_ivr_record_session(new_session, list[i], stop_times[i], NULL); } From 332a5805a16f1afb1fd5fa96c59c255e29b551db Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Tue, 31 May 2011 14:10:21 -0500 Subject: [PATCH 50/64] trivial compiler warning --- src/switch_core_media_bug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_core_media_bug.c b/src/switch_core_media_bug.c index b211022b28..d546fba47d 100644 --- a/src/switch_core_media_bug.c +++ b/src/switch_core_media_bug.c @@ -411,7 +411,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_recordings(switch if (!strcmp(bp->function, "session_record")) { list[x] = switch_core_session_strdup(new_session, bp->target); if (bp->stop_time > 0) { - stop_times[x] = bp->stop_time - switch_epoch_time_now(NULL); + stop_times[x] = (int)(bp->stop_time - switch_epoch_time_now(NULL)); } x++; } From 3ef2692fb898fbbe994f9a9755021a75c0bc9756 Mon Sep 17 00:00:00 2001 From: Michael S Collins Date: Tue, 31 May 2011 18:09:03 -0700 Subject: [PATCH 51/64] config: Fix mod_directory phrase file references to 'dir-press.wav' (correct: vm-press) --- conf/lang/en/dir/sounds.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/conf/lang/en/dir/sounds.xml b/conf/lang/en/dir/sounds.xml index 15ecec304a..85dd01c599 100644 --- a/conf/lang/en/dir/sounds.xml +++ b/conf/lang/en/dir/sounds.xml @@ -94,16 +94,16 @@ - + - + - + - + From 7bbbb9ccc5e3597fae65a9bf713ef51bb46f8db4 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 31 May 2011 22:22:09 -0500 Subject: [PATCH 52/64] add vars: flip_record_on_hold to make the recording flip to the other leg on hold, record_check_bridge to make recording the same file on the opposite leg of a bridge considered a duplicate attempt and record_toggle_on_repeat to make repeat recording the same file toggle the recording off --- src/mod/endpoints/mod_sofia/sofia.c | 13 +++++++++- src/switch_channel.c | 14 ++++++++++- src/switch_core_media_bug.c | 2 +- src/switch_ivr_async.c | 37 ++++++++++++++++++++++++++--- src/switch_ivr_originate.c | 14 ++++++++++- 5 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index c9468872aa..4e5860e8a0 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -5886,17 +5886,19 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END()); } else { - switch_core_session_t *t_session; + switch_core_session_t *t_session, *hup_session; switch_channel_t *hup_channel; const char *ext; if (br_a && !br_b) { t_session = switch_core_session_locate(br_a); hup_channel = channel_b; + hup_session = b_session; } else { private_object_t *h_tech_pvt = (private_object_t *) switch_core_session_get_private(b_session); t_session = switch_core_session_locate(br_b); hup_channel = channel_a; + hup_session = session; sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); switch_channel_clear_flag(tech_pvt->channel, CF_LEG_HOLDING); sofia_clear_flag_locked(h_tech_pvt, TFLAG_SIP_HOLD); @@ -5917,6 +5919,11 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_channel_set_variable(t_channel, SOFIA_REFER_TO_VARIABLE, full_ref_to); } + + if (switch_true(switch_channel_get_variable(hup_channel, "recording_follow_transfer"))) { + switch_core_media_bug_transfer_recordings(hup_session, t_session); + } + if (idest) { switch_ivr_session_transfer(t_session, idest, "inline", NULL); } else { @@ -6079,6 +6086,10 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_channel_set_variable(b_channel, SOFIA_REFER_TO_VARIABLE, full_ref_to); } + if (switch_true(switch_channel_get_variable(channel, "recording_follow_transfer"))) { + switch_core_media_bug_transfer_recordings(session, b_session); + } + switch_ivr_session_transfer(b_session, exten, NULL, NULL); switch_core_session_rwunlock(b_session); } diff --git a/src/switch_channel.c b/src/switch_channel.c index ebddafb236..6ccaedee3d 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -635,7 +635,7 @@ SWITCH_DECLARE(void) switch_channel_mark_hold(switch_channel_t *channel, switch_ switch_event_t *event; if (!!on == !!switch_channel_test_flag(channel, CF_LEG_HOLDING)) { - return; + goto end; } if (on) { @@ -649,6 +649,18 @@ SWITCH_DECLARE(void) switch_channel_mark_hold(switch_channel_t *channel, switch_ switch_event_fire(&event); } + end: + + if (on) { + if (switch_true(switch_channel_get_variable(channel, "flip_record_on_hold"))) { + switch_core_session_t *other_session; + if (switch_core_session_get_partner(channel->session, &other_session) == SWITCH_STATUS_SUCCESS) { + switch_core_media_bug_transfer_recordings(channel->session, other_session); + switch_core_session_rwunlock(other_session); + } + } + } + } SWITCH_DECLARE(const char *) switch_channel_get_hold_music(switch_channel_t *channel) diff --git a/src/switch_core_media_bug.c b/src/switch_core_media_bug.c index d546fba47d..2c33ca2707 100644 --- a/src/switch_core_media_bug.c +++ b/src/switch_core_media_bug.c @@ -420,7 +420,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_recordings(switch switch_thread_rwlock_unlock(orig_session->bug_rwlock); for(i = 0; i < x; i++) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(orig_session), SWITCH_LOG_DEBUG, "Transfering %s from %s to %s\n", list[i], + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(orig_session), SWITCH_LOG_CRIT, "Transfering %s from %s to %s\n", list[i], switch_core_session_get_name(orig_session), switch_core_session_get_name(new_session)); switch_ivr_stop_record_session(orig_session, list[i]); switch_ivr_record_session(new_session, list[i], stop_times[i], NULL); diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 955fdee14c..7f0b37905a 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -1444,7 +1444,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t int file_flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT; switch_bool_t hangup_on_error = SWITCH_FALSE; char *file_path = NULL; - + if ((p = switch_channel_get_variable(channel, "RECORD_HANGUP_ON_ERROR"))) { hangup_on_error = switch_true(p); } @@ -1463,7 +1463,36 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t channels = read_impl.number_of_channels; if ((bug = switch_channel_get_private(channel, file))) { - return switch_ivr_stop_record_session(session, file); + if (switch_true(switch_channel_get_variable(channel, "RECORD_TOGGLE_ON_REPEAT"))) { + return switch_ivr_stop_record_session(session, file); + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Already recording [%s]\n", file); + return SWITCH_STATUS_SUCCESS; + } + + + if ((p = switch_channel_get_variable(channel, "RECORD_CHECK_BRIDGE")) && switch_true(p)) { + switch_core_session_t *other_session; + int exist = 0; + switch_status_t rstatus = SWITCH_STATUS_SUCCESS; + + if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { + switch_channel_t *other_channel = switch_core_session_get_channel(other_session); + if ((bug = switch_channel_get_private(other_channel, file))) { + if (switch_true(switch_channel_get_variable(other_channel, "RECORD_TOGGLE_ON_REPEAT"))) { + rstatus = switch_ivr_stop_record_session(other_session, file); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(other_session), SWITCH_LOG_WARNING, "Already recording [%s]\n", file); + } + exist = 1; + } + switch_core_session_rwunlock(other_session); + } + + if (exist) { + return rstatus; + } } if (!fh) { @@ -1615,7 +1644,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t rh->file = switch_core_session_strdup(session, file); rh->packet_len = read_impl.decoded_bytes_per_packet; - rh->min_sec = 3; + if (file_flags & SWITCH_FILE_WRITE_APPEND) { + rh->min_sec = 3; + } if ((p = switch_channel_get_variable(channel, "RECORD_MIN_SEC"))) { int tmp = atoi(p); diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 78b553601b..3f5c576c31 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -3123,10 +3123,22 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess switch_core_session_t *holding_session; if ((holding_session = switch_core_session_locate(holding))) { - switch_channel_set_variable(switch_core_session_get_channel(holding_session), SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE, "true"); + switch_channel_t *holding_channel = switch_core_session_get_channel(holding_session); + + switch_channel_set_variable(holding_channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE, "true"); + + if (caller_channel && switch_true(switch_channel_get_variable(caller_channel, "recording_follow_transfer"))) { + switch_core_media_bug_transfer_recordings(session, originate_status[i].peer_session); + } + + if (switch_true(switch_channel_get_variable(holding_channel, "recording_follow_transfer"))) { + switch_core_media_bug_transfer_recordings(holding_session, originate_status[i].peer_session); + } + switch_core_session_rwunlock(holding_session); } switch_channel_set_flag(originate_status[i].peer_channel, CF_LAZY_ATTENDED_TRANSFER); + switch_ivr_uuid_bridge(holding, switch_core_session_get_uuid(originate_status[i].peer_session)); holding = NULL; } else { From 14ef54cd4e4e411b9c72ee3da1285fee0cfce3d5 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Wed, 1 Jun 2011 10:48:42 -0500 Subject: [PATCH 53/64] FS-3315 Fix this differently convert to cdecl so SWIG likes --- src/include/switch_platform.h | 5 ----- src/include/switch_regex.h | 2 +- src/include/switch_types.h | 2 +- src/switch_regex.c | 2 +- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/include/switch_platform.h b/src/include/switch_platform.h index 7603b58544..609dde8b7a 100644 --- a/src/include/switch_platform.h +++ b/src/include/switch_platform.h @@ -137,17 +137,14 @@ typedef int gid_t; #ifdef WIN32 #if defined(SWITCH_CORE_DECLARE_STATIC) #define SWITCH_DECLARE(type) type __stdcall -#define SWITCH_DECLARE_TYPEDEF(type, name) type (__stdcall name) #define SWITCH_DECLARE_NONSTD(type) type __cdecl #define SWITCH_DECLARE_DATA #elif defined(FREESWITCHCORE_EXPORTS) #define SWITCH_DECLARE(type) __declspec(dllexport) type __stdcall -#define SWITCH_DECLARE_TYPEDEF(type, name) __declspec(dllexport) type (__stdcall name) #define SWITCH_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl #define SWITCH_DECLARE_DATA __declspec(dllexport) #else #define SWITCH_DECLARE(type) __declspec(dllimport) type __stdcall -#define SWITCH_DECLARE_TYPEDEF(type, name) __declspec(dllimport) type (__stdcall name) #define SWITCH_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl #define SWITCH_DECLARE_DATA __declspec(dllimport) #endif @@ -177,7 +174,6 @@ typedef int gid_t; #define O_BINARY 0 #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(SWITCH_API_VISIBILITY) #define SWITCH_DECLARE(type) __attribute__((visibility("default"))) type -#define SWITCH_DECLARE_TYPEDEF(type, name) type (name) #define SWITCH_DECLARE_NONSTD(type) __attribute__((visibility("default"))) type #define SWITCH_DECLARE_DATA __attribute__((visibility("default"))) #define SWITCH_MOD_DECLARE(type) __attribute__((visibility("default"))) type @@ -186,7 +182,6 @@ typedef int gid_t; #define SWITCH_DECLARE_CLASS __attribute__((visibility("default"))) #else #define SWITCH_DECLARE(type) type -#define SWITCH_DECLARE_TYPEDEF(type, name) type (name) #define SWITCH_DECLARE_NONSTD(type) type #define SWITCH_DECLARE_DATA #define SWITCH_MOD_DECLARE(type) type diff --git a/src/include/switch_regex.h b/src/include/switch_regex.h index 15b54aa09e..27f4852966 100644 --- a/src/include/switch_regex.h +++ b/src/include/switch_regex.h @@ -73,7 +73,7 @@ SWITCH_DECLARE(switch_status_t) switch_regex_match_partial(const char *target, c SWITCH_DECLARE(void) switch_capture_regex(switch_regex_t *re, int match_count, const char *field_data, int *ovector, const char *var, switch_cap_callback_t callback, void *user_data); -SWITCH_DECLARE(void) switch_regex_set_var_callback(const char *var, const char *val, void *user_data); +SWITCH_DECLARE_NONSTD(void) switch_regex_set_var_callback(const char *var, const char *val, void *user_data); #define switch_regex_safe_free(re) if (re) {\ switch_regex_free(re);\ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index a94bfbd29b..2b2b3de45d 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1690,7 +1690,7 @@ struct switch_console_callback_match { }; typedef struct switch_console_callback_match switch_console_callback_match_t; -typedef SWITCH_DECLARE_TYPEDEF(void, *switch_cap_callback_t) (const char *var, const char *val, void *user_data); +typedef void (*switch_cap_callback_t) (const char *var, const char *val, void *user_data); typedef switch_status_t (*switch_console_complete_callback_t) (const char *, const char *, switch_console_callback_match_t **matches); typedef switch_bool_t (*switch_media_bug_callback_t) (switch_media_bug_t *, void *, switch_abc_type_t); typedef switch_bool_t (*switch_tone_detect_callback_t) (switch_core_session_t *, const char *, const char *); diff --git a/src/switch_regex.c b/src/switch_regex.c index 3cfa01e116..e6aa375077 100644 --- a/src/switch_regex.c +++ b/src/switch_regex.c @@ -249,7 +249,7 @@ SWITCH_DECLARE(switch_status_t) switch_regex_match(const char *target, const cha return switch_regex_match_partial(target, expression, &partial); } -SWITCH_DECLARE(void) switch_regex_set_var_callback(const char *var, const char *val, void *user_data) +SWITCH_DECLARE_NONSTD(void) switch_regex_set_var_callback(const char *var, const char *val, void *user_data) { switch_core_session_t *session = (switch_core_session_t *) user_data; switch_channel_t *channel = switch_core_session_get_channel(session); From 3b81d1fcddee62ba2c8e8e22ea068822a605b6de Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Wed, 1 Jun 2011 10:50:15 -0500 Subject: [PATCH 54/64] vs2010 reswig --- .../mod_managed/freeswitch_wrap.2010.cxx | 30 +++++++++++++++++++ .../mod_managed/managed/swig.2010.cs | 19 ++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx index d5141e7c04..24a6591078 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx @@ -6449,6 +6449,20 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_media_bug_enumerate(void * jarg1, } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_media_bug_transfer_recordings(void * jarg1, void * jarg2) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + switch_core_session_t *arg2 = (switch_core_session_t *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (switch_core_session_t *)jarg2; + result = (switch_status_t)switch_core_media_bug_transfer_recordings(arg1,arg2); + jresult = result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_media_bug_read(void * jarg1, void * jarg2, int jarg3) { int jresult ; switch_media_bug_t *arg1 = (switch_media_bug_t *) 0 ; @@ -25393,6 +25407,22 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_event_del_header_val(void * jarg1, char } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_event_add_array(void * jarg1, char * jarg2, char * jarg3) { + int jresult ; + switch_event_t *arg1 = (switch_event_t *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + int result; + + arg1 = (switch_event_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (char *)jarg3; + result = (int)switch_event_add_array(arg1,(char const *)arg2,(char const *)arg3); + jresult = result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_event_destroy(void * jarg1) { switch_event_t **arg1 = (switch_event_t **) 0 ; diff --git a/src/mod/languages/mod_managed/managed/swig.2010.cs b/src/mod/languages/mod_managed/managed/swig.2010.cs index 09b9570021..4779f13044 100644 --- a/src/mod/languages/mod_managed/managed/swig.2010.cs +++ b/src/mod/languages/mod_managed/managed/swig.2010.cs @@ -1073,6 +1073,11 @@ public class freeswitch { return ret; } + public static switch_status_t switch_core_media_bug_transfer_recordings(SWIGTYPE_p_switch_core_session orig_session, SWIGTYPE_p_switch_core_session new_session) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_media_bug_transfer_recordings(SWIGTYPE_p_switch_core_session.getCPtr(orig_session), SWIGTYPE_p_switch_core_session.getCPtr(new_session)); + return ret; + } + public static switch_status_t switch_core_media_bug_read(SWIGTYPE_p_switch_media_bug bug, switch_frame frame, switch_bool_t fill) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_media_bug_read(SWIGTYPE_p_switch_media_bug.getCPtr(bug), switch_frame.getCPtr(frame), (int)fill); return ret; @@ -3956,6 +3961,11 @@ public class freeswitch { return ret; } + public static int switch_event_add_array(switch_event arg0, string var, string val) { + int ret = freeswitchPINVOKE.switch_event_add_array(switch_event.getCPtr(arg0), var, val); + return ret; + } + public static void switch_event_destroy(SWIGTYPE_p_p_switch_event arg0) { freeswitchPINVOKE.switch_event_destroy(SWIGTYPE_p_p_switch_event.getCPtr(arg0)); } @@ -7566,6 +7576,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_core_media_bug_enumerate")] public static extern int switch_core_media_bug_enumerate(HandleRef jarg1, HandleRef jarg2); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_media_bug_transfer_recordings")] + public static extern int switch_core_media_bug_transfer_recordings(HandleRef jarg1, HandleRef jarg2); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_media_bug_read")] public static extern int switch_core_media_bug_read(HandleRef jarg1, HandleRef jarg2, int jarg3); @@ -12138,6 +12151,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_event_del_header_val")] public static extern int switch_event_del_header_val(HandleRef jarg1, string jarg2, string jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_switch_event_add_array")] + public static extern int switch_event_add_array(HandleRef jarg1, string jarg2, string jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_switch_event_destroy")] public static extern void switch_event_destroy(HandleRef jarg1); @@ -25168,8 +25184,7 @@ public class switch_event : IDisposable { namespace FreeSWITCH.Native { public enum switch_event_flag_t { - EF_UNIQ_HEADERS = (1 << 0), - EF_CONTAINS_ARRAYS = (1 << 1) + EF_UNIQ_HEADERS = (1 << 0) } } From 64f8ad3f847dfa62d6411b09fa4794f7237de115 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 1 Jun 2011 10:59:32 -0500 Subject: [PATCH 55/64] FS-3324 --resolve I think this is a misconfiguration where you have nat detected and no external ip configured --- src/mod/endpoints/mod_sofia/sofia.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 4e5860e8a0..4fc4d9f418 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -6900,7 +6900,7 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ if (sip->sip_to && sip->sip_to->a_url) { const char *host, *user; - int port; + int port, check_nat = 0; url_t *transport_url; if (sip->sip_record_route && sip->sip_record_route->r_url) { @@ -6940,10 +6940,22 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ if (sofia_glue_check_nat(profile, tech_pvt->remote_ip)) { url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_public_url : profile->public_url; + check_nat = 1; } else { url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url; } + if (!url) { + if (check_nat) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Nat detected but no external address configured.\n"); + } + url = profile->url; + } + + if (!url) { + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } + tmp = sofia_overcome_sip_uri_weakness(session, url, transport, SWITCH_TRUE, NULL); if ((at = strchr(tmp, '@'))) { From 51c215809fdb1a203ef20ac23b049c549e3b6bc3 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 1 Jun 2011 13:19:28 -0500 Subject: [PATCH 56/64] only accept info dtmf when its configured to --- src/mod/endpoints/mod_sofia/sofia.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 4fc4d9f418..096d2ea7c1 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -6190,6 +6190,11 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t const char *clientcode_header; switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0) }; switch_event_t *event; + private_object_t *tech_pvt = NULL; + + if (session) { + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + } if (sofia_test_pflag(profile, PFLAG_EXTENDED_INFO_PARSING)) { if (sip && sip->sip_content_type && sip->sip_content_type->c_type && sip->sip_content_type->c_subtype && @@ -6322,7 +6327,7 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t goto end; } - if (dtmf.digit) { + if (dtmf.digit && tech_pvt->dtmf_type == DTMF_INFO) { /* queue it up */ switch_channel_queue_dtmf(channel, &dtmf); @@ -6347,6 +6352,9 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t /* Send 200 OK response */ nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END()); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "IGNORE INFO DTMF(%c) (This channel was not configured to use INFO DTMF!)\n", dtmf.digit); } goto end; } From 37c2b1ff7b6455890521961b2e120e77014573b3 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 1 Jun 2011 17:40:56 -0500 Subject: [PATCH 57/64] fix race --- src/mod/endpoints/mod_loopback/mod_loopback.c | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/mod/endpoints/mod_loopback/mod_loopback.c b/src/mod/endpoints/mod_loopback/mod_loopback.c index 8fb8384e6b..97684b6f10 100644 --- a/src/mod/endpoints/mod_loopback/mod_loopback.c +++ b/src/mod/endpoints/mod_loopback/mod_loopback.c @@ -54,7 +54,8 @@ typedef enum { TFLAG_BLEG = (1 << 6), TFLAG_APP = (1 << 7), TFLAG_RUNNING_APP = (1 << 8), - TFLAG_BOWOUT_USED = (1 << 9) + TFLAG_BOWOUT_USED = (1 << 9), + TFLAG_CLEAR = (1 << 10) } TFLAGS; struct private_object { @@ -105,6 +106,17 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig); + +static void clear_queue(private_t *tech_pvt) +{ + void *pop; + + while (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { + switch_frame_t *frame = (switch_frame_t *) pop; + switch_frame_free(&frame); + } +} + static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *session, switch_codec_t *codec) { const char *iananame = "L16"; @@ -566,6 +578,12 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch mutex = tech_pvt->mutex; switch_mutex_lock(mutex); + + if (switch_test_flag(tech_pvt, TFLAG_CLEAR)) { + clear_queue(tech_pvt); + switch_clear_flag(tech_pvt, TFLAG_CLEAR); + } + if (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { if (tech_pvt->write_frame) { switch_frame_free(&tech_pvt->write_frame); @@ -599,17 +617,6 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch return status; } -static void clear_queue(private_t *tech_pvt) -{ - void *pop; - - while (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { - switch_frame_t *frame = (switch_frame_t *) pop; - switch_frame_free(&frame); - } -} - - 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_channel_t *channel = NULL; @@ -750,9 +757,9 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s { done = 1; + switch_set_flag(tech_pvt, TFLAG_CLEAR); + switch_set_flag(tech_pvt->other_tech_pvt, TFLAG_CLEAR); - clear_queue(tech_pvt); - clear_queue(tech_pvt->other_tech_pvt); switch_core_timer_sync(&tech_pvt->timer); switch_core_timer_sync(&tech_pvt->other_tech_pvt->timer); } From 5409caca226edc34e53523467380db21e8f70fb6 Mon Sep 17 00:00:00 2001 From: Michael S Collins Date: Wed, 1 Jun 2011 16:33:07 -0700 Subject: [PATCH 58/64] Update to-be-recorded prompts --- docs/phrase/phrase_en.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/phrase/phrase_en.xml b/docs/phrase/phrase_en.xml index 6871ecafe4..88d0950d29 100644 --- a/docs/phrase/phrase_en.xml +++ b/docs/phrase/phrase_en.xml @@ -492,6 +492,8 @@ + + From 5923f71a842797942ac4259a4b563656ecb711e9 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Wed, 1 Jun 2011 22:36:19 -0500 Subject: [PATCH 59/64] more code analysis mostly trivial except string formating changes --- libs/stfu/stfu.c | 4 ++-- libs/stfu/stfu.h | 7 +++++++ src/switch_channel.c | 4 ++-- src/switch_console.c | 5 +++-- src/switch_event.c | 10 ++++------ src/switch_xml.c | 24 ++++++++++++------------ 6 files changed, 30 insertions(+), 24 deletions(-) diff --git a/libs/stfu/stfu.c b/libs/stfu/stfu.c index a4c3bb78d3..75a659d894 100644 --- a/libs/stfu/stfu.c +++ b/libs/stfu/stfu.c @@ -231,7 +231,7 @@ void stfu_n_debug(stfu_instance_t *i, const char *name) void stfu_n_report(stfu_instance_t *i, stfu_report_t *r) { - assert(i); + stfu_assert(i); r->qlen = i->qlen; r->packet_in_count = i->period_packet_in_count; r->clean_count = i->period_clean_count; @@ -580,7 +580,7 @@ static int stfu_n_find_any_frame(stfu_instance_t *in, stfu_queue_t *queue, stfu_ uint32_t i = 0; stfu_frame_t *frame = NULL; - assert(r_frame); + stfu_assert(r_frame); *r_frame = NULL; diff --git a/libs/stfu/stfu.h b/libs/stfu/stfu.h index b802bbaef6..3e989b0a97 100644 --- a/libs/stfu/stfu.h +++ b/libs/stfu/stfu.h @@ -40,6 +40,13 @@ extern "C" { #include #include +#if (_MSC_VER >= 1400) // VC8+ +#define stfu_assert(expr) assert(expr);__analysis_assume( expr ) +#endif + +#ifndef stfu_assert +#define stfu_assert(_x) assert(_x) +#endif #ifdef _MSC_VER #ifndef uint32_t diff --git a/src/switch_channel.c b/src/switch_channel.c index 6ccaedee3d..01c2937470 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -3643,7 +3643,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * switch_snprintf(tmp, sizeof(tmp), "%d", billsec); switch_channel_set_variable(channel, "billsec", tmp); - switch_snprintf(tmp, sizeof(tmp), "%d", progresssec); + switch_snprintf(tmp, sizeof(tmp), "%"SWITCH_TIME_T_FMT, progresssec); switch_channel_set_variable(channel, "progresssec", tmp); switch_snprintf(tmp, sizeof(tmp), "%d", answersec); @@ -3652,7 +3652,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(switch_channel_t * switch_snprintf(tmp, sizeof(tmp), "%d", waitsec); switch_channel_set_variable(channel, "waitsec", tmp); - switch_snprintf(tmp, sizeof(tmp), "%d", progress_mediasec); + switch_snprintf(tmp, sizeof(tmp), "%"SWITCH_TIME_T_FMT, progress_mediasec); switch_channel_set_variable(channel, "progress_mediasec", tmp); switch_snprintf(tmp, sizeof(tmp), "%d", legbillsec); diff --git a/src/switch_console.c b/src/switch_console.c index d902af69e7..c54ba643d2 100644 --- a/src/switch_console.c +++ b/src/switch_console.c @@ -105,7 +105,7 @@ static switch_status_t console_xml_config(void) for (param = switch_xml_child(settings, "key"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); - int i = atoi(var); + i = atoi(var); if ((i < 1) || (i > 12)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Keybind %s is invalid, range is from 1 to 12\n", var); } else { @@ -913,7 +913,7 @@ static unsigned char console_fnkey_pressed(int i) { char *c, *cmd; - assert((i > 0) && (i <= 12)); + switch_assert((i > 0) && (i <= 12)); c = console_fnkeys[i - 1]; @@ -1675,6 +1675,7 @@ SWITCH_DECLARE(void) switch_console_sort_matches(switch_console_callback_match_t sort[3] = sort[2] ? sort[2]->next : NULL; for (j = 1; j <= (matches->count - i); j++) { + switch_assert(sort[1] && sort[2]); if (strcmp(sort[1]->val, sort[2]->val) > 0) { sort[1]->next = sort[3]; sort[2]->next = sort[1]; diff --git a/src/switch_event.c b/src/switch_event.c index b1f5762887..0929be27d9 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -1302,11 +1302,10 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize(switch_event_t *event, ch llen = strlen(hp->name) + strlen(encode_buf) + 8; if ((len + llen) > dlen) { - char *m; + char *m = buf; dlen += (blocksize + (len + llen)); - if ((m = realloc(buf, dlen))) { + if (!(buf = realloc(buf, dlen))) { buf = m; - } else { abort(); } } @@ -1329,11 +1328,10 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize(switch_event_t *event, ch } if ((len + llen) > dlen) { - char *m; + char *m = buf; dlen += (blocksize + (len + llen)); - if ((m = realloc(buf, dlen))) { + if (!(buf = realloc(buf, dlen))) { buf = m; - } else { abort(); } } diff --git a/src/switch_xml.c b/src/switch_xml.c index 4664c07c71..fa53406822 100644 --- a/src/switch_xml.c +++ b/src/switch_xml.c @@ -1125,12 +1125,12 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_parse_fp(FILE * fp) do { len += (l = fread((s + len), 1, SWITCH_XML_BUFSIZE, fp)); if (l == SWITCH_XML_BUFSIZE) { - char *tmp = (char *) realloc(s, len + SWITCH_XML_BUFSIZE); - if (!tmp) { - free(s); + char *tmp = s; + s = (char *) realloc(s, len + SWITCH_XML_BUFSIZE); + if (!s) { + free(tmp); return NULL; } - s = tmp; } } while (s && l == SWITCH_XML_BUFSIZE); @@ -2279,10 +2279,10 @@ static char *switch_xml_toxml_r(switch_xml_t xml, char **s, switch_size_t *len, *s = switch_xml_ampencode(txt + start, xml->off - start, s, len, max, 0); while (*len + strlen(xml->name) + 5 + (strlen(XML_INDENT) * (*count)) + 1 > *max) { /* reallocate s */ - char *tmp = (char *) realloc(*s, *max += SWITCH_XML_BUFSIZE); - if (!tmp) - return *s; - *s = tmp; + char *tmp = *s; + *s = (char *) realloc(*s, *max += SWITCH_XML_BUFSIZE); + if (!*s) + return tmp; } if (*len && *(*s + (*len) - 1) == '>') { @@ -2335,10 +2335,10 @@ static char *switch_xml_toxml_r(switch_xml_t xml, char **s, switch_size_t *len, } while (*len + strlen(xml->name) + 5 + (strlen(XML_INDENT) * (*count)) > *max) { /* reallocate s */ - char *tmp = (char *) realloc(*s, *max += SWITCH_XML_BUFSIZE); - if (!tmp) - return *s; - *s = tmp; + char *tmp = *s; + *s = (char *) realloc(*s, *max += SWITCH_XML_BUFSIZE); + if (!*s) + return tmp; } if (xml->child || xml->txt) { From 68c389df4644acad809b282910a92a5a7a30cecb Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 3 Jun 2011 09:45:07 -0500 Subject: [PATCH 60/64] FS-3326 --resolve ok thx --- src/mod/endpoints/mod_sofia/mod_sofia.c | 78 +++++++++++++++++++- src/mod/endpoints/mod_sofia/mod_sofia.h | 1 + src/mod/endpoints/mod_sofia/sofia.c | 92 +++++++++++++++++++++--- src/mod/endpoints/mod_sofia/sofia_glue.c | 17 +++-- src/switch_ivr_originate.c | 2 +- 5 files changed, 169 insertions(+), 21 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 16a24df9bd..b672cccb80 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -569,9 +569,31 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) const char *val; const char *b_sdp = NULL; int is_proxy = 0; + int is_3pcc = 0; char *sticky = NULL; const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full"); + + if(sofia_test_flag(tech_pvt, TFLAG_3PCC_INVITE)) { + // SNARK: complete hack to get final ack sent when a 3pcc invite has been passed from the other leg in bypass_media mode. + // This code handles the pass_indication sent after the 3pcc ack is received by the other leg in the is_3pcc && is_proxy case below. + // Is there a better place to hang this...? + b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE); + sofia_glue_tech_set_local_sdp(tech_pvt, b_sdp, SWITCH_TRUE); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY nomedia - sending ack\n"); + nua_ack(tech_pvt->nh, + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + SIPTAG_CONTACT_STR(tech_pvt->reply_contact), + SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), + SOATAG_REUSE_REJECTED(1), + SOATAG_RTP_SELECT(1), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), + TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), + TAG_END()); + sofia_clear_flag(tech_pvt, TFLAG_3PCC_INVITE); // all done + return SWITCH_STATUS_SUCCESS; + } + if (sofia_test_flag(tech_pvt, TFLAG_ANS) || switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_SUCCESS; } @@ -579,8 +601,9 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE); is_proxy = (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)); + is_3pcc = (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC)); - if (b_sdp && is_proxy) { + if (b_sdp && is_proxy && !is_3pcc) { sofia_glue_tech_set_local_sdp(tech_pvt, b_sdp, SWITCH_TRUE); if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { @@ -591,23 +614,35 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) } } else { /* This if statement check and handles the 3pcc proxy mode */ - if (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC)) { + if (is_3pcc) { + if(!is_proxy) { tech_pvt->num_codecs = 0; sofia_glue_tech_prepare_codecs(tech_pvt); tech_pvt->local_sdp_str = NULL; sofia_glue_tech_choose_port(tech_pvt, 0); sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0); + } else { + sofia_glue_tech_set_local_sdp(tech_pvt, b_sdp, SWITCH_TRUE); + + if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { + sofia_glue_tech_patch_sdp(tech_pvt); + if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + } + } /* Send the 200 OK */ if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX); if (sofia_use_soa(tech_pvt)) { nua_respond(tech_pvt->nh, SIP_200_OK, + TAG_IF(is_proxy, NUTAG_AUTOANSWER(0)), SIPTAG_CONTACT_STR(tech_pvt->profile->url), SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), - SOATAG_REUSE_REJECTED(1), + SOATAG_REUSE_REJECTED(1), TAG_IF(is_proxy, SOATAG_RTP_SELECT(1)), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote), @@ -639,6 +674,14 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) /* Regain lock on sofia */ switch_mutex_lock(tech_pvt->sofia_mutex); + if(is_proxy) { + sofia_clear_flag(tech_pvt, TFLAG_3PCC_HAS_ACK); + sofia_clear_flag(tech_pvt, TFLAG_3PCC); + // This sends the message to the other leg that causes it to call the TFLAG_3PCC_INVITE code at the start of this function. + // Is there another message it would be better to hang this on though? + switch_core_session_pass_indication(session, SWITCH_MESSAGE_INDICATE_ANSWER); + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Done waiting for ACK\n"); return SWITCH_STATUS_SUCCESS; } @@ -1685,6 +1728,10 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch_channel_get_name(channel), msg->string_arg); sofia_glue_tech_set_local_sdp(tech_pvt, msg->string_arg, SWITCH_TRUE); + if(zstr(tech_pvt->local_sdp_str)) { + sofia_set_flag(tech_pvt, TFLAG_3PCC_INVITE); + } + sofia_set_flag_locked(tech_pvt, TFLAG_SENT_UPDATE); switch_channel_set_flag(channel, CF_REQ_MEDIA); sofia_glue_do_invite(session); @@ -2183,6 +2230,23 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi SIPTAG_PAYLOAD_STR(tech_pvt->local_sdp_str), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); } + if (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC)) { + /* Unlock the session signal to allow the ack to make it in */ + // Maybe we should timeout? + switch_mutex_unlock(tech_pvt->sofia_mutex); + + while (switch_channel_ready(channel) && !sofia_test_flag(tech_pvt, TFLAG_3PCC_HAS_ACK)) { + switch_cond_next(); + } + + /* Regain lock on sofia */ + switch_mutex_lock(tech_pvt->sofia_mutex); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Done waiting for ACK\n"); + sofia_clear_flag(tech_pvt, TFLAG_3PCC); + sofia_clear_flag(tech_pvt, TFLAG_3PCC_HAS_ACK); + switch_core_session_pass_indication(session, SWITCH_MESSAGE_INDICATE_ANSWER); + } } else { nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); @@ -4379,6 +4443,14 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session } else { sofia_clear_flag(ctech_pvt, TFLAG_ENABLE_SOA); } + + /* SNARK: lets copy this across so we can see if we're the other leg of 3PCC + bypass_media... */ + if (sofia_test_flag(ctech_pvt, TFLAG_3PCC) && (switch_channel_test_flag(o_channel, CF_PROXY_MODE) || switch_channel_test_flag(o_channel, CF_PROXY_MEDIA))) { + sofia_set_flag(tech_pvt, TFLAG_3PCC_INVITE); + sofia_set_flag(tech_pvt, TFLAG_LATE_NEGOTIATION); + } else { + sofia_clear_flag(tech_pvt, TFLAG_3PCC_INVITE); + } } if (switch_channel_test_flag(o_channel, CF_PROXY_MEDIA)) { diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 8e1c43d1df..4b41189a02 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -294,6 +294,7 @@ typedef enum { TFLAG_AUTOFLUSH_DURING_BRIDGE, TFLAG_NOTIMER_DURING_BRIDGE, TFLAG_JB_PAUSED, + TFLAG_3PCC_INVITE, /* No new flags below this line */ TFLAG_MAX } TFLAGS; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 096d2ea7c1..12b0280974 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -4534,7 +4534,9 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status } } - switch_core_session_queue_message(other_session, msg); + /* SNARK: message to respond to reinvite wasn't being delivered in 3pcc+bypass media case. */ + //switch_core_session_queue_message(other_session, msg); + switch_core_session_receive_message(other_session, msg); switch_core_session_rwunlock(other_session); } @@ -4708,6 +4710,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, const char *uuid; switch_core_session_t *other_session = NULL; switch_channel_t *other_channel = NULL; + private_object_t *other_tech_pvt = NULL; char st[80] = ""; int is_dup_sdp = 0; switch_event_t *s_event = NULL; @@ -4908,6 +4911,24 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, break; case nua_callstate_completing: { + if (r_sdp && sofia_test_flag(tech_pvt, TFLAG_3PCC_INVITE) && !sofia_test_flag(tech_pvt, TFLAG_SDP)) { + sofia_set_flag(tech_pvt, TFLAG_SDP); + + if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) + && (other_session = switch_core_session_locate(uuid))) { + other_channel = switch_core_session_get_channel(other_session); + other_tech_pvt = switch_core_session_get_private(other_session); + + if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) { + switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp); + } + switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER); + switch_core_session_rwunlock(other_session); + } + goto done; + + } + if (sofia_test_pflag(profile, PFLAG_TRACK_CALLS)) { const char *invite_full_via = switch_channel_get_variable(tech_pvt->channel, "sip_invite_full_via"); const char *invite_route_uri = switch_channel_get_variable(tech_pvt->channel, "sip_invite_route_uri"); @@ -5020,10 +5041,12 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); } } else { + if (sofia_test_pflag(profile, PFLAG_3PCC)) { if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { - goto done; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "No SDP in INVITE and 3pcc=yes cannot work with bypass or proxy media, hanging up.\n"); + switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "3PCC DISABLED"); + switch_channel_hangup(channel, SWITCH_CAUSE_MANDATORY_IE_MISSING); } else { - if (sofia_test_pflag(profile, PFLAG_3PCC)) { switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP"); sofia_glue_tech_choose_port(tech_pvt, 0); sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0); @@ -5042,8 +5065,10 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, SIPTAG_CONTACT_STR(tech_pvt->profile->url), SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->local_sdp_str), TAG_END()); } + } } else if (sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) { //3PCC proxy mode delays the 200 OK until the call is answered + // so can be made to work with bypass media as we have time to find out what the other end thinks codec offer should be... switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP"); sofia_set_flag_locked(tech_pvt, TFLAG_3PCC); //sofia_glue_tech_choose_port(tech_pvt, 0); @@ -5058,11 +5083,29 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } goto done; } - } } else if (tech_pvt && sofia_test_flag(tech_pvt, TFLAG_SDP) && !r_sdp) { - nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END()); sofia_set_flag_locked(tech_pvt, TFLAG_NOSDP_REINVITE); + if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { + sofia_set_flag_locked(tech_pvt, TFLAG_3PCC); + if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) + && (other_session = switch_core_session_locate(uuid))) { + switch_core_session_message_t *msg; + msg = switch_core_session_alloc(other_session, sizeof(*msg)); + msg->message_id = SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT; + msg->from = __FILE__; + msg->string_arg = NULL; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing NOSDP to other leg.\n"); + switch_core_session_queue_message(other_session, msg); + switch_core_session_rwunlock(other_session); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "NOSDP Re-INVITE to a proxy mode channel that is not in a bridge.\n"); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } + goto done; + } + nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END()); goto done; } else { ss_state = nua_callstate_completed; @@ -5074,12 +5117,10 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, break; case nua_callstate_completed: if (r_sdp) { + const char *var; uint8_t match = 0, is_ok = 1, is_t38 = 0; tech_pvt->hold_laps = 0; - if (r_sdp) { - const char *var; - if ((var = switch_channel_get_variable(channel, "sip_ignore_reinvites")) && switch_true(var)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Ignoring Re-invite\n"); nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END()); @@ -5240,7 +5281,6 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); } } - } break; case nua_callstate_ready: if (r_sdp && !is_dup_sdp && switch_rtp_ready(tech_pvt->rtp_session)) { @@ -5273,10 +5313,34 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } if (r_sdp && sofia_test_flag(tech_pvt, TFLAG_NOSDP_REINVITE)) { + sofia_clear_flag_locked(tech_pvt, TFLAG_NOSDP_REINVITE); + if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { + if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { + if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) { + goto done; + } + } + + if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) + && (other_session = switch_core_session_locate(uuid))) { + other_channel = switch_core_session_get_channel(other_session); + if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) { + switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp); + } + + if (sofia_test_flag(tech_pvt, TFLAG_3PCC) && sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my ACK\n"); + sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK); + } else { + switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER); + } + + switch_core_session_rwunlock(other_session); + } + } else { uint8_t match = 0; int is_ok = 1; - sofia_clear_flag_locked(tech_pvt, TFLAG_NOSDP_REINVITE); if (tech_pvt->num_codecs) { match = sofia_glue_negotiate_sdp(session, r_sdp); @@ -5299,7 +5363,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); } - + } goto done; } @@ -5366,6 +5430,12 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_core_session_rwunlock(other_session); } + + if (sofia_test_flag(tech_pvt, TFLAG_3PCC) && sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my ACK\n"); + sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK); + } + goto done; } else { uint8_t match = 0; diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index e1b4ac7011..b308b6038e 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -2396,6 +2396,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) if (sofia_use_soa(tech_pvt)) { nua_invite(tech_pvt->nh, NUTAG_AUTOANSWER(0), + NUTAG_AUTOACK(0), NUTAG_SESSION_TIMER(session_timeout), NUTAG_SESSION_REFRESHER(session_timeout ? nua_local_refresher : nua_no_refresher), TAG_IF(sofia_test_flag(tech_pvt, TFLAG_RECOVERED), NUTAG_INVITE_TIMER(UINT_MAX)), @@ -2417,15 +2418,19 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) TAG_IF(!zstr(route), SIPTAG_ROUTE_STR(route)), TAG_IF(tech_pvt->profile->minimum_session_expires, NUTAG_MIN_SE(tech_pvt->profile->minimum_session_expires)), TAG_IF(cseq, SIPTAG_CSEQ(cseq)), - SOATAG_ADDRESS(tech_pvt->adv_sdp_audio_ip), - SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), - SOATAG_REUSE_REJECTED(1), - SOATAG_ORDERED_USER(1), - SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE), - SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), SOATAG_HOLD(holdstr), TAG_END()); + TAG_IF(zstr(tech_pvt->local_sdp_str), SIPTAG_PAYLOAD_STR("")), + TAG_IF(!zstr(tech_pvt->local_sdp_str), SOATAG_ADDRESS(tech_pvt->adv_sdp_audio_ip)), + TAG_IF(!zstr(tech_pvt->local_sdp_str), SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str)), + TAG_IF(!zstr(tech_pvt->local_sdp_str), SOATAG_REUSE_REJECTED(1)), + TAG_IF(!zstr(tech_pvt->local_sdp_str), SOATAG_ORDERED_USER(1)), + TAG_IF(!zstr(tech_pvt->local_sdp_str), SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE)), + TAG_IF(!zstr(tech_pvt->local_sdp_str), SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL)), + TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), + TAG_IF(!zstr(tech_pvt->local_sdp_str), SOATAG_HOLD(holdstr)), TAG_END()); } else { nua_invite(tech_pvt->nh, NUTAG_AUTOANSWER(0), + NUTAG_AUTOACK(0), NUTAG_SESSION_TIMER(session_timeout), TAG_IF(session_timeout, NUTAG_SESSION_REFRESHER(nua_remote_refresher)), TAG_IF(sofia_test_flag(tech_pvt, TFLAG_RECOVERED), NUTAG_INVITE_TIMER(UINT_MAX)), diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 3f5c576c31..840705aad5 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -2934,7 +2934,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess oglobals.idx = IDX_CANCEL; } - if (oglobals.session && (ringback_data || !(switch_channel_test_flag(caller_channel, CF_PROXY_MODE) && + if (oglobals.session && (ringback_data || !(switch_channel_test_flag(caller_channel, CF_PROXY_MODE) || switch_channel_test_flag(caller_channel, CF_PROXY_MEDIA)))) { switch_core_session_reset(oglobals.session, SWITCH_FALSE, SWITCH_TRUE); } From 94e9957e515f143c6153143d94c8c9ec3a7d2933 Mon Sep 17 00:00:00 2001 From: Christopher Rienzo Date: Tue, 24 May 2011 17:58:17 +0000 Subject: [PATCH 61/64] FS-3311 fire SWITCH_EVENT_RECORD_STOP after closing file --- src/switch_ivr_async.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 7f0b37905a..f9cf24ef83 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -936,12 +936,6 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Stop recording file %s\n", rh->file); switch_channel_set_private(channel, rh->file, NULL); - if (switch_event_create(&event, SWITCH_EVENT_RECORD_STOP) == SWITCH_STATUS_SUCCESS) { - switch_channel_event_set_data(channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file); - switch_event_fire(&event); - } - if (rh->fh) { switch_size_t len; uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE]; @@ -970,6 +964,12 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s } } + if (switch_event_create(&event, SWITCH_EVENT_RECORD_STOP) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file); + switch_event_fire(&event); + } + if ((var = switch_channel_get_variable(channel, "record_post_process_exec_app"))) { char *app = switch_core_session_strdup(session, var); char *data; From 5099d3b8e3236844ef2502a6f7e40f0f98bb2730 Mon Sep 17 00:00:00 2001 From: Christopher Rienzo Date: Fri, 3 Jun 2011 20:41:09 +0000 Subject: [PATCH 62/64] fix mod_unimrcp reloadxml issue --- src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c b/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c index 53281bc389..c869d9e8da 100644 --- a/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c +++ b/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c @@ -3958,8 +3958,13 @@ static mrcp_client_t *mod_unimrcp_client_create(switch_memory_pool_t *mod_pool) client = NULL; goto done; } + if (zstr(param_value)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing SPEAK param value\n"); + client = NULL; + goto done; + } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading SPEAK Param %s:%s\n", param_name, param_value); - switch_core_hash_insert(mod_profile->default_synth_params, param_name, param_value); + switch_core_hash_insert(mod_profile->default_synth_params, switch_core_strdup(pool, param_name), switch_core_strdup(pool, param_value)); } } @@ -3976,8 +3981,13 @@ static mrcp_client_t *mod_unimrcp_client_create(switch_memory_pool_t *mod_pool) client = NULL; goto done; } + if (zstr(param_value)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing RECOGNIZE param value\n"); + client = NULL; + goto done; + } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading RECOGNIZE Param %s:%s\n", param_name, param_value); - switch_core_hash_insert(mod_profile->default_recog_params, param_name, param_value); + switch_core_hash_insert(mod_profile->default_recog_params, switch_core_strdup(pool, param_name), switch_core_strdup(pool, param_value)); } } From 048ee41efbcc9167649c06890b6f5865c4c3ebde Mon Sep 17 00:00:00 2001 From: cypromis Date: Sun, 5 Jun 2011 21:51:02 +0200 Subject: [PATCH 63/64] add hu package comment --- freeswitch.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freeswitch.spec b/freeswitch.spec index d13ae2686d..102879dd28 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -5,7 +5,7 @@ # # includes module(s): freeswitch-devel freeswitch-codec-passthru-amr freeswitch-codec-passthru-amrwb freeswitch-codec-passthru-g729 # freeswitch-codec-passthru-g7231 freeswitch-lua freeswitch-perl freeswitch-python freeswitch-spidermonkey -# freeswitch-lan-de freeswitch-lang-en freeswitch-lang-fr freeswitch-lang-ru freeswitch-freetdm +# freeswitch-lan-de freeswitch-lang-en freeswitch-lang-fr freeswitch-lang-hu freeswitch-lang-ru freeswitch-freetdm # # Initial Version Copyright (C) 2007 Peter Nixon and Michal Bielicki, All Rights Reserved. # From 98e754e4505b85570bb5de781ec8a8001bf7b5c9 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Mon, 6 Jun 2011 09:47:16 +0000 Subject: [PATCH 64/64] gitignore some libcodec2 build products --- libs/.gitignore | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libs/.gitignore b/libs/.gitignore index b9aa87286c..2a213f9ee0 100644 --- a/libs/.gitignore +++ b/libs/.gitignore @@ -276,6 +276,17 @@ /ldns/packaging/ldns-config /ldns/packaging/libldns.pc /ldns-1.6.9/ +/libcodec2/src/c2dec +/libcodec2/src/c2enc +/libcodec2/src/c2sim +/libcodec2/unittest/extract +/libcodec2/unittest/genlsp +/libcodec2/unittest/genres +/libcodec2/unittest/tcodec2 +/libcodec2/unittest/tinterp +/libcodec2/unittest/tnlp +/libcodec2/unittest/tquant +/libcodec2/unittest/vqtrain /libdingaling/Makefile /libdingaling/Makefile.in /libdingaling/aclocal.m4