FS-5034 --resolve please document accordingly on the wiki
This commit is contained in:
parent
64341dc194
commit
429e0fdec9
|
@ -25,6 +25,7 @@
|
||||||
*
|
*
|
||||||
* Anthony Minessale II <anthm@freeswitch.org>
|
* Anthony Minessale II <anthm@freeswitch.org>
|
||||||
* Cesar Cepeda <cesar@auronix.com>
|
* Cesar Cepeda <cesar@auronix.com>
|
||||||
|
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* mod_local_stream.c -- Local Streaming Audio
|
* mod_local_stream.c -- Local Streaming Audio
|
||||||
|
@ -38,6 +39,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_local_stream_load);
|
||||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_local_stream_shutdown);
|
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_local_stream_shutdown);
|
||||||
SWITCH_MODULE_DEFINITION(mod_local_stream, mod_local_stream_load, mod_local_stream_shutdown, NULL);
|
SWITCH_MODULE_DEFINITION(mod_local_stream, mod_local_stream_load, mod_local_stream_shutdown, NULL);
|
||||||
|
|
||||||
|
static void launch_streams(const char *name);
|
||||||
|
static void launch_thread(const char *name, const char *path, switch_xml_t directory);
|
||||||
|
|
||||||
|
static const char *global_cf = "local_stream.conf";
|
||||||
|
|
||||||
struct local_stream_source;
|
struct local_stream_source;
|
||||||
|
|
||||||
|
@ -82,6 +87,9 @@ struct local_stream_source {
|
||||||
switch_thread_rwlock_t *rwlock;
|
switch_thread_rwlock_t *rwlock;
|
||||||
int ready;
|
int ready;
|
||||||
int stopped;
|
int stopped;
|
||||||
|
int stop_request;
|
||||||
|
int part_reload;
|
||||||
|
int full_reload;
|
||||||
int chime_freq;
|
int chime_freq;
|
||||||
int chime_total;
|
int chime_total;
|
||||||
int chime_max;
|
int chime_max;
|
||||||
|
@ -315,6 +323,64 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void
|
||||||
|
|
||||||
switch_dir_close(source->dir_handle);
|
switch_dir_close(source->dir_handle);
|
||||||
source->dir_handle = NULL;
|
source->dir_handle = NULL;
|
||||||
|
|
||||||
|
if(source->stop_request||source->full_reload) {
|
||||||
|
if (source->rwlock && switch_thread_rwlock_trywrlock(source->rwlock) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot stop local_stream://%s because it is in use.\n",source->name);
|
||||||
|
if (source->part_reload) {
|
||||||
|
switch_xml_t cfg, xml, directory, param;
|
||||||
|
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
|
||||||
|
}
|
||||||
|
if ((directory = switch_xml_find_child(cfg, "directory", "name", source->name))) {
|
||||||
|
for (param = switch_xml_child(directory, "param"); param; param = param->next) {
|
||||||
|
char *var = (char *) switch_xml_attr_soft(param, "name");
|
||||||
|
char *val = (char *) switch_xml_attr_soft(param, "value");
|
||||||
|
if (!strcasecmp(var, "shuffle")) {
|
||||||
|
source->shuffle = switch_true(val);
|
||||||
|
} else if (!strcasecmp(var, "chime-freq")) {
|
||||||
|
int tmp = atoi(val);
|
||||||
|
if (tmp > 1) {
|
||||||
|
source->chime_freq = tmp;
|
||||||
|
}
|
||||||
|
} else if (!strcasecmp(var, "chime-max")) {
|
||||||
|
int tmp = atoi(val);
|
||||||
|
if (tmp > 1) {
|
||||||
|
source->chime_max = tmp;
|
||||||
|
}
|
||||||
|
} else if (!strcasecmp(var, "chime-list")) {
|
||||||
|
char *list_dup = switch_core_strdup(source->pool, val);
|
||||||
|
source->chime_total =
|
||||||
|
switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0])));
|
||||||
|
} else if (!strcasecmp(var, "interval")) {
|
||||||
|
int tmp = atoi(val);
|
||||||
|
if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
|
||||||
|
source->interval = tmp;
|
||||||
|
} else {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||||
|
"Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (source->chime_max) {
|
||||||
|
source->chime_max *= source->rate;
|
||||||
|
}
|
||||||
|
if (source->chime_total) {
|
||||||
|
source->chime_counter = source->rate * source->chime_freq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s partially reloaded.\n",source->name);
|
||||||
|
source->part_reload = 0;
|
||||||
|
}
|
||||||
|
} else if(source->stop_request) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s stopped.\n",source->name);
|
||||||
|
source->stopped = 1;
|
||||||
|
} else {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s fully reloaded.\n",source->name);
|
||||||
|
launch_streams(source->name);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -493,114 +559,113 @@ static switch_status_t local_stream_file_read(switch_file_handle_t *handle, void
|
||||||
|
|
||||||
static char *supported_formats[SWITCH_MAX_CODECS] = { 0 };
|
static char *supported_formats[SWITCH_MAX_CODECS] = { 0 };
|
||||||
|
|
||||||
static void launch_threads(void)
|
static void launch_thread(const char *name, const char *path, switch_xml_t directory)
|
||||||
{
|
{
|
||||||
char *cf = "local_stream.conf";
|
local_stream_source_t *source = NULL;
|
||||||
switch_xml_t cfg, xml, directory, param;
|
|
||||||
switch_memory_pool_t *pool;
|
switch_memory_pool_t *pool;
|
||||||
local_stream_source_t *source;
|
switch_xml_t param;
|
||||||
switch_thread_t *thread;
|
switch_thread_t *thread;
|
||||||
switch_threadattr_t *thd_attr = NULL;
|
switch_threadattr_t *thd_attr = NULL;
|
||||||
|
|
||||||
if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
|
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
|
||||||
return;
|
abort();
|
||||||
}
|
}
|
||||||
|
source = switch_core_alloc(pool, sizeof(*source));
|
||||||
|
assert(source != NULL);
|
||||||
|
source->pool = pool;
|
||||||
|
|
||||||
for (directory = switch_xml_child(cfg, "directory"); directory; directory = directory->next) {
|
source->name = switch_core_strdup(source->pool, name);
|
||||||
char *path = (char *) switch_xml_attr(directory, "path");
|
source->location = switch_core_strdup(source->pool, path);
|
||||||
char *name = (char *) switch_xml_attr(directory, "name");
|
source->rate = 8000;
|
||||||
|
source->interval = 20;
|
||||||
|
source->channels = 1;
|
||||||
|
source->timer_name = "soft";
|
||||||
|
source->prebuf = DEFAULT_PREBUFFER_SIZE;
|
||||||
|
source->stopped = 0;
|
||||||
|
source->chime_freq = 30;
|
||||||
|
for (param = switch_xml_child(directory, "param"); param; param = param->next) {
|
||||||
|
char *var = (char *) switch_xml_attr_soft(param, "name");
|
||||||
|
char *val = (char *) switch_xml_attr_soft(param, "value");
|
||||||
|
|
||||||
if (!(name && path)) {
|
if (!strcasecmp(var, "rate")) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid config!\n");
|
int tmp = atoi(val);
|
||||||
continue;
|
if (tmp == 8000 || tmp == 12000 || tmp == 16000 || tmp == 24000 || tmp == 32000 || tmp == 48000) {
|
||||||
}
|
source->rate = tmp;
|
||||||
|
|
||||||
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
source = switch_core_alloc(pool, sizeof(*source));
|
|
||||||
assert(source != NULL);
|
|
||||||
source->pool = pool;
|
|
||||||
|
|
||||||
source->name = switch_core_strdup(source->pool, name);
|
|
||||||
source->location = switch_core_strdup(source->pool, path);
|
|
||||||
source->rate = 8000;
|
|
||||||
source->interval = 20;
|
|
||||||
source->channels = 1;
|
|
||||||
source->timer_name = "soft";
|
|
||||||
source->prebuf = DEFAULT_PREBUFFER_SIZE;
|
|
||||||
source->stopped = 0;
|
|
||||||
source->chime_freq = 30;
|
|
||||||
|
|
||||||
for (param = switch_xml_child(directory, "param"); param; param = param->next) {
|
|
||||||
char *var = (char *) switch_xml_attr_soft(param, "name");
|
|
||||||
char *val = (char *) switch_xml_attr_soft(param, "value");
|
|
||||||
|
|
||||||
if (!strcasecmp(var, "rate")) {
|
|
||||||
int tmp = atoi(val);
|
|
||||||
if (tmp == 8000 || tmp == 12000 || tmp == 16000 || tmp == 24000 || tmp == 32000 || tmp == 48000) {
|
|
||||||
source->rate = tmp;
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "shuffle")) {
|
|
||||||
source->shuffle = switch_true(val);
|
|
||||||
} else if (!strcasecmp(var, "prebuf")) {
|
|
||||||
int tmp = atoi(val);
|
|
||||||
if (tmp > 0) {
|
|
||||||
source->prebuf = (uint32_t) tmp;
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "channels")) {
|
|
||||||
int tmp = atoi(val);
|
|
||||||
if (tmp == 1 || tmp == 2) {
|
|
||||||
source->channels = (uint8_t) tmp;
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "chime-freq")) {
|
|
||||||
int tmp = atoi(val);
|
|
||||||
if (tmp > 1) {
|
|
||||||
source->chime_freq = tmp;
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "chime-max")) {
|
|
||||||
int tmp = atoi(val);
|
|
||||||
if (tmp > 1) {
|
|
||||||
source->chime_max = tmp;
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "chime-list")) {
|
|
||||||
char *list_dup = switch_core_strdup(source->pool, val);
|
|
||||||
source->chime_total =
|
|
||||||
switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0])));
|
|
||||||
} else if (!strcasecmp(var, "interval")) {
|
|
||||||
int tmp = atoi(val);
|
|
||||||
if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
|
|
||||||
source->interval = tmp;
|
|
||||||
} else {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
|
||||||
"Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "timer-name")) {
|
|
||||||
source->timer_name = switch_core_strdup(source->pool, val);
|
|
||||||
}
|
}
|
||||||
|
} else if (!strcasecmp(var, "shuffle")) {
|
||||||
|
source->shuffle = switch_true(val);
|
||||||
|
} else if (!strcasecmp(var, "prebuf")) {
|
||||||
|
int tmp = atoi(val);
|
||||||
|
if (tmp > 0) {
|
||||||
|
source->prebuf = (uint32_t) tmp;
|
||||||
|
}
|
||||||
|
} else if (!strcasecmp(var, "channels")) {
|
||||||
|
int tmp = atoi(val);
|
||||||
|
if (tmp == 1 || tmp == 2) {
|
||||||
|
source->channels = (uint8_t) tmp;
|
||||||
|
}
|
||||||
|
} else if (!strcasecmp(var, "chime-freq")) {
|
||||||
|
int tmp = atoi(val);
|
||||||
|
if (tmp > 1) {
|
||||||
|
source->chime_freq = tmp;
|
||||||
|
}
|
||||||
|
} else if (!strcasecmp(var, "chime-max")) {
|
||||||
|
int tmp = atoi(val);
|
||||||
|
if (tmp > 1) {
|
||||||
|
source->chime_max = tmp;
|
||||||
|
}
|
||||||
|
} else if (!strcasecmp(var, "chime-list")) {
|
||||||
|
char *list_dup = switch_core_strdup(source->pool, val);
|
||||||
|
source->chime_total =
|
||||||
|
switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0])));
|
||||||
|
} else if (!strcasecmp(var, "interval")) {
|
||||||
|
int tmp = atoi(val);
|
||||||
|
if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
|
||||||
|
source->interval = tmp;
|
||||||
|
} else {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||||
|
"Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
|
||||||
|
}
|
||||||
|
} else if (!strcasecmp(var, "timer-name")) {
|
||||||
|
source->timer_name = switch_core_strdup(source->pool, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source->chime_max) {
|
|
||||||
source->chime_max *= source->rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source->chime_total) {
|
|
||||||
source->chime_counter = source->rate * source->chime_freq;
|
|
||||||
}
|
|
||||||
|
|
||||||
source->samples = switch_samples_per_packet(source->rate, source->interval);
|
|
||||||
|
|
||||||
switch_mutex_init(&source->mutex, SWITCH_MUTEX_NESTED, source->pool);
|
|
||||||
|
|
||||||
switch_threadattr_create(&thd_attr, source->pool);
|
|
||||||
switch_threadattr_detach_set(thd_attr, 1);
|
|
||||||
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
|
||||||
switch_thread_create(&thread, thd_attr, read_stream_thread, source, source->pool);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (source->chime_max) {
|
||||||
|
source->chime_max *= source->rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source->chime_total) {
|
||||||
|
source->chime_counter = source->rate * source->chime_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
source->samples = switch_samples_per_packet(source->rate, source->interval);
|
||||||
|
switch_mutex_init(&source->mutex, SWITCH_MUTEX_NESTED, source->pool);
|
||||||
|
switch_threadattr_create(&thd_attr, source->pool);
|
||||||
|
switch_threadattr_detach_set(thd_attr, 1);
|
||||||
|
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
||||||
|
switch_thread_create(&thread, thd_attr, read_stream_thread, source, source->pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void launch_streams(const char *name)
|
||||||
|
{
|
||||||
|
switch_xml_t cfg, xml, directory;
|
||||||
|
|
||||||
|
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (zstr(name)) {
|
||||||
|
for (directory = switch_xml_child(cfg, "directory"); directory; directory = directory->next) {
|
||||||
|
char *name = (char *) switch_xml_attr(directory, "name");
|
||||||
|
char *path = (char *) switch_xml_attr(directory, "path");
|
||||||
|
launch_thread(name, path, directory);
|
||||||
|
}
|
||||||
|
} else if ((directory = switch_xml_find_child(cfg, "directory", "name", name))) {
|
||||||
|
char *path = (char *) switch_xml_attr(directory, "path");
|
||||||
|
launch_thread(name, path, directory);
|
||||||
|
}
|
||||||
switch_xml_free(xml);
|
switch_xml_free(xml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,6 +674,56 @@ static void event_handler(switch_event_t *event)
|
||||||
RUNNING = 0;
|
RUNNING = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define RELOAD_LOCAL_STREAM_SYNTAX "<local_stream_name>"
|
||||||
|
SWITCH_STANDARD_API(reload_local_stream_function)
|
||||||
|
{
|
||||||
|
local_stream_source_t *source = NULL;
|
||||||
|
char *mycmd = NULL, *argv[1] = { 0 };
|
||||||
|
char *local_stream_name = NULL;
|
||||||
|
int argc = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (zstr(cmd)) {
|
||||||
|
goto usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(mycmd = strdup(cmd))) {
|
||||||
|
goto usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 1) {
|
||||||
|
goto usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_stream_name = argv[0];
|
||||||
|
if (zstr(local_stream_name)) {
|
||||||
|
goto usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_mutex_lock(globals.mutex);
|
||||||
|
source = switch_core_hash_find(globals.source_hash, local_stream_name);
|
||||||
|
switch_mutex_unlock(globals.mutex);
|
||||||
|
|
||||||
|
if (!source) {
|
||||||
|
stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
source->full_reload = 1;
|
||||||
|
source->part_reload = 1;
|
||||||
|
stream->write_function(stream, "+OK");
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
usage:
|
||||||
|
stream->write_function(stream, "-USAGE: %s\n", RELOAD_LOCAL_STREAM_SYNTAX);
|
||||||
|
switch_safe_free(mycmd);
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
switch_safe_free(mycmd);
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
#define STOP_LOCAL_STREAM_SYNTAX "<local_stream_name>"
|
#define STOP_LOCAL_STREAM_SYNTAX "<local_stream_name>"
|
||||||
SWITCH_STANDARD_API(stop_local_stream_function)
|
SWITCH_STANDARD_API(stop_local_stream_function)
|
||||||
{
|
{
|
||||||
|
@ -644,7 +759,7 @@ SWITCH_STANDARD_API(stop_local_stream_function)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
source->stopped = 1;
|
source->stop_request = 1;
|
||||||
stream->write_function(stream, "+OK");
|
stream->write_function(stream, "+OK");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
@ -723,7 +838,8 @@ SWITCH_STANDARD_API(show_local_stream_function)
|
||||||
stream->write_function(stream, " total: %d\n", source->total);
|
stream->write_function(stream, " total: %d\n", source->total);
|
||||||
stream->write_function(stream, " shuffle: %s\n", (source->shuffle) ? "true" : "false");
|
stream->write_function(stream, " shuffle: %s\n", (source->shuffle) ? "true" : "false");
|
||||||
stream->write_function(stream, " ready: %s\n", (source->ready) ? "true" : "false");
|
stream->write_function(stream, " ready: %s\n", (source->ready) ? "true" : "false");
|
||||||
stream->write_function(stream, " stopped: %s\n", (source->stopped) ? "true" : "false");
|
stream->write_function(stream, " stopping: %s\n", (source->stop_request) ? "true" : "false");
|
||||||
|
stream->write_function(stream, " reloading: %s\n", (source->full_reload) ? "true" : "false");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
|
stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
|
||||||
|
@ -744,23 +860,13 @@ SWITCH_STANDARD_API(show_local_stream_function)
|
||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define START_LOCAL_STREAM_SYNTAX "<local_stream_name> [<path>] [<rate>] [<shuffle>] [<prebuf>] [<channels>] [<interval>] [<timer_name>]"
|
#define START_LOCAL_STREAM_SYNTAX "<local_stream_name>"
|
||||||
SWITCH_STANDARD_API(start_local_stream_function)
|
SWITCH_STANDARD_API(start_local_stream_function)
|
||||||
{
|
{
|
||||||
local_stream_source_t *source = NULL;
|
local_stream_source_t *source = NULL;
|
||||||
switch_memory_pool_t *pool;
|
|
||||||
switch_thread_t *thread;
|
|
||||||
switch_threadattr_t *thd_attr = NULL;
|
|
||||||
char *mycmd = NULL, *argv[8] = { 0 };
|
char *mycmd = NULL, *argv[8] = { 0 };
|
||||||
char *local_stream_name = NULL, *path = NULL, *timer_name = NULL, *chime_list = NULL, *list_dup = NULL;
|
char *local_stream_name = NULL;
|
||||||
uint32_t prebuf = 1;
|
|
||||||
int rate = 8000, shuffle = 1, interval = 20, chime_freq = 30;
|
|
||||||
uint8_t channels = 1;
|
|
||||||
uint32_t chime_max = 0;
|
|
||||||
int argc = 0;
|
int argc = 0;
|
||||||
char *cf = "local_stream.conf";
|
|
||||||
switch_xml_t cfg, xml, directory, param;
|
|
||||||
int tmp;
|
|
||||||
|
|
||||||
if (zstr(cmd)) {
|
if (zstr(cmd)) {
|
||||||
goto usage;
|
goto usage;
|
||||||
|
@ -776,159 +882,19 @@ SWITCH_STANDARD_API(start_local_stream_function)
|
||||||
|
|
||||||
local_stream_name = argv[0];
|
local_stream_name = argv[0];
|
||||||
|
|
||||||
if (argv[1]) {
|
|
||||||
path = strdup(argv[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argv[2]) {
|
|
||||||
tmp = atoi(argv[2]);
|
|
||||||
if (tmp == 8000 || tmp == 16000 || tmp == 32000) {
|
|
||||||
rate = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shuffle = argv[3] ? switch_true(argv[3]) : 1;
|
|
||||||
prebuf = argv[4] ? atoi(argv[4]) : DEFAULT_PREBUFFER_SIZE;
|
|
||||||
|
|
||||||
if (argv[5]) {
|
|
||||||
tmp = atoi(argv[5]);
|
|
||||||
if (tmp == 1 || tmp == 2) {
|
|
||||||
channels = (uint8_t) tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interval = argv[6] ? atoi(argv[6]) : 20;
|
|
||||||
|
|
||||||
if (!SWITCH_ACCEPTABLE_INTERVAL(interval)) {
|
|
||||||
interval = 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!path) {
|
|
||||||
if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
|
|
||||||
stream->write_function(stream, "-ERR unable to open file %s!\n", cf);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (directory = switch_xml_child(cfg, "directory"); directory; directory = directory->next) {
|
|
||||||
char *name = (char *) switch_xml_attr(directory, "name");
|
|
||||||
if (!name || !local_stream_name || strcasecmp(name, local_stream_name)) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
path = (char *) switch_xml_attr(directory, "path");
|
|
||||||
if (!(name && path)) {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid config!\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (param = switch_xml_child(directory, "param"); param; param = param->next) {
|
|
||||||
char *var = (char *) switch_xml_attr_soft(param, "name");
|
|
||||||
char *val = (char *) switch_xml_attr_soft(param, "value");
|
|
||||||
|
|
||||||
if (!strcasecmp(var, "rate")) {
|
|
||||||
tmp = atoi(val);
|
|
||||||
if (tmp == 8000 || tmp == 16000 || tmp == 32000) {
|
|
||||||
rate = tmp;
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "shuffle")) {
|
|
||||||
shuffle = switch_true(val);
|
|
||||||
} else if (!strcasecmp(var, "prebuf")) {
|
|
||||||
tmp = atoi(val);
|
|
||||||
if (tmp > 0) {
|
|
||||||
prebuf = (uint32_t) tmp;
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "channels")) {
|
|
||||||
tmp = atoi(val);
|
|
||||||
if (tmp == 1 || tmp == 2) {
|
|
||||||
channels = (uint8_t) tmp;
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "interval")) {
|
|
||||||
tmp = atoi(val);
|
|
||||||
if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
|
|
||||||
interval = tmp;
|
|
||||||
} else {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
|
||||||
"Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "timer-name")) {
|
|
||||||
timer_name = strdup(val);
|
|
||||||
} else if (!strcasecmp(var, "chime-freq")) {
|
|
||||||
tmp = atoi(val);
|
|
||||||
if (tmp > 1) {
|
|
||||||
chime_freq = (uint32_t) tmp;
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "chime-max")) {
|
|
||||||
tmp = atoi(val);
|
|
||||||
if (tmp > 1) {
|
|
||||||
chime_max = (uint32_t) tmp;
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(var, "chime-list")) {
|
|
||||||
chime_list = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path) {
|
|
||||||
path = strdup(path);
|
|
||||||
}
|
|
||||||
switch_xml_free(xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zstr(local_stream_name) || zstr(path)) {
|
|
||||||
goto usage;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch_mutex_lock(globals.mutex);
|
switch_mutex_lock(globals.mutex);
|
||||||
source = switch_core_hash_find(globals.source_hash, local_stream_name);
|
source = switch_core_hash_find(globals.source_hash, local_stream_name);
|
||||||
switch_mutex_unlock(globals.mutex);
|
switch_mutex_unlock(globals.mutex);
|
||||||
if (source) {
|
if (source) {
|
||||||
source->stopped = 0;
|
source->stopped = 0;
|
||||||
stream->write_function(stream, "+OK stream: %s[%s] %s", source->name, source->location, source->shuffle ? "shuffle" : "no shuffle");
|
source->stop_request = 0;
|
||||||
|
stream->write_function(stream, "+OK stream: %s", source->name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
|
launch_streams(local_stream_name);
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool for new local_stream\n");
|
stream->write_function(stream, "+OK stream: %s", local_stream_name);
|
||||||
stream->write_function(stream, "-ERR unable to allocate memory for local_stream %s!\n", local_stream_name);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
source = switch_core_alloc(pool, sizeof(*source));
|
|
||||||
assert(source != NULL);
|
|
||||||
source->pool = pool;
|
|
||||||
|
|
||||||
source->name = switch_core_strdup(source->pool, local_stream_name);
|
|
||||||
source->location = switch_core_strdup(source->pool, path);
|
|
||||||
source->rate = rate;
|
|
||||||
source->interval = interval;
|
|
||||||
source->channels = channels;
|
|
||||||
source->timer_name = switch_core_strdup(source->pool, timer_name ? timer_name : (argv[7] ? argv[7] : "soft"));
|
|
||||||
list_dup = switch_core_strdup(source->pool, chime_list);
|
|
||||||
source->chime_total = switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0])));
|
|
||||||
if (source->chime_total) {
|
|
||||||
source->chime_freq = chime_freq;
|
|
||||||
|
|
||||||
if (chime_max) {
|
|
||||||
source->chime_max = chime_max * source->rate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
source->chime_counter = source->rate * source->chime_freq;
|
|
||||||
source->prebuf = prebuf;
|
|
||||||
source->stopped = 0;
|
|
||||||
source->shuffle = shuffle;
|
|
||||||
source->samples = switch_samples_per_packet(source->rate, source->interval);
|
|
||||||
|
|
||||||
switch_mutex_init(&source->mutex, SWITCH_MUTEX_NESTED, source->pool);
|
|
||||||
|
|
||||||
switch_threadattr_create(&thd_attr, source->pool);
|
|
||||||
switch_threadattr_detach_set(thd_attr, 1);
|
|
||||||
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
|
||||||
switch_thread_create(&thread, thd_attr, read_stream_thread, source, source->pool);
|
|
||||||
|
|
||||||
stream->write_function(stream, "+OK stream: %s[%s] %s", source->name, source->location, source->shuffle ? "shuffle" : "no shuffle");
|
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
usage:
|
usage:
|
||||||
|
@ -936,8 +902,6 @@ SWITCH_STANDARD_API(start_local_stream_function)
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
switch_safe_free(path);
|
|
||||||
switch_safe_free(timer_name);
|
|
||||||
switch_safe_free(mycmd);
|
switch_safe_free(mycmd);
|
||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -963,8 +927,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_local_stream_load)
|
||||||
memset(&globals, 0, sizeof(globals));
|
memset(&globals, 0, sizeof(globals));
|
||||||
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, pool);
|
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, pool);
|
||||||
switch_core_hash_init(&globals.source_hash, pool);
|
switch_core_hash_init(&globals.source_hash, pool);
|
||||||
launch_threads();
|
launch_streams(NULL);
|
||||||
|
|
||||||
|
SWITCH_ADD_API(commands_api_interface, "reload_local_stream", "Reloads a local_stream", reload_local_stream_function, RELOAD_LOCAL_STREAM_SYNTAX);
|
||||||
SWITCH_ADD_API(commands_api_interface, "stop_local_stream", "Stops and unloads a local_stream", stop_local_stream_function, STOP_LOCAL_STREAM_SYNTAX);
|
SWITCH_ADD_API(commands_api_interface, "stop_local_stream", "Stops and unloads a local_stream", stop_local_stream_function, STOP_LOCAL_STREAM_SYNTAX);
|
||||||
SWITCH_ADD_API(commands_api_interface, "start_local_stream", "Starts a new local_stream", start_local_stream_function, START_LOCAL_STREAM_SYNTAX);
|
SWITCH_ADD_API(commands_api_interface, "start_local_stream", "Starts a new local_stream", start_local_stream_function, START_LOCAL_STREAM_SYNTAX);
|
||||||
SWITCH_ADD_API(commands_api_interface, "show_local_stream", "Shows a local stream", show_local_stream_function, SHOW_LOCAL_STREAM_SYNTAX);
|
SWITCH_ADD_API(commands_api_interface, "show_local_stream", "Shows a local stream", show_local_stream_function, SHOW_LOCAL_STREAM_SYNTAX);
|
||||||
|
|
Loading…
Reference in New Issue