<h1>Project "FreeSWITCH Source" received a push.</h1>

<h2>branch: master updated</h2>
<pre>
       via: 33b74ca8c710a58d245ea8903f98e0e86cffe164 (commit)
      from: 68d08547f36777e2c091008b5e1207ca5b15e9e2 (commit)


</pre>= COMMIT LOG ===========================================================
<div class="highlight"><pre>committer: Anthony Minessale
comments: 
FS-3006

<span style="color: #000080; font-weight: bold">diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c</span>
<span style="color: #000080; font-weight: bold">index 8978b85..baa33d4 100644</span>
<span style="color: #A00000">--- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c</span>
<span style="color: #00A000">+++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c</span>
<span style="color: #800080; font-weight: bold">@@ -40,6 +40,8 @@</span>
 
 #define MY_EVENT_RINGING &quot;portaudio::ringing&quot;
 #define MY_EVENT_MAKE_CALL &quot;portaudio::makecall&quot;
<span style="color: #00A000">+#define MY_EVENT_CALL_HELD &quot;portaudio::callheld&quot;</span>
<span style="color: #00A000">+#define MY_EVENT_CALL_RESUMED &quot;portaudio::callresumed&quot;</span>
 #define MY_EVENT_ERROR_AUDIO_DEV &quot;portaudio::audio_dev_error&quot;
 #define SWITCH_PA_CALL_ID_VARIABLE &quot;pa_call_id&quot;
 
<span style="color: #800080; font-weight: bold">@@ -90,12 +92,20 @@ struct private_object {</span>
         switch_file_handle_t *hfh;
         switch_frame_t hold_frame;
         unsigned char holdbuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
<span style="color: #A00000">-        switch_codec_t write_codec;</span>
         struct private_object *next;
 };
 
 typedef struct private_object private_t;
 
<span style="color: #00A000">+struct audio_stream {</span>
<span style="color: #00A000">+        int indev;</span>
<span style="color: #00A000">+        int outdev;</span>
<span style="color: #00A000">+        PABLIO_Stream *stream;</span>
<span style="color: #00A000">+        switch_timer_t write_timer;</span>
<span style="color: #00A000">+        struct audio_stream *next;</span>
<span style="color: #00A000">+};</span>
<span style="color: #00A000">+typedef struct audio_stream audio_stream_t;</span>
<span style="color: #00A000">+</span>
 static struct {
         int debug;
         int port;
<span style="color: #800080; font-weight: bold">@@ -113,12 +123,13 @@ static struct {</span>
         switch_hash_t *call_hash;
         switch_mutex_t *device_lock;
         switch_mutex_t *pvt_lock;
<span style="color: #00A000">+        switch_mutex_t *streams_lock;</span>
         switch_mutex_t *flag_mutex;
         switch_mutex_t *pa_mutex;
         int sample_rate;
         int codec_ms;
<span style="color: #A00000">-        PABLIO_Stream *audio_stream;</span>
<span style="color: #A00000">-        PABLIO_Stream *ring_stream;</span>
<span style="color: #00A000">+        audio_stream_t *main_stream;</span>
<span style="color: #00A000">+        audio_stream_t *ring_stream;</span>
         switch_codec_t read_codec;
         switch_codec_t write_codec;
         switch_frame_t read_frame;
<span style="color: #800080; font-weight: bold">@@ -126,13 +137,20 @@ static struct {</span>
         unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
         unsigned char cngbuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
         private_t *call_list;
<span style="color: #00A000">+        audio_stream_t *stream_list;</span>
         int ring_interval;
         GFLAGS flags;
         switch_timer_t read_timer;
<span style="color: #A00000">-        switch_timer_t write_timer;</span>
<span style="color: #00A000">+        switch_timer_t readfile_timer;</span>
         switch_timer_t hold_timer;
         int dual_streams;
         time_t deactivate_timer;
<span style="color: #00A000">+        int live_stream_switch;</span>
<span style="color: #00A000">+        int no_auto_resume_call;</span>
<span style="color: #00A000">+        int no_ring_during_call;</span>
<span style="color: #00A000">+        int codecs_inited;</span>
<span style="color: #00A000">+        int stream_in_use; //only really used by playdev</span>
<span style="color: #00A000">+        int destroying_streams;</span>
 } globals;
 
 
<span style="color: #800080; font-weight: bold">@@ -164,9 +182,22 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi</span>
 static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
 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);
<span style="color: #A00000">-static switch_status_t engage_device(int restart);</span>
<span style="color: #A00000">-static switch_status_t engage_ring_device(void);</span>
<span style="color: #A00000">-static void deactivate_ring_device(void);</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static switch_status_t create_codecs(int restart);</span>
<span style="color: #00A000">+static void create_hold_event(private_t *tech_pvt, int unhold);</span>
<span style="color: #00A000">+static audio_stream_t * find_audio_stream(int indev, int outdev, int already_locked);</span>
<span style="color: #00A000">+static audio_stream_t * get_audio_stream(int indev, int outdev);</span>
<span style="color: #00A000">+static audio_stream_t * create_audio_stream(int indev, int outdev);</span>
<span style="color: #00A000">+PaError open_audio_stream(PABLIO_Stream **stream, const PaStreamParameters * inputParameters, const PaStreamParameters * outputParameters);</span>
<span style="color: #00A000">+static switch_status_t switch_audio_stream();</span>
<span style="color: #00A000">+static void add_stream(audio_stream_t *stream, int already_locked);</span>
<span style="color: #00A000">+static void remove_stream(audio_stream_t *stream, int already_locked);</span>
<span style="color: #00A000">+static switch_status_t destroy_audio_stream(int indev, int outdev);</span>
<span style="color: #00A000">+static switch_status_t destroy_actual_stream(audio_stream_t *stream);</span>
<span style="color: #00A000">+static void destroy_audio_streams();</span>
<span style="color: #00A000">+static switch_status_t validate_main_audio_stream();</span>
<span style="color: #00A000">+static switch_status_t validate_ring_audio_stream();</span>
<span style="color: #00A000">+</span>
 static int dump_info(int verbose);
 static switch_status_t load_config(void);
 static int get_dev_by_name(char *name, int in);
<span style="color: #800080; font-weight: bold">@@ -212,9 +243,8 @@ static switch_status_t channel_on_routing(switch_core_session_t *session)</span>
         if (hold_file) {
                 tech_pvt-&gt;hold_file = switch_core_session_strdup(session, hold_file);
         }
<span style="color: #A00000">-        </span>
<span style="color: #A00000">-        if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {</span>
<span style="color: #A00000">-                if (engage_device(0) != SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {</span>
<span style="color: #00A000">+                if (validate_main_audio_stream() != SWITCH_STATUS_SUCCESS) {</span>
                         switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
                         return SWITCH_STATUS_FALSE;
                 }
<span style="color: #800080; font-weight: bold">@@ -238,7 +268,7 @@ static switch_status_t channel_on_routing(switch_core_session_t *session)</span>
                                                                                   globals.read_codec.implementation-&gt;actual_samples_per_second,
                                                                                   SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) == SWITCH_STATUS_SUCCESS) {
 
<span style="color: #A00000">-                                        if (engage_ring_device() != SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                                        if (validate_ring_audio_stream() != SWITCH_STATUS_SUCCESS) {</span>
                                                 switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
                                                 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, &quot;Ring Error!\n&quot;);
                                                 switch_core_file_close(&amp;fh);
<span style="color: #800080; font-weight: bold">@@ -263,7 +293,7 @@ static switch_status_t channel_on_routing(switch_core_session_t *session)</span>
                 }
 
                 while (switch_channel_get_state(channel) == CS_ROUTING &amp;&amp; !switch_test_flag(tech_pvt, TFLAG_ANSWER)) {
<span style="color: #A00000">-                        switch_size_t olen = globals.read_timer.samples;</span>
<span style="color: #00A000">+                        switch_size_t olen = globals.readfile_timer.samples;</span>
 
                         if (switch_micro_time_now() - last &gt;= waitsec) {
                                 char buf[512];
<span style="color: #800080; font-weight: bold">@@ -273,7 +303,8 @@ static switch_status_t channel_on_routing(switch_core_session_t *session)</span>
 
                                 if (switch_event_create_subclass(&amp;event, SWITCH_EVENT_CUSTOM, MY_EVENT_RINGING) == SWITCH_STATUS_SUCCESS) {
                                         switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_info&quot;, buf);
<span style="color: #A00000">-                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;call_id&quot;, tech_pvt-&gt;call_id);</span>
<span style="color: #00A000">+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;call_id&quot;, tech_pvt-&gt;call_id); /* left behind for backwards compatability */</span>
<span style="color: #00A000">+                                        switch_channel_set_variable(channel, SWITCH_PA_CALL_ID_VARIABLE, tech_pvt-&gt;call_id);</span>
                                         switch_channel_event_set_data(channel, event);
                                         switch_event_fire(&amp;event);
                                 }
<span style="color: #800080; font-weight: bold">@@ -282,7 +313,7 @@ static switch_status_t channel_on_routing(switch_core_session_t *session)</span>
                         }
 
                         if (ring_file) {
<span style="color: #A00000">-                                if (switch_core_timer_next(&amp;globals.read_timer) != SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                                if (switch_core_timer_next(&amp;globals.readfile_timer) != SWITCH_STATUS_SUCCESS) {</span>
                                         switch_core_file_close(&amp;fh);
                                         break;
                                 }
<span style="color: #800080; font-weight: bold">@@ -292,8 +323,9 @@ static switch_status_t channel_on_routing(switch_core_session_t *session)</span>
                                         switch_core_file_seek(&amp;fh, &amp;pos, 0, SEEK_SET);
                                 }
 
<span style="color: #A00000">-                                if (globals.ring_stream) {</span>
<span style="color: #A00000">-                                        WriteAudioStream(globals.ring_stream, abuf, (long) olen, &amp;globals.write_timer);</span>
<span style="color: #00A000">+                                if (globals.ring_stream &amp;&amp; (! switch_test_flag(globals.call_list, TFLAG_MASTER) || </span>
<span style="color: #00A000">+                                                        ( !globals.no_ring_during_call &amp;&amp; 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                                                </span>
<span style="color: #00A000">+                                                WriteAudioStream(globals.ring_stream-&gt;stream, abuf, (long) olen, &amp;globals.ring_stream-&gt;write_timer);</span>
                                 }
                         } else {
                                 switch_yield(10000);
<span style="color: #800080; font-weight: bold">@@ -303,7 +335,6 @@ static switch_status_t channel_on_routing(switch_core_session_t *session)</span>
         }
 
         if (ring_file) {
<span style="color: #A00000">-                deactivate_ring_device();</span>
                 switch_core_file_close(&amp;fh);
         }
 
<span style="color: #800080; font-weight: bold">@@ -329,27 +360,130 @@ static switch_status_t channel_on_execute(switch_core_session_t *session)</span>
         return SWITCH_STATUS_SUCCESS;
 }
 
<span style="color: #A00000">-static void deactivate_audio_device(void)</span>
<span style="color: #00A000">+static audio_stream_t* find_audio_stream(int indev, int outdev, int already_locked)</span>
 {
<span style="color: #A00000">-        if (!globals.audio_stream) {</span>
<span style="color: #A00000">-                return;</span>
<span style="color: #00A000">+        audio_stream_t *cur_stream;</span>
<span style="color: #00A000">+        </span>
<span style="color: #00A000">+        if (! globals.stream_list) {</span>
<span style="color: #00A000">+                return NULL;</span>
         }
 
<span style="color: #A00000">-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Stop audio device.\n&quot;);</span>
<span style="color: #00A000">+        if (! already_locked) {</span>
<span style="color: #00A000">+                switch_mutex_lock(globals.streams_lock);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        cur_stream = globals.stream_list;</span>
 
<span style="color: #A00000">-        switch_mutex_lock(globals.device_lock);</span>
<span style="color: #A00000">-        /* LOCKED ************************************************************************************************** */</span>
<span style="color: #00A000">+        while (cur_stream != NULL) {</span>
<span style="color: #00A000">+                if (cur_stream-&gt;outdev == outdev) {</span>
<span style="color: #00A000">+                        if (indev == -1 || cur_stream-&gt;indev == indev) {</span>
<span style="color: #00A000">+                                if (! already_locked) {</span>
<span style="color: #00A000">+                                        switch_mutex_unlock(globals.streams_lock);</span>
<span style="color: #00A000">+                                }</span>
<span style="color: #00A000">+                                return cur_stream;</span>
<span style="color: #00A000">+                        }</span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+                cur_stream = cur_stream-&gt;next;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (! already_locked) {</span>
<span style="color: #00A000">+                switch_mutex_unlock(globals.streams_lock);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        return NULL;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+static void destroy_audio_streams()</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        int close_wait = 4;</span>
<span style="color: #00A000">+        globals.destroying_streams = 1;</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        while (globals.stream_in_use &amp;&amp; close_wait--) {</span>
<span style="color: #00A000">+                switch_yield(250000);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        while (globals.stream_list != NULL) {</span>
<span style="color: #00A000">+                destroy_audio_stream(globals.stream_list-&gt;indev, globals.stream_list-&gt;outdev);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        globals.destroying_streams = 0;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+static switch_status_t validate_main_audio_stream()</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        if (globals.read_timer.timer_interface) {</span>
<span style="color: #00A000">+                switch_core_timer_sync(&amp;globals.read_timer);</span>
<span style="color: #00A000">+        }</span>
 
<span style="color: #A00000">-        if (globals.audio_stream) {</span>
<span style="color: #A00000">-                if (globals.ring_stream == globals.audio_stream) {</span>
<span style="color: #A00000">-                        globals.ring_stream = NULL;</span>
<span style="color: #00A000">+        if (globals.main_stream) {</span>
<span style="color: #00A000">+                if (globals.main_stream-&gt;write_timer.timer_interface) {</span>
<span style="color: #00A000">+                        switch_core_timer_sync(&amp;(globals.main_stream-&gt;write_timer));</span>
                 }
<span style="color: #A00000">-                CloseAudioStream(globals.audio_stream);</span>
<span style="color: #A00000">-                globals.audio_stream = NULL;</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+                return SWITCH_STATUS_SUCCESS;</span>
         }
 
<span style="color: #A00000">-        /* UNLOCKED ************************************************************************************************* */</span>
<span style="color: #A00000">-        switch_mutex_unlock(globals.device_lock);</span>
<span style="color: #00A000">+        globals.main_stream = get_audio_stream(globals.indev, globals.outdev);</span>
<span style="color: #00A000">+        </span>
<span style="color: #00A000">+        if (globals.main_stream) {</span>
<span style="color: #00A000">+                return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static switch_status_t validate_ring_audio_stream()</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        if (globals.ringdev == -1) {</span>
<span style="color: #00A000">+                return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (globals.ring_stream) {</span>
<span style="color: #00A000">+                if (globals.ring_stream-&gt;write_timer.timer_interface) {</span>
<span style="color: #00A000">+                        switch_core_timer_sync(&amp;(globals.ring_stream-&gt;write_timer));</span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+                return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        globals.ring_stream = get_audio_stream(-1, globals.ringdev);</span>
<span style="color: #00A000">+        if (globals.ring_stream) {</span>
<span style="color: #00A000">+                return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static switch_status_t destroy_actual_stream(audio_stream_t *stream)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        if (stream == NULL) {</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (globals.main_stream == stream) {</span>
<span style="color: #00A000">+                globals.main_stream = NULL;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (globals.ring_stream == stream) {</span>
<span style="color: #00A000">+                globals.ring_stream = NULL;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        CloseAudioStream(stream-&gt;stream);</span>
<span style="color: #00A000">+        stream-&gt;stream = NULL;</span>
<span style="color: #00A000">+        </span>
<span style="color: #00A000">+        if (stream-&gt;write_timer.timer_interface) {</span>
<span style="color: #00A000">+                switch_core_timer_destroy(&amp;stream-&gt;write_timer);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        switch_safe_free(stream);</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+static switch_status_t destroy_audio_stream(int indev, int outdev)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        audio_stream_t *stream;</span>
<span style="color: #00A000">+        </span>
<span style="color: #00A000">+        switch_mutex_lock(globals.streams_lock);</span>
<span style="color: #00A000">+        stream = find_audio_stream(indev, outdev,1);</span>
<span style="color: #00A000">+        if (stream == NULL) {</span>
<span style="color: #00A000">+                switch_mutex_unlock(globals.streams_lock);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;                </span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        remove_stream(stream, 1);</span>
<span style="color: #00A000">+        switch_mutex_unlock(globals.streams_lock);</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        destroy_actual_stream(stream);</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
 }
 
 
<span style="color: #800080; font-weight: bold">@@ -368,34 +502,69 @@ static void destroy_codecs(void)</span>
                 switch_core_timer_destroy(&amp;globals.read_timer);
         }
 
<span style="color: #A00000">-        if (globals.write_timer.timer_interface) {</span>
<span style="color: #A00000">-                switch_core_timer_destroy(&amp;globals.write_timer);</span>
<span style="color: #00A000">+        if (globals.readfile_timer.timer_interface) {</span>
<span style="color: #00A000">+                switch_core_timer_destroy(&amp;globals.readfile_timer);</span>
         }
 
         if (globals.hold_timer.timer_interface) {
                 switch_core_timer_destroy(&amp;globals.hold_timer);
         }
 
<span style="color: #A00000">-</span>
<span style="color: #A00000">-</span>
<span style="color: #00A000">+        globals.codecs_inited = 0;</span>
 }
 
<span style="color: #A00000">-static void deactivate_ring_device(void)</span>
<span style="color: #00A000">+static void create_hold_event(private_t *tech_pvt, int unhold)</span>
 {
<span style="color: #A00000">-        if (!globals.ring_stream) {</span>
<span style="color: #A00000">-                return;</span>
<span style="color: #00A000">+        switch_event_t *event;</span>
<span style="color: #00A000">+        char * event_id;</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (unhold) {</span>
<span style="color: #00A000">+                event_id = MY_EVENT_CALL_RESUMED;</span>
<span style="color: #00A000">+        } else {</span>
<span style="color: #00A000">+                event_id = MY_EVENT_CALL_HELD;</span>
         }
 
<span style="color: #A00000">-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Stop ring device.\n&quot;);</span>
<span style="color: #A00000">-        switch_mutex_lock(globals.device_lock);</span>
<span style="color: #A00000">-        if (globals.ring_stream &amp;&amp; globals.ring_stream != globals.audio_stream) {</span>
<span style="color: #A00000">-                CloseAudioStream(globals.ring_stream);</span>
<span style="color: #00A000">+        if (switch_event_create_subclass(&amp;event, SWITCH_EVENT_CUSTOM, event_id) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                switch_channel_event_set_data(switch_core_session_get_channel(tech_pvt-&gt;session), event);</span>
<span style="color: #00A000">+                switch_event_fire(&amp;event);</span>
         }
<span style="color: #A00000">-        globals.ring_stream = NULL;</span>
<span style="color: #A00000">-        switch_mutex_unlock(globals.device_lock);</span>
 }
 
<span style="color: #00A000">+static void add_stream(audio_stream_t * stream, int already_locked)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        audio_stream_t *last;</span>
 
<span style="color: #00A000">+        if (! already_locked) {</span>
<span style="color: #00A000">+                switch_mutex_lock(globals.streams_lock);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        for (last = globals.stream_list; last &amp;&amp; last-&gt;next; last = last-&gt;next);</span>
<span style="color: #00A000">+        if (last == NULL) {</span>
<span style="color: #00A000">+                globals.stream_list = stream;</span>
<span style="color: #00A000">+        } else {</span>
<span style="color: #00A000">+                last-&gt;next = stream;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (! already_locked) {</span>
<span style="color: #00A000">+                switch_mutex_unlock(globals.streams_lock);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+static void remove_stream(audio_stream_t * stream, int already_locked)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        audio_stream_t *previous;</span>
<span style="color: #00A000">+        if (! already_locked) {</span>
<span style="color: #00A000">+                switch_mutex_lock(globals.streams_lock);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (globals.stream_list == stream) {</span>
<span style="color: #00A000">+                globals.stream_list = stream-&gt;next;</span>
<span style="color: #00A000">+        } else {</span>
<span style="color: #00A000">+                for (previous = globals.stream_list; previous &amp;&amp; previous-&gt;next &amp;&amp; previous-&gt;next != stream; previous = previous-&gt;next) {</span>
<span style="color: #00A000">+                        </span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+                previous-&gt;next = stream-&gt;next;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (! already_locked) {</span>
<span style="color: #00A000">+                switch_mutex_unlock(globals.streams_lock);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+}</span>
 
 static void add_pvt(private_t *tech_pvt, int master)
 {
<span style="color: #800080; font-weight: bold">@@ -418,8 +587,9 @@ static void add_pvt(private_t *tech_pvt, int master)</span>
                 if (tp == tech_pvt) {
                         in_list = 1;
                 }
<span style="color: #A00000">-                if (master) {</span>
<span style="color: #00A000">+                if (master &amp;&amp; switch_test_flag(tp, TFLAG_MASTER) ) {</span>
                         switch_clear_flag_locked(tp, TFLAG_MASTER);
<span style="color: #00A000">+                        create_hold_event(tp,0);</span>
                 }
         }
 
<span style="color: #800080; font-weight: bold">@@ -446,11 +616,16 @@ static void add_pvt(private_t *tech_pvt, int master)</span>
 static void remove_pvt(private_t *tech_pvt)
 {
         private_t *tp, *last = NULL;
<span style="color: #00A000">+        int was_master = 0;</span>
 
         switch_mutex_lock(globals.pvt_lock);
         for (tp = globals.call_list; tp; tp = tp-&gt;next) {
<span style="color: #A00000">-                switch_clear_flag_locked(tp, TFLAG_MASTER);</span>
<span style="color: #00A000">+                </span>
                 if (tp == tech_pvt) {
<span style="color: #00A000">+                        if (switch_test_flag(tp, TFLAG_MASTER)) {</span>
<span style="color: #00A000">+                                switch_clear_flag_locked(tp, TFLAG_MASTER);</span>
<span style="color: #00A000">+                                was_master = 1;</span>
<span style="color: #00A000">+                        }</span>
                         if (last) {
                                 last-&gt;next = tp-&gt;next;
                         } else {
<span style="color: #800080; font-weight: bold">@@ -461,10 +636,13 @@ static void remove_pvt(private_t *tech_pvt)</span>
         }
 
         if (globals.call_list) {
<span style="color: #A00000">-                switch_set_flag_locked(globals.call_list, TFLAG_MASTER);</span>
<span style="color: #00A000">+                if (was_master &amp;&amp; ! globals.no_auto_resume_call) {</span>
<span style="color: #00A000">+                        switch_set_flag_locked(globals.call_list, TFLAG_MASTER);</span>
<span style="color: #00A000">+                        create_hold_event(globals.call_list, 1);</span>
<span style="color: #00A000">+                }</span>
         } else {
                 globals.deactivate_timer = switch_epoch_time_now(NULL) + 2;
<span style="color: #A00000">-                deactivate_audio_device();</span>
<span style="color: #00A000">+                destroy_audio_streams();</span>
         }
 
         switch_mutex_unlock(globals.pvt_lock);
<span style="color: #800080; font-weight: bold">@@ -555,8 +733,8 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch</span>
         int samples = 0;
         switch_status_t status = SWITCH_STATUS_FALSE;
         switch_assert(tech_pvt != NULL);
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        if (!globals.audio_stream) {</span>
<span style="color: #00A000">+        </span>
<span style="color: #00A000">+        if (!globals.main_stream) {</span>
                 goto normal_return;
         }
 
<span style="color: #800080; font-weight: bold">@@ -618,7 +796,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch</span>
         }
 
         switch_mutex_lock(globals.device_lock);
<span style="color: #A00000">-        samples = ReadAudioStream(globals.audio_stream, globals.read_frame.data, globals.read_codec.implementation-&gt;samples_per_packet, &amp;globals.read_timer);</span>
<span style="color: #00A000">+        samples = ReadAudioStream(globals.main_stream-&gt;stream, globals.read_frame.data, globals.read_codec.implementation-&gt;samples_per_packet, &amp;globals.read_timer);</span>
         switch_mutex_unlock(globals.device_lock);
 
         if (samples) {
<span style="color: #800080; font-weight: bold">@@ -635,7 +813,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch</span>
                 goto cng_nowait;
         }
 
<span style="color: #A00000">-  normal_return:</span>
<span style="color: #00A000">+normal_return:</span>
         return status;
 
   cng_nowait:
<span style="color: #800080; font-weight: bold">@@ -655,7 +833,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc</span>
         private_t *tech_pvt = switch_core_session_get_private(session);
         switch_assert(tech_pvt != NULL);
 
<span style="color: #A00000">-        if (!globals.audio_stream) {</span>
<span style="color: #00A000">+        if (!globals.main_stream) {</span>
                 return SWITCH_STATUS_FALSE;
         }
 
<span style="color: #800080; font-weight: bold">@@ -667,9 +845,9 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc</span>
                 return SWITCH_STATUS_SUCCESS;
         }
 
<span style="color: #A00000">-        if (globals.audio_stream) {</span>
<span style="color: #00A000">+        if (globals.main_stream) {</span>
                 if (switch_test_flag((&amp;globals), GFLAG_EAR)) {
<span style="color: #A00000">-                        WriteAudioStream(globals.audio_stream, (short *) frame-&gt;data, (int) (frame-&gt;datalen / sizeof(SAMPLE)), &amp;globals.write_timer);</span>
<span style="color: #00A000">+                        WriteAudioStream(globals.main_stream-&gt;stream, (short *) frame-&gt;data, (int) (frame-&gt;datalen / sizeof(SAMPLE)), &amp;(globals.main_stream-&gt;write_timer));</span>
                 }
                 status = SWITCH_STATUS_SUCCESS;
         }
<span style="color: #800080; font-weight: bold">@@ -747,7 +925,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi</span>
                         channel = switch_core_session_get_channel(*new_session);
                         switch_core_session_set_private(*new_session, tech_pvt);
                         tech_pvt-&gt;session = *new_session;
<span style="color: #A00000">-                        globals.flags = GFLAG_EAR | GFLAG_MOUTH;</span>
                 } else {
                         switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, &quot;Hey where is my memory pool?\n&quot;);
                         switch_core_session_destroy(new_session);
<span style="color: #800080; font-weight: bold">@@ -796,16 +973,17 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load)</span>
         switch_core_hash_init(&amp;globals.call_hash, module_pool);
         switch_mutex_init(&amp;globals.device_lock, SWITCH_MUTEX_NESTED, module_pool);
         switch_mutex_init(&amp;globals.pvt_lock, SWITCH_MUTEX_NESTED, module_pool);
<span style="color: #00A000">+        switch_mutex_init(&amp;globals.streams_lock, SWITCH_MUTEX_NESTED, module_pool);</span>
         switch_mutex_init(&amp;globals.flag_mutex, SWITCH_MUTEX_NESTED, module_pool);
         switch_mutex_init(&amp;globals.pa_mutex, SWITCH_MUTEX_NESTED, module_pool);
<span style="color: #A00000">-</span>
<span style="color: #00A000">+        globals.codecs_inited=0;</span>
         globals.read_frame.data = globals.databuf;
         globals.read_frame.buflen = sizeof(globals.databuf);
         globals.cng_frame.data = globals.cngbuf;
         globals.cng_frame.buflen = sizeof(globals.cngbuf);
         globals.cng_frame.datalen = switch_samples_per_packet(globals.sample_rate, globals.codec_ms) * 2;
         switch_set_flag((&amp;globals.cng_frame), SFF_CNG);
<span style="color: #A00000">-</span>
<span style="color: #00A000">+        globals.flags = GFLAG_EAR | GFLAG_MOUTH;</span>
         /* dual streams makes portaudio on solaris choke */
 #if defined(sun) || defined(__sun)
         globals.dual_streams = 0;
<span style="color: #800080; font-weight: bold">@@ -834,6 +1012,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load)</span>
                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn&#39;t register subclass!\n&quot;);
                 return SWITCH_STATUS_GENERR;
         }
<span style="color: #00A000">+        if (switch_event_reserve_subclass(MY_EVENT_CALL_HELD) != SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn&#39;t register subclass!\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_GENERR;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (switch_event_reserve_subclass(MY_EVENT_CALL_RESUMED) != SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn&#39;t register subclass!\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_GENERR;</span>
<span style="color: #00A000">+        }</span>
 
         if (switch_event_reserve_subclass(MY_EVENT_ERROR_AUDIO_DEV) != SWITCH_STATUS_SUCCESS) {
                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn&#39;t register subclass!\n&quot;);
<span style="color: #800080; font-weight: bold">@@ -861,9 +1047,13 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load)</span>
         switch_console_set_complete(&quot;add pa devlist&quot;);
         switch_console_set_complete(&quot;add pa indev&quot;);
         switch_console_set_complete(&quot;add pa outdev&quot;);
<span style="color: #00A000">+        switch_console_set_complete(&quot;add pa preparestream&quot;);</span>
<span style="color: #00A000">+        switch_console_set_complete(&quot;add pa switchstream&quot;);</span>
<span style="color: #00A000">+        switch_console_set_complete(&quot;add pa closestreams&quot;);</span>
         switch_console_set_complete(&quot;add pa ringdev&quot;);
         switch_console_set_complete(&quot;add pa ringfile&quot;);
         switch_console_set_complete(&quot;add pa play&quot;);
<span style="color: #00A000">+        switch_console_set_complete(&quot;add pa playdev&quot;);</span>
         switch_console_set_complete(&quot;add pa looptest&quot;);
 
         /* indicate that the module should continue to be loaded */
<span style="color: #800080; font-weight: bold">@@ -881,9 +1071,12 @@ static switch_status_t load_config(void)</span>
                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Open of %s failed\n&quot;, cf);
                 return SWITCH_STATUS_TERM;
         }
<span style="color: #A00000">-</span>
<span style="color: #00A000">+        destroy_audio_streams();</span>
<span style="color: #00A000">+        destroy_codecs();</span>
         globals.dual_streams = 0;
<span style="color: #A00000">-</span>
<span style="color: #00A000">+        globals.live_stream_switch = 0;</span>
<span style="color: #00A000">+        globals.no_auto_resume_call = 0;</span>
<span style="color: #00A000">+        globals.no_ring_during_call = 0;</span>
         globals.indev = globals.outdev = globals.ringdev = -1;
         globals.sample_rate = 8000;
 
<span style="color: #800080; font-weight: bold">@@ -896,6 +1089,24 @@ static switch_status_t load_config(void)</span>
                                 globals.debug = atoi(val);
                         } else if (!strcmp(var, &quot;ring-interval&quot;)) {
                                 globals.ring_interval = atoi(val);
<span style="color: #00A000">+                        } else if (!strcmp(var, &quot;no-auto-resume-call&quot;)) {</span>
<span style="color: #00A000">+                                if (switch_true(val)) {</span>
<span style="color: #00A000">+                                        globals.no_auto_resume_call = 1;</span>
<span style="color: #00A000">+                                } else {</span>
<span style="color: #00A000">+                                        globals.no_auto_resume_call = 0;</span>
<span style="color: #00A000">+                                }</span>
<span style="color: #00A000">+                        } else if (!strcmp(var, &quot;no-ring-during-call&quot;)) {</span>
<span style="color: #00A000">+                                if (switch_true(val)) {</span>
<span style="color: #00A000">+                                        globals.no_ring_during_call = 1;</span>
<span style="color: #00A000">+                                } else {</span>
<span style="color: #00A000">+                                        globals.no_ring_during_call = 0;</span>
<span style="color: #00A000">+                                }</span>
<span style="color: #00A000">+                        } else if (!strcmp(var, &quot;live-stream-switch&quot;)) {</span>
<span style="color: #00A000">+                                if (switch_true(val)) {</span>
<span style="color: #00A000">+                                        globals.live_stream_switch = 1;</span>
<span style="color: #00A000">+                                } else {</span>
<span style="color: #00A000">+                                        globals.live_stream_switch = 0;</span>
<span style="color: #00A000">+                                }</span>
                         } else if (!strcmp(var, &quot;ring-file&quot;)) {
                                 set_global_ring_file(val);
                         } else if (!strcmp(var, &quot;hold-file&quot;)) {
<span style="color: #800080; font-weight: bold">@@ -1007,8 +1218,7 @@ static switch_status_t load_config(void)</span>
 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_shutdown)
 {
 
<span style="color: #A00000">-        deactivate_audio_device();</span>
<span style="color: #A00000">-        deactivate_ring_device();</span>
<span style="color: #00A000">+        destroy_audio_streams();</span>
         destroy_codecs();
 
         Pa_Terminate();
<span style="color: #800080; font-weight: bold">@@ -1017,6 +1227,9 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_shutdown)</span>
         switch_event_free_subclass(MY_EVENT_RINGING);
         switch_event_free_subclass(MY_EVENT_MAKE_CALL);
         switch_event_free_subclass(MY_EVENT_ERROR_AUDIO_DEV);
<span style="color: #00A000">+        switch_event_free_subclass(MY_EVENT_CALL_HELD);</span>
<span style="color: #00A000">+        switch_event_free_subclass(MY_EVENT_CALL_RESUMED);</span>
<span style="color: #00A000">+        </span>
 
         switch_safe_free(globals.dialplan);
         switch_safe_free(globals.context);
<span style="color: #800080; font-weight: bold">@@ -1118,7 +1331,99 @@ static void PrintSupportedStandardSampleRates(const PaStreamParameters * inputPa</span>
 }
 
 /*******************************************************************/
<span style="color: #00A000">+static switch_status_t play_dev(switch_stream_handle_t *stream, int outdev, char * file, const char * max_seconds, const char * no_close)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        switch_file_handle_t fh = { 0 };</span>
<span style="color: #00A000">+        int samples = 0;</span>
<span style="color: #00A000">+        int seconds = 5;</span>
<span style="color: #00A000">+        audio_stream_t * audio_stream;</span>
<span style="color: #00A000">+        int created_stream = 0;</span>
<span style="color: #00A000">+        int wrote = 0;</span>
<span style="color: #00A000">+        switch_size_t olen;</span>
<span style="color: #00A000">+        int16_t abuf[2048];</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (!strcasecmp(file, &quot;ringtest&quot;)) {</span>
<span style="color: #00A000">+                file = globals.ring_file;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (outdev == -1) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;Invalid output audio device\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        audio_stream = get_audio_stream(-1, outdev);</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (switch_core_file_open(&amp;fh,        file,</span>
<span style="color: #00A000">+                globals.read_codec.implementation-&gt;number_of_channels,</span>
<span style="color: #00A000">+                globals.read_codec.implementation-&gt;actual_samples_per_second,</span>
<span style="color: #00A000">+                SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                        stream-&gt;write_function(stream, &quot;Cannot play requested file %s\n&quot;, file);</span>
<span style="color: #00A000">+                        return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        olen = globals.read_codec.implementation-&gt;samples_per_packet;</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (max_seconds) {</span>
<span style="color: #00A000">+                int i = atoi(max_seconds);</span>
<span style="color: #00A000">+                if (i &gt;= 0) {</span>
<span style="color: #00A000">+                        seconds = i;</span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (globals.call_list) {</span>
<span style="color: #00A000">+                switch_mutex_lock(globals.pvt_lock);</span>
<span style="color: #00A000">+                if (!globals.main_stream) {</span>
<span style="color: #00A000">+                        switch_mutex_unlock(globals.pvt_lock);</span>
<span style="color: #00A000">+                        return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+                if ( switch_test_flag(globals.call_list, TFLAG_MASTER) &amp;&amp; globals.main_stream-&gt;outdev == outdev) { /*so we are the active stream so we need to dupe it basically */</span>
<span style="color: #00A000">+                        audio_stream = create_audio_stream(-1,outdev);</span>
<span style="color: #00A000">+                        created_stream=1;</span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+                switch_mutex_unlock(globals.pvt_lock);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (! audio_stream) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;Failed to engage audio device\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+</span>
 
<span style="color: #00A000">+        samples = globals.read_codec.implementation-&gt;actual_samples_per_second * seconds;</span>
<span style="color: #00A000">+        globals.stream_in_use=1;</span>
<span style="color: #00A000">+        while (switch_core_file_read(&amp;fh, abuf, &amp;olen) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                if (globals.destroying_streams ||  ! audio_stream-&gt;stream) {</span>
<span style="color: #00A000">+                        break;</span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+                </span>
<span style="color: #00A000">+                WriteAudioStream(audio_stream-&gt;stream, abuf, (long) olen, &amp;(audio_stream-&gt;write_timer));</span>
<span style="color: #00A000">+                wrote += (int) olen;</span>
<span style="color: #00A000">+                if (samples) {</span>
<span style="color: #00A000">+                        samples -= (int) olen;</span>
<span style="color: #00A000">+                        if (samples &lt;= 0) {</span>
<span style="color: #00A000">+                                break;</span>
<span style="color: #00A000">+                        }</span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+                olen = globals.read_codec.implementation-&gt;samples_per_packet;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        globals.stream_in_use = 0;</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        switch_core_file_close(&amp;fh);</span>
<span style="color: #00A000">+        if (! globals.call_list &amp;&amp; ( ! no_close || strcasecmp(no_close,  &quot;no_close&quot;))) {</span>
<span style="color: #00A000">+                destroy_audio_streams();</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        seconds = wrote / globals.read_codec.implementation-&gt;actual_samples_per_second;</span>
<span style="color: #00A000">+        stream-&gt;write_function(stream, &quot;playback test [%s] %d second(s) %d samples @%dkhz&quot;,</span>
<span style="color: #00A000">+                file, seconds, wrote, globals.read_codec.implementation-&gt;actual_samples_per_second);</span>
<span style="color: #00A000">+        if (created_stream) { /*still need this as not added to the global pool */</span>
<span style="color: #00A000">+                destroy_actual_stream(audio_stream);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
 static switch_status_t devlist(char **argv, int argc, switch_stream_handle_t *stream)
 {
         int i, numDevices, prev;
<span style="color: #800080; font-weight: bold">@@ -1200,8 +1505,7 @@ static int dump_info(int verbose)</span>
         }
 
         if (verbose &lt; 0) {
<span style="color: #A00000">-                deactivate_audio_device();</span>
<span style="color: #A00000">-                deactivate_ring_device();</span>
<span style="color: #00A000">+                destroy_audio_streams();</span>
                 destroy_codecs();
                 Pa_Terminate();
                 Pa_Initialize();
<span style="color: #800080; font-weight: bold">@@ -1309,36 +1613,15 @@ static int dump_info(int verbose)</span>
         return err;
 }
 
<span style="color: #A00000">-static switch_status_t engage_device(int restart)</span>
<span style="color: #00A000">+static switch_status_t create_codecs(int restart)</span>
 {
<span style="color: #A00000">-        PaStreamParameters inputParameters, outputParameters;</span>
<span style="color: #A00000">-        PaError err;</span>
         int sample_rate = globals.sample_rate;
         int codec_ms = globals.codec_ms;
<span style="color: #A00000">-        switch_event_t *event;</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        switch_mutex_lock(globals.device_lock);</span>
<span style="color: #A00000">-        while (globals.deactivate_timer &gt; switch_epoch_time_now(NULL)) {</span>
<span style="color: #A00000">-                switch_yield(1000000);</span>
<span style="color: #A00000">-        }</span>
<span style="color: #A00000">-        switch_mutex_unlock(globals.device_lock);</span>
<span style="color: #A00000">-</span>
 
         if (restart) {
<span style="color: #A00000">-                deactivate_audio_device();</span>
<span style="color: #A00000">-                deactivate_ring_device();</span>
                 destroy_codecs();
         }
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        if (globals.read_timer.timer_interface) {</span>
<span style="color: #A00000">-                switch_core_timer_sync(&amp;globals.read_timer);</span>
<span style="color: #A00000">-        }</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        if (globals.write_timer.timer_interface) {</span>
<span style="color: #A00000">-                switch_core_timer_sync(&amp;globals.write_timer);</span>
<span style="color: #A00000">-        }</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        if (globals.audio_stream) {</span>
<span style="color: #00A000">+        if (globals.codecs_inited) {</span>
                 return SWITCH_STATUS_SUCCESS;
         }
 
<span style="color: #800080; font-weight: bold">@@ -1375,20 +1658,18 @@ static switch_status_t engage_device(int restart)</span>
                         return SWITCH_STATUS_FALSE;
                 }
         }
<span style="color: #A00000">-</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        if (!globals.write_timer.timer_interface) {</span>
<span style="color: #A00000">-                if (switch_core_timer_init(&amp;globals.write_timer,</span>
<span style="color: #00A000">+        if (!globals.readfile_timer.timer_interface) {</span>
<span style="color: #00A000">+                if (switch_core_timer_init(&amp;globals.readfile_timer,</span>
                                                                    globals.timer_name, codec_ms, globals.read_codec.implementation-&gt;samples_per_packet,
                                                                    module_pool) != SWITCH_STATUS_SUCCESS) {
                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;setup timer failed!\n&quot;);
                         switch_core_codec_destroy(&amp;globals.read_codec);
                         switch_core_codec_destroy(&amp;globals.write_codec);
<span style="color: #A00000">-                        switch_core_timer_destroy(&amp;globals.read_timer);</span>
                         return SWITCH_STATUS_FALSE;
                 }
         }
 
<span style="color: #00A000">+</span>
         if (!globals.hold_timer.timer_interface) {
                 if (switch_core_timer_init(&amp;globals.hold_timer,
                                                                    globals.timer_name, codec_ms, globals.read_codec.implementation-&gt;samples_per_packet,
<span style="color: #800080; font-weight: bold">@@ -1397,106 +1678,119 @@ static switch_status_t engage_device(int restart)</span>
                         switch_core_codec_destroy(&amp;globals.read_codec);
                         switch_core_codec_destroy(&amp;globals.write_codec);
                         switch_core_timer_destroy(&amp;globals.read_timer);
<span style="color: #A00000">-                        switch_core_timer_destroy(&amp;globals.write_timer);</span>
<span style="color: #00A000">+                        switch_core_timer_destroy(&amp;globals.readfile_timer);</span>
<span style="color: #00A000">+                        </span>
                         return SWITCH_STATUS_FALSE;
                 }
         }
 
<span style="color: #A00000">-        globals.read_frame.rate = sample_rate;</span>
<span style="color: #A00000">-        globals.read_frame.codec = &amp;globals.read_codec;</span>
<span style="color: #00A000">+        globals.cng_frame.rate = globals.read_frame.rate = sample_rate;</span>
<span style="color: #00A000">+        globals.cng_frame.codec = globals.read_frame.codec = &amp;globals.read_codec;</span>
 
<span style="color: #A00000">-        switch_mutex_lock(globals.device_lock);</span>
<span style="color: #A00000">-        /* LOCKED ************************************************************************************************** */</span>
<span style="color: #A00000">-        inputParameters.device = globals.indev;</span>
<span style="color: #A00000">-        inputParameters.channelCount = 1;</span>
<span style="color: #A00000">-        inputParameters.sampleFormat = SAMPLE_TYPE;</span>
<span style="color: #A00000">-        inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)-&gt;defaultLowInputLatency;</span>
<span style="color: #A00000">-        inputParameters.hostApiSpecificStreamInfo = NULL;</span>
<span style="color: #A00000">-        outputParameters.device = globals.outdev;</span>
<span style="color: #00A000">+        globals.codecs_inited=1;</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static switch_status_t switch_audio_stream()</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        audio_stream_t *stream;</span>
<span style="color: #00A000">+        if (! globals.call_list) { /* If no active calls then it will automatically switch over on next call */</span>
<span style="color: #00A000">+                return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        stream = get_audio_stream(globals.indev, globals.outdev);</span>
<span style="color: #00A000">+        if (stream == NULL) {</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        globals.main_stream = stream;//TODO: need locks around here??</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+PaError open_audio_stream(PABLIO_Stream **stream, const PaStreamParameters * inputParameters, const PaStreamParameters * outputParameters)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        if (inputParameters-&gt;device != -1) {</span>
<span style="color: #00A000">+                return OpenAudioStream(stream, inputParameters, outputParameters, globals.sample_rate, paClipOff, globals.read_codec.implementation-&gt;samples_per_packet, globals.dual_streams);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        return OpenAudioStream(stream, NULL, outputParameters, globals.sample_rate, paClipOff, globals.read_codec.implementation-&gt;samples_per_packet, 0);</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static audio_stream_t *create_audio_stream(int indev, int outdev)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        PaStreamParameters inputParameters, outputParameters;</span>
<span style="color: #00A000">+        PaError err;</span>
<span style="color: #00A000">+        switch_event_t *event;</span>
<span style="color: #00A000">+        audio_stream_t *stream;</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        stream = malloc(sizeof(audio_stream_t));</span>
<span style="color: #00A000">+        if (stream == NULL) {</span>
<span style="color: #00A000">+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Unable to alloc memory\n&quot;);</span>
<span style="color: #00A000">+                return NULL;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        memset(stream, 0, sizeof(audio_stream_t));</span>
<span style="color: #00A000">+        stream-&gt;next = NULL;</span>
<span style="color: #00A000">+        stream-&gt;stream = NULL;</span>
<span style="color: #00A000">+        stream-&gt;indev = indev;</span>
<span style="color: #00A000">+        stream-&gt;outdev = outdev;</span>
<span style="color: #00A000">+        if (!stream-&gt;write_timer.timer_interface) {</span>
<span style="color: #00A000">+                if (switch_core_timer_init(&amp;(stream-&gt;write_timer),</span>
<span style="color: #00A000">+                                                                   globals.timer_name, globals.codec_ms, globals.read_codec.implementation-&gt;samples_per_packet,</span>
<span style="color: #00A000">+                                                                   module_pool) != SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;setup timer failed!\n&quot;);</span>
<span style="color: #00A000">+                        switch_safe_free(stream);</span>
<span style="color: #00A000">+                        return NULL;</span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        inputParameters.device = indev;</span>
<span style="color: #00A000">+        if (indev != -1) {</span>
<span style="color: #00A000">+                inputParameters.channelCount = 1;</span>
<span style="color: #00A000">+                inputParameters.sampleFormat = SAMPLE_TYPE;</span>
<span style="color: #00A000">+                inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)-&gt;defaultLowInputLatency;</span>
<span style="color: #00A000">+                inputParameters.hostApiSpecificStreamInfo = NULL;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        outputParameters.device = outdev;</span>
         outputParameters.channelCount = 1;
         outputParameters.sampleFormat = SAMPLE_TYPE;
         outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)-&gt;defaultLowOutputLatency;
         outputParameters.hostApiSpecificStreamInfo = NULL;
<span style="color: #A00000">-        //err = OpenAudioStream(&amp;globals.audio_stream, NULL/*&amp;inputParameters*/, &amp;outputParameters, sample_rate, paClipOff,</span>
<span style="color: #A00000">-        //globals.read_codec.implementation-&gt;samples_per_packet);</span>
<span style="color: #A00000">-        err = OpenAudioStream(&amp;globals.audio_stream, &amp;inputParameters, &amp;outputParameters, sample_rate, paClipOff,</span>
<span style="color: #A00000">-                                                  globals.read_codec.implementation-&gt;samples_per_packet, globals.dual_streams);</span>
<span style="color: #A00000">-        /* UNLOCKED ************************************************************************************************* */</span>
<span style="color: #00A000">+        </span>
<span style="color: #00A000">+        err = open_audio_stream(&amp;(stream-&gt;stream), &amp;inputParameters, &amp;outputParameters);</span>
         if (err != paNoError) {
                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error opening audio device retrying\n&quot;);
                 switch_yield(1000000);
<span style="color: #A00000">-                err = OpenAudioStream(&amp;globals.audio_stream, &amp;inputParameters, &amp;outputParameters, sample_rate, paClipOff,</span>
<span style="color: #A00000">-                                                          globals.read_codec.implementation-&gt;samples_per_packet, globals.dual_streams);</span>
<span style="color: #00A000">+                err = open_audio_stream(&amp;(stream-&gt;stream), &amp;inputParameters, &amp;outputParameters);</span>
         }
 
<span style="color: #A00000">-        switch_mutex_unlock(globals.device_lock);</span>
<span style="color: #A00000">-</span>
         if (err != paNoError) {
<span style="color: #00A000">+                switch_safe_free(stream);</span>
                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can&#39;t open audio device\n&quot;);
<span style="color: #A00000">-                switch_core_codec_destroy(&amp;globals.read_codec);</span>
<span style="color: #A00000">-                switch_core_codec_destroy(&amp;globals.write_codec);</span>
<span style="color: #A00000">-                switch_core_timer_destroy(&amp;globals.read_timer);</span>
<span style="color: #A00000">-                switch_core_timer_destroy(&amp;globals.write_timer);</span>
<span style="color: #A00000">-                switch_core_timer_destroy(&amp;globals.hold_timer);</span>
                 if (switch_event_create_subclass(&amp;event, SWITCH_EVENT_CUSTOM, MY_EVENT_ERROR_AUDIO_DEV) == SWITCH_STATUS_SUCCESS) {
                         switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;Reason&quot;, Pa_GetErrorText(err));
                         switch_event_fire(&amp;event);
                 }
<span style="color: #A00000">-                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+                return NULL;</span>
         }
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Engage audio device rate: %d channels %d\n&quot;, sample_rate, outputParameters.channelCount);</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        engage_ring_device();</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Created audio stream: %d channels %d\n&quot;, globals.sample_rate, outputParameters.channelCount);</span>
<span style="color: #00A000">+        return stream;</span>
 }
 
<span style="color: #A00000">-static switch_status_t engage_ring_device(void)</span>
<span style="color: #00A000">+audio_stream_t *get_audio_stream(int indev, int outdev)</span>
 {
<span style="color: #A00000">-        PaStreamParameters outputParameters = { 0 };</span>
<span style="color: #A00000">-        PaError err;</span>
<span style="color: #A00000">-        int sample_rate = globals.sample_rate;</span>
<span style="color: #A00000">-        int channels = 1;</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        if (globals.ring_stream) {</span>
<span style="color: #A00000">-                return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+        audio_stream_t *stream;</span>
<span style="color: #00A000">+        if (outdev == -1) {</span>
<span style="color: #00A000">+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error invalid output audio device\n&quot;);</span>
         }
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        if (globals.ringdev == globals.outdev) {</span>
<span style="color: #A00000">-                if (engage_device(0) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #A00000">-                        globals.ring_stream = globals.audio_stream;</span>
<span style="color: #A00000">-                } else {</span>
<span style="color: #A00000">-                        goto error;</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-        } else {</span>
<span style="color: #A00000">-                switch_mutex_lock(globals.device_lock);</span>
<span style="color: #A00000">-                /* LOCKED ************************************************************************************************** */</span>
<span style="color: #A00000">-                outputParameters.device = globals.ringdev;</span>
<span style="color: #A00000">-                outputParameters.channelCount = channels;</span>
<span style="color: #A00000">-                outputParameters.sampleFormat = SAMPLE_TYPE;</span>
<span style="color: #A00000">-                outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)-&gt;defaultLowOutputLatency;</span>
<span style="color: #A00000">-                outputParameters.hostApiSpecificStreamInfo = NULL;</span>
<span style="color: #A00000">-                err = OpenAudioStream(&amp;globals.ring_stream, NULL,</span>
<span style="color: #A00000">-                                                          &amp;outputParameters, sample_rate, paClipOff, globals.read_codec.implementation-&gt;samples_per_packet, globals.dual_streams);</span>
<span style="color: #A00000">-                /* UNLOCKED ************************************************************************************************* */</span>
<span style="color: #A00000">-                switch_mutex_unlock(globals.device_lock);</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                if (err != paNoError) {</span>
<span style="color: #A00000">-                        goto error;</span>
<span style="color: #A00000">-                }</span>
<span style="color: #00A000">+        if (create_codecs(0) != SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                return NULL;</span>
         }
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        switch_yield(10000);</span>
<span style="color: #A00000">-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Engage ring device rate: %d channels %d\n&quot;, sample_rate, channels);</span>
<span style="color: #A00000">-        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-  error:</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can&#39;t open ring device\n&quot;);</span>
<span style="color: #A00000">-        return SWITCH_STATUS_FALSE;</span>
<span style="color: #A00000">-</span>
<span style="color: #00A000">+        stream = find_audio_stream(indev, outdev, 0);</span>
<span style="color: #00A000">+        if (stream != NULL) {</span>
<span style="color: #00A000">+                return stream;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        stream = create_audio_stream(indev, outdev);</span>
<span style="color: #00A000">+        if (stream) {</span>
<span style="color: #00A000">+                add_stream(stream, 0);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        return stream;</span>
 }
 
 static switch_status_t dtmf_call(char **argv, int argc, switch_stream_handle_t *stream)
<span style="color: #800080; font-weight: bold">@@ -1523,6 +1817,211 @@ static switch_status_t dtmf_call(char **argv, int argc, switch_stream_handle_t *</span>
         return SWITCH_STATUS_SUCCESS;
 }
 
<span style="color: #00A000">+static switch_status_t close_streams(char **argv, int argc, switch_stream_handle_t *stream)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        if (globals.call_list) {</span>
<span style="color: #00A000">+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;ERROR: Cannot use this command this while a call is in progress\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        destroy_audio_streams();</span>
<span style="color: #00A000">+        stream-&gt;write_function(stream, &quot;closestreams all open streams closed\n&quot;);</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static switch_status_t set_indev(char **argv, int argc, switch_stream_handle_t *stream)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        int devval;</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (globals.call_list &amp;&amp; ! globals.live_stream_switch) {</span>
<span style="color: #00A000">+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;ERROR: Cannot use this command this while a call is in progress\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (*argv[0] == &#39;#&#39;) {</span>
<span style="color: #00A000">+                devval = get_dev_by_number(argv[0] + 1, 1);</span>
<span style="color: #00A000">+        } else {</span>
<span style="color: #00A000">+                devval = get_dev_by_name(argv[0], 1);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (devval &lt; 0) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;indev not set (invalid value)\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        globals.indev = devval;</span>
<span style="color: #00A000">+        switch_audio_stream();</span>
<span style="color: #00A000">+        stream-&gt;write_function(stream, &quot;indev set to %d\n&quot;, devval);</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static switch_status_t set_outdev(char **argv, int argc, switch_stream_handle_t *stream)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        int devval;</span>
<span style="color: #00A000">+        if (globals.call_list &amp;&amp; ! globals.live_stream_switch) {</span>
<span style="color: #00A000">+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;ERROR: Cannot use this command this while a call is in progress\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (*argv[0] == &#39;#&#39;) {</span>
<span style="color: #00A000">+                devval = get_dev_by_number(argv[0] + 1, 0);</span>
<span style="color: #00A000">+        } else {</span>
<span style="color: #00A000">+                devval = get_dev_by_name(argv[0], 0);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (devval &lt; 0) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;outdev not set (invalid value)\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        globals.outdev = devval;</span>
<span style="color: #00A000">+        switch_audio_stream();</span>
<span style="color: #00A000">+        stream-&gt;write_function(stream, &quot;outdev set to %d\n&quot;, devval);</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static switch_status_t prepare_stream(char **argv, int argc, switch_stream_handle_t *stream)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        int devval=-2,devval2=-1;</span>
<span style="color: #00A000">+        if (! strcmp(argv[0], &quot;#-1&quot;)) {</span>
<span style="color: #00A000">+                devval = -1;</span>
<span style="color: #00A000">+        } else if (*argv[0] == &#39;#&#39;) {</span>
<span style="color: #00A000">+                devval = get_dev_by_number(argv[0]+1, 1);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (devval == -2) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;preparestream not prepared as indev has (invalid value)\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (*argv[1] == &#39;#&#39;) {</span>
<span style="color: #00A000">+                devval2 = get_dev_by_number(argv[1]+1, 0);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (devval2 == -1) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;preparestream not prepared as outdev has (invalid value)\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (! get_audio_stream(devval,devval2)) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;preparestream not prepared received an invalid stream back\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        stream-&gt;write_function(stream, &quot;preparestream prepared indev: %d outdev: %d\n&quot;, devval, devval2);</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static switch_status_t switch_stream(char **argv, int argc, switch_stream_handle_t *stream)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        int devval =-1, devval2 = -1;</span>
<span style="color: #00A000">+        if (globals.call_list &amp;&amp; ! globals.live_stream_switch) {</span>
<span style="color: #00A000">+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;ERROR: Cannot use this command this while a call is in progress\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (*argv[0] == &#39;#&#39;) {</span>
<span style="color: #00A000">+                devval = get_dev_by_number(argv[0]+1, 1);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (devval == -1) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;switchstream not prepared as indev has (invalid value)\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (*argv[1] == &#39;#&#39;) {</span>
<span style="color: #00A000">+                devval2 = get_dev_by_number(argv[1]+1, 0);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (devval2 == -1) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;switchstream not prepared as outdev has (invalid value)\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        globals.indev = devval;</span>
<span style="color: #00A000">+        globals.outdev = devval2;</span>
<span style="color: #00A000">+        if (switch_audio_stream() != SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;switchstream was unable to switch\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        stream-&gt;write_function(stream, &quot;switchstream switched to indev: %d outdev: %d\n&quot;, devval, devval2);</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static switch_status_t set_ringdev(char **argv, int argc, switch_stream_handle_t *stream)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        int devval;</span>
<span style="color: #00A000">+        if (globals.call_list &amp;&amp; ! globals.live_stream_switch) {</span>
<span style="color: #00A000">+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;ERROR: Cannot use this command this while a call is in progress\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (! strcmp(argv[0], &quot;#-1&quot;)) {</span>
<span style="color: #00A000">+                globals.ring_stream = NULL;</span>
<span style="color: #00A000">+                globals.ringdev = -1;</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;ringdev set to %d\n&quot;, globals.ringdev);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+        } else if (*argv[0] == &#39;#&#39;) {</span>
<span style="color: #00A000">+                devval = get_dev_by_number(argv[0] + 1, 0);</span>
<span style="color: #00A000">+        } else {</span>
<span style="color: #00A000">+                devval = get_dev_by_name(argv[0], 0);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (devval == -1) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;ringdev not set as dev has (invalid value)\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        globals.ringdev = devval;</span>
<span style="color: #00A000">+        stream-&gt;write_function(stream, &quot;ringdev set to %d\n&quot;, globals.ringdev);</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static switch_status_t looptest(char **argv, int argc, switch_stream_handle_t *stream)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        int samples = 0;</span>
<span style="color: #00A000">+        int success = 0;</span>
<span style="color: #00A000">+        int i;</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (globals.call_list) {</span>
<span style="color: #00A000">+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;ERROR: Cannot use this command this while a call is in progress\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (validate_main_audio_stream() != SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;looptest Failed to engage audio device\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        globals.stream_in_use = 1;</span>
<span style="color: #00A000">+        for (i = 0; i &lt; 400; i++) {</span>
<span style="color: #00A000">+                if (globals.destroying_streams ||  ! globals.main_stream-&gt;stream) {</span>
<span style="color: #00A000">+                        break;</span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+                if ((samples = ReadAudioStream(globals.main_stream-&gt;stream, globals.read_frame.data, globals.read_codec.implementation-&gt;samples_per_packet, &amp;globals.read_timer))) {</span>
<span style="color: #00A000">+                        WriteAudioStream(globals.main_stream-&gt;stream, globals.read_frame.data, (long) samples, &amp;(globals.main_stream-&gt;write_timer));</span>
<span style="color: #00A000">+                        success = 1;</span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+                switch_yield(10000);</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        globals.stream_in_use = 0;</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+        if (!success) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;Failed to read any bytes from indev\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        destroy_audio_streams();</span>
<span style="color: #00A000">+        stream-&gt;write_function(stream, &quot;looptest complete\n&quot;);</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
<span style="color: #00A000">+static switch_status_t set_ringfile(char **argv, int argc, switch_stream_handle_t *stream)</span>
<span style="color: #00A000">+{</span>
<span style="color: #00A000">+        if (! argv[0]) {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;%s&quot;, globals.ring_file);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        if (create_codecs(0) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                switch_file_handle_t fh = { 0 };</span>
<span style="color: #00A000">+                if (switch_core_file_open(&amp;fh,</span>
<span style="color: #00A000">+                                                                  argv[0],</span>
<span style="color: #00A000">+                                                                  globals.read_codec.implementation-&gt;number_of_channels,</span>
<span style="color: #00A000">+                                                                  globals.read_codec.implementation-&gt;actual_samples_per_second,</span>
<span style="color: #00A000">+                                                                  SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                        switch_core_file_close(&amp;fh);</span>
<span style="color: #00A000">+                        set_global_ring_file(argv[0]);</span>
<span style="color: #00A000">+                } else {</span>
<span style="color: #00A000">+                        stream-&gt;write_function(stream, &quot;ringfile Unable to open ring file %s\n&quot;, argv[0]);</span>
<span style="color: #00A000">+                        return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+                }</span>
<span style="color: #00A000">+        } else {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;ringfile Failed to init codecs device\n&quot;);</span>
<span style="color: #00A000">+                return SWITCH_STATUS_FALSE;</span>
<span style="color: #00A000">+        }</span>
<span style="color: #00A000">+        stream-&gt;write_function(stream, &quot;ringfile set to %s&quot;, globals.ring_file);</span>
<span style="color: #00A000">+        return SWITCH_STATUS_SUCCESS;</span>
<span style="color: #00A000">+}</span>
<span style="color: #00A000">+</span>
 static switch_status_t switch_call(char **argv, int argc, switch_stream_handle_t *stream)
 {
         private_t *tp, *tech_pvt = NULL;
<span style="color: #800080; font-weight: bold">@@ -1542,7 +2041,10 @@ static switch_status_t switch_call(char **argv, int argc, switch_stream_handle_t</span>
                 }
         } else if (!strcasecmp(callid, &quot;none&quot;)) {
                 for (tp = globals.call_list; tp; tp = tp-&gt;next) {
<span style="color: #00A000">+                        if (switch_test_flag(tp, TFLAG_MASTER))        {</span>
                         switch_clear_flag_locked(tp, TFLAG_MASTER);
<span style="color: #00A000">+                                create_hold_event(tp,0);</span>
<span style="color: #00A000">+                        }</span>
                 }
                 stream-&gt;write_function(stream, &quot;OK\n&quot;);
                 goto done;
<span style="color: #800080; font-weight: bold">@@ -1559,6 +2061,7 @@ static switch_status_t switch_call(char **argv, int argc, switch_stream_handle_t</span>
                         remove_pvt(tech_pvt);
                 }
                 add_pvt(tech_pvt, PA_MASTER);
<span style="color: #00A000">+                create_hold_event(tech_pvt, 1);</span>
                 stream-&gt;write_function(stream, &quot;OK\n&quot;);
         } else {
                 stream-&gt;write_function(stream, &quot;NO SUCH CALL\n&quot;);
<span style="color: #800080; font-weight: bold">@@ -1609,7 +2112,6 @@ static switch_status_t answer_call(char **argv, int argc, switch_stream_handle_t</span>
                                 switch_channel_t *channel = switch_core_session_get_channel(tp-&gt;session);
                                 switch_set_flag_locked(tp, TFLAG_ANSWER);
                                 add_pvt(tp, PA_MASTER);
<span style="color: #A00000">-                                deactivate_ring_device();</span>
                                 switch_channel_mark_answered(channel);
                         }
                 } else {
<span style="color: #800080; font-weight: bold">@@ -1624,7 +2126,6 @@ static switch_status_t answer_call(char **argv, int argc, switch_stream_handle_t</span>
                         switch_channel_t *channel = switch_core_session_get_channel(tp-&gt;session);
                         switch_set_flag_locked(tp, TFLAG_ANSWER);
                         add_pvt(tp, PA_MASTER);
<span style="color: #A00000">-                        deactivate_ring_device();</span>
                         switch_channel_mark_answered(channel);
                         x++;
                         break;
<span style="color: #800080; font-weight: bold">@@ -1766,7 +2267,6 @@ static switch_status_t place_call(char **argv, int argc, switch_stream_handle_t</span>
                         channel = switch_core_session_get_channel(session);
                         switch_core_session_set_private(session, tech_pvt);
                         tech_pvt-&gt;session = session;
<span style="color: #A00000">-                        globals.flags = GFLAG_EAR | GFLAG_MOUTH;</span>
                 } else {
                         switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, &quot;Hey where is my memory pool?\n&quot;);
                         switch_core_session_destroy(&amp;session);
<span style="color: #800080; font-weight: bold">@@ -1805,9 +2305,8 @@ static switch_status_t place_call(char **argv, int argc, switch_stream_handle_t</span>
                         switch_channel_set_caller_profile(channel, tech_pvt-&gt;caller_profile);
                 }
                 tech_pvt-&gt;session = session;
<span style="color: #A00000">-                if ((status = engage_device(0)) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                if ((status = validate_main_audio_stream()) == SWITCH_STATUS_SUCCESS) {</span>
                         switch_set_flag_locked(tech_pvt, TFLAG_ANSWER);
<span style="color: #A00000">-                        deactivate_ring_device();</span>
                         switch_channel_mark_answered(channel);
                         switch_channel_set_state(channel, CS_INIT);
                         if (switch_core_session_thread_launch(tech_pvt-&gt;session) != SWITCH_STATUS_SUCCESS) {
<span style="color: #800080; font-weight: bold">@@ -1855,10 +2354,11 @@ SWITCH_STANDARD_API(pa_cmd)</span>
 {
         char *argv[1024] = { 0 };
         int argc = 0;
<span style="color: #A00000">-        char *mycmd = NULL, *devname = NULL;</span>
<span style="color: #00A000">+        char *mycmd = NULL;</span>
         switch_status_t status = SWITCH_STATUS_SUCCESS;
         pa_command_t func = NULL;
<span style="color: #A00000">-        int lead = 1, devval = 0;</span>
<span style="color: #00A000">+        int devval;</span>
<span style="color: #00A000">+        int lead = 1;</span>
         char *wcmd = NULL, *action = NULL;
         char cmd_buf[1024] = &quot;&quot;;
         char *http = NULL;
<span style="color: #800080; font-weight: bold">@@ -1878,9 +2378,15 @@ SWITCH_STANDARD_API(pa_cmd)</span>
                 &quot;pa devlist [xml]\n&quot;
                 &quot;pa indev #&lt;num&gt;|&lt;partial name&gt;\n&quot;
                 &quot;pa outdev #&lt;num&gt;|&lt;partial name&gt;\n&quot;
<span style="color: #00A000">+                &quot;pa preparestream #&lt;indev_num&gt; #&lt;outdev_num&gt;\n&quot;</span>
<span style="color: #00A000">+                &quot;pa switchstream #&lt;indev_num&gt; #&lt;outdev_num&gt;\n&quot;</span>
<span style="color: #00A000">+                &quot;pa closestreams\n&quot;</span>
                 &quot;pa ringdev #&lt;num&gt;|&lt;partial name&gt;\n&quot;
<span style="color: #A00000">-                &quot;pa play [ringtest|&lt;filename&gt;]\n&quot;</span>
<span style="color: #A00000">-                &quot;pa ringfile [filename]\n&quot; &quot;pa looptest\n&quot; &quot;--------------------------------------------------------------------------------\n&quot;;</span>
<span style="color: #00A000">+                &quot;pa play [ringtest|&lt;filename&gt;] [seconds] [no_close]\n&quot;</span>
<span style="color: #00A000">+                &quot;pa playdev #&lt;num&gt; [ringtest|&lt;filename&gt;] [seconds] [no_close]\n&quot;</span>
<span style="color: #00A000">+                &quot;pa ringfile [filename]\n&quot;</span>
<span style="color: #00A000">+                &quot;pa looptest\n&quot;</span>
<span style="color: #00A000">+                &quot;--------------------------------------------------------------------------------\n&quot;;</span>
 
 
         if (stream-&gt;param_event) {
<span style="color: #800080; font-weight: bold">@@ -1973,169 +2479,42 @@ SWITCH_STANDARD_API(pa_cmd)</span>
                 func = switch_call;
         } else if (!strcasecmp(argv[0], &quot;dtmf&quot;)) {
                 func = dtmf_call;
<span style="color: #00A000">+        } else if (!strcasecmp(argv[0], &quot;closestreams&quot;)) {</span>
<span style="color: #00A000">+                func = close_streams;</span>
         } else if (argv[1] &amp;&amp; !strcmp(argv[0], &quot;indev&quot;)) {
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                if (globals.call_list) {</span>
<span style="color: #A00000">-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;ERROR: Cannot use this command this while a call is in progress\n&quot;);</span>
<span style="color: #A00000">-                        goto done;</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                if (*argv[1] == &#39;#&#39;) {</span>
<span style="color: #A00000">-                        devval = get_dev_by_number(argv[1] + 1, 1);</span>
<span style="color: #A00000">-                } else {</span>
<span style="color: #A00000">-                        devval = get_dev_by_name(argv[1], 1);</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-                devname = &quot;indev&quot;;</span>
<span style="color: #A00000">-                if (devval &gt; -1) {</span>
<span style="color: #A00000">-                        globals.indev = devval;</span>
<span style="color: #A00000">-                        //engage_device(1);</span>
<span style="color: #A00000">-                }</span>
<span style="color: #00A000">+                func = set_indev;</span>
         } else if (argv[1] &amp;&amp; !strcmp(argv[0], &quot;outdev&quot;)) {
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                if (globals.call_list) {</span>
<span style="color: #A00000">-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;ERROR: Cannot use this command this while a call is in progress\n&quot;);</span>
<span style="color: #A00000">-                        goto done;</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                if (*argv[1] == &#39;#&#39;) {</span>
<span style="color: #A00000">-                        devval = get_dev_by_number(argv[1] + 1, 0);</span>
<span style="color: #A00000">-                } else {</span>
<span style="color: #A00000">-                        devval = get_dev_by_name(argv[1], 0);</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-                devname = &quot;outdev&quot;;</span>
<span style="color: #A00000">-                if (devval &gt; -1) {</span>
<span style="color: #A00000">-                        globals.outdev = devval;</span>
<span style="color: #A00000">-                        //engage_device(1);</span>
<span style="color: #A00000">-                }</span>
<span style="color: #00A000">+                func = set_outdev;</span>
<span style="color: #00A000">+        } else if (argv[1] &amp;&amp; argv[2] &amp;&amp; !strcmp(argv[0], &quot;preparestream&quot;)) {</span>
<span style="color: #00A000">+                func = prepare_stream;        </span>
<span style="color: #00A000">+        } else if (argv[1] &amp;&amp; argv[2] &amp;&amp; !strcmp(argv[0], &quot;switchstream&quot;)) {</span>
<span style="color: #00A000">+                func = switch_stream;        </span>
         } else if (argv[1] &amp;&amp; !strcmp(argv[0], &quot;ringdev&quot;)) {
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                if (globals.call_list) {</span>
<span style="color: #A00000">-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;ERROR: Cannot use this command this while a call is in progress\n&quot;);</span>
<span style="color: #A00000">-                        goto done;</span>
<span style="color: #00A000">+                func = set_ringdev;</span>
<span style="color: #00A000">+        } else if ((argv[1] &amp;&amp; !strcmp(argv[0], &quot;play&quot;))) {</span>
<span style="color: #00A000">+                if (validate_main_audio_stream() == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #00A000">+                        play_dev(stream, globals.main_stream ? globals.main_stream-&gt;outdev : -1,argv[1],argv[2], argv[3]);</span>
<span style="color: #00A000">+                }else{</span>
<span style="color: #00A000">+                        stream-&gt;write_function(stream, &quot;Failed to engage audio device\n&quot;);</span>
                 }
<span style="color: #A00000">-</span>
<span style="color: #00A000">+                goto done;</span>
<span style="color: #00A000">+        } else if ((argv[1] &amp;&amp; argv[2] &amp;&amp; !strcmp(argv[0], &quot;playdev&quot;))) {</span>
                 if (*argv[1] == &#39;#&#39;) {
                         devval = get_dev_by_number(argv[1] + 1, 0);
                 } else {
<span style="color: #A00000">-                        devval = get_dev_by_name(argv[1], 0);</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-                devname = &quot;ringdev&quot;;</span>
<span style="color: #A00000">-                if (devval &gt; -1) {</span>
<span style="color: #A00000">-                        globals.ringdev = devval;</span>
<span style="color: #A00000">-                        //engage_device(1);</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-        } else if ((argv[1] &amp;&amp; !strcasecmp(argv[0], &quot;play&quot;))) {</span>
<span style="color: #A00000">-                switch_file_handle_t fh = { 0 };</span>
<span style="color: #A00000">-                char *playfile = NULL;</span>
<span style="color: #A00000">-                int samples = 0;</span>
<span style="color: #A00000">-                int seconds = 5;</span>
<span style="color: #A00000">-                int wrote = 0;</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                if (globals.call_list) {</span>
<span style="color: #A00000">-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;ERROR: Cannot use this command this while a call is in progress\n&quot;);</span>
<span style="color: #A00000">-                        goto done;</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                if (!strcasecmp(argv[1], &quot;ringtest&quot;)) {</span>
<span style="color: #A00000">-                        playfile = globals.ring_file;</span>
<span style="color: #A00000">-                } else {</span>
<span style="color: #A00000">-                        playfile = argv[1];</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;</span>
<span style="color: #A00000">-                if (engage_device(0) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #A00000">-                        if (switch_core_file_open(&amp;fh,</span>
<span style="color: #A00000">-                                                                          playfile,</span>
<span style="color: #A00000">-                                                                          globals.read_codec.implementation-&gt;number_of_channels,</span>
<span style="color: #A00000">-                                                                          globals.read_codec.implementation-&gt;actual_samples_per_second,</span>
<span style="color: #A00000">-                                                                          SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #A00000">-                                switch_size_t olen = globals.read_codec.implementation-&gt;samples_per_packet;</span>
<span style="color: #A00000">-                                int16_t abuf[2048];</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                                if (argv[2]) {</span>
<span style="color: #A00000">-                                        int i = atoi(argv[2]);</span>
<span style="color: #A00000">-                                        if (i &gt;= 0) {</span>
<span style="color: #A00000">-                                                seconds = i;</span>
<span style="color: #A00000">-                                        }</span>
<span style="color: #A00000">-                                }</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                                samples = globals.read_codec.implementation-&gt;actual_samples_per_second * seconds;</span>
<span style="color: #A00000">-                                while (switch_core_file_read(&amp;fh, abuf, &amp;olen) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #A00000">-                                        WriteAudioStream(globals.audio_stream, abuf, (long) olen, &amp;globals.read_timer);</span>
<span style="color: #A00000">-                                        wrote += (int) olen;</span>
<span style="color: #A00000">-                                        if (samples) {</span>
<span style="color: #A00000">-                                                samples -= (int) olen;</span>
<span style="color: #A00000">-                                                if (samples &lt;= 0) {</span>
<span style="color: #A00000">-                                                        break;</span>
<span style="color: #A00000">-                                                }</span>
<span style="color: #A00000">-                                        }</span>
<span style="color: #A00000">-                                        olen = globals.read_codec.implementation-&gt;samples_per_packet;</span>
<span style="color: #A00000">-                                }</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                                switch_core_file_close(&amp;fh);</span>
<span style="color: #A00000">-                                deactivate_audio_device();</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                                seconds = wrote / globals.read_codec.implementation-&gt;actual_samples_per_second;</span>
<span style="color: #A00000">-                                stream-&gt;write_function(stream, &quot;playback test [%s] %d second(s) %d samples @%dkhz&quot;,</span>
<span style="color: #A00000">-                                                                           playfile, seconds, wrote, globals.read_codec.implementation-&gt;actual_samples_per_second);</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                        } else {</span>
<span style="color: #A00000">-                                stream-&gt;write_function(stream, &quot;Cannot play requested file %s\n&quot;, argv[1]);</span>
<span style="color: #A00000">-                        }</span>
<span style="color: #A00000">-                } else {</span>
<span style="color: #A00000">-                        stream-&gt;write_function(stream, &quot;Failed to engage audio device\n&quot;);</span>
<span style="color: #00A000">+                        devval = -1;</span>
                 }
<span style="color: #00A000">+                play_dev(stream, devval,argv[2],argv[3],argv[4]);</span>
                 goto done;
         } else if (!strcasecmp(argv[0], &quot;looptest&quot;)) {
<span style="color: #A00000">-                if (globals.call_list) {</span>
<span style="color: #A00000">-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;ERROR: Cannot use this command this while a call is in progress\n&quot;);</span>
<span style="color: #A00000">-                        goto done;</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-</span>
<span style="color: #A00000">-                if (engage_device(0) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #A00000">-                        int samples = 0;</span>
<span style="color: #A00000">-                        int success = 0;</span>
<span style="color: #A00000">-                        int i;</span>
<span style="color: #A00000">-                        for (i = 0; i &lt; 400; i++) {</span>
<span style="color: #A00000">-                                if ((samples = ReadAudioStream(globals.audio_stream, globals.read_frame.data,</span>
<span style="color: #A00000">-                                                                                           globals.read_codec.implementation-&gt;samples_per_packet, &amp;globals.read_timer))) {</span>
<span style="color: #A00000">-                                        WriteAudioStream(globals.audio_stream, globals.read_frame.data, (long) samples, &amp;globals.write_timer);</span>
<span style="color: #A00000">-                                        success = 1;</span>
<span style="color: #A00000">-                                }</span>
<span style="color: #A00000">-                                switch_yield(10000);</span>
<span style="color: #A00000">-                        }</span>
<span style="color: #A00000">-                        if (!success) {</span>
<span style="color: #A00000">-                                stream-&gt;write_function(stream, &quot;Failed to read any bytes from indev\n&quot;);</span>
<span style="color: #A00000">-                        }</span>
<span style="color: #A00000">-                        deactivate_audio_device();</span>
<span style="color: #A00000">-                } else {</span>
<span style="color: #A00000">-                        stream-&gt;write_function(stream, &quot;Failed to engage audio device\n&quot;);</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-                goto done;</span>
<span style="color: #00A000">+                func = looptest;</span>
         } else if (!strcasecmp(argv[0], &quot;ringfile&quot;)) {
<span style="color: #A00000">-                if (argv[1]) {</span>
<span style="color: #A00000">-                        if (engage_device(0) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #A00000">-                                switch_file_handle_t fh = { 0 };</span>
<span style="color: #A00000">-                                if (switch_core_file_open(&amp;fh,</span>
<span style="color: #A00000">-                                                                                  argv[1],</span>
<span style="color: #A00000">-                                                                                  globals.read_codec.implementation-&gt;number_of_channels,</span>
<span style="color: #A00000">-                                                                                  globals.read_codec.implementation-&gt;actual_samples_per_second,</span>
<span style="color: #A00000">-                                                                                  SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) == SWITCH_STATUS_SUCCESS) {</span>
<span style="color: #A00000">-                                        switch_core_file_close(&amp;fh);</span>
<span style="color: #A00000">-                                        set_global_ring_file(argv[1]);</span>
<span style="color: #A00000">-                                } else {</span>
<span style="color: #A00000">-                                        stream-&gt;write_function(stream, &quot;Unable to open ring file %s\n&quot;, argv[1]);</span>
<span style="color: #A00000">-                                }</span>
<span style="color: #A00000">-                        } else {</span>
<span style="color: #A00000">-                                stream-&gt;write_function(stream, &quot;Failed to engage audio device\n&quot;);</span>
<span style="color: #A00000">-                        }</span>
<span style="color: #A00000">-                } else {</span>
<span style="color: #A00000">-                        stream-&gt;write_function(stream, &quot;%s&quot;, globals.ring_file);</span>
<span style="color: #A00000">-                }</span>
<span style="color: #A00000">-                goto done;</span>
<span style="color: #00A000">+                func = set_ringfile;</span>
<span style="color: #00A000">+        } else {</span>
<span style="color: #00A000">+                stream-&gt;write_function(stream, &quot;Unknown Command or not enough args [%s]\n&quot;, argv[0]);</span>
         }
 
<span style="color: #00A000">+</span>
         if (func) {
                 if (http) {
                         stream-&gt;write_function(stream, &quot;&lt;pre&gt;&quot;);
<span style="color: #800080; font-weight: bold">@@ -2143,21 +2522,12 @@ SWITCH_STANDARD_API(pa_cmd)</span>
 
                 switch_mutex_lock(globals.pa_mutex);
                 status = func(&amp;argv[lead], argc - lead, stream);
<span style="color: #00A000">+                status = SWITCH_STATUS_SUCCESS; /*if func was defined we want to always return success as the command was found */</span>
                 switch_mutex_unlock(globals.pa_mutex);
 
                 if (http) {
                         stream-&gt;write_function(stream, &quot;\n\n&lt;/pre&gt;&quot;);
                 }
<span style="color: #A00000">-        } else {</span>
<span style="color: #A00000">-                if (devname) {</span>
<span style="color: #A00000">-                        if (devval &gt; -1) {</span>
<span style="color: #A00000">-                                stream-&gt;write_function(stream, &quot;%s set to %d\n&quot;, devname, devval);</span>
<span style="color: #A00000">-                        } else {</span>
<span style="color: #A00000">-                                stream-&gt;write_function(stream, &quot;%s not set (invalid value)\n&quot;, devname);</span>
<span style="color: #A00000">-                        }</span>
<span style="color: #A00000">-                } else {</span>
<span style="color: #A00000">-                        stream-&gt;write_function(stream, &quot;Unknown Command [%s]\n&quot;, argv[0]);</span>
<span style="color: #A00000">-                }</span>
         }
 
   done:
<span style="color: #800080; font-weight: bold">@@ -2171,6 +2541,14 @@ SWITCH_STANDARD_API(pa_cmd)</span>
                                                            &quot;&lt;input name=action type=submit value=\&quot;switch\&quot;&gt; &quot;
                                                            &quot;&lt;input name=action type=submit value=\&quot;mute\&quot;&gt; &quot;
                                                            &quot;&lt;input name=action type=submit value=\&quot;unmute\&quot;&gt; &quot;
<span style="color: #00A000">+                                                           &quot;&lt;input name=action type=submit value=\&quot;indev\&quot;&gt; &quot;</span>
<span style="color: #00A000">+                                                           &quot;&lt;input name=action type=submit value=\&quot;outdev\&quot;&gt; &quot;</span>
<span style="color: #00A000">+                                                           &quot;&lt;input name=action type=submit value=\&quot;preparestream\&quot;&gt; &quot;</span>
<span style="color: #00A000">+                                                           &quot;&lt;input name=action type=submit value=\&quot;switchstream\&quot;&gt; &quot;</span>
<span style="color: #00A000">+                                                           &quot;&lt;input name=action type=submit value=\&quot;closestreams\&quot;&gt; &quot;</span>
<span style="color: #00A000">+                                                           &quot;&lt;input name=action type=submit value=\&quot;ringdev\&quot;&gt; &quot;</span>
<span style="color: #00A000">+                                                           &quot;&lt;input name=action type=submit value=\&quot;play\&quot;&gt; &quot;</span>
<span style="color: #00A000">+                                                           &quot;&lt;input name=action type=submit value=\&quot;playdev\&quot;&gt; &quot;</span>
                                                            &quot;&lt;input name=action type=submit value=\&quot;answer\&quot;&gt; &lt;br&gt;&lt;br&gt;&quot;
                                                            &quot;&lt;table border=1&gt;\n&quot;
                                                            &quot;&lt;tr&gt;&lt;td&gt;&lt;input name=action type=submit value=\&quot;1\&quot;&gt;&lt;/td&gt;&quot;
</pre></div>
========================================================================<pre>

Summary of changes:
 src/mod/endpoints/mod_portaudio/mod_portaudio.c | 1046 +++++++++++++++--------
 1 files changed, 712 insertions(+), 334 deletions(-)
</pre>
<p>this email was generated because of /git/your-repo.git/hooks/post-receive by the file /git-core/contrib/hooks/post-receive-email<br />
For more info, see <a href="http://blog.chomperstomp.com/?p=630">http://blog.chomperstomp.com/?p=630</a>
-- <br />
FreeSWITCH Source</p>