]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
mod_portaudio: XML parsing of endpoints
authorMoises Silva <moises.silva@gmail.com>
Sat, 19 Mar 2011 20:01:11 +0000 (16:01 -0400)
committerMoises Silva <moises.silva@gmail.com>
Sat, 19 Mar 2011 20:01:11 +0000 (16:01 -0400)
src/mod/endpoints/mod_portaudio/mod_portaudio.c

index 76f609f7b11eaa8a479ec7bf210f99fd3e42426d..249f681feaf0bed7b2d8e39f376b66eb7207b561 100644 (file)
@@ -24,6 +24,7 @@
  * Contributor(s):
  * 
  * Anthony Minessale II <anthm@freeswitch.org>
+ * Moises Silva <moises.silva@gmail.com> (Multiple endpoints work sponsored by Comrex Corporation)
  *
  *
  * mod_portaudio.c -- PortAudio Endpoint Module
@@ -1102,6 +1103,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load)
        switch_console_set_complete("add pa playdev");
        switch_console_set_complete("add pa looptest");
        switch_console_set_complete("add pa shstreams");
+       switch_console_set_complete("add pa endpoints");
 
        /* indicate that the module should continue to be loaded */
        return SWITCH_STATUS_SUCCESS;
@@ -1122,11 +1124,17 @@ static switch_status_t load_streams(switch_xml_t streams)
 {
        switch_status_t status = SWITCH_STATUS_SUCCESS;
        switch_xml_t param, mystream;
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading streams ...\n");
        for (mystream = switch_xml_child(streams, "stream"); mystream; mystream = mystream->next) {
                shared_audio_stream_t *stream = NULL;
                int devval = -1;
                char *stream_name = (char *) switch_xml_attr_soft(mystream, "name");
 
+               if (!stream_name) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing stream name attribute, skipping ...\n");
+                       continue;
+               }
+
                /* check if that stream name is not already used */
                stream = switch_core_hash_find(globals.sh_streams, stream_name);
                if (stream) {
@@ -1140,6 +1148,7 @@ static switch_status_t load_streams(switch_xml_t streams)
                }
                stream->indev = -1;
                stream->outdev = -1;
+               stream->sample_rate = globals.sample_rate;
                switch_snprintf(stream->name, sizeof(stream->name), "%s", stream_name);
                for (param = switch_xml_child(mystream, "param"); param; param = param->next) {
                        char *var = (char *) switch_xml_attr_soft(param, "name");
@@ -1148,6 +1157,8 @@ static switch_status_t load_streams(switch_xml_t streams)
                        if (!strcmp(var, "indev")) {
                                devval = check_device(val, 1);
                                if (devval < 0) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 
+                                                       "Invalid indev specified for stream '%s'\n", stream_name);
                                        stream->indev = -1;
                                        continue;
                                }
@@ -1178,7 +1189,7 @@ static switch_status_t load_streams(switch_xml_t streams)
                                }
                        } else if (!strcmp(var, "channels")) {
                                stream->channels = atoi(val);
-                               if (stream->channels < 1) {
+                               if (stream->channels < 1 || stream->channels > MAX_IO_CHANNELS) {
                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 
                                                        "Invalid number of channels specified for stream '%s', forcing to 1\n", stream_name);
                                        stream->channels = 1;
@@ -1197,10 +1208,130 @@ static switch_status_t load_streams(switch_xml_t streams)
        return status;
 }
 
+static int check_stream_compat(shared_audio_stream_t *in_stream, shared_audio_stream_t *out_stream)
+{
+       if (!in_stream || !out_stream) {
+               /* nothing to be compatible with */
+               return 0;
+       }
+       if (in_stream->sample_rate != out_stream->sample_rate) {
+               return -1;
+       }
+       if (in_stream->codec_ms != out_stream->codec_ms) {
+               return -1;
+       }
+       return 0;
+}
+
+static shared_audio_stream_t *check_stream(char *streamstr, int check_input, int *chanindex)
+{
+       shared_audio_stream_t *stream = NULL;
+       int cnum = 0;
+       char stream_name[255];
+       char *chan = NULL;
+
+       *chanindex = -1;
+
+       switch_snprintf(stream_name, sizeof(stream_name), "%s", streamstr);
+
+       chan = strchr(stream_name, ':');
+       if (!chan) {
+               return NULL;
+       }
+       *chan = 0;
+       chan++;
+       cnum = atoi(chan);
+
+       stream = switch_core_hash_find(globals.sh_streams, stream_name);
+       if (!stream) {
+               return NULL;
+       }
+
+       if (cnum < 0 || cnum > stream->channels) {
+               return NULL;
+       }
+       
+       *chanindex = cnum;
+
+       return stream;
+}
+
+static switch_status_t load_endpoints(switch_xml_t endpoints)
+{
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+       switch_xml_t param, myendpoint;
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading endpoints ...\n");
+       for (myendpoint = switch_xml_child(endpoints, "endpoint"); myendpoint; myendpoint = myendpoint->next) {
+               audio_endpoint_t *endpoint = NULL;
+               shared_audio_stream_t *stream = NULL;
+               char *endpoint_name = (char *) switch_xml_attr_soft(myendpoint, "name");
+
+               if (!endpoint_name) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing endpoint name attribute, skipping ...\n");
+                       continue;
+               }
+
+               /* check if that endpoint name is not already used */
+               endpoint = switch_core_hash_find(globals.endpoints, endpoint_name);
+               if (endpoint) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "An endpoint with name '%s' already exists\n", endpoint_name);
+                       continue;
+               }
+
+               endpoint = switch_core_alloc(module_pool, sizeof(*endpoint));
+               if (!endpoint) {
+                       continue;
+               }
+               endpoint->inchan = -1;
+               endpoint->outchan = -1;
+               switch_snprintf(endpoint->name, sizeof(endpoint->name), "%s", endpoint_name);
+               for (param = switch_xml_child(myendpoint, "param"); param; param = param->next) {
+                       char *var = (char *) switch_xml_attr_soft(param, "name");
+                       char *val = (char *) switch_xml_attr_soft(param, "value");
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parsing endpoint '%s' parameter %s = %s\n", endpoint_name, var, val);
+                       if (!strcmp(var, "instream")) {
+                               stream = check_stream(val, 1, &endpoint->inchan) ;
+                               if (!stream) {
+                                       endpoint->in_stream = NULL;
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 
+                                                       "Invalid instream specified for endpoint '%s'\n", endpoint_name);
+                                       continue;
+                               }
+                               endpoint->in_stream = stream;
+                       } else if (!strcmp(var, "outstream")) {
+                               stream = check_stream(val, 0, &endpoint->outchan);
+                               if (!stream) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 
+                                                       "Invalid outstream specified for endpoint '%s'\n", endpoint_name);
+                                       endpoint->out_stream = NULL;
+                                       continue;
+                               }
+                               endpoint->out_stream = stream;
+                       }
+               }
+               if (!endpoint->in_stream && !endpoint->out_stream) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 
+                                       "You need at least one stream for endpoint '%s'\n", endpoint_name);
+                       continue;
+               }
+               if (check_stream_compat(endpoint->in_stream, endpoint->out_stream)) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 
+                                       "Incomatible input and output streams for endpoint '%s'\n", endpoint_name);
+                       continue;
+               }
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, 
+                               "Created endpoint '%s', instream = %s, outstream = %s\n", endpoint->name, 
+                               endpoint->in_stream ? endpoint->in_stream->name : "(none)", 
+                               endpoint->out_stream ? endpoint->out_stream->name : "(none)");
+               switch_core_hash_insert(globals.endpoints, endpoint->name, endpoint);
+       }
+       return status;
+}
+
 static switch_status_t load_config(void)
 {
        char *cf = "portaudio.conf";
-       switch_xml_t cfg, xml, settings, streams, param;
+       switch_xml_t cfg, xml, settings, streams, endpoints, param;
        switch_status_t status = SWITCH_STATUS_SUCCESS;
 
        if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
@@ -1299,6 +1430,10 @@ static switch_status_t load_config(void)
                load_streams(streams);
        }
 
+       if ((endpoints = switch_xml_child(cfg, "endpoints"))) {
+               load_endpoints(endpoints);
+       }
+
        if (!globals.dialplan) {
                set_global_dialplan("XML");
        }
@@ -1969,7 +2104,7 @@ static switch_status_t list_shared_streams(char **argv, int argc, switch_stream_
                shared_audio_stream_t *s = NULL;
                switch_hash_this(hi, &var, NULL, &val);
                s = val;
-               stream->write_function(stream, "%s> outdev: %d, indev: %d, sample-rate: %d, codec-ms: %d, channels: %d\n",
+               stream->write_function(stream, "%s> indev: %d, outdev: %d, sample-rate: %d, codec-ms: %d, channels: %d\n",
                                s->name, s->indev, s->outdev, s->sample_rate, s->codec_ms, s->channels);
                cnt++;
        }
@@ -1977,6 +2112,25 @@ static switch_status_t list_shared_streams(char **argv, int argc, switch_stream_
        return SWITCH_STATUS_SUCCESS;
 }
 
+static switch_status_t list_endpoints(char **argv, int argc, switch_stream_handle_t *stream)
+{
+       switch_hash_index_t *hi;
+       int cnt = 0;
+       for (hi = switch_hash_first(NULL, globals.endpoints); hi; hi = switch_hash_next(hi)) {
+               const void *var;
+               void *val;
+               audio_endpoint_t *e = NULL;
+               switch_hash_this(hi, &var, NULL, &val);
+               e = val;
+               stream->write_function(stream, "%s> instream: %s, outstream: %s\n",
+                               e->name, e->in_stream ? e->in_stream->name : "(none)", 
+                               e->out_stream ? e->out_stream->name : "(none)");
+               cnt++;
+       }
+       stream->write_function(stream, "Total endpoints: %d\n", cnt);
+       return SWITCH_STATUS_SUCCESS;
+}
+
 static switch_status_t close_streams(char **argv, int argc, switch_stream_handle_t *stream)
 {
        if (globals.call_list) {
@@ -2547,6 +2701,7 @@ SWITCH_STANDARD_API(pa_cmd)
                "pa ringfile [filename]\n"
                "pa looptest\n"
                "pa shstreams\n"
+               "pa endpoints\n"
                "--------------------------------------------------------------------------------\n";
 
 
@@ -2673,6 +2828,8 @@ SWITCH_STANDARD_API(pa_cmd)
                func = set_ringfile;
        } else if (!strcasecmp(argv[0], "shstreams")) {
                func = list_shared_streams;
+       } else if (!strcasecmp(argv[0], "endpoints")) {
+               func = list_endpoints;
        } else {
                stream->write_function(stream, "Unknown Command or not enough args [%s]\n", argv[0]);
        }