Skip to content
项目
群组
代码片段
帮助
正在加载...
登录
切换导航
F
freeswitch
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
张华
freeswitch
Commits
c4e34838
提交
c4e34838
authored
4月 17, 2013
作者:
Anthony Minessale
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
FS-5034 --resolve please document accordingly on the wiki
上级
18360a22
显示空白字符变更
内嵌
并排
正在显示
1 个修改的文件
包含
218 行增加
和
253 行删除
+218
-253
mod_local_stream.c
src/mod/formats/mod_local_stream/mod_local_stream.c
+218
-253
没有找到文件。
src/mod/formats/mod_local_stream/mod_local_stream.c
浏览文件 @
c4e34838
...
...
@@ -25,6 +25,7 @@
*
* Anthony Minessale II <anthm@freeswitch.org>
* Cesar Cepeda <cesar@auronix.com>
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
*
*
* 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_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
;
...
...
@@ -82,6 +87,9 @@ struct local_stream_source {
switch_thread_rwlock_t
*
rwlock
;
int
ready
;
int
stopped
;
int
stop_request
;
int
part_reload
;
int
full_reload
;
int
chime_freq
;
int
chime_total
;
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
);
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:
...
...
@@ -493,34 +559,18 @@ static switch_status_t local_stream_file_read(switch_file_handle_t *handle, void
static
char
*
supported_formats
[
SWITCH_MAX_CODECS
]
=
{
0
};
static
void
launch_thread
s
(
void
)
static
void
launch_thread
(
const
char
*
name
,
const
char
*
path
,
switch_xml_t
directory
)
{
char
*
cf
=
"local_stream.conf"
;
switch_xml_t
cfg
,
xml
,
directory
,
param
;
local_stream_source_t
*
source
=
NULL
;
switch_memory_pool_t
*
pool
;
local_stream_source_t
*
source
;
switch_xml_t
param
;
switch_thread_t
*
thread
;
switch_threadattr_t
*
thd_attr
=
NULL
;
if
(
!
(
xml
=
switch_xml_open_cfg
(
cf
,
&
cfg
,
NULL
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Open of %s failed
\n
"
,
cf
);
return
;
}
for
(
directory
=
switch_xml_child
(
cfg
,
"directory"
);
directory
;
directory
=
directory
->
next
)
{
char
*
path
=
(
char
*
)
switch_xml_attr
(
directory
,
"path"
);
char
*
name
=
(
char
*
)
switch_xml_attr
(
directory
,
"name"
);
if
(
!
(
name
&&
path
))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Invalid config!
\n
"
);
continue
;
}
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
;
...
...
@@ -534,7 +584,6 @@ static void launch_threads(void)
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"
);
...
...
@@ -592,15 +641,31 @@ static void launch_threads(void)
}
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
);
}
...
...
@@ -609,6 +674,56 @@ static void event_handler(switch_event_t *event)
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>"
SWITCH_STANDARD_API
(
stop_local_stream_function
)
{
...
...
@@ -644,7 +759,7 @@ SWITCH_STANDARD_API(stop_local_stream_function)
goto
done
;
}
source
->
stop
ped
=
1
;
source
->
stop
_request
=
1
;
stream
->
write_function
(
stream
,
"+OK"
);
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
,
" shuffle: %s
\n
"
,
(
source
->
shuffle
)
?
"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
{
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
;
}
#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
)
{
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
*
local_stream_name
=
NULL
,
*
path
=
NULL
,
*
timer_name
=
NULL
,
*
chime_list
=
NULL
,
*
list_dup
=
NULL
;
uint32_t
prebuf
=
1
;
int
rate
=
8000
,
shuffle
=
1
,
interval
=
20
,
chime_freq
=
30
;
uint8_t
channels
=
1
;
uint32_t
chime_max
=
0
;
char
*
local_stream_name
=
NULL
;
int
argc
=
0
;
char
*
cf
=
"local_stream.conf"
;
switch_xml_t
cfg
,
xml
,
directory
,
param
;
int
tmp
;
if
(
zstr
(
cmd
))
{
goto
usage
;
...
...
@@ -776,159 +882,19 @@ SWITCH_STANDARD_API(start_local_stream_function)
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
);
source
=
switch_core_hash_find
(
globals
.
source_hash
,
local_stream_name
);
switch_mutex_unlock
(
globals
.
mutex
);
if
(
source
)
{
source
->
stopped
=
0
;
stream
->
write_function
(
stream
,
"+OK stream: %s[%s] %s"
,
source
->
name
,
source
->
location
,
source
->
shuffle
?
"shuffle"
:
"no shuffle"
);
goto
done
;
}
if
(
switch_core_new_memory_pool
(
&
pool
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"OH OH no pool for new local_stream
\n
"
);
stream
->
write_function
(
stream
,
"-ERR unable to allocate memory for local_stream %s!
\n
"
,
local_stream_name
);
source
->
stop_request
=
0
;
stream
->
write_function
(
stream
,
"+OK stream: %s"
,
source
->
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
);
launch_streams
(
local_stream_name
);
stream
->
write_function
(
stream
,
"+OK stream: %s"
,
local_stream_name
);
stream
->
write_function
(
stream
,
"+OK stream: %s[%s] %s"
,
source
->
name
,
source
->
location
,
source
->
shuffle
?
"shuffle"
:
"no shuffle"
);
goto
done
;
usage
:
...
...
@@ -936,8 +902,6 @@ SWITCH_STANDARD_API(start_local_stream_function)
done
:
switch_safe_free
(
path
);
switch_safe_free
(
timer_name
);
switch_safe_free
(
mycmd
);
return
SWITCH_STATUS_SUCCESS
;
}
...
...
@@ -963,8 +927,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_local_stream_load)
memset
(
&
globals
,
0
,
sizeof
(
globals
));
switch_mutex_init
(
&
globals
.
mutex
,
SWITCH_MUTEX_NESTED
,
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
,
"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
);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论