Skip to content
项目
群组
代码片段
帮助
正在加载...
登录
切换导航
F
freeswitch
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
张华
freeswitch
Commits
166249b0
提交
166249b0
authored
6月 20, 2012
作者:
Mathieu Rene
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Check in TDM and RTP controllable channels (incomplete)
上级
af39d4c9
隐藏空白字符变更
内嵌
并排
正在显示
9 个修改的文件
包含
1110 行增加
和
21 行删除
+1110
-21
Makefile.in
libs/freetdm/mod_freetdm/Makefile.in
+1
-0
mod_freetdm.c
libs/freetdm/mod_freetdm/mod_freetdm.c
+2
-2
tdm.c
libs/freetdm/mod_freetdm/tdm.c
+413
-0
sdp_parse.c
libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
+29
-16
sdp.h
libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
+8
-2
Makefile.am
src/mod/endpoints/mod_sofia/Makefile.am
+1
-1
mod_sofia.c
src/mod/endpoints/mod_sofia/mod_sofia.c
+2
-0
mod_sofia.h
src/mod/endpoints/mod_sofia/mod_sofia.h
+1
-0
rtp.c
src/mod/endpoints/mod_sofia/rtp.c
+653
-0
没有找到文件。
libs/freetdm/mod_freetdm/Makefile.in
浏览文件 @
166249b0
...
@@ -4,6 +4,7 @@ BASE=../../..
...
@@ -4,6 +4,7 @@ BASE=../../..
FT_DIR
=
..
FT_DIR
=
..
VERBOSE
=
1
VERBOSE
=
1
FTLA
=
$(FT_DIR)
/libfreetdm.la
FTLA
=
$(FT_DIR)
/libfreetdm.la
LOCAL_OBJS
=
tdm.o
LOCAL_CFLAGS
=
-I
$(FT_DIR)
/src/include
-I
$(FT_DIR)
/src/isdn/include
$(FT_CFLAGS)
LOCAL_CFLAGS
=
-I
$(FT_DIR)
/src/include
-I
$(FT_DIR)
/src/isdn/include
$(FT_CFLAGS)
LOCAL_LDFLAGS
=
-L
$(FT_DIR)
-lfreetdm
LOCAL_LDFLAGS
=
-L
$(FT_DIR)
-lfreetdm
include
$(BASE)/build/modmake.rules
include
$(BASE)/build/modmake.rules
...
...
libs/freetdm/mod_freetdm/mod_freetdm.c
浏览文件 @
166249b0
...
@@ -873,7 +873,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
...
@@ -873,7 +873,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
if
(
!
tech_pvt
->
ftdmchan
)
{
if
(
!
tech_pvt
->
ftdmchan
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"no ftdmchan set in channel %s!
\n
"
,
name
);
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"no ftdmchan set in channel %s!
\n
"
,
name
);
return
SWITCH_STATUS_FALSE
;
return
SWITCH_STATUS_FALSE
;
}
}
span_id
=
ftdm_channel_get_span_id
(
tech_pvt
->
ftdmchan
);
span_id
=
ftdm_channel_get_span_id
(
tech_pvt
->
ftdmchan
);
chan_id
=
ftdm_channel_get_id
(
tech_pvt
->
ftdmchan
);
chan_id
=
ftdm_channel_get_id
(
tech_pvt
->
ftdmchan
);
...
@@ -906,7 +906,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
...
@@ -906,7 +906,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
ftdm_channel_wait
(
tech_pvt
->
ftdmchan
,
&
wflags
,
ftdm_channel_get_io_interval
(
tech_pvt
->
ftdmchan
)
*
10
);
ftdm_channel_wait
(
tech_pvt
->
ftdmchan
,
&
wflags
,
ftdm_channel_get_io_interval
(
tech_pvt
->
ftdmchan
)
*
10
);
if
(
!
(
wflags
&
FTDM_WRITE
))
{
if
(
!
(
wflags
&
FTDM_WRITE
))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Dropping frame! (write not
e
ready) in channel %s device %d:%d!
\n
"
,
name
,
span_id
,
chan_id
);
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Dropping frame! (write not ready) in channel %s device %d:%d!
\n
"
,
name
,
span_id
,
chan_id
);
return
SWITCH_STATUS_SUCCESS
;
return
SWITCH_STATUS_SUCCESS
;
}
}
...
...
libs/freetdm/mod_freetdm/tdm.c
0 → 100644
浏览文件 @
166249b0
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Mathieu Rene <mrene@avgs.ca>
*
* tdm.c -- FreeTDM Controllable Channel Module
*
*/
#include <switch.h>
#include "freetdm.h"
void
ctdm_init
(
switch_loadable_module_interface_t
*
module_interface
);
/* Parameters */
#define kSPAN_ID "span"
#define kCHAN_ID "chan"
static
struct
{
switch_memory_pool_t
*
pool
;
switch_endpoint_interface_t
*
endpoint_interface
;
}
ctdm
;
typedef
struct
{
int
span_id
;
int
chan_id
;
ftdm_channel_t
*
ftdm_channel
;
switch_core_session_t
*
session
;
switch_codec_t
read_codec
,
write_codec
;
switch_frame_t
read_frame
;
}
ctdm_private_t
;
static
switch_status_t
channel_on_init
(
switch_core_session_t
*
session
);
static
switch_status_t
channel_on_destroy
(
switch_core_session_t
*
session
);
static
switch_call_cause_t
channel_outgoing_channel
(
switch_core_session_t
*
session
,
switch_event_t
*
var_event
,
switch_caller_profile_t
*
outbound_profile
,
switch_core_session_t
**
new_session
,
switch_memory_pool_t
**
pool
,
switch_originate_flag_t
flags
,
switch_call_cause_t
*
cancel_cause
);
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_receive_message
(
switch_core_session_t
*
session
,
switch_core_session_message_t
*
msg
);
static
switch_status_t
channel_send_dtmf
(
switch_core_session_t
*
session
,
const
switch_dtmf_t
*
dtmf
);
switch_state_handler_table_t
ctdm_state_handlers
=
{
.
on_init
=
channel_on_init
,
.
on_destroy
=
channel_on_destroy
};
switch_io_routines_t
ctdm_io_routines
=
{
.
send_dtmf
=
channel_send_dtmf
,
.
outgoing_channel
=
channel_outgoing_channel
,
.
read_frame
=
channel_read_frame
,
.
write_frame
=
channel_write_frame
,
.
receive_message
=
channel_receive_message
};
void
ctdm_init
(
switch_loadable_module_interface_t
*
module_interface
)
{
switch_endpoint_interface_t
*
endpoint_interface
;
ctdm
.
pool
=
module_interface
->
pool
;
endpoint_interface
=
switch_loadable_module_create_interface
(
module_interface
,
SWITCH_ENDPOINT_INTERFACE
);
endpoint_interface
->
interface_name
=
"tdm"
;
endpoint_interface
->
io_routines
=
&
ctdm_io_routines
;
endpoint_interface
->
state_handler
=
&
ctdm_state_handlers
;
ctdm
.
endpoint_interface
=
endpoint_interface
;
}
static
switch_call_cause_t
channel_outgoing_channel
(
switch_core_session_t
*
session
,
switch_event_t
*
var_event
,
switch_caller_profile_t
*
outbound_profile
,
switch_core_session_t
**
new_session
,
switch_memory_pool_t
**
pool
,
switch_originate_flag_t
flags
,
switch_call_cause_t
*
cancel_cause
)
{
const
char
*
szspanid
=
switch_event_get_header
(
var_event
,
kSPAN_ID
),
*
szchanid
=
switch_event_get_header
(
var_event
,
kCHAN_ID
);
int
chan_id
;
int
span_id
;
ftdm_span_t
*
span
;
ftdm_channel_t
*
chan
;
switch_channel_t
*
channel
;
char
name
[
128
];
const
char
*
dname
;
ftdm_codec_t
codec
;
uint32_t
interval
;
ctdm_private_t
*
tech_pvt
;
if
(
zstr
(
szchanid
)
||
zstr
(
szspanid
))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Both "
kSPAN_ID
" and "
kCHAN_ID
" have to be set.
\n
"
);
goto
fail
;
}
chan_id
=
atoi
(
szchanid
);
span_id
=
atoi
(
szspanid
);
if
(
!
(
*
new_session
=
switch_core_session_request
(
ctdm
.
endpoint_interface
,
SWITCH_CALL_DIRECTION_OUTBOUND
,
0
,
pool
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Couldn't request session.
\n
"
);
goto
fail
;
}
channel
=
switch_core_session_get_channel
(
*
new_session
);
if
(
ftdm_channel_open
(
span_id
,
chan_id
,
&
chan
)
!=
FTDM_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Couldn't open span or channel.
\n
"
);
goto
fail
;
}
span
=
ftdm_channel_get_span
(
chan
);
tech_pvt
=
switch_core_session_alloc
(
*
new_session
,
sizeof
*
tech_pvt
);
tech_pvt
->
chan_id
=
chan_id
;
tech_pvt
->
span_id
=
span_id
;
tech_pvt
->
ftdm_channel
=
chan
;
tech_pvt
->
session
=
*
new_session
;
switch_core_session_set_private
(
*
new_session
,
tech_pvt
);
snprintf
(
name
,
sizeof
(
name
),
"tdm/%d:%d"
,
span_id
,
chan_id
);
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Connect outbound channel %s
\n
"
,
name
);
switch_channel_set_name
(
channel
,
name
);
switch_channel_set_state
(
channel
,
CS_INIT
);
if
(
FTDM_SUCCESS
!=
ftdm_channel_command
(
chan
,
FTDM_COMMAND_GET_CODEC
,
&
codec
))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to retrieve channel codec.
\n
"
);
return
SWITCH_STATUS_GENERR
;
}
if
(
FTDM_SUCCESS
!=
ftdm_channel_command
(
chan
,
FTDM_COMMAND_GET_INTERVAL
,
&
interval
))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to retrieve channel interval.
\n
"
);
return
SWITCH_STATUS_GENERR
;
}
switch
(
codec
)
{
case
FTDM_CODEC_ULAW
:
{
dname
=
"PCMU"
;
}
break
;
case
FTDM_CODEC_ALAW
:
{
dname
=
"PCMA"
;
}
break
;
case
FTDM_CODEC_SLIN
:
{
dname
=
"L16"
;
}
break
;
default:
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Invalid codec value retrieved from channel, codec value: %d
\n
"
,
codec
);
goto
fail
;
}
}
if
(
switch_core_codec_init
(
&
tech_pvt
->
read_codec
,
dname
,
NULL
,
8000
,
interval
,
1
,
SWITCH_CODEC_FLAG_ENCODE
|
SWITCH_CODEC_FLAG_DECODE
,
NULL
,
switch_core_session_get_pool
(
tech_pvt
->
session
))
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Can't load codec?
\n
"
);
goto
fail
;
}
else
{
if
(
switch_core_codec_init
(
&
tech_pvt
->
write_codec
,
dname
,
NULL
,
8000
,
interval
,
1
,
SWITCH_CODEC_FLAG_ENCODE
|
SWITCH_CODEC_FLAG_DECODE
,
NULL
,
switch_core_session_get_pool
(
tech_pvt
->
session
))
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Can't load codec?
\n
"
);
switch_core_codec_destroy
(
&
tech_pvt
->
read_codec
);
goto
fail
;
}
}
if
(
switch_core_session_set_read_codec
(
*
new_session
,
&
tech_pvt
->
read_codec
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Can't set read codec?
\n
"
);
goto
fail
;
}
if
(
switch_core_session_set_write_codec
(
*
new_session
,
&
tech_pvt
->
write_codec
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Can't set write codec?
\n
"
);
}
if
(
switch_core_session_thread_launch
(
*
new_session
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Couldn't start session thread.
\n
"
);
goto
fail
;
}
return
SWITCH_CAUSE_SUCCESS
;
fail:
if
(
tech_pvt
)
{
if
(
tech_pvt
->
ftdm_channel
)
{
ftdm_channel_close
(
&
tech_pvt
->
ftdm_channel
);
}
if
(
tech_pvt
->
read_codec
.
implementation
)
{
switch_core_codec_destroy
(
&
tech_pvt
->
read_codec
);
}
if
(
tech_pvt
->
write_codec
.
implementation
)
{
switch_core_codec_destroy
(
&
tech_pvt
->
write_codec
);
}
}
if
(
*
new_session
)
{
switch_core_session_destroy
(
new_session
);
}
return
SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER
;
}
static
switch_status_t
channel_on_init
(
switch_core_session_t
*
session
)
{
return
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
channel_on_destroy
(
switch_core_session_t
*
session
)
{
ctdm_private_t
*
tech_pvt
=
switch_core_session_get_private
(
session
);
if
((
tech_pvt
=
switch_core_session_get_private
(
session
)))
{
if
(
tech_pvt
->
read_codec
.
implementation
)
{
switch_core_codec_destroy
(
&
tech_pvt
->
read_codec
);
}
if
(
tech_pvt
->
write_codec
.
implementation
)
{
switch_core_codec_destroy
(
&
tech_pvt
->
write_codec
);
}
}
ftdm_channel_close
(
&
tech_pvt
->
ftdm_channel
);
return
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
channel_read_frame
(
switch_core_session_t
*
session
,
switch_frame_t
**
frame
,
switch_io_flag_t
flags
,
int
stream_id
)
{
ftdm_wait_flag_t
wflags
=
FTDM_READ
;
ftdm_status_t
status
;
ctdm_private_t
*
tech_pvt
;
const
char
*
name
;
switch_channel_t
*
channel
;
int
chunk
;
uint32_t
span_id
,
chan_id
;
ftdm_size_t
len
;
char
dtmf
[
128
]
=
""
;
channel
=
switch_core_session_get_channel
(
session
);
assert
(
channel
!=
NULL
);
tech_pvt
=
switch_core_session_get_private
(
session
);
assert
(
tech_pvt
!=
NULL
);
name
=
switch_channel_get_name
(
channel
);
top:
wflags
=
FTDM_READ
;
chunk
=
ftdm_channel_get_io_interval
(
tech_pvt
->
ftdm_channel
)
*
2
;
status
=
ftdm_channel_wait
(
tech_pvt
->
ftdm_channel
,
&
wflags
,
chunk
);
span_id
=
ftdm_channel_get_span_id
(
tech_pvt
->
ftdm_channel
);
chan_id
=
ftdm_channel_get_id
(
tech_pvt
->
ftdm_channel
);
if
(
status
==
FTDM_FAIL
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to read from channel %s device %d:%d!
\n
"
,
name
,
span_id
,
chan_id
);
goto
fail
;
}
if
(
status
==
FTDM_TIMEOUT
)
{
goto
top
;
}
if
(
!
(
wflags
&
FTDM_READ
))
{
goto
top
;
}
len
=
tech_pvt
->
read_frame
.
buflen
;
if
(
ftdm_channel_read
(
tech_pvt
->
ftdm_channel
,
tech_pvt
->
read_frame
.
data
,
&
len
)
!=
FTDM_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Failed to read from channel %s device %d:%d!
\n
"
,
name
,
span_id
,
chan_id
);
}
*
frame
=
&
tech_pvt
->
read_frame
;
tech_pvt
->
read_frame
.
datalen
=
(
uint32_t
)
len
;
tech_pvt
->
read_frame
.
samples
=
tech_pvt
->
read_frame
.
datalen
;
if
(
ftdm_channel_get_codec
(
tech_pvt
->
ftdm_channel
)
==
FTDM_CODEC_SLIN
)
{
tech_pvt
->
read_frame
.
samples
/=
2
;
}
while
(
ftdm_channel_dequeue_dtmf
(
tech_pvt
->
ftdm_channel
,
dtmf
,
sizeof
(
dtmf
)))
{
switch_dtmf_t
_dtmf
=
{
0
,
switch_core_default_dtmf_duration
(
0
)
};
char
*
p
;
for
(
p
=
dtmf
;
p
&&
*
p
;
p
++
)
{
if
(
is_dtmf
(
*
p
))
{
_dtmf
.
digit
=
*
p
;
ftdm_log
(
FTDM_LOG_DEBUG
,
"Queuing DTMF [%c] in channel %s device %d:%d
\n
"
,
*
p
,
name
,
span_id
,
chan_id
);
switch_channel_queue_dtmf
(
channel
,
&
_dtmf
);
}
}
}
return
SWITCH_STATUS_SUCCESS
;
fail:
return
SWITCH_STATUS_GENERR
;
}
static
switch_status_t
channel_write_frame
(
switch_core_session_t
*
session
,
switch_frame_t
*
frame
,
switch_io_flag_t
flags
,
int
stream_id
)
{
ftdm_wait_flag_t
wflags
=
FTDM_WRITE
;
ctdm_private_t
*
tech_pvt
;
const
char
*
name
;
switch_channel_t
*
channel
;
uint32_t
span_id
,
chan_id
;
ftdm_size_t
len
;
unsigned
char
data
[
SWITCH_RECOMMENDED_BUFFER_SIZE
]
=
{
0
};
channel
=
switch_core_session_get_channel
(
session
);
assert
(
channel
!=
NULL
);
tech_pvt
=
switch_core_session_get_private
(
session
);
assert
(
tech_pvt
!=
NULL
);
span_id
=
ftdm_channel_get_span_id
(
tech_pvt
->
ftdm_channel
);
chan_id
=
ftdm_channel_get_id
(
tech_pvt
->
ftdm_channel
);
name
=
switch_channel_get_name
(
channel
);
if
(
switch_test_flag
(
frame
,
SFF_CNG
))
{
frame
->
data
=
data
;
frame
->
buflen
=
sizeof
(
data
);
if
((
frame
->
datalen
=
tech_pvt
->
write_codec
.
implementation
->
encoded_bytes_per_packet
)
>
frame
->
buflen
)
{
goto
fail
;
}
memset
(
data
,
255
,
frame
->
datalen
);
}
wflags
=
FTDM_WRITE
;
ftdm_channel_wait
(
tech_pvt
->
ftdm_channel
,
&
wflags
,
ftdm_channel_get_io_interval
(
tech_pvt
->
ftdm_channel
)
*
10
);
if
(
!
(
wflags
&
FTDM_WRITE
))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Dropping frame! (write not ready) in channel %s device %d:%d!
\n
"
,
name
,
span_id
,
chan_id
);
return
SWITCH_STATUS_SUCCESS
;
}
len
=
frame
->
datalen
;
if
(
ftdm_channel_write
(
tech_pvt
->
ftdm_channel
,
frame
->
data
,
frame
->
buflen
,
&
len
)
!=
FTDM_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Failed to write to channel %s device %d:%d!
\n
"
,
name
,
span_id
,
chan_id
);
}
return
SWITCH_STATUS_SUCCESS
;
fail:
return
SWITCH_STATUS_GENERR
;
}
static
switch_status_t
channel_send_dtmf
(
switch_core_session_t
*
session
,
const
switch_dtmf_t
*
dtmf
)
{
ctdm_private_t
*
tech_pvt
=
NULL
;
char
tmp
[
2
]
=
""
;
tech_pvt
=
switch_core_session_get_private
(
session
);
assert
(
tech_pvt
!=
NULL
);
tmp
[
0
]
=
dtmf
->
digit
;
ftdm_channel_command
(
tech_pvt
->
ftdm_channel
,
FTDM_COMMAND_SEND_DTMF
,
tmp
);
return
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
channel_receive_message
(
switch_core_session_t
*
session
,
switch_core_session_message_t
*
msg
)
{
return
SWITCH_STATUS_SUCCESS
;
}
libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
浏览文件 @
166249b0
...
@@ -81,6 +81,7 @@ struct sdp_parser_s {
...
@@ -81,6 +81,7 @@ struct sdp_parser_s {
unsigned
pr_insane
:
1
;
unsigned
pr_insane
:
1
;
unsigned
pr_c_missing
:
1
;
unsigned
pr_c_missing
:
1
;
unsigned
pr_config
:
1
;
unsigned
pr_config
:
1
;
unsigned
pr_megaco
:
1
;
};
};
#define is_posdigit(c) ((c) >= '1' && (c) <= '9')
#define is_posdigit(c) ((c) >= '1' && (c) <= '9')
...
@@ -176,6 +177,7 @@ sdp_parse(su_home_t *home, char const msg[], issize_t msgsize, int flags)
...
@@ -176,6 +177,7 @@ sdp_parse(su_home_t *home, char const msg[], issize_t msgsize, int flags)
if
(
flags
&
sdp_f_config
)
if
(
flags
&
sdp_f_config
)
p
->
pr_c_missing
=
1
,
p
->
pr_config
=
1
;
p
->
pr_c_missing
=
1
,
p
->
pr_config
=
1
;
p
->
pr_mode_manual
=
(
flags
&
sdp_f_mode_manual
)
!=
0
;
p
->
pr_mode_manual
=
(
flags
&
sdp_f_mode_manual
)
!=
0
;
p
->
pr_megaco
=
(
flags
&
sdp_f_megaco
)
!=
0
;
p
->
pr_session_mode
=
sdp_sendrecv
;
p
->
pr_session_mode
=
sdp_sendrecv
;
parse_message
(
p
);
parse_message
(
p
);
...
@@ -1502,8 +1504,18 @@ static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
...
@@ -1502,8 +1504,18 @@ static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
{
{
while
(
*
r
)
{
while
(
*
r
)
{
unsigned
long
value
;
unsigned
long
value
;
if
(((
p
->
pr_config
&&
r
[
0
]
==
'*'
)
||
(
p
->
pr_megaco
&&
r
[
0
]
==
MEGACO_CHOOSE_TOK
))
&&
(
r
[
1
]
==
' '
||
r
[
1
]
==
'\0'
))
{
PARSE_ALLOC
(
p
,
sdp_rtpmap_t
,
rm
);
*
result
=
rm
;
result
=
&
rm
->
rm_next
;
rm
->
rm_predef
=
1
;
rm
->
rm_any
=
1
;
rm
->
rm_encoding
=
"*"
;
rm
->
rm_rate
=
0
;
if
(
parse_ul
(
p
,
&
r
,
&
value
,
128
)
==
0
)
{
return
;
}
else
if
(
parse_ul
(
p
,
&
r
,
&
value
,
128
)
==
0
&&
value
<
128
)
{
PARSE_ALLOC
(
p
,
sdp_rtpmap_t
,
rm
);
PARSE_ALLOC
(
p
,
sdp_rtpmap_t
,
rm
);
assert
(
0
<=
value
&&
value
<
128
);
assert
(
0
<=
value
&&
value
<
128
);
...
@@ -1519,21 +1531,8 @@ static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
...
@@ -1519,21 +1531,8 @@ static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
rm
->
rm_encoding
=
""
;
rm
->
rm_encoding
=
""
;
rm
->
rm_rate
=
0
;
rm
->
rm_rate
=
0
;
}
}
}
}
else
{
else
if
(
p
->
pr_config
&&
r
[
0
]
==
'*'
&&
(
r
[
1
]
==
' '
||
r
[
1
]
==
'\0'
))
{
parsing_error
(
p
,
"m= invalid format for RTP/AVP"
);
PARSE_ALLOC
(
p
,
sdp_rtpmap_t
,
rm
);
*
result
=
rm
;
result
=
&
rm
->
rm_next
;
rm
->
rm_predef
=
1
;
rm
->
rm_any
=
1
;
rm
->
rm_encoding
=
"*"
;
rm
->
rm_rate
=
0
;
return
;
}
else
{
parsing_error
(
p
,
"m= invalid format for RTP/AVT"
);
return
;
return
;
}
}
...
@@ -1797,6 +1796,13 @@ static int parse_ul(sdp_parser_t *p, char **r,
...
@@ -1797,6 +1796,13 @@ static int parse_ul(sdp_parser_t *p, char **r,
return
0
;
return
0
;
}
}
if
(
p
->
pr_megaco
&&
*
ul
==
MEGACO_CHOOSE_TOK
)
{
*
result
=
MEGACO_CHOOSE
;
(
*
r
)
++
;
*
r
+=
strspn
(
*
r
,
SPACE
TAB
);
return
0
;
}
return
-
1
;
return
-
1
;
}
}
...
@@ -1824,6 +1830,13 @@ static int parse_ull(sdp_parser_t *p, char **r,
...
@@ -1824,6 +1830,13 @@ static int parse_ull(sdp_parser_t *p, char **r,
return
0
;
return
0
;
}
}
if
(
p
->
pr_megaco
&&
*
s
==
MEGACO_CHOOSE_TOK
)
{
*
result
=
MEGACO_CHOOSE
;
(
*
r
)
++
;
*
r
+=
strspn
(
*
r
,
SPACE
TAB
);
return
0
;
}
return
-
1
;
return
-
1
;
}
}
...
...
libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
浏览文件 @
166249b0
...
@@ -24,6 +24,10 @@
...
@@ -24,6 +24,10 @@
#ifndef SDP_H
#ifndef SDP_H
#define SDP_H
#define SDP_H
#define MEGACO_CHOOSE_TOK '$'
#define MEGACO_CHOOSE (UINT16_MAX + 1)
/**@file sofia-sip/sdp.h Simple SDP (RFC 2327) Interface.
/**@file sofia-sip/sdp.h Simple SDP (RFC 2327) Interface.
*
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
...
@@ -260,7 +264,7 @@ typedef enum {
...
@@ -260,7 +264,7 @@ typedef enum {
/** Media announcement.
/** Media announcement.
*
*
* This structure describes one media type, e.g., audio. The description
* This structure describes one media type, e.g., audio. The description
* contains the transport address (IP address and port) used for the group,
* contains the transport address (IP address and port) used for the group,
/Users/mrene/Downloads
* the transport protocol used, the media formats or RTP payload types, and
* the transport protocol used, the media formats or RTP payload types, and
* optionally media-specific bandwidth specification, encryption key and
* optionally media-specific bandwidth specification, encryption key and
* attributes.
* attributes.
...
@@ -525,7 +529,9 @@ enum sdp_parse_flags_e {
...
@@ -525,7 +529,9 @@ enum sdp_parse_flags_e {
/** Do not generate or parse SDP mode */
/** Do not generate or parse SDP mode */
sdp_f_mode_manual
=
512
,
sdp_f_mode_manual
=
512
,
/** Always generate media-level mode attributes */
/** Always generate media-level mode attributes */
sdp_f_mode_always
=
1024
sdp_f_mode_always
=
1024
,
/** Allow optional (choose) parameters */
sdp_f_megaco
=
2048
};
};
/** SDP parser handle. */
/** SDP parser handle. */
...
...
src/mod/endpoints/mod_sofia/Makefile.am
浏览文件 @
166249b0
...
@@ -9,7 +9,7 @@ SOFIAUA_BUILDDIR=$(SOFIA_BUILDDIR)/libsofia-sip-ua
...
@@ -9,7 +9,7 @@ SOFIAUA_BUILDDIR=$(SOFIA_BUILDDIR)/libsofia-sip-ua
SOFIALA
=
$(SOFIAUA_BUILDDIR)
/libsofia-sip-ua.la
SOFIALA
=
$(SOFIAUA_BUILDDIR)
/libsofia-sip-ua.la
mod_LTLIBRARIES
=
mod_sofia.la
mod_LTLIBRARIES
=
mod_sofia.la
mod_sofia_la_SOURCES
=
mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c mod_sofia.h
mod_sofia_la_SOURCES
=
mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c
rtp.c
mod_sofia.h
mod_sofia_la_CFLAGS
=
$(AM_CFLAGS)
-I
.
$(SOFIA_CMD_LINE_CFLAGS)
mod_sofia_la_CFLAGS
=
$(AM_CFLAGS)
-I
.
$(SOFIA_CMD_LINE_CFLAGS)
mod_sofia_la_CFLAGS
+=
-I
$(SOFIAUA_DIR)
/bnf
-I
$(SOFIAUA_BUILDDIR)
/bnf
mod_sofia_la_CFLAGS
+=
-I
$(SOFIAUA_DIR)
/bnf
-I
$(SOFIAUA_BUILDDIR)
/bnf
mod_sofia_la_CFLAGS
+=
-I
$(SOFIAUA_DIR)
/http
-I
$(SOFIAUA_BUILDDIR)
/http
mod_sofia_la_CFLAGS
+=
-I
$(SOFIAUA_DIR)
/http
-I
$(SOFIAUA_BUILDDIR)
/http
...
...
src/mod/endpoints/mod_sofia/mod_sofia.c
浏览文件 @
166249b0
...
@@ -5634,6 +5634,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
...
@@ -5634,6 +5634,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
SWITCH_ADD_API
(
api_interface
,
"sofia_count_reg"
,
"Count Sofia registration"
,
sofia_count_reg_function
,
"[profile/]<user>@<domain>"
);
SWITCH_ADD_API
(
api_interface
,
"sofia_count_reg"
,
"Count Sofia registration"
,
sofia_count_reg_function
,
"[profile/]<user>@<domain>"
);
SWITCH_ADD_API
(
api_interface
,
"sofia_dig"
,
"SIP DIG"
,
sip_dig_function
,
"<url>"
);
SWITCH_ADD_API
(
api_interface
,
"sofia_dig"
,
"SIP DIG"
,
sip_dig_function
,
"<url>"
);
SWITCH_ADD_CHAT
(
chat_interface
,
SOFIA_CHAT_PROTO
,
sofia_presence_chat_send
);
SWITCH_ADD_CHAT
(
chat_interface
,
SOFIA_CHAT_PROTO
,
sofia_presence_chat_send
);
crtp_init
(
*
module_interface
);
/* indicate that the module should continue to be loaded */
/* indicate that the module should continue to be loaded */
return
SWITCH_STATUS_SUCCESS
;
return
SWITCH_STATUS_SUCCESS
;
...
...
src/mod/endpoints/mod_sofia/mod_sofia.h
浏览文件 @
166249b0
...
@@ -1152,3 +1152,4 @@ void sofia_process_dispatch_event(sofia_dispatch_event_t **dep);
...
@@ -1152,3 +1152,4 @@ void sofia_process_dispatch_event(sofia_dispatch_event_t **dep);
char
*
sofia_glue_get_host
(
const
char
*
str
,
switch_memory_pool_t
*
pool
);
char
*
sofia_glue_get_host
(
const
char
*
str
,
switch_memory_pool_t
*
pool
);
void
sofia_presence_check_subscriptions
(
sofia_profile_t
*
profile
,
time_t
now
);
void
sofia_presence_check_subscriptions
(
sofia_profile_t
*
profile
,
time_t
now
);
void
sofia_msg_thread_start
(
int
idx
);
void
sofia_msg_thread_start
(
int
idx
);
void
crtp_init
(
switch_loadable_module_interface_t
*
module_interface
);
src/mod/endpoints/mod_sofia/rtp.c
0 → 100644
浏览文件 @
166249b0
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Mathieu Rene <mrene@avgs.ca>
*
* rtp.c -- RTP Controllable Channel Module
*
*/
#include <switch.h>
#include "mod_sofia.h"
#define kRSDP "r_sdp"
#define kLSDP "l_sdp"
#define kBINDADDRESS "bind_address"
#define kCODECSTRING "codec_string"
static
struct
{
switch_memory_pool_t
*
pool
;
switch_endpoint_interface_t
*
endpoint_interface
;
}
crtp
;
typedef
struct
{
switch_core_session_t
*
session
;
switch_channel_t
*
channel
;
switch_codec_t
read_codec
,
write_codec
;
switch_frame_t
read_frame
;
switch_rtp_bug_flag_t
rtp_bugs
;
switch_rtp_t
*
rtp_session
;
const
char
*
bind_address
;
const
switch_codec_implementation_t
*
negotiated_codecs
[
SWITCH_MAX_CODECS
];
int
num_negotiated_codecs
;
char
*
origin
;
int
local_port
;
}
crtp_private_t
;
static
switch_status_t
channel_on_init
(
switch_core_session_t
*
session
);
static
switch_status_t
channel_on_destroy
(
switch_core_session_t
*
session
);
static
switch_call_cause_t
channel_outgoing_channel
(
switch_core_session_t
*
session
,
switch_event_t
*
var_event
,
switch_caller_profile_t
*
outbound_profile
,
switch_core_session_t
**
new_session
,
switch_memory_pool_t
**
pool
,
switch_originate_flag_t
flags
,
switch_call_cause_t
*
cancel_cause
);
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_receive_message
(
switch_core_session_t
*
session
,
switch_core_session_message_t
*
msg
);
static
switch_status_t
channel_send_dtmf
(
switch_core_session_t
*
session
,
const
switch_dtmf_t
*
dtmf
);
switch_state_handler_table_t
crtp_state_handlers
=
{
.
on_init
=
channel_on_init
,
.
on_destroy
=
channel_on_destroy
};
switch_io_routines_t
crtp_io_routines
=
{
.
outgoing_channel
=
channel_outgoing_channel
,
.
read_frame
=
channel_read_frame
,
.
write_frame
=
channel_write_frame
,
.
receive_message
=
channel_receive_message
,
.
send_dtmf
=
channel_send_dtmf
};
SWITCH_STANDARD_API
(
test_function
)
{
return
SWITCH_STATUS_SUCCESS
;
}
void
crtp_init
(
switch_loadable_module_interface_t
*
module_interface
)
{
switch_endpoint_interface_t
*
endpoint_interface
;
switch_api_interface_t
*
api_interface
;
crtp
.
pool
=
module_interface
->
pool
;
endpoint_interface
=
switch_loadable_module_create_interface
(
module_interface
,
SWITCH_ENDPOINT_INTERFACE
);
endpoint_interface
->
interface_name
=
"rtp"
;
endpoint_interface
->
io_routines
=
&
crtp_io_routines
;
endpoint_interface
->
state_handler
=
&
crtp_state_handlers
;
crtp
.
endpoint_interface
=
endpoint_interface
;
// SWITCH_ADD_API(api_interface, "rtp_test", "test", test_function, "");
}
typedef
struct
parsed_sdp_s
{
const
char
*
c
;
/*!< Connection */
}
parsed_sdp_t
;
//static switch_status_t check_codec
/*
* Setup the local RTP side
* A lot of values can be chosen by the MG, those will have $ as a placeholder.
* We need to validate the SDP, making sure we can support everything that's offered on our behalf,
* amend it if we don't support everything, or systematically reject it if we cannot support it.
*
* Would this function be called using NULL as l_sdp, we will generate an SDP payload.
*/
static
switch_status_t
setup_local_rtp
(
crtp_private_t
*
tech_pvt
,
const
char
*
l_sdp
,
const
char
*
codec_string
)
{
switch_core_session_t
const
*
session
=
tech_pvt
->
session
;
int
num_codecs
;
const
switch_codec_implementation_t
*
codecs
[
SWITCH_MAX_CODECS
]
=
{
0
};
char
*
codec_order
[
SWITCH_MAX_CODECS
]
=
{
0
};
int
codec_order_last
;
/* Load in the list of codecs we support. If we have a codec string we use our priorities first */
if
(
codec_string
)
{
char
*
tmp_codec_string
;
if
((
tmp_codec_string
=
switch_core_session_strdup
(
tech_pvt
->
session
,
codec_string
)))
{
codec_order_last
=
switch_separate_string
(
tmp_codec_string
,
','
,
codec_order
,
SWITCH_MAX_CODECS
);
num_codecs
=
switch_loadable_module_get_codecs_sorted
(
codecs
,
SWITCH_MAX_CODECS
,
codec_order
,
codec_order_last
);
}
}
else
{
num_codecs
=
switch_loadable_module_get_codecs
(
codecs
,
switch_arraylen
(
codecs
));
}
/* TODO: Look at remote settings */
if
(
zstr
(
l_sdp
))
{
/* Generate a local SDP here */
const
char
*
sdpbuf
=
switch_core_session_sprintf
(
session
,
"v=0
\n
IN IP4 %s
\n
m=audio %d RTP/AVP %d"
);
}
else
{
/* Parse the SDP and remove anything we cannot support, then validate it to make sure it contains at least one codec
* so that we reject invalid ones. */
#if 1
uint8_t
match
=
0
;
int
first
=
0
,
last
=
0
;
int
ptime
=
0
,
dptime
=
0
,
maxptime
=
0
,
dmaxptime
=
0
;
int
sendonly
=
0
,
recvonly
=
0
;
int
greedy
=
0
,
x
=
0
,
skip
=
0
,
mine
=
0
;
int
got_crypto
=
0
,
got_audio
=
0
,
got_avp
=
0
,
got_savp
=
0
,
got_udptl
=
0
;
#endif
int
sdp_modified
=
0
;
int
cur_codec
=
0
;
sdp_parser_t
*
parser
=
NULL
;
sdp_session_t
*
sdp
,
*
lsdp
;
sdp_media_t
*
m
;
sdp_attribute_t
*
attr
;
su_home_t
*
sdp_home
;
if
(
!
(
parser
=
sdp_parse
(
NULL
,
l_sdp
,
(
int
)
strlen
(
l_sdp
),
sdp_f_megaco
/* accept $ values */
|
sdp_f_insane
/* accept omitted o= */
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Malformed SDP
\n
"
);
goto
fail
;
}
if
(
!
(
sdp
=
sdp_session
(
parser
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Couldn't get session from sdp.
\n
"
);
goto
fail
;
}
sdp_home
=
sdp_parser_home
(
parser
);
for
(
m
=
sdp
->
sdp_media
;
m
;
m
=
m
->
m_next
)
{
if
(
m
->
m_type
==
sdp_media_audio
)
{
sdp_rtpmap_t
*
map
;
for
(
attr
=
m
->
m_attributes
;
attr
;
attr
=
attr
->
a_next
)
{
if
(
!
strcasecmp
(
attr
->
a_name
,
"ptime"
)
&&
attr
->
a_value
)
{
ptime
=
atoi
(
attr
->
a_value
);
}
else
if
(
!
strcasecmp
(
attr
->
a_name
,
"maxptime"
)
&&
attr
->
a_value
)
{
maxptime
=
atoi
(
attr
->
a_value
);
}
}
sdp_connection_t
*
connection
;
connection
=
sdp
->
sdp_connection
;
if
(
m
->
m_connections
)
{
connection
=
m
->
m_connections
;
}
/* Check for wildcards in m= (media) and c= (connection) */
if
(
!
zstr
(
connection
->
c_address
))
{
if
(
!
strcmp
(
connection
->
c_address
,
"$"
))
{
connection
->
c_address
=
su_strdup
(
sdp_home
,
tech_pvt
->
bind_address
);
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Using bind address: %s
\n
"
,
tech_pvt
->
bind_address
);
switch_channel_set_variable
(
tech_pvt
->
channel
,
kBINDADDRESS
,
tech_pvt
->
bind_address
);
sdp_modified
=
1
;
}
else
if
(
strcmp
(
connection
->
c_address
,
tech_pvt
->
bind_address
))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"MGC requested to bind on [%s] which is different than the configuration [%s]
\n
"
,
connection
->
c_address
,
tech_pvt
->
bind_address
);
goto
fail
;
}
if
(
m
->
m_port
==
MEGACO_CHOOSE
)
{
tech_pvt
->
local_port
=
m
->
m_port
=
switch_rtp_request_port
(
tech_pvt
->
bind_address
);
switch_channel_set_variable_printf
(
tech_pvt
->
channel
,
"rtp_local_port"
,
"%d"
,
tech_pvt
->
local_port
);
if
(
!
tech_pvt
->
local_port
)
{
/* Port request failed */
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"No available RTP ports on [%s]
\n
"
,
tech_pvt
->
bind_address
);
goto
fail
;
}
sdp_modified
=
1
;
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Using local port: %d
\n
"
,
tech_pvt
->
local_port
);
}
}
/* Validate codecs */
for
(
map
=
m
->
m_rtpmaps
;
map
;
map
=
map
->
rm_next
)
{
if
(
map
->
rm_any
)
{
/* Pick our first favorite codec */
if
(
codecs
[
cur_codec
])
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Choosing a codec: %s/%d
\n
"
,
codecs
[
cur_codec
]
->
iananame
,
codecs
[
cur_codec
]
->
ianacode
);
map
->
rm_encoding
=
su_strdup
(
sdp_home
,
codecs
[
cur_codec
]
->
iananame
);
map
->
rm_pt
=
codecs
[
cur_codec
]
->
ianacode
;
map
->
rm_any
=
0
;
map
->
rm_predef
=
codecs
[
cur_codec
]
->
ianacode
<
96
;
cur_codec
++
;
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"No more codecs in preferences!
\n
"
);
goto
fail
;
}
}
}
}
else
if
(
m
->
m_type
==
sdp_media_image
&&
m
->
m_port
)
{
/* TODO: Handle T38 */
}
}
char
sdpbuf
[
2048
]
=
""
;
sdp_printer_t
*
printer
=
sdp_print
(
sdp_home
,
sdp
,
sdpbuf
,
sizeof
(
sdpbuf
),
0
);
switch_channel_set_variable
(
tech_pvt
->
channel
,
kLSDP
,
sdpbuf
);
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Setting local SDP: [%s]
\n
"
,
sdpbuf
);
sdp_printer_free
(
printer
);
goto
done
;
fail:
if
(
tech_pvt
->
local_port
)
{
switch_rtp_release_port
(
tech_pvt
->
bind_address
,
tech_pvt
->
local_port
);
}
if
(
parser
)
{
sdp_parser_free
(
parser
);
}
return
SWITCH_STATUS_FALSE
;
}
done:
return
SWITCH_STATUS_SUCCESS
;
}
#if 0
static void setup_rtp(crtp_private_t *tech_pvt, const char *r_sdp, const char *l_sdp)
{
switch_core_session_t const * session = tech_pvt->session;
uint8_t match = 0;
int first = 0, last = 0;
int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0;
int sendonly = 0, recvonly = 0;
int greedy = 0, x = 0, skip = 0, mine = 0;
int got_crypto = 0, got_audio = 0, got_avp = 0, got_savp = 0, got_udptl = 0;
sdp_parser_t *parser = NULL, *l_parser = NULL;
sdp_session_t *sdp, *lsdp;
sdp_media_t *m;
sdp_attribute_t *attr;
int scrooge = 0;
if (zstr(r_sdp)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No SDP\n");
goto fail;
}
if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Malformed SDP\n");
goto fail;
}
if (!(sdp = sdp_session(parser))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't get session from sdp.\n");
goto fail;
}
for (m = sdp->sdp_media; m; m = m->m_next) {
sdp_connection_t *connection;
ptime = dptime;
maxptime = dmaxptime;
if (m->m_proto == sdp_proto_srtp) {
got_savp++;
} else if (m->m_proto == sdp_proto_rtp) {
got_avp++;
} else if (m->m_proto == sdp_proto_udptl) {
got_udptl++;
}
if (got_udptl && m->m_type == sdp_media_image && m->m_port) {
//switch_t38_options_t *t38_options = tech_process_udptl(tech_pvt, sdp, m);
/* TODO: Process T38 */
} else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) {
sdp_rtpmap_t *map;
connection = sdp->sdp_connection;
if (m->m_connections) {
connection = m->m_connections;
}
if (!connection) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
match = 0;
break;
}
/* Begin Codec Negotiation */
for (map = m->m_rtpmaps; map; map = map->rm_next) {
int32_t i;
uint32_t near_rate = 0;
const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
const char *rm_encoding;
uint32_t map_bit_rate = 0;
int codec_ms = 0;
switch_codec_fmtp_t codec_fmtp = { 0 };
if (x++ < skip) {
continue;
}
if (!(rm_encoding = map->rm_encoding)) {
rm_encoding = "";
}
if (!strcasecmp(rm_encoding, "telephone-event")) {
if (!best_te || map->rm_rate == tech_pvt->rm_rate) {
best_te = (switch_payload_t) map->rm_pt;
}9
}
if (!cng_pt && !strcasecmp(rm_encoding, "CN")) {
cng_pt = (switch_payload_t) map->rm_pt;
if (tech_pvt->rtp_session) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt);
switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
}
}
if (match) {
continue;
}
if (greedy) {
first = mine;
last = first + 1;
} else {
first = 0;
last = num_codecs;
}
codec_ms = ptime;
if (maxptime && (!codec_ms || codec_ms > maxptime)) {
codec_ms = maxptime;
}
if (!codec_ms) {
codec_ms = switch_default_ptime(rm_encoding, map->rm_pt);
}
map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt);
if (!ptime && !strcasecmp(map->rm_encoding, "g723")) {
ptime = codec_ms = 30;
}
if (zstr(map->rm_fmtp)) {
if (!strcasecmp(map->rm_encoding, "ilbc")) {
ptime = codec_ms = 30;
map_bit_rate = 13330;
}
} else {
if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) {
if (codec_fmtp.bits_per_second) {
map_bit_rate = codec_fmtp.bits_per_second;
}
if (codec_fmtp.microseconds_per_packet) {
codec_ms = (codec_fmtp.microseconds_per_packet / 1000);
}
}
}
for (i = first; i < last && i < total_codecs; i++) {
const switch_codec_implementation_t *imp = codec_array[i];
uint32_t bit_rate = imp->bits_per_second;
uint32_t codec_rate = imp->samples_per_second;
if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
continue;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d:%u]/[%s:%d:%u:%d:%u]\n",
rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, map_bit_rate,
imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate);
if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
match = (map->rm_pt == imp->ianacode) ? 1 : 0;
} else {
match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
}
if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate && strcasecmp(map->rm_encoding, "ilbc")) {
/* nevermind */
match = 0;
}
if (match) {
if (scrooge) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Bah HUMBUG! Sticking with %s@%uh@%ui\n",
imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000);
} else {
if ((ptime && codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) {
near_rate = map->rm_rate;
near_match = imp;
match = 0;
continue;
}
}
mimp = imp;
break;
} else {
match = 0;
}
}
}
/* End */
}
}
fail:
if (parser) {
sdp_parser_free(parser);
}
}
#endif
static
switch_call_cause_t
channel_outgoing_channel
(
switch_core_session_t
*
session
,
switch_event_t
*
var_event
,
switch_caller_profile_t
*
outbound_profile
,
switch_core_session_t
**
new_session
,
switch_memory_pool_t
**
pool
,
switch_originate_flag_t
flags
,
switch_call_cause_t
*
cancel_cause
)
{
switch_channel_t
*
channel
;
char
name
[
128
];
const
char
*
dname
=
"PCMU"
;
uint32_t
interval
=
20
;
crtp_private_t
*
tech_pvt
;
const
char
*
r_sdp
=
switch_event_get_header
(
var_event
,
kRSDP
);
const
char
*
l_sdp
=
switch_event_get_header
(
var_event
,
kLSDP
);
const
char
*
codec_string
=
switch_event_get_header_nil
(
var_event
,
kCODECSTRING
);
if
(
!
(
*
new_session
=
switch_core_session_request
(
crtp
.
endpoint_interface
,
SWITCH_CALL_DIRECTION_OUTBOUND
,
0
,
pool
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Couldn't request session.
\n
"
);
goto
fail
;
}
channel
=
switch_core_session_get_channel
(
*
new_session
);
tech_pvt
=
switch_core_session_alloc
(
*
new_session
,
sizeof
*
tech_pvt
);
tech_pvt
->
session
=
*
new_session
;
tech_pvt
->
channel
=
channel
;
tech_pvt
->
bind_address
=
switch_core_session_strdup
(
*
new_session
,
switch_event_get_header_nil
(
var_event
,
kBINDADDRESS
));
switch_core_session_set_private
(
*
new_session
,
tech_pvt
);
if
(
setup_local_rtp
(
tech_pvt
,
l_sdp
,
codec_string
)
!=
SWITCH_STATUS_SUCCESS
)
{
goto
fail
;
}
snprintf
(
name
,
sizeof
(
name
),
"rtp/ctrl"
);
/* TODO add addresses */
switch_channel_set_name
(
channel
,
name
);
switch_channel_set_state
(
channel
,
CS_INIT
);
if
(
switch_core_codec_init
(
&
tech_pvt
->
read_codec
,
dname
,
NULL
,
8000
,
interval
,
1
,
SWITCH_CODEC_FLAG_ENCODE
|
SWITCH_CODEC_FLAG_DECODE
,
NULL
,
switch_core_session_get_pool
(
tech_pvt
->
session
))
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Can't load codec?
\n
"
);
goto
fail
;
}
else
{
if
(
switch_core_codec_init
(
&
tech_pvt
->
write_codec
,
dname
,
NULL
,
8000
,
interval
,
1
,
SWITCH_CODEC_FLAG_ENCODE
|
SWITCH_CODEC_FLAG_DECODE
,
NULL
,
switch_core_session_get_pool
(
tech_pvt
->
session
))
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Can't load codec?
\n
"
);
switch_core_codec_destroy
(
&
tech_pvt
->
read_codec
);
goto
fail
;
}
}
if
(
switch_core_session_set_read_codec
(
*
new_session
,
&
tech_pvt
->
read_codec
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Can't set read codec?
\n
"
);
goto
fail
;
}
if
(
switch_core_session_set_write_codec
(
*
new_session
,
&
tech_pvt
->
write_codec
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Can't set write codec?
\n
"
);
}
if
(
switch_core_session_thread_launch
(
*
new_session
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Couldn't start session thread.
\n
"
);
goto
fail
;
}
switch_channel_mark_answered
(
channel
);
return
SWITCH_CAUSE_SUCCESS
;
fail:
if
(
tech_pvt
)
{
if
(
tech_pvt
->
read_codec
.
implementation
)
{
switch_core_codec_destroy
(
&
tech_pvt
->
read_codec
);
}
if
(
tech_pvt
->
write_codec
.
implementation
)
{
switch_core_codec_destroy
(
&
tech_pvt
->
write_codec
);
}
}
if
(
*
new_session
)
{
switch_core_session_destroy
(
new_session
);
}
return
SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER
;
}
static
switch_status_t
channel_on_init
(
switch_core_session_t
*
session
)
{
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
session
);
switch_channel_set_state
(
channel
,
CS_ROUTING
);
return
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
channel_on_destroy
(
switch_core_session_t
*
session
)
{
crtp_private_t
*
tech_pvt
=
switch_core_session_get_private
(
session
);
if
((
tech_pvt
=
switch_core_session_get_private
(
session
)))
{
if
(
tech_pvt
->
read_codec
.
implementation
)
{
switch_core_codec_destroy
(
&
tech_pvt
->
read_codec
);
}
if
(
tech_pvt
->
write_codec
.
implementation
)
{
switch_core_codec_destroy
(
&
tech_pvt
->
write_codec
);
}
}
return
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
channel_read_frame
(
switch_core_session_t
*
session
,
switch_frame_t
**
frame
,
switch_io_flag_t
flags
,
int
stream_id
)
{
crtp_private_t
*
tech_pvt
;
switch_channel_t
*
channel
;
channel
=
switch_core_session_get_channel
(
session
);
assert
(
channel
!=
NULL
);
tech_pvt
=
switch_core_session_get_private
(
session
);
assert
(
tech_pvt
!=
NULL
);
return
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
channel_write_frame
(
switch_core_session_t
*
session
,
switch_frame_t
*
frame
,
switch_io_flag_t
flags
,
int
stream_id
)
{
crtp_private_t
*
tech_pvt
;
switch_channel_t
*
channel
;
channel
=
switch_core_session_get_channel
(
session
);
assert
(
channel
!=
NULL
);
tech_pvt
=
switch_core_session_get_private
(
session
);
assert
(
tech_pvt
!=
NULL
);
return
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
channel_send_dtmf
(
switch_core_session_t
*
session
,
const
switch_dtmf_t
*
dtmf
)
{
crtp_private_t
*
tech_pvt
=
NULL
;
tech_pvt
=
switch_core_session_get_private
(
session
);
assert
(
tech_pvt
!=
NULL
);
return
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
channel_receive_message
(
switch_core_session_t
*
session
,
switch_core_session_message_t
*
msg
)
{
return
SWITCH_STATUS_SUCCESS
;
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论