Skip to content
项目
群组
代码片段
帮助
正在加载...
登录
切换导航
F
freeswitch
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
张华
freeswitch
Commits
2899b4ae
提交
2899b4ae
authored
7月 30, 2012
作者:
David Yat Sin
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Updated to latest code used on test machines
上级
b1b2bee3
隐藏空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
703 行增加
和
925 行删除
+703
-925
mod_opal.cpp
src/mod/endpoints/mod_opal/mod_opal.cpp
+518
-776
mod_opal.h
src/mod/endpoints/mod_opal/mod_opal.h
+185
-149
没有找到文件。
src/mod/endpoints/mod_opal/mod_opal.cpp
浏览文件 @
2899b4ae
...
...
@@ -4,6 +4,7 @@
* Version: MPL 1.1
*
* Copyright (c) 2007 Tuyan Ozipek (tuyanozipek@gmail.com)
* Copyright (c) 2008-2012 Vox Lucida Pty. Ltd. (robertj@voxlucida.com.au)
*
* 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
...
...
@@ -28,29 +29,34 @@
#include <h323/h323pdu.h>
#include <h323/gkclient.h>
SWITCH_DECLARE_GLOBAL_STRING_FUNC
(
set_global_codec_string
,
mod_opal_globals
.
codec_string
);
SWITCH_DECLARE_GLOBAL_STRING_FUNC
(
set_global_context
,
mod_opal_globals
.
context
);
SWITCH_DECLARE_GLOBAL_STRING_FUNC
(
set_global_dialplan
,
mod_opal_globals
.
dialplan
);
/* FreeSWITCH does not correctly handle an H.323 subtely, that is that a
MAXIMUM audio frames per packet is nototiated, and there is no
requirement for the remote to actually send that many. So, in say GSM, we
negotiate up to 3 frames or 60ms of data and the remote actually sends one
(20ms) frame per packet. Perfectly legal but blows up the media handling
in FS.
#define CF_NEED_FLUSH (1 << 1)
struct
mod_opal_globals
mod_opal_globals
=
{
0
};
Eventually we will get around to bundling the packets, but not yet. This
compile flag will just force one frame/packet for all audio codecs.
*/
#define IMPLEMENT_MULTI_FAME_AUDIO 0
static
switch_call_cause_t
create_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_call_cause_t
create_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
FSProcess
*
opal_process
=
NULL
;
static
const
char
ModuleName
[]
=
"opal"
;
static
switch_status_t
on_hangup
(
switch_core_session_t
*
session
);
static
switch_status_t
on_destroy
(
switch_core_session_t
*
session
);
static
PConstString
const
ModuleName
(
"opal"
);
static
char
const
ConfigFile
[]
=
"opal.conf"
;
static
switch_io_routines_t
opalfs_io_routines
=
{
...
...
@@ -70,7 +76,7 @@ static switch_state_handler_table_t opalfs_event_handlers = {
/*.on_init */
FSConnection
::
on_init
,
/*.on_routing */
FSConnection
::
on_routing
,
/*.on_execute */
FSConnection
::
on_execute
,
/*.on_hangup */
on_hangup
,
/*.on_hangup */
FSConnection
::
on_hangup
,
/*.on_exchange_media */
FSConnection
::
on_exchange_media
,
/*.on_soft_execute */
FSConnection
::
on_soft_execute
,
/*.on_consume_media*/
NULL
,
...
...
@@ -78,7 +84,7 @@ static switch_state_handler_table_t opalfs_event_handlers = {
/*.on_reset*/
NULL
,
/*.on_park*/
NULL
,
/*.on_reporting*/
NULL
,
/*.on_destroy*/
on_destroy
/*.on_destroy*/
FSConnection
::
on_destroy
};
...
...
@@ -89,7 +95,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION
(
mod_opal_shutdown
);
SWITCH_MODULE_DEFINITION
(
mod_opal
,
mod_opal_load
,
mod_opal_shutdown
,
NULL
);
SWITCH_MODULE_LOAD_FUNCTION
(
mod_opal_load
)
{
SWITCH_MODULE_LOAD_FUNCTION
(
mod_opal_load
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CONSOLE
,
"Starting loading mod_opal
\n
"
);
/* Prevent the loading of OPAL codecs via "plug ins", this is a directory
...
...
@@ -110,8 +117,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load) {
if
(
opal_process
->
Initialise
(
*
module_interface
))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CONSOLE
,
"Opal manager initialized and running
\n
"
);
//unloading causes a seg in linux
return
SWITCH_STATUS_NO
UNLOAD
;
//
return SWITCH_STATUS_SUCCESS;
//return SWITCH_STATUS_
UNLOAD;
return
SWITCH_STATUS_SUCCESS
;
}
delete
opal_process
;
...
...
@@ -120,11 +127,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opal_load) {
}
SWITCH_MODULE_SHUTDOWN_FUNCTION
(
mod_opal_shutdown
)
{
switch_safe_free
(
mod_opal_globals
.
context
);
switch_safe_free
(
mod_opal_globals
.
dialplan
);
switch_safe_free
(
mod_opal_globals
.
codec_string
);
SWITCH_MODULE_SHUTDOWN_FUNCTION
(
mod_opal_shutdown
)
{
delete
opal_process
;
opal_process
=
NULL
;
return
SWITCH_STATUS_SUCCESS
;
...
...
@@ -133,161 +137,79 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_opal_shutdown) {
SWITCH_END_EXTERN_C
/*******************************************************************************/
static
switch_call_cause_t
create_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
)
{
if
(
opal_process
==
NULL
)
{
return
SWITCH_CAUSE_CRASH
;
}
PString
token
;
FSManager
&
manager
=
opal_process
->
GetManager
();
if
(
!
manager
.
SetUpCall
(
"local:"
,
outbound_profile
->
destination_number
,
token
,
outbound_profile
))
{
return
SWITCH_CAUSE_INVALID_NUMBER_FORMAT
;
}
PSafePtr
<
OpalCall
>
call
=
manager
.
FindCallWithLock
(
token
);
if
(
call
==
NULL
)
{
return
SWITCH_CAUSE_PROTOCOL_ERROR
;
}
PSafePtr
<
FSConnection
>
connection
=
call
->
GetConnectionAs
<
FSConnection
>
(
0
);
if
(
connection
==
NULL
)
{
return
SWITCH_CAUSE_PROTOCOL_ERROR
;
}
*
new_session
=
connection
->
GetSession
();
return
SWITCH_CAUSE_SUCCESS
;
}
///////////////////////////////////////////////////////////////////////
#if PTRACING
class
FSTrace
:
public
ostream
{
public
:
FSTrace
()
:
ostream
(
&
buffer
)
{
}
private
:
class
Buffer
:
public
streambuf
{
char
buffer
[
250
];
public
:
Buffer
()
{
setg
(
buffer
,
buffer
,
&
buffer
[
sizeof
(
buffer
)
-
2
]);
setp
(
buffer
,
&
buffer
[
sizeof
(
buffer
)
-
2
]);
}
virtual
int
sync
()
{
return
overflow
(
EOF
);
}
virtual
int
underflow
()
{
return
EOF
;
}
virtual
int
overflow
(
int
c
)
{
const
char
*
fmt
=
"%s"
;
char
*
func
=
NULL
;
int
bufSize
=
pptr
()
-
pbase
();
if
(
c
!=
EOF
)
{
*
pptr
()
=
(
char
)
c
;
bufSize
++
;
}
if
(
bufSize
!=
0
)
{
char
*
bufPtr
=
pbase
();
char
*
bufEndPtr
=
NULL
;
setp
(
bufPtr
,
epptr
());
bufPtr
[
bufSize
]
=
'\0'
;
int
line
=
0
;
char
*
p
;
char
*
file
=
NULL
;
switch_log_level_t
level
;
switch
(
strtoul
(
bufPtr
,
&
file
,
10
))
{
case
1
:
level
=
SWITCH_LOG_INFO
;
break
;
default
:
level
=
SWITCH_LOG_DEBUG
;
break
;
}
if
(
file
)
{
while
(
isspace
(
*
file
))
file
++
;
if
(
file
&&
(
bufPtr
=
strchr
(
file
,
'('
))
&&
(
bufEndPtr
=
strchr
(
bufPtr
,
')'
)))
{
char
*
e
;
for
(
p
=
bufPtr
;
p
&&
*
p
;
p
++
)
{
if
(
*
p
==
'\t'
)
{
*
p
=
' '
;
}
}
*
bufPtr
++
=
'\0'
;
line
=
atoi
(
bufPtr
);
while
(
bufEndPtr
&&
isspace
(
*
(
++
bufEndPtr
)));
bufPtr
=
bufEndPtr
;
if
(
bufPtr
&&
((
e
=
strchr
(
bufPtr
,
' '
))
||
(
e
=
strchr
(
bufPtr
,
'\t'
))))
{
func
=
bufPtr
;
bufPtr
=
e
;
*
bufPtr
++
=
'\0'
;
}
}
}
switch_text_channel_t
tchannel
=
SWITCH_CHANNEL_ID_LOG
;
if
(
!
bufPtr
)
{
bufPtr
=
pbase
();
level
=
SWITCH_LOG_DEBUG
;
}
class
FSTrace
:
public
std
::
ostream
{
private
:
class
Buffer
:
public
std
::
stringbuf
{
virtual
int
sync
()
{
std
::
string
s
=
str
();
if
(
s
.
empty
())
return
0
;
//Due to explicit setting of flags we know exactly what we are getting
PStringArray
fields
(
6
);
static
PRegularExpression
logRE
(
"^([0-9]+)
\t
*([^(]+)
\\
(([0-9]+)
\\
)
\t
(.*)"
,
PRegularExpression
::
Extended
);
if
(
!
logRE
.
Execute
(
s
.
c_str
(),
fields
))
{
fields
[
1
]
=
"4"
;
fields
[
2
]
=
__FILE__
;
fields
[
3
]
=
__LINE__
;
fields
[
4
]
=
s
;
}
if
(
bufPtr
)
{
if
(
end_of
(
bufPtr
)
!=
'\n'
)
{
fmt
=
"%s
\n
"
;
}
if
(
!
(
file
&&
func
&&
line
))
tchannel
=
SWITCH_CHANNEL_ID_LOG_CLEAN
;
switch_log_level_t
level
;
switch
(
fields
[
1
].
AsUnsigned
())
{
case
0
:
level
=
SWITCH_LOG_ALERT
;
break
;
case
1
:
level
=
SWITCH_LOG_ERROR
;
break
;
case
2
:
level
=
SWITCH_LOG_WARNING
;
break
;
case
3
:
level
=
SWITCH_LOG_INFO
;
break
;
default
:
level
=
SWITCH_LOG_DEBUG
;
break
;
}
switch_log_printf
(
tchannel
,
file
,
func
,
line
,
NULL
,
level
,
fmt
,
bufPtr
);
}
}
fields
[
4
].
Replace
(
"
\t
"
,
" "
,
true
);
switch_log_printf
(
SWITCH_CHANNEL_ID_LOG
,
fields
[
2
],
"PTLib-OPAL"
,
fields
[
3
].
AsUnsigned
(),
NULL
,
level
,
"%s"
,
fields
[
4
].
GetPointer
());
// Reset string
str
(
std
::
string
());
return
0
;
}
}
buffer
;
return
0
;
}
}
buffer
;
public
:
FSTrace
()
:
ostream
(
&
buffer
)
{
}
};
#endif
#endif
// PTRACING
///////////////////////////////////////////////////////////////////////
FSProcess
::
FSProcess
()
:
PLibraryProcess
(
"Vox Lucida Pty. Ltd."
,
"mod_opal"
,
1
,
0
,
Alph
aCode
,
1
)
:
PLibraryProcess
(
"Vox Lucida Pty. Ltd."
,
MODNAME
,
1
,
1
,
Bet
aCode
,
1
)
,
m_manager
(
NULL
)
{
}
...
...
@@ -296,19 +218,24 @@ FSProcess::FSProcess()
FSProcess
::~
FSProcess
()
{
delete
m_manager
;
#if PTRACING
PTrace
::
SetStream
(
NULL
);
// This will delete the FSTrace object
#endif
}
bool
FSProcess
::
Initialise
(
switch_loadable_module_interface_t
*
iface
)
{
m_manager
=
new
FSManager
();
return
m_manager
!=
NULL
&&
m_manager
->
Initialise
(
iface
);
m_manager
=
new
FSManager
();
return
m_manager
!=
NULL
&&
m_manager
->
Initialise
(
iface
);
}
///////////////////////////////////////////////////////////////////////
FSManager
::
FSManager
()
:
m_context
(
"default"
)
,
m_dialplan
(
"XML"
)
{
// These are deleted by the OpalManager class, no need to have destructor
m_h323ep
=
new
H323EndPoint
(
*
this
);
...
...
@@ -321,12 +248,6 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface)
{
ReadConfig
(
false
);
#if PTRACING
PTrace
::
SetLevel
(
mod_opal_globals
.
trace_level
);
//just for fun and eyecandy ;)
PTrace
::
SetOptions
(
PTrace
::
TraceLevel
);
PTrace
::
SetStream
(
new
FSTrace
);
#endif
m_FreeSwitch
=
(
switch_endpoint_interface_t
*
)
switch_loadable_module_create_interface
(
iface
,
SWITCH_ENDPOINT_INTERFACE
);
m_FreeSwitch
->
interface_name
=
ModuleName
;
m_FreeSwitch
->
io_routines
=
&
opalfs_io_routines
;
...
...
@@ -338,8 +259,8 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface)
m_h323ep
->
StartListener
(
""
);
}
else
{
for
(
std
::
list
<
FSListener
>::
iterator
it
=
m_listeners
.
begin
();
it
!=
m_listeners
.
end
();
++
it
)
{
if
(
!
m_h323ep
->
StartListener
(
it
->
listenAddress
))
{
PTRACE
(
3
,
"mod_opal
\t
Cannot start listener for "
<<
it
->
name
);
if
(
!
m_h323ep
->
StartListener
(
OpalTransportAddress
(
it
->
m_address
,
it
->
m_port
)
))
{
PTRACE
(
2
,
"mod_opal
\t
Cannot start listener for "
<<
it
->
m_
name
);
}
}
}
...
...
@@ -363,15 +284,16 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface)
GetOpalGSMAMR
();
GetOpaliLBC
();
/* For compatibility with the algorithm in FSConnection::SetCodecs() we need
to set all audio media formats to be 1 frame per packet */
#if !IMPLEMENT_MULTI_FAME_AUDIO
OpalMediaFormatList
allCodecs
=
OpalMediaFormat
::
GetAllRegisteredMediaFormats
();
for
(
OpalMediaFormatList
::
iterator
it
=
allCodecs
.
begin
();
it
!=
allCodecs
.
end
();
++
it
)
{
if
(
it
->
GetMediaType
()
==
OpalMediaType
::
Audio
())
{
it
->
SetOptionInteger
(
OpalAudioFormat
::
RxFramesPerPacketOption
(),
1
);
it
->
SetOptionInteger
(
OpalAudioFormat
::
TxFramesPerPacketOption
(),
1
);
OpalMediaFormat
::
SetRegisteredMediaFormat
(
*
it
);
}
}
#endif // IMPLEMENT_MULTI_FAME_AUDIO
if
(
!
m_gkAddress
.
IsEmpty
())
{
if
(
m_h323ep
->
UseGatekeeper
(
m_gkAddress
,
m_gkIdentifer
,
m_gkInterface
))
...
...
@@ -391,61 +313,53 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface)
switch_status_t
FSManager
::
ReadConfig
(
int
reload
)
{
const
char
*
cf
=
"opal.conf"
;
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
switch_memory_pool_t
*
pool
=
NULL
;
if
((
status
=
switch_core_new_memory_pool
(
&
pool
))
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Memory Error!
\n
"
);
return
status
;
}
switch_event_t
*
request_params
=
NULL
;
switch_event_create
(
&
request_params
,
SWITCH_EVENT_REQUEST_PARAMS
);
switch_assert
(
request_params
);
switch_event_add_header_string
(
request_params
,
SWITCH_STACK_BOTTOM
,
"profile"
,
switch_str_nil
(
""
));
set_global_context
(
"default"
);
set_global_dialplan
(
"XML"
);
switch_event_t
*
params
=
NULL
;
switch_event_create
(
&
params
,
SWITCH_EVENT_REQUEST_PARAMS
);
switch_assert
(
params
);
switch_event_add_header_string
(
params
,
SWITCH_STACK_BOTTOM
,
"profile"
,
switch_str_nil
(
""
));
switch_xml_t
cfg
;
switch_xml_t
xml
=
switch_xml_open_cfg
(
cf
,
&
cfg
,
params
);
switch_xml_t
xml
=
switch_xml_open_cfg
(
ConfigFile
,
&
cfg
,
request_
params
);
if
(
xml
==
NULL
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"open of %s failed
\n
"
,
cf
);
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"open of %s failed
\n
"
,
ConfigFile
);
return
SWITCH_STATUS_FALSE
;
}
switch_xml_t
xmlSettings
=
switch_xml_child
(
cfg
,
"settings"
);
if
(
xmlSettings
)
{
for
(
switch_xml_t
xmlParam
=
switch_xml_child
(
xmlSettings
,
"param"
);
xmlParam
!=
NULL
;
xmlParam
=
xmlParam
->
next
)
{
const
char
*
var
=
switch_xml_attr_soft
(
xmlParam
,
"name"
);
const
char
*
val
=
switch_xml_attr_soft
(
xmlParam
,
"value"
);
if
(
!
strcasecmp
(
var
,
"trace-level"
))
{
int
level
=
atoi
(
val
);
if
(
level
>
0
)
{
mod_opal_globals
.
trace_level
=
level
;
}
}
else
if
(
!
strcasecmp
(
var
,
"context"
))
{
set_global_context
(
val
);
}
else
if
(
!
strcasecmp
(
var
,
"dialplan"
))
{
set_global_dialplan
(
val
);
}
else
if
(
!
strcasecmp
(
var
,
"codec-prefs"
))
{
set_global_codec_string
(
val
);
}
else
if
(
!
strcasecmp
(
var
,
"jitter-size"
))
{
char
*
next
;
unsigned
minJitter
=
strtoul
(
val
,
&
next
,
10
);
if
(
minJitter
>=
10
)
{
unsigned
maxJitter
=
minJitter
;
if
(
*
next
==
','
)
maxJitter
=
atoi
(
next
+
1
);
SetAudioJitterDelay
(
minJitter
,
maxJitter
);
// In milliseconds
}
}
else
if
(
!
strcasecmp
(
var
,
"gk-address"
))
{
PConstCaselessString
const
var
(
switch_xml_attr_soft
(
xmlParam
,
"name"
));
PConstString
const
val
(
switch_xml_attr_soft
(
xmlParam
,
"value"
));
if
(
var
==
"context"
)
{
m_context
=
val
;
}
else
if
(
var
==
"dialplan"
)
{
m_dialplan
=
val
;
}
else
if
(
var
==
"codec-prefs"
)
{
m_codecPrefs
=
val
;
}
else
if
(
var
==
"jitter-size"
)
{
SetAudioJitterDelay
(
val
.
AsUnsigned
(),
val
.
Mid
(
val
.
Find
(
','
)
+
1
).
AsUnsigned
());
// In milliseconds
}
else
if
(
var
==
"gk-address"
)
{
m_gkAddress
=
val
;
}
else
if
(
!
strcasecmp
(
var
,
"gk-identifer"
)
)
{
}
else
if
(
var
==
"gk-identifer"
)
{
m_gkIdentifer
=
val
;
}
else
if
(
!
strcasecmp
(
var
,
"gk-interface"
)
)
{
}
else
if
(
var
==
"gk-interface"
)
{
m_gkInterface
=
val
;
#if PTRACING
}
else
if
(
var
==
"trace-level"
)
{
unsigned
level
=
val
.
AsUnsigned
();
if
(
level
>
0
)
{
PTrace
::
SetLevel
(
level
);
PTrace
::
ClearOptions
(
0xffffffff
);
// Everything off
PTrace
::
SetOptions
(
// Except these
PTrace
::
TraceLevel
|
PTrace
::
FileAndLine
#if PTLIB_CHECK_VERSION(2,11,1)
|
PTrace
::
ContextIdentifier
#endif
);
PTrace
::
SetStream
(
new
FSTrace
);
}
#endif
}
}
}
...
...
@@ -457,196 +371,205 @@ switch_status_t FSManager::ReadConfig(int reload)
m_listeners
.
push_back
(
FSListener
());
FSListener
&
listener
=
m_listeners
.
back
();
listener
.
name
=
switch_xml_attr_soft
(
xmlListener
,
"name"
);
if
(
listener
.
name
.
IsEmpty
())
listener
.
name
=
"unnamed"
;
PIPSocket
::
Address
ip
;
WORD
port
=
1720
;
listener
.
m_name
=
switch_xml_attr_soft
(
xmlListener
,
"name"
);
if
(
listener
.
m_name
.
IsEmpty
())
listener
.
m_name
=
"unnamed"
;
for
(
switch_xml_t
xmlParam
=
switch_xml_child
(
xmlListener
,
"param"
);
xmlParam
!=
NULL
;
xmlParam
=
xmlParam
->
next
)
{
const
char
*
var
=
switch_xml_attr_soft
(
xmlParam
,
"name"
);
const
char
*
val
=
switch_xml_attr_soft
(
xmlParam
,
"value"
);
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Var - '%s' and Val - '%s' \n", var, val);
if
(
!
strcasecmp
(
var
,
"h323-ip"
))
ip
=
val
;
else
if
(
!
strcasecmp
(
var
,
"h323-port"
))
port
=
(
WORD
)
atoi
(
val
);
PConstCaselessString
const
var
(
switch_xml_attr_soft
(
xmlParam
,
"name"
));
PConstString
const
val
(
switch_xml_attr_soft
(
xmlParam
,
"value"
));
if
(
var
==
"h323-ip"
)
listener
.
m_address
=
val
;
else
if
(
var
==
"h323-port"
)
listener
.
m_port
=
(
uint16_t
)
val
.
AsUnsigned
();
}
listener
.
listenAddress
=
OpalTransportAddress
(
ip
,
port
);
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Created Listener '%s'
\n
"
,
(
const
char
*
)
listener
.
name
);
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Created Listener '%s'
\n
"
,
(
const
char
*
)
listener
.
m_name
);
}
}
switch_event_destroy
(
&
params
);
switch_event_destroy
(
&
request_
params
);
if
(
xml
)
switch_xml_free
(
xml
);
return
status
;
return
SWITCH_STATUS_SUCCESS
;
}
OpalCall
*
FSManager
::
CreateCall
(
void
*
/*userData*/
)
static
switch_call_cause_t
create_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
)
{
return
new
FSCall
(
*
this
);
if
(
opal_process
==
NULL
)
return
SWITCH_CAUSE_CRASH
;
FSConnection
::
outgoing_params
params
;
params
.
var_event
=
var_event
;
params
.
outbound_profile
=
outbound_profile
;
params
.
new_session
=
new_session
;
params
.
pool
=
pool
;
params
.
flags
=
flags
;
params
.
cancel_cause
=
cancel_cause
;
params
.
fail_cause
=
SWITCH_CAUSE_INVALID_NUMBER_FORMAT
;
if
(
opal_process
->
GetManager
().
SetUpCall
(
"local:"
,
outbound_profile
->
destination_number
,
&
params
)
!=
NULL
)
return
SWITCH_CAUSE_SUCCESS
;
if
(
*
new_session
!=
NULL
)
switch_core_session_destroy
(
new_session
);
return
params
.
fail_cause
;
}
///////////////////////////////////////////////////////////////////////
FSEndPoint
::
FSEndPoint
(
FSManager
&
manager
)
:
OpalLocalEndPoint
(
manager
)
{
PTRACE
(
3
,
"mod_opal
\t
FSEndPoint Created!"
);
}
bool
FSEndPoint
::
OnIncomingCall
(
OpalLocalConnection
&
connection
)
:
OpalLocalEndPoint
(
manager
)
,
m_manager
(
manager
)
{
return
((
FSConnection
&
)
connection
).
OnIncoming
(
);
PTRACE
(
4
,
"mod_opal
\t
FSEndPoint created."
);
}
OpalLocalConnection
*
FSEndPoint
::
CreateConnection
(
OpalCall
&
call
,
void
*
userData
,
unsigned
options
,
OpalConnection
::
StringOptions
*
stringOptions
)
{
FSManager
&
mgr
=
(
FSManager
&
)
GetManager
();
switch_core_session_t
*
fsSession
=
switch_core_session_request
(
mgr
.
GetSwitchInterface
(),
(
switch_caller_profile_t
*
)
userData
?
SWITCH_CALL_DIRECTION_OUTBOUND
:
SWITCH_CALL_DIRECTION_INBOUND
,
SOF_NONE
,
NULL
);
if
(
fsSession
==
NULL
)
return
NULL
;
switch_channel_t
*
fsChannel
=
switch_core_session_get_channel
(
fsSession
);
if
(
fsChannel
==
NULL
)
{
switch_core_session_destroy
(
&
fsSession
);
return
NULL
;
}
return
new
FSConnection
(
call
,
*
this
,
userData
,
options
,
stringOptions
,
(
switch_caller_profile_t
*
)
userData
,
fsSession
,
fsChannel
);
return
new
FSConnection
(
call
,
*
this
,
options
,
stringOptions
,
(
FSConnection
::
outgoing_params
*
)
userData
);
}
///////////////////////////////////////////////////////////////////////
FSCall
::
FSCall
(
OpalManager
&
manager
)
:
OpalCall
(
manager
)
FSConnection
::
FSConnection
(
OpalCall
&
call
,
FSEndPoint
&
endpoint
,
unsigned
options
,
OpalConnection
::
StringOptions
*
stringOptions
,
outgoing_params
*
params
)
:
OpalLocalConnection
(
call
,
endpoint
,
NULL
,
options
,
stringOptions
)
,
m_endpoint
(
endpoint
)
,
m_fsSession
(
NULL
)
,
m_fsChannel
(
NULL
)
,
m_flushAudio
(
false
)
{
}
memset
(
&
m_read_timer
,
0
,
sizeof
(
m_read_timer
));
memset
(
&
m_read_codec
,
0
,
sizeof
(
m_read_codec
));
memset
(
&
m_write_codec
,
0
,
sizeof
(
m_write_codec
));
memset
(
&
m_vid_read_timer
,
0
,
sizeof
(
m_vid_read_timer
));
memset
(
&
m_vid_read_codec
,
0
,
sizeof
(
m_vid_read_codec
));
memset
(
&
m_vid_write_codec
,
0
,
sizeof
(
m_vid_write_codec
));
if
(
params
!=
NULL
)
{
// If we fail, this is the cause
params
->
fail_cause
=
SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER
;
if
((
m_fsSession
=
switch_core_session_request
(
endpoint
.
GetManager
().
GetSwitchInterface
(),
SWITCH_CALL_DIRECTION_INBOUND
,
params
->
flags
,
params
->
pool
))
==
NULL
)
{
PTRACE
(
1
,
"mod_opal
\t
Cannot create session for outgoing call."
);
return
;
}
}
else
{
if
((
m_fsSession
=
switch_core_session_request
(
endpoint
.
GetManager
().
GetSwitchInterface
(),
SWITCH_CALL_DIRECTION_INBOUND
,
SOF_NONE
,
NULL
))
==
NULL
)
{
PTRACE
(
1
,
"mod_opal
\t
Cannot create session for incoming call."
);
return
;
}
}
PBoolean
FSCall
::
OnSetUp
(
OpalConnection
&
connection
)
{
// Transfer FS caller_id_number & caller_id_name from the FSConnection
// to the protocol connectionm (e.g. H.323) so gets sent correctly
// in outgoing packets
PSafePtr
<
FSConnection
>
local
=
GetConnectionAs
<
FSConnection
>
();
if
(
local
!=
NULL
)
{
PSafePtr
<
OpalConnection
>
proto
=
local
->
GetOtherPartyConnection
();
if
(
proto
!=
NULL
)
{
proto
->
SetLocalPartyName
(
local
->
GetLocalPartyName
());
proto
->
SetDisplayName
(
local
->
GetDisplayName
());
if
((
m_fsChannel
=
switch_core_session_get_channel
(
m_fsSession
))
==
NULL
)
{
switch_core_session_destroy
(
&
m_fsSession
);
return
;
}
}
return
OpalCall
::
OnSetUp
(
connection
);
}
switch_core_session_set_private
(
m_fsSession
,
this
);
SafeReference
();
// Make sure cannot be deleted until on_destroy()
if
(
params
!=
NULL
)
{
switch_caller_profile_t
*
caller_profile
=
switch_caller_profile_clone
(
m_fsSession
,
params
->
outbound_profile
);
switch_channel_set_caller_profile
(
m_fsChannel
,
caller_profile
);
SetLocalPartyName
(
caller_profile
->
caller_id_number
);
SetDisplayName
(
caller_profile
->
caller_id_name
);
*
params
->
new_session
=
m_fsSession
;
}
///////////////////////////////////////////////////////////////////////
switch_channel_set_state
(
m_fsChannel
,
CS_INIT
);
}
FSConnection
::
FSConnection
(
OpalCall
&
call
,
FSEndPoint
&
endpoint
,
void
*
userData
,
unsigned
options
,
OpalConnection
::
StringOptions
*
stringOptions
,
switch_caller_profile_t
*
outbound_profile
,
switch_core_session_t
*
fsSession
,
switch_channel_t
*
fsChannel
)
:
OpalLocalConnection
(
call
,
endpoint
,
userData
,
options
,
stringOptions
)
,
m_endpoint
(
endpoint
)
,
m_fsSession
(
fsSession
)
,
m_fsChannel
(
fsChannel
)
bool
FSConnection
::
OnOutgoingSetUp
()
{
opal_private_t
*
tech_pvt
;
tech_pvt
=
(
opal_private_t
*
)
switch_core_session_alloc
(
m_fsSession
,
sizeof
(
*
tech_pvt
));
tech_pvt
->
me
=
this
;
switch_core_session_set_private
(
m_fsSession
,
tech_pvt
);
if
(
outbound_profile
!=
NULL
)
{
SetLocalPartyName
(
outbound_profile
->
caller_id_number
);
SetDisplayName
(
outbound_profile
->
caller_id_name
);
if
(
m_fsSession
==
NULL
||
m_fsChannel
==
NULL
)
{
PTRACE
(
1
,
"mod_opal
\t
Session request failed."
);
return
false
;
}
switch_caller_profile_t
*
caller_profile
=
switch_caller_profile_clone
(
m_fsSession
,
outbound_profile
);
switch_channel_set_caller_profile
(
m_fsChannel
,
caller_profile
);
// Transfer FS caller_id_number & caller_id_name from the FSConnection
// to the protocol connection (e.g. H.323) so gets sent correctly
// in outgoing packets
PSafePtr
<
OpalConnection
>
proto
=
GetOtherPartyConnection
();
if
(
proto
==
NULL
)
{
PTRACE
(
1
,
"mod_opal
\t
No protocol connection in call."
);
return
false
;
}
PString
name
=
"opal/"
;
name
+=
outbound_profile
->
destination_number
;
switch_channel_set_name
(
m_fsChannel
,
name
);
proto
->
SetLocalPartyName
(
GetLocalPartyName
());
proto
->
SetDisplayName
(
GetDisplayName
());
switch_channel_set_state
(
m_fsChannel
,
CS_INIT
);
}
switch_channel_set_name
(
m_fsChannel
,
ModuleName
+
'/'
+
GetRemotePartyURL
()
);
return
true
;
}
bool
FSConnection
::
OnIncoming
()
{
if
(
m_fsSession
==
NULL
)
{
if
(
m_fsSession
==
NULL
||
m_fsChannel
==
NULL
)
{
PTRACE
(
1
,
"mod_opal
\t
Session request failed."
);
return
false
;
}
switch_core_session_add_stream
(
m_fsSession
,
NULL
);
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
m_fsSession
);
if
(
channel
==
NULL
)
{
PTRACE
(
1
,
"mod_opal
\t
Session does not have a channel"
);
return
false
;
}
PURL
url
=
GetRemotePartyURL
();
switch_caller_profile_t
*
caller_profile
=
switch_caller_profile_new
(
switch_core_session_get_pool
(
m_fsSession
),
url
.
GetUserName
(),
/** username */
mod_opal_globals
.
dialplan
,
/** dial plan */
GetRemotePartyName
(),
/** caller_id_name */
GetRemotePartyNumber
(),
/** caller_id_number */
url
.
GetHostName
(),
/** network addr */
NULL
,
/** ANI */
NULL
,
/** ANI II */
NULL
,
/** RDNIS */
ModuleName
,
/** source */
mod_opal_globals
.
context
,
/** set context */
GetCalledPartyNumber
()
/** destination_number */
);
switch_caller_profile_t
*
caller_profile
=
switch_caller_profile_new
(
switch_core_session_get_pool
(
m_fsSession
),
url
.
GetUserName
(),
/** username */
m_endpoint
.
GetManager
().
GetDialPlan
(),
/** dial plan */
GetRemotePartyName
(),
/** caller_id_name */
GetRemotePartyNumber
(),
/** caller_id_number */
url
.
GetHostName
(),
/** network addr */
NULL
,
/** ANI */
NULL
,
/** ANI II */
NULL
,
/** RDNIS */
ModuleName
,
/** source */
m_endpoint
.
GetManager
().
GetContext
(),
/** set context */
GetCalledPartyNumber
()
/** destination_number */
);
if
(
caller_profile
==
NULL
)
{
PTRACE
(
1
,
"mod_opal
\t
Could not create caller profile"
);
return
false
;
}
PTRACE
(
4
,
"mod_opal
\t
Created switch caller profile:
\n
"
" username = "
<<
caller_profile
->
username
<<
"
\n
"
" dialplan = "
<<
caller_profile
->
dialplan
<<
"
\n
"
" caller_id_name = "
<<
caller_profile
->
caller_id_name
<<
"
\n
"
" caller_id_number = "
<<
caller_profile
->
caller_id_number
<<
"
\n
"
" network_addr = "
<<
caller_profile
->
network_addr
<<
"
\n
"
" source = "
<<
caller_profile
->
source
<<
"
\n
"
" context = "
<<
caller_profile
->
context
<<
"
\n
"
" destination_number= "
<<
caller_profile
->
destination_number
);
switch_channel_set_caller_profile
(
channel
,
caller_profile
);
char
name
[
256
]
=
"opal/in:"
;
switch_copy_string
(
name
+
8
,
caller_profile
->
destination_number
,
sizeof
(
name
)
-
8
);
switch_channel_set_name
(
channel
,
name
);
switch_channel_set_state
(
channel
,
CS_INIT
);
" username = "
<<
caller_profile
->
username
<<
"
\n
"
" dialplan = "
<<
caller_profile
->
dialplan
<<
"
\n
"
" caller_id_name = "
<<
caller_profile
->
caller_id_name
<<
"
\n
"
" caller_id_number = "
<<
caller_profile
->
caller_id_number
<<
"
\n
"
" network_addr = "
<<
caller_profile
->
network_addr
<<
"
\n
"
" source = "
<<
caller_profile
->
source
<<
"
\n
"
" context = "
<<
caller_profile
->
context
<<
"
\n
"
" destination_number= "
<<
caller_profile
->
destination_number
);
switch_channel_set_caller_profile
(
m_fsChannel
,
caller_profile
);
switch_channel_set_name
(
m_fsChannel
,
ModuleName
+
'/'
+
url
.
GetScheme
()
+
':'
+
caller_profile
->
destination_number
);
if
(
switch_core_session_thread_launch
(
m_fsSession
)
!=
SWITCH_STATUS_SUCCESS
)
{
PTRACE
(
1
,
"mod_opal
\t
Could not launch session thread"
);
switch_core_session_destroy
(
&
m_fsSession
);
m_fsChannel
=
NULL
;
return
false
;
}
...
...
@@ -656,57 +579,44 @@ bool FSConnection::OnIncoming()
void
FSConnection
::
OnReleased
()
{
opal_private_t
*
tech_pvt
=
(
opal_private_t
*
)
switch_core_session_get_private
(
m_fsSession
);
/* so FS on_hangup will not try to deref a landmine */
tech_pvt
->
me
=
NULL
;
m_rxAudioOpened
.
Signal
();
// Just in case
m_txAudioOpened
.
Signal
();
H225_ReleaseCompleteReason
dummy
;
switch_channel_hangup
(
switch_core_session_get_channel
(
m_fsSession
),
(
switch_call_cause_t
)
H323TranslateFromCallEndReason
(
GetCallEndReason
(),
dummy
));
OpalLocalConnection
::
OnReleased
();
}
if
(
m_fsChannel
==
NULL
)
{
PTRACE
(
3
,
"mod_opal
\t
Hanging up FS side"
);
switch_channel_hangup
(
m_fsChannel
,
(
switch_call_cause_t
)
callEndReason
.
q931
);
}
void
FSConnection
::
OnAlerting
()
{
switch_channel_mark_ring_ready
(
m_fsChannel
);
return
OpalLocalConnection
::
OnAlerting
();
OpalLocalConnection
::
OnReleased
();
}
PBoolean
FSConnection
::
SetAlerting
(
const
PString
&
calleeName
,
PBoolean
withMedia
)
{
return
OpalLocalConnection
::
SetAlerting
(
calleeName
,
withMedia
);
}
if
(
PAssertNULL
(
m_fsChannel
)
==
NULL
)
return
false
;
void
FSConnection
::
OnEstablished
()
{
OpalLocalConnection
::
OnEstablished
();
switch_channel_mark_ring_ready
(
m_fsChannel
);
return
OpalLocalConnection
::
SetAlerting
(
calleeName
,
withMedia
);
}
PBoolean
FSConnection
::
SendUserInputTone
(
char
tone
,
unsigned
duration
)
{
if
(
PAssertNULL
(
m_fsChannel
)
==
NULL
)
return
false
;
switch_dtmf_t
dtmf
=
{
tone
,
duration
};
return
switch_channel_queue_dtmf
(
m_fsChannel
,
&
dtmf
)
==
SWITCH_STATUS_SUCCESS
;
}
PBoolean
FSConnection
::
SendUserInputString
(
const
PString
&
value
)
{
return
OpalConnection
::
SendUserInputString
(
value
);
}
OpalMediaFormatList
FSConnection
::
GetMediaFormats
()
const
{
if
(
m_switchMediaFormats
.
IsEmpty
())
{
const_cast
<
FSConnection
*>
(
this
)
->
SetCodecs
();
}
return
m_switchMediaFormats
;
}
...
...
@@ -714,39 +624,29 @@ OpalMediaFormatList FSConnection::GetMediaFormats() const
void
FSConnection
::
SetCodecs
()
{
int
numCodecs
=
0
;
const
switch_codec_implementation_t
*
codecs
[
SWITCH_MAX_CODECS
];
const
char
*
codec_string
=
NULL
,
*
abs
,
*
ocodec
;
char
*
tmp_codec_string
=
NULL
;
char
*
codec_order
[
SWITCH_MAX_CODECS
];
int
codec_order_last
;
if
((
abs
=
switch_channel_get_variable
(
m_fsChannel
,
"absolute_codec_string"
)))
{
codec_string
=
abs
;
}
else
{
if
((
abs
=
switch_channel_get_variable
(
m_fsChannel
,
"codec_string"
)))
{
codec_string
=
abs
;
}
if
((
ocodec
=
switch_channel_get_variable
(
m_fsChannel
,
SWITCH_ORIGINATOR_CODEC_VARIABLE
)))
{
codec_string
=
switch_core_session_sprintf
(
m_fsSession
,
"%s,%s"
,
ocodec
,
codec_string
);
const
switch_codec_implementation_t
*
codecs
[
SWITCH_MAX_CODECS
];
PString
codec_string
=
switch_channel_get_variable
(
m_fsChannel
,
"absolute_codec_string"
);
if
(
codec_string
.
IsEmpty
())
{
codec_string
=
switch_channel_get_variable
(
m_fsChannel
,
"codec_string"
);
const
char
*
orig_codec
=
switch_channel_get_variable
(
m_fsChannel
,
SWITCH_ORIGINATOR_CODEC_VARIABLE
);
if
(
orig_codec
)
{
codec_string
.
Splice
(
orig_codec
,
0
);
}
}
if
(
!
codec_string
)
{
codec_string
=
m
od_opal_globals
.
codec_string
;
if
(
codec_string
.
IsEmpty
()
)
{
codec_string
=
m
_endpoint
.
GetManager
().
GetCodecPrefs
()
;
}
if
(
codec_string
)
{
if
((
tmp_codec_string
=
strdup
(
codec_string
)))
{
codec_order_last
=
switch_separate_string
(
tmp_codec_string
,
','
,
codec_order
,
SWITCH_MAX_CODECS
);
numCodecs
=
switch_loadable_module_get_codecs_sorted
(
codecs
,
SWITCH_MAX_CODECS
,
codec_order
,
codec_order_last
);
}
}
else
{
if
(
codec_string
.
IsEmpty
())
{
numCodecs
=
switch_loadable_module_get_codecs
(
codecs
,
sizeof
(
codecs
)
/
sizeof
(
codecs
[
0
]));
}
else
{
char
*
codec_order
[
SWITCH_MAX_CODECS
];
int
codec_order_last
=
switch_separate_string
((
char
*
)
codec_string
.
GetPointer
(),
','
,
codec_order
,
SWITCH_MAX_CODECS
);
numCodecs
=
switch_loadable_module_get_codecs_sorted
(
codecs
,
SWITCH_MAX_CODECS
,
codec_order
,
codec_order_last
);
}
for
(
int
i
=
0
;
i
<
numCodecs
;
i
++
)
{
const
switch_codec_implementation_t
*
codec
=
codecs
[
i
];
...
...
@@ -762,12 +662,12 @@ void FSConnection::SetCodecs()
continue
;
}
}
// Did we match or create a new media format?
if
(
switchFormat
.
IsValid
()
&&
codec
->
codec_type
==
SWITCH_CODEC_TYPE_AUDIO
)
{
PTRACE
(
2
,
"mod_opal
\t
Matched FS codec "
<<
codec
->
iananame
<<
" to OPAL media format "
<<
switchFormat
);
PTRACE
(
3
,
"mod_opal
\t
Matched FS codec "
<<
codec
->
iananame
<<
" to OPAL media format "
<<
switchFormat
);
#if IMPLEMENT_MULTI_FAME_AUDIO
// Calculate frames per packet, do not use codec->codec_frames_per_packet as that field
// has slightly different semantics when used in streamed codecs such as G.711
int
fpp
=
codec
->
samples_per_packet
/
switchFormat
.
GetFrameTime
();
...
...
@@ -778,7 +678,7 @@ void FSConnection::SetCodecs()
could end up with 60ms and the codec cannot be created. The "holes" are unlikely in
all but streamed codecs such as G.711, where it is theoretically possible for OPAL to
come up with 32ms and there is only 30ms and 40ms in the FS table. We deem these
scenarios su
ccif
iently rare that we can safely ignore them ... for now. */
scenarios su
ffic
iently rare that we can safely ignore them ... for now. */
if
(
fpp
>
switchFormat
.
GetOptionInteger
(
OpalAudioFormat
::
RxFramesPerPacketOption
()))
{
switchFormat
.
SetOptionInteger
(
OpalAudioFormat
::
RxFramesPerPacketOption
(),
fpp
);
...
...
@@ -787,12 +687,11 @@ void FSConnection::SetCodecs()
if
(
fpp
>
switchFormat
.
GetOptionInteger
(
OpalAudioFormat
::
TxFramesPerPacketOption
()))
{
switchFormat
.
SetOptionInteger
(
OpalAudioFormat
::
TxFramesPerPacketOption
(),
fpp
);
}
#endif // IMPLEMENT_MULTI_FAME_AUDIO
}
m_switchMediaFormats
+=
switchFormat
;
}
switch_safe_free
(
tmp_codec_string
);
}
...
...
@@ -802,110 +701,91 @@ OpalMediaStream *FSConnection::CreateMediaStream(const OpalMediaFormat & mediaFo
}
PBoolean
FSConnection
::
OnOpenMediaStream
(
OpalMediaStream
&
stream
)
void
FSConnection
::
OnPatchMediaStream
(
PBoolean
isSource
,
OpalMediaPatch
&
patch
)
{
if
(
!
OpalConnection
::
OnOpenMediaStream
(
stream
))
{
return
false
;
}
OpalConnection
::
OnPatchMediaStream
(
isSource
,
patch
);
if
(
stream
.
GetMediaFormat
().
GetMediaType
()
!=
OpalMediaType
::
Audio
())
{
return
true
;
}
if
(
PAssertNULL
(
m_fsChannel
)
==
NULL
)
return
;
if
(
stream
.
IsSource
())
{
m_rxAudioOpened
.
Signal
();
}
else
{
m_txAudioOpened
.
Signal
();
}
if
(
patch
.
GetSource
().
GetMediaFormat
().
GetMediaType
()
!=
OpalMediaType
::
Audio
())
return
;
if
(
GetMediaStream
(
stream
.
GetSessionID
(),
stream
.
IsSink
())
!=
NULL
)
{
if
(
switch_channel_direction
(
m_fsChannel
)
==
SWITCH_CALL_DIRECTION_INBOUND
)
{
if
(
isSource
)
m_rxAudioOpened
.
Signal
();
else
m_txAudioOpened
.
Signal
();
}
else
if
(
GetMediaStream
(
OpalMediaType
::
Audio
(),
!
isSource
)
!=
NULL
)
{
// Have open media in both directions.
if
(
GetPhase
()
==
AlertingPhase
)
{
switch_channel_mark_pre_answered
(
m_fsChannel
);
}
else
if
(
GetPhase
()
<
ReleasingPhase
)
{
if
(
IsEstablished
())
switch_channel_mark_answered
(
m_fsChannel
);
}
else
if
(
!
IsReleased
())
switch_channel_mark_pre_answered
(
m_fsChannel
);
}
return
true
;
}
switch_status_t
FSConnection
::
on_init
()
{
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
m_fsSession
);
if
(
channel
==
NULL
)
{
if
(
PAssertNULL
(
m_fsChannel
)
==
NULL
)
return
SWITCH_STATUS_FALSE
;
}
PTRACE
(
3
,
"mod_opal
\t
Started routing for connection "
<<
*
this
);
switch_channel_set_state
(
c
hannel
,
CS_ROUTING
);
PTRACE
(
4
,
"mod_opal
\t
Started routing for connection "
<<
*
this
);
switch_channel_set_state
(
m_fsC
hannel
,
CS_ROUTING
);
return
SWITCH_STATUS_SUCCESS
;
}
switch_status_t
FSConnection
::
on_routing
()
{
PTRACE
(
3
,
"mod_opal
\t
Routing connection "
<<
*
this
);
if
(
PAssertNULL
(
m_fsChannel
)
==
NULL
)
return
SWITCH_STATUS_FALSE
;
PTRACE
(
4
,
"mod_opal
\t
Routing connection "
<<
*
this
);
return
SWITCH_STATUS_SUCCESS
;
}
switch_status_t
FSConnection
::
on_execute
()
{
PTRACE
(
3
,
"mod_opal
\t
Executing connection "
<<
*
this
);
if
(
PAssertNULL
(
m_fsChannel
)
==
NULL
)
return
SWITCH_STATUS_FALSE
;
PTRACE
(
4
,
"mod_opal
\t
Executing connection "
<<
*
this
);
return
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
on_destroy
(
switch_core_session_t
*
session
)
{
//switch_channel_t *channel = switch_core_session_get_channel(session);
opal_private_t
*
tech_pvt
=
(
opal_private_t
*
)
switch_core_session_get_private
(
session
);
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
(
tech_pvt
->
vid_read_codec
.
implementation
)
{
switch_core_codec_destroy
(
&
tech_pvt
->
vid_read_codec
);
}
switch_status_t
FSConnection
::
on_destroy
()
{
PTRACE
(
3
,
"mod_opal
\t
FS on_destroy for connection "
<<
*
this
);
if
(
tech_pvt
->
vid_write_codec
.
implementation
)
{
switch_core_codec_destroy
(
&
tech_pvt
->
vid_write_codec
);
}
m_fsChannel
=
NULL
;
// Will be destoyed by FS, so don't use it any more.
if
(
tech_pvt
->
read_timer
.
timer_interface
)
{
switch_core_timer_destroy
(
&
tech_pvt
->
read_timer
);
}
switch_core_codec_destroy
(
&
m_read_codec
);
switch_core_codec_destroy
(
&
m_write_codec
);
switch_core_codec_destroy
(
&
m_vid_read_codec
);
switch_core_codec_destroy
(
&
m_vid_write_codec
);
switch_core_timer_destroy
(
&
m_read_timer
);
switch_core_timer_destroy
(
&
m_vid_read_timer
);
if
(
tech_pvt
->
vid_read_timer
.
timer_interface
)
{
switch_core_timer_destroy
(
&
tech_pvt
->
vid_read_timer
);
}
}
switch_core_session_set_private
(
m_fsSession
,
NULL
);
SafeDereference
();
return
SWITCH_STATUS_SUCCESS
;
}
/* this function has to be called with the original session beause the FSConnection might already be destroyed and we
will can't have it be a method of a dead object
*/
static
switch_status_t
on_hangup
(
switch_core_session_t
*
session
)
switch_status_t
FSConnection
::
on_hangup
()
{
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
session
);
opal_private_t
*
tech_pvt
=
(
opal_private_t
*
)
switch_core_session_get_private
(
session
)
;
if
(
PAssertNULL
(
m_fsChannel
)
==
NULL
)
return
SWITCH_STATUS_FALSE
;
/* if this is still here it was our idea to hangup not opal's */
if
(
tech_pvt
->
me
)
{
Q931
::
CauseValues
cause
=
(
Q931
::
CauseValues
)
switch_channel_get_cause_q850
(
channel
);
tech_pvt
->
me
->
SetQ931Cause
(
cause
);
tech_pvt
->
me
->
ClearCallSynchronous
(
NULL
,
H323TranslateToCallEndReason
(
cause
,
UINT_MAX
));
tech_pvt
->
me
=
NULL
;
}
ClearCallSynchronous
(
NULL
,
H323TranslateToCallEndReason
(
(
Q931
::
CauseValues
)
switch_channel_get_cause_q850
(
m_fsChannel
),
UINT_MAX
));
return
SWITCH_STATUS_SUCCESS
;
}
...
...
@@ -913,30 +793,30 @@ static switch_status_t on_hangup(switch_core_session_t *session)
switch_status_t
FSConnection
::
on_exchange_media
()
{
PTRACE
(
3
,
"mod_opal
\t
Loopback
on connection "
<<
*
this
);
PTRACE
(
4
,
"mod_opal
\t
Exchanging media
on connection "
<<
*
this
);
return
SWITCH_STATUS_SUCCESS
;
}
switch_status_t
FSConnection
::
on_soft_execute
()
{
PTRACE
(
3
,
"mod_opal
\t
Transmit on connection "
<<
*
this
);
PTRACE
(
4
,
"mod_opal
\t
Transmit on connection "
<<
*
this
);
return
SWITCH_STATUS_SUCCESS
;
}
switch_status_t
FSConnection
::
kill_channel
(
int
sig
)
{
PTRACE
(
3
,
"mod_opal
\t
Kill "
<<
sig
<<
" on connection "
<<
*
this
);
switch
(
sig
)
{
case
SWITCH_SIG_BREAK
:
break
;
case
SWITCH_SIG_KILL
:
m_rxAudioOpened
.
Signal
();
m_txAudioOpened
.
Signal
();
PTRACE
(
4
,
"mod_opal
\t
Signal channel KILL on connection "
<<
*
this
);
break
;
case
SWITCH_SIG_XFER
:
case
SWITCH_SIG_BREAK
:
default
:
PTRACE
(
4
,
"mod_opal
\t
Signal channel "
<<
sig
<<
" on connection "
<<
*
this
);
break
;
}
...
...
@@ -953,41 +833,16 @@ switch_status_t FSConnection::send_dtmf(const switch_dtmf_t *dtmf)
switch_status_t
FSConnection
::
receive_message
(
switch_core_session_message_t
*
msg
)
{
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
m_fsSession
);
/*
SWITCH_MESSAGE_INDICATE_PROGRESS: establish early media now and return SWITCH_STATUS_FALSE if you can't
SWITCH_MESSAGE_INDICATE_ANSWER: answer and set up media now if it's not already and return SWITCH_STATUS_FALSE if you can't
Neither message means anything on an outbound call....
It would only happen if someone called switch_channel_answer() instead of switch_channel_mark_answered() on an outbound call.
it should not do anything if someone does it by accident somewhere hense this in both cases:
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
return SWITCH_STATUS_FALSE;
}
When we get these messages the core will trust that you have triggered FSMediaStream::Open and are ready for media if we do not
have media we MUST return SWITCH_STATUS_FALSE or it will cause a CRASH.
if
(
PAssertNULL
(
m_fsChannel
)
==
NULL
)
return
SWITCH_STATUS_FALSE
;
*/
switch
(
msg
->
message_id
)
{
case
SWITCH_MESSAGE_INDICATE_BRIDGE
:
case
SWITCH_MESSAGE_INDICATE_UNBRIDGE
:
case
SWITCH_MESSAGE_INDICATE_AUDIO_SYNC
:
switch_channel_set_private_flag
(
channel
,
CF_NEED_FLUSH
);
break
;
case
SWITCH_MESSAGE_INDICATE_RINGING
:
case
SWITCH_MESSAGE_INDICATE_PROGRESS
:
case
SWITCH_MESSAGE_INDICATE_ANSWER
:
{
switch_caller_profile_t
*
profile
=
switch_channel_get_caller_profile
(
channel
);
case
SWITCH_MESSAGE_INDICATE_DEFLECT
:
if
(
switch_channel_direction
(
m_fsChannel
)
==
SWITCH_CALL_DIRECTION_INBOUND
)
{
switch_caller_profile_t
*
profile
=
switch_channel_get_caller_profile
(
m_fsChannel
);
if
(
profile
!=
NULL
&&
profile
->
caller_extension
!=
NULL
)
{
PSafePtr
<
OpalConnection
>
other
=
GetOtherPartyConnection
();
...
...
@@ -999,6 +854,9 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg
SetDisplayName
(
profile
->
caller_extension
->
extension_name
);
}
}
else
{
return
SWITCH_STATUS_FALSE
;
}
break
;
default
:
...
...
@@ -1006,89 +864,78 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg
}
switch
(
msg
->
message_id
)
{
case
SWITCH_MESSAGE_INDICATE_RINGING
:
SetPhase
(
OpalConnection
::
AlertingPhase
);
OnAlerting
();
case
SWITCH_MESSAGE_INDICATE_BRIDGE
:
case
SWITCH_MESSAGE_INDICATE_UNBRIDGE
:
case
SWITCH_MESSAGE_INDICATE_AUDIO_SYNC
:
m_flushAudio
=
true
;
break
;
case
SWITCH_MESSAGE_INDICATE_DEFLECT
:
{
PSafePtr
<
OpalConnection
>
other
=
GetOtherPartyConnection
();
if
(
other
!=
NULL
)
other
->
TransferConnection
(
msg
->
string_arg
);
case
SWITCH_MESSAGE_INDICATE_RINGING
:
AlertingIncoming
();
break
;
}
case
SWITCH_MESSAGE_INDICATE_PROGRESS
:
case
SWITCH_MESSAGE_INDICATE_ANSWER
:
{
int
fixed
=
0
;
if
(
switch_channel_direction
(
channel
)
==
SWITCH_CALL_DIRECTION_OUTBOUND
)
{
return
SWITCH_STATUS_FALSE
;
}
AutoStartMediaStreams
();
AlertingIncoming
();
if
(
msg
->
message_id
==
SWITCH_MESSAGE_INDICATE_PROGRESS
)
{
if
(
fixed
)
{
/* this should send alerting + media and wait for it to be established and return SUCCESS or FAIL
depending on if media was able to be established. Need code to tell the other side we want early media here.
*/
GetCall
().
OpenSourceMediaStreams
(
*
this
,
OpalMediaType
::
Audio
());
SetPhase
(
OpalConnection
::
AlertingPhase
);
/* how do i say please establish early media ? */
OnAlerting
();
}
else
{
/* hack to avoid getting stuck, pre_answer will imply answer */
OnConnectedInternal
();
}
}
else
{
OnConnectedInternal
();
}
if
(
!
WaitForMedia
())
return
SWITCH_STATUS_FALSE
;
// Wait for media
PTRACE
(
2
,
"mod_opal
\t
Awaiting media start on connection "
<<
*
this
);
m_rxAudioOpened
.
Wait
();
m_txAudioOpened
.
Wait
();
if
(
GetPhase
()
>=
ReleasingPhase
)
{
// Call got aborted
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
m_fsSession
),
SWITCH_LOG_ERROR
,
"Call abandoned!
\n
"
);
return
SWITCH_STATUS_FALSE
;
}
if
(
!
switch_channel_test_flag
(
m_fsChannel
,
CF_EARLY_MEDIA
))
{
switch_channel_mark_pre_answered
(
m_fsChannel
);
}
break
;
PTRACE
(
4
,
"mod_opal
\t
Media started on connection "
<<
*
this
);
case
SWITCH_MESSAGE_INDICATE_ANSWER
:
AcceptIncoming
();
if
(
msg
->
message_id
==
SWITCH_MESSAGE_INDICATE_PROGRESS
)
{
if
(
!
switch_channel_test_flag
(
m_fsChannel
,
CF_EARLY_MEDIA
))
{
switch_channel_mark_pre_answered
(
m_fsChannel
);
}
}
else
{
if
(
!
switch_channel_test_flag
(
m_fsChannel
,
CF_EARLY_MEDIA
))
{
switch_channel_mark_answered
(
m_fsChannel
);
}
}
if
(
!
WaitForMedia
())
return
SWITCH_STATUS_FALSE
;
if
(
!
switch_channel_test_flag
(
m_fsChannel
,
CF_ANSWERED
))
{
switch_channel_mark_answered
(
m_fsChannel
);
}
break
;
case
SWITCH_MESSAGE_INDICATE_DEFLECT
:
ownerCall
.
Transfer
(
msg
->
string_arg
,
GetOtherPartyConnection
());
break
;
default
:
PTRACE
(
3
,
"mod_opal
\t
Received message "
<<
msg
->
message_id
<<
" on connection "
<<
*
this
);
PTRACE
(
3
,
"mod_opal
\t
Received
unhandled
message "
<<
msg
->
message_id
<<
" on connection "
<<
*
this
);
}
return
SWITCH_STATUS_SUCCESS
;
}
bool
FSConnection
::
WaitForMedia
()
{
PTRACE
(
4
,
"mod_opal
\t
Awaiting media start on connection "
<<
*
this
);
m_rxAudioOpened
.
Wait
();
m_txAudioOpened
.
Wait
();
if
(
IsReleased
())
{
// Call got aborted
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
m_fsSession
),
SWITCH_LOG_ERROR
,
"Call abandoned!
\n
"
);
return
false
;
}
PTRACE
(
3
,
"mod_opal
\t
Media started on connection "
<<
*
this
);
return
true
;
}
switch_status_t
FSConnection
::
receive_event
(
switch_event_t
*
event
)
{
PTRACE
(
3
,
"mod_opal
\t
Received event "
<<
event
->
event_id
<<
" on connection "
<<
*
this
);
PTRACE
(
4
,
"mod_opal
\t
Received event "
<<
event
->
event_id
<<
" on connection "
<<
*
this
);
return
SWITCH_STATUS_SUCCESS
;
}
switch_status_t
FSConnection
::
state_change
()
{
PTRACE
(
3
,
"mod_opal
\t
State changed on connection "
<<
*
this
);
PTRACE
(
4
,
"mod_opal
\t
State changed on connection "
<<
*
this
);
return
SWITCH_STATUS_SUCCESS
;
}
...
...
@@ -1119,14 +966,14 @@ switch_status_t FSConnection::write_video_frame(switch_frame_t *frame, switch_io
switch_status_t
FSConnection
::
read_frame
(
const
OpalMediaType
&
mediaType
,
switch_frame_t
**
frame
,
switch_io_flag_t
flags
)
{
PSafePtr
<
FSMediaStream
>
stream
=
PSafePtrCast
<
OpalMediaStream
,
FSMediaStream
>
(
GetMediaStream
(
mediaType
,
false
));
PSafePtr
<
FSMediaStream
>
stream
=
PSafePtrCast
<
OpalMediaStream
,
FSMediaStream
>
(
GetMediaStream
(
mediaType
,
false
));
return
stream
!=
NULL
?
stream
->
read_frame
(
frame
,
flags
)
:
SWITCH_STATUS_FALSE
;
}
switch_status_t
FSConnection
::
write_frame
(
const
OpalMediaType
&
mediaType
,
const
switch_frame_t
*
frame
,
switch_io_flag_t
flags
)
{
PSafePtr
<
FSMediaStream
>
stream
=
PSafePtrCast
<
OpalMediaStream
,
FSMediaStream
>
(
GetMediaStream
(
mediaType
,
true
));
PSafePtr
<
FSMediaStream
>
stream
=
PSafePtrCast
<
OpalMediaStream
,
FSMediaStream
>
(
GetMediaStream
(
mediaType
,
true
));
return
stream
!=
NULL
?
stream
->
write_frame
(
frame
,
flags
)
:
SWITCH_STATUS_FALSE
;
}
...
...
@@ -1135,24 +982,24 @@ switch_status_t FSConnection::write_frame(const OpalMediaType & mediaType, const
FSMediaStream
::
FSMediaStream
(
FSConnection
&
conn
,
const
OpalMediaFormat
&
mediaFormat
,
unsigned
sessionID
,
bool
isSource
)
:
OpalMediaStream
(
conn
,
mediaFormat
,
sessionID
,
isSource
)
,
m_fsSession
(
conn
.
GetSession
())
,
m_readRTP
(
0
,
512
)
,
m_callOnStart
(
true
)
,
m_connection
(
conn
)
,
m_readRTP
(
0
,
SWITCH_RECOMMENDED_BUFFER_SIZE
)
{
memset
(
&
m_readFrame
,
0
,
sizeof
(
m_readFrame
));
m_readFrame
.
codec
=
m_switchCodec
;
m_readFrame
.
flags
=
SFF_RAW_RTP
;
}
PBoolean
FSMediaStream
::
Open
()
{
opal_private_t
*
tech_pvt
=
(
opal_private_t
*
)
switch_core_session_get_private
(
m_fsSession
);
if
(
IsOpen
())
{
return
true
;
}
switch_core_session_t
*
fsSession
=
m_connection
.
GetSession
();
switch_channel_t
*
fsChannel
=
m_connection
.
GetChannel
();
if
(
PAssertNULL
(
fsSession
)
==
NULL
||
PAssertNULL
(
fsChannel
)
==
NULL
)
return
false
;
bool
isAudio
;
if
(
mediaFormat
.
GetMediaType
()
==
OpalMediaType
::
Audio
())
{
isAudio
=
true
;
...
...
@@ -1162,86 +1009,76 @@ PBoolean FSMediaStream::Open()
return
OpalMediaStream
::
Open
();
}
m_fsChannel
=
switch_core_session_get_channel
(
m_fsSession
);
int
ptime
=
mediaFormat
.
GetOptionInteger
(
OpalAudioFormat
::
TxFramesPerPacketOption
())
*
mediaFormat
.
GetFrameTime
()
/
mediaFormat
.
GetTimeUnits
();
if
(
IsSink
())
{
m_switchCodec
=
isAudio
?
&
tech_pvt
->
read_codec
:
&
tech_pvt
->
vid_read_codec
;
m_switchTimer
=
isAudio
?
&
tech_pvt
->
read_timer
:
&
tech_pvt
->
vid_read_timer
;
m_switchCodec
=
isAudio
?
&
m_connection
.
m_read_codec
:
&
m_connection
.
m_vid_read_codec
;
m_switchTimer
=
isAudio
?
&
m_connection
.
m_read_timer
:
&
m_connection
.
m_vid_read_timer
;
m_readFrame
.
codec
=
m_switchCodec
;
m_readFrame
.
rate
=
mediaFormat
.
GetClockRate
();
}
else
{
m_switchCodec
=
isAudio
?
&
tech_pvt
->
write_codec
:
&
tech_pvt
->
vid_write_codec
;
m_switchCodec
=
isAudio
?
&
m_connection
.
m_write_codec
:
&
m_connection
.
m_
vid_write_codec
;
}
// The following is performed on two different instances of this object.
if
(
switch_core_codec_init
(
m_switchCodec
,
mediaFormat
.
GetEncodingName
(),
NULL
,
// FMTP
mediaFormat
.
GetClockRate
(),
ptime
,
1
,
// Channels
SWITCH_CODEC_FLAG_ENCODE
|
SWITCH_CODEC_FLAG_DECODE
,
NULL
,
// Settings
switch_core_session_get_pool
(
m_
fsSession
))
!=
SWITCH_STATUS_SUCCESS
)
{
switch_core_session_get_pool
(
fsSession
))
!=
SWITCH_STATUS_SUCCESS
)
{
// Could not select a codecs using negotiated frames/packet, so try using default.
if
(
switch_core_codec_init
(
m_switchCodec
,
mediaFormat
.
GetEncodingName
(),
NULL
,
// FMTP
mediaFormat
.
GetClockRate
(),
0
,
1
,
// Channels
SWITCH_CODEC_FLAG_ENCODE
|
SWITCH_CODEC_FLAG_DECODE
,
NULL
,
// Settings
switch_core_session_get_pool
(
m_fsSession
))
!=
SWITCH_STATUS_SUCCESS
)
{
PTRACE
(
1
,
"mod_opal "
<<
switch_channel_get_name
(
m_fsChannel
)
<<
" Cannot initialise "
<<
(
IsSink
()
?
"read"
:
"write"
)
<<
' '
switch_core_session_get_pool
(
fsSession
))
!=
SWITCH_STATUS_SUCCESS
)
{
PTRACE
(
1
,
"mod_opal
\t
"
<<
switch_channel_get_name
(
fsChannel
)
<<
" cannot initialise "
<<
(
IsSink
()
?
"read"
:
"write"
)
<<
' '
<<
mediaFormat
.
GetMediaType
()
<<
" codec "
<<
mediaFormat
<<
" for connection "
<<
*
this
);
switch_channel_hangup
(
m_
fsChannel
,
SWITCH_CAUSE_INCOMPATIBLE_DESTINATION
);
switch_channel_hangup
(
fsChannel
,
SWITCH_CAUSE_INCOMPATIBLE_DESTINATION
);
return
false
;
}
PTRACE
(
2
,
"mod_opal "
<<
switch_channel_get_name
(
m_fsChannel
)
<<
" Unsupported ptime of "
<<
ptime
<<
" on "
<<
(
IsSink
()
?
"read"
:
"write"
)
<<
' '
PTRACE
(
2
,
"mod_opal
\t
"
<<
switch_channel_get_name
(
fsChannel
)
<<
" unsupported ptime of "
<<
ptime
<<
" on "
<<
(
IsSink
()
?
"read"
:
"write"
)
<<
' '
<<
mediaFormat
.
GetMediaType
()
<<
" codec "
<<
mediaFormat
<<
" for connection "
<<
*
this
);
}
PTRACE
(
1
,
"mod_opal "
<<
switch_channel_get_name
(
m_fsChannel
)
<<
" initialise "
<<
switch_channel_get_name
(
m_fsChannel
)
<<
(
IsSink
()
?
"read"
:
"write"
)
<<
' '
<<
mediaFormat
.
GetMediaType
()
<<
" codec "
<<
mediaFormat
<<
" for connection "
<<
*
this
);
if
(
IsSink
())
{
m_readFrame
.
rate
=
mediaFormat
.
GetClockRate
();
if
(
isAudio
)
{
switch_core_session_set_read_codec
(
m_
fsSession
,
m_switchCodec
);
switch_core_session_set_read_codec
(
fsSession
,
m_switchCodec
);
if
(
switch_core_timer_init
(
m_switchTimer
,
"soft"
,
m_switchCodec
->
implementation
->
microseconds_per_packet
/
1000
,
m_switchCodec
->
implementation
->
samples_per_packet
,
switch_core_session_get_pool
(
m_fsSession
))
!=
SWITCH_STATUS_SUCCESS
)
{
switch_core_session_get_pool
(
fsSession
))
!=
SWITCH_STATUS_SUCCESS
)
{
PTRACE
(
1
,
"mod_opal
\t
"
<<
switch_channel_get_name
(
fsChannel
)
<<
" timer init failed on "
<<
(
IsSink
()
?
"read"
:
"write"
)
<<
' '
<<
mediaFormat
.
GetMediaType
()
<<
" codec "
<<
mediaFormat
<<
" for connection "
<<
*
this
);
switch_core_codec_destroy
(
m_switchCodec
);
m_switchCodec
=
NULL
;
return
false
;
}
}
else
{
switch_core_session_set_video_read_codec
(
m_
fsSession
,
m_switchCodec
);
switch_channel_set_flag
(
m_
fsChannel
,
CF_VIDEO
);
switch_core_session_set_video_read_codec
(
fsSession
,
m_switchCodec
);
switch_channel_set_flag
(
fsChannel
,
CF_VIDEO
);
}
}
else
{
if
(
isAudio
)
{
switch_core_session_set_write_codec
(
m_
fsSession
,
m_switchCodec
);
switch_core_session_set_write_codec
(
fsSession
,
m_switchCodec
);
}
else
{
switch_core_session_set_video_write_codec
(
m_
fsSession
,
m_switchCodec
);
switch_channel_set_flag
(
m_
fsChannel
,
CF_VIDEO
);
switch_core_session_set_video_write_codec
(
fsSession
,
m_switchCodec
);
switch_channel_set_flag
(
fsChannel
,
CF_VIDEO
);
}
}
PTRACE
(
3
,
"mod_opal
\t
Set "
<<
(
IsSink
()
?
"read"
:
"write"
)
<<
' '
<<
mediaFormat
.
GetMediaType
()
<<
" codec to << "
<<
mediaFormat
<<
" for connection "
<<
*
this
);
PTRACE
(
3
,
"mod_opal
\t
"
<<
switch_channel_get_name
(
fsChannel
)
<<
" initialised "
<<
(
IsSink
()
?
"read"
:
"write"
)
<<
' '
<<
mediaFormat
.
GetMediaType
()
<<
" codec "
<<
mediaFormat
<<
" for connection "
<<
*
this
);
return
OpalMediaStream
::
Open
();
}
PBoolean
FSMediaStream
::
Close
()
void
FSMediaStream
::
Internal
Close
()
{
if
(
!
IsOpen
())
return
false
;
/* forget these FS will properly destroy them for us */
m_switchTimer
=
NULL
;
m_switchCodec
=
NULL
;
return
OpalMediaStream
::
Close
();
}
...
...
@@ -1256,149 +1093,88 @@ PBoolean FSMediaStream::RequiresPatchThread(OpalMediaStream *) const
return
false
;
}
bool
FSMediaStream
::
CheckPatchAndLock
()
{
if
(
GetConnection
().
GetPhase
()
>=
GetConnection
().
ReleasingPhase
||
!
IsOpen
())
return
false
;
if
(
LockReadWrite
())
{
if
(
!
GetPatch
()
||
!
IsOpen
())
{
UnlockReadWrite
();
return
false
;
}
return
true
;
}
else
{
return
false
;
}
}
switch_status_t
FSMediaStream
::
read_frame
(
switch_frame_t
**
frame
,
switch_io_flag_t
flags
)
int
FSMediaStream
::
StartReadWrite
(
PatchPtr
&
mediaPatch
)
const
{
if
(
!
IsOpen
())
{
PTRACE
(
2
,
"mod_opal
\t
Not open!"
);
return
-
1
;
}
if
(
!
m_switchCodec
)
{
return
SWITCH_STATUS_FALSE
;
PTRACE
(
2
,
"mod_opal
\t
No codec!"
);
return
-
1
;
}
if
(
m_callOnStart
)
{
/*
There is a race here... sometimes we make it here and GetPatch() is NULL
if we wait it shows up in 1ms, maybe there is a better way to wait.
*/
while
(
!
GetPatch
())
{
if
(
!
m_fsChannel
||
!
switch_channel_up
(
m_fsChannel
))
{
return
SWITCH_STATUS_FALSE
;
}
switch_cond_next
();
}
if
(
CheckPatchAndLock
())
{
GetPatch
()
->
OnStartMediaPatch
();
m_callOnStart
=
false
;
UnlockReadWrite
();
}
else
{
return
SWITCH_STATUS_FALSE
;
}
if
(
!
m_connection
.
IsChannelReady
())
{
PTRACE
(
2
,
"mod_opal
\t
Channel not ready!"
);
return
-
1
;
}
m_readFrame
.
flags
=
0
;
// We make referenced copy of pointer so can't be deleted out from under us
mediaPatch
=
m_mediaPatch
;
if
(
mediaPatch
==
NULL
)
{
/*There is a race here... sometimes we make it here and m_mediaPatch is NULL
if we wait it shows up in 1ms, maybe there is a better way to wait. */
PTRACE
(
3
,
"mod_opal
\t
Patch not ready!"
);
return
1
;
}
return
0
;
}
/*
while (switch_channel_ready(m_fsChannel)) {
if (CheckPatchAndLock()) {
if (!GetPatch()->GetSource().ReadPacket(m_readRTP)) {
UnlockReadWrite();
return SWITCH_STATUS_FALSE;
}
UnlockReadWrite();
} else {
return SWITCH_STATUS_FALSE;
}
if ((m_readFrame.datalen = m_readRTP.GetPayloadSize()) || switch_core_timer_check(&m_switchTimer, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
if (m_readFrame.datalen) {
} else {
m_readFrame.flags = SFF_CNG;
}
break;
}
switch_yield(1000);
switch_status_t
FSMediaStream
::
read_frame
(
switch_frame_t
**
frame
,
switch_io_flag_t
flags
)
{
PatchPtr
mediaPatch
;
switch
(
StartReadWrite
(
mediaPatch
))
{
case
-
1
:
return
SWITCH_STATUS_FALSE
;
case
1
:
return
SWITCH_STATUS_SUCCESS
;
}
*/
if
(
switch_channel_test_private_flag
(
m_fsChannel
,
CF_NEED_FLUSH
))
{
switch_channel_clear_private_flag
(
m_fsChannel
,
CF_NEED_FLUSH
);
for
(;;)
{
if
(
CheckPatchAndLock
())
{
if
(
!
GetPatch
()
->
GetSource
().
ReadPacket
(
m_readRTP
))
{
UnlockReadWrite
();
return
SWITCH_STATUS_FALSE
;
}
UnlockReadWrite
();
}
else
{
return
SWITCH_STATUS_FALSE
;
}
if
(
!
m_readRTP
.
GetPayloadSize
())
{
m_readFrame
.
flags
=
SFF_CNG
;
break
;
}
}
if
(
m_connection
.
NeedFlushAudio
())
{
mediaPatch
->
GetSource
().
EnableJitterBuffer
();
// This flushes data and resets jitter buffer
m_readRTP
.
SetPayloadSize
(
0
);
}
else
{
m_readRTP
.
SetTimestamp
(
m_readFrame
.
timestamp
+
m_switchCodec
->
implementation
->
samples_per_packet
);
if
(
CheckPatchAndLock
())
{
if
(
!
m_switchTimer
||
!
GetPatch
()
->
GetSource
().
ReadPacket
(
m_readRTP
))
{
UnlockReadWrite
();
return
SWITCH_STATUS_FALSE
;
}
UnlockReadWrite
();
}
else
{
return
SWITCH_STATUS_FALSE
;
}
switch_core_timer_next
(
m_switchTimer
);
if
(
!
(
m_readFrame
.
datalen
=
m_readRTP
.
GetPayloadSize
()))
{
m_readFrame
.
flags
=
SFF_CNG
;
if
(
!
mediaPatch
->
GetSource
().
ReadPacket
(
m_readRTP
))
{
return
SWITCH_STATUS_FALSE
;
}
}
if
(
!
switch_channel_ready
(
m_fsChannel
))
{
if
(
!
m_switchTimer
)
{
PTRACE
(
2
,
"mod_opal
\t
read_frame: no timer!"
);
return
SWITCH_STATUS_FALSE
;
}
switch_core_timer_next
(
m_switchTimer
);
if
(
!
switch_core_codec_ready
(
m_switchCodec
))
{
PTRACE
(
2
,
"mod_opal
\t
read_frame: codec not ready!"
);
return
SWITCH_STATUS_FALSE
;
}
//switch_core_timer_step(&m_switchTimer);
#if IMPLEMENT_MULTI_FAME_AUDIO
// Repackage frames in incoming packet to agree with what FS expects.
// Not implmented yet!!!!!!!!!
// Cheating and only supporting one frame per packet
#endif
if
(
m_readFrame
.
payload
==
RTP_DataFrame
::
CN
||
m_readFrame
.
payload
==
RTP_DataFrame
::
Cisco_CN
)
{
m_readFrame
.
flags
=
SFF_CNG
;
}
if
(
m_readFrame
.
flags
&
SFF_CNG
)
{
m_readFrame
.
buflen
=
sizeof
(
m_buf
);
m_readFrame
.
data
=
m_buf
;
m_readFrame
.
packet
=
NULL
;
m_readFrame
.
packetlen
=
0
;
m_readFrame
.
timestamp
=
0
;
m_readFrame
.
m
=
SWITCH_FALSE
;
m_readFrame
.
seq
=
0
;
m_readFrame
.
ssrc
=
0
;
m_readFrame
.
codec
=
m_switchCodec
;
}
else
{
m_readFrame
.
buflen
=
m_readRTP
.
GetSize
();
m_readFrame
.
data
=
m_readRTP
.
GetPayloadPtr
();
m_readFrame
.
packet
=
m_readRTP
.
GetPointer
();
m_readFrame
.
packetlen
=
m_readRTP
.
GetHeaderSize
()
+
m_readFrame
.
datalen
;
m_readFrame
.
payload
=
(
switch_payload_t
)
m_readRTP
.
GetPayloadType
();
m_readFrame
.
timestamp
=
m_readRTP
.
GetTimestamp
();
m_readFrame
.
m
=
(
switch_bool_t
)
m_readRTP
.
GetMarker
();
m_readFrame
.
seq
=
m_readRTP
.
GetSequenceNumber
();
m_readFrame
.
ssrc
=
m_readRTP
.
GetSyncSource
();
m_readFrame
.
codec
=
m_switchCodec
;
}
m_readFrame
.
buflen
=
m_readRTP
.
GetSize
();
m_readFrame
.
data
=
m_readRTP
.
GetPayloadPtr
();
m_readFrame
.
datalen
=
m_readRTP
.
GetPayloadSize
();
m_readFrame
.
packet
=
m_readRTP
.
GetPointer
();
m_readFrame
.
packetlen
=
m_readRTP
.
GetHeaderSize
()
+
m_readFrame
.
datalen
;
m_readFrame
.
timestamp
=
m_readRTP
.
GetTimestamp
();
m_readFrame
.
seq
=
m_readRTP
.
GetSequenceNumber
();
m_readFrame
.
ssrc
=
m_readRTP
.
GetSyncSource
();
m_readFrame
.
m
=
m_readRTP
.
GetMarker
()
?
SWITCH_TRUE
:
SWITCH_FALSE
;
m_readFrame
.
payload
=
(
switch_payload_t
)
m_readRTP
.
GetPayloadType
();
m_readFrame
.
flags
=
m_readFrame
.
datalen
==
0
||
m_readFrame
.
payload
==
RTP_DataFrame
::
CN
||
m_readFrame
.
payload
==
RTP_DataFrame
::
Cisco_CN
?
SFF_CNG
:
0
;
*
frame
=
&
m_readFrame
;
...
...
@@ -1408,69 +1184,35 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag
switch_status_t
FSMediaStream
::
write_frame
(
const
switch_frame_t
*
frame
,
switch_io_flag_t
flags
)
{
if
(
!
switch_channel_ready
(
m_fsChannel
))
{
PatchPtr
mediaPatch
;
switch
(
StartReadWrite
(
mediaPatch
))
{
case
-
1
:
return
SWITCH_STATUS_FALSE
;
}
if
(
m_callOnStart
)
{
if
(
CheckPatchAndLock
())
{
GetPatch
()
->
OnStartMediaPatch
();
m_callOnStart
=
false
;
UnlockReadWrite
();
}
else
{
return
SWITCH_STATUS_FALSE
;
}
}
if
((
frame
->
flags
&
SFF_CNG
))
{
case
1
:
return
SWITCH_STATUS_SUCCESS
;
}
if
((
frame
->
flags
&
SFF_RAW_RTP
)
!=
0
)
{
RTP_DataFrame
rtp
((
const
BYTE
*
)
frame
->
packet
,
frame
->
packetlen
,
false
);
if
(
CheckPatchAndLock
())
{
if
(
GetPatch
()
->
PushFrame
(
rtp
))
{
UnlockReadWrite
();
return
SWITCH_STATUS_SUCCESS
;
}
UnlockReadWrite
();
}
else
{
return
SWITCH_STATUS_FALSE
;
}
}
/* If we reach this code it means a call to an ivr or something else that does not generate timestamps
Its possible that frame->timestamp is set but not guarenteed and is best ignored for the time being.
We are probably relying on the rtp stack to generate the timestamp and ssrc for us at this point.
As a quick hack I am going to keep a sample counter and increment it by frame->samples but it would be
better if we could engage whatever it is in opal that makes it generate the timestamp.
*/
RTP_DataFrame
rtp
((
const
BYTE
*
)
frame
->
packet
,
frame
->
packetlen
,
false
);
return
mediaPatch
->
PushFrame
(
rtp
)
?
SWITCH_STATUS_SUCCESS
:
SWITCH_STATUS_FALSE
;
}
RTP_DataFrame
rtp
(
frame
->
datalen
);
rtp
.
SetPayloadType
(
mediaFormat
.
GetPayloadType
());
m_timeStamp
+=
frame
->
samples
;
rtp
.
SetTimestamp
(
m_timeStamp
);
//rtp.SetTimestamp(frame->timestamp);
//rtp.SetSyncSource(frame->ssrc);
//rtp.SetMarker(frame->m);
memcpy
(
rtp
.
GetPayloadPtr
(),
frame
->
data
,
frame
->
datalen
);
if
(
CheckPatchAndLock
())
{
if
(
GetPatch
()
->
PushFrame
(
rtp
))
{
UnlockReadWrite
();
return
SWITCH_STATUS_SUCCESS
;
}
UnlockReadWrite
();
}
else
{
return
SWITCH_STATUS_FALSE
;
}
rtp
.
SetPayloadType
(
mediaFormat
.
GetPayloadType
());
return
SWITCH_STATUS_FALSE
;
/* Not sure what FS is going to give us!
Suspect it depends on the mod on the other side sending it. */
if
(
frame
->
timestamp
!=
0
)
timestamp
=
frame
->
timestamp
;
else
if
(
frame
->
samples
!=
0
)
timestamp
+=
frame
->
samples
;
else
timestamp
+=
m_switchCodec
->
implementation
->
samples_per_packet
;
rtp
.
SetTimestamp
(
timestamp
);
return
mediaPatch
->
PushFrame
(
rtp
)
?
SWITCH_STATUS_SUCCESS
:
SWITCH_STATUS_FALSE
;
}
...
...
src/mod/endpoints/mod_opal/mod_opal.h
浏览文件 @
2899b4ae
...
...
@@ -4,6 +4,7 @@
* Version: MPL 1.1
*
* Copyright (c) 2007 Tuyan Ozipek (tuyanozipek@gmail.com)
* Copyright (c) 2008-2012 Vox Lucida Pty. Ltd. (robertj@voxlucida.com.au)
*
* 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
...
...
@@ -46,6 +47,8 @@
#define HAVE_APR
#include <switch.h>
#include <switch_version.h>
#define MODNAME "mod_opal"
...
...
@@ -53,206 +56,239 @@ class FSEndPoint;
class
FSManager
;
struct
mod_opal_globals
{
int
trace_level
;
char
*
codec_string
;
char
*
context
;
char
*
dialplan
;
}
;
class
FSProcess
:
public
PLibraryProcess
{
PCLASSINFO
(
FSProcess
,
PLibraryProcess
)
;
public
:
FSProcess
()
;
~
FSProcess
()
;
extern
struct
mod_opal_globals
mod_opal_globals
;
bool
Initialise
(
switch_loadable_module_interface_t
*
iface
)
;
FSManager
&
GetManager
()
const
{
return
*
m_manager
;
}
class
FSProcess
:
public
PLibraryProcess
{
PCLASSINFO
(
FSProcess
,
PLibraryProcess
);
protected
:
FSManager
*
m_manager
;
};
public
:
FSProcess
();
~
FSProcess
();
bool
Initialise
(
switch_loadable_module_interface_t
*
iface
);
struct
FSListener
{
FSListener
()
:
m_port
(
H323EndPoint
::
DefaultTcpSignalPort
)
{
}
FSManager
&
GetManager
()
const
{
return
*
m_manager
;
}
protected
:
FSManager
*
m_manager
;
PString
m_name
;
PIPSocket
::
Address
m_address
;
uint16_t
m_port
;
};
struct
FSListener
{
FSListener
()
{
}
PString
name
;
OpalTransportAddress
listenAddress
;
PString
localUserName
;
PString
gatekeeper
;
};
class
FSManager
:
public
OpalManager
{
PCLASSINFO
(
FSManager
,
OpalManager
);
class
FSCall
:
public
OpalCall
{
PCLASSINFO
(
FSCall
,
OpalCall
);
public
:
FSCall
(
OpalManager
&
manager
);
virtual
PBoolean
OnSetUp
(
OpalConnection
&
connection
);
};
FSManager
();
bool
Initialise
(
switch_loadable_module_interface_t
*
iface
);
class
FSManager
:
public
OpalManager
{
PCLASSINFO
(
FSManager
,
OpalManager
);
switch_status_t
ReadConfig
(
int
reload
);
public
:
FSManager
();
switch_endpoint_interface_t
*
GetSwitchInterface
()
const
{
return
m_FreeSwitch
;
}
const
PString
&
GetContext
()
const
{
return
m_context
;
}
const
PString
&
GetDialPlan
()
const
{
return
m_dialplan
;
}
const
PString
&
GetCodecPrefs
()
const
{
return
m_codecPrefs
;
}
bool
Initialise
(
switch_loadable_module_interface_t
*
iface
);
private
:
switch_endpoint_interface_t
*
m_FreeSwitch
;
switch_status_t
ReadConfig
(
int
reload
);
H323EndPoint
*
m_h323ep
;
IAX2EndPoint
*
m_iaxep
;
FSEndPoint
*
m_fsep
;
switch_endpoint_interface_t
*
GetSwitchInterface
()
const
{
return
m_FreeSwitch
;
}
virtual
OpalCall
*
CreateCall
(
void
*
userData
);
PString
m_context
;
PString
m_dialplan
;
PString
m_codecPrefs
;
PString
m_gkAddress
;
PString
m_gkIdentifer
;
PString
m_gkInterface
;
private
:
switch_endpoint_interface_t
*
m_FreeSwitch
;
list
<
FSListener
>
m_listeners
;
}
;
H323EndPoint
*
m_h323ep
;
IAX2EndPoint
*
m_iaxep
;
FSEndPoint
*
m_fsep
;
PString
m_gkAddress
;
PString
m_gkIdentifer
;
PString
m_gkInterface
;
class
FSEndPoint
:
public
OpalLocalEndPoint
{
PCLASSINFO
(
FSEndPoint
,
OpalLocalEndPoint
);
public
:
FSEndPoint
(
FSManager
&
manager
);
virtual
OpalLocalConnection
*
CreateConnection
(
OpalCall
&
call
,
void
*
userData
,
unsigned
options
,
OpalConnection
::
StringOptions
*
stringOptions
);
list
<
FSListener
>
m_listeners
;
FSManager
&
GetManager
()
const
{
return
m_manager
;
}
protected
:
FSManager
&
m_manager
;
};
class
FSConnection
;
typedef
struct
{
switch_timer_t
read_timer
;
switch_codec_t
read_codec
;
switch_codec_t
write_codec
;
switch_timer_t
vid_read_timer
;
switch_codec_t
vid_read_codec
;
switch_codec_t
vid_write_codec
;
FSConnection
*
me
;
}
opal_private_t
;
class
FSEndPoint
:
public
OpalLocalEndPoint
{
PCLASSINFO
(
FSEndPoint
,
OpalLocalEndPoint
);
class
FSMediaStream
:
public
OpalMediaStream
{
PCLASSINFO
(
FSMediaStream
,
OpalMediaStream
);
public
:
FSEndPoint
(
FSManager
&
manager
);
FSMediaStream
(
FSConnection
&
conn
,
const
OpalMediaFormat
&
mediaFormat
,
///< Media format for stream
unsigned
sessionID
,
///< Session number for stream
bool
isSource
///< Is a source stream
);
virtual
PBoolean
Open
();
virtual
PBoolean
IsSynchronous
()
const
;
virtual
PBoolean
RequiresPatchThread
(
OpalMediaStream
*
)
const
;
switch_status_t
read_frame
(
switch_frame_t
**
frame
,
switch_io_flag_t
flags
);
switch_status_t
write_frame
(
const
switch_frame_t
*
frame
,
switch_io_flag_t
flags
);
protected
:
virtual
void
InternalClose
();
int
StartReadWrite
(
PatchPtr
&
mediaPatch
)
const
;
virtual
bool
OnIncomingCall
(
OpalLocalConnection
&
);
virtual
OpalLocalConnection
*
CreateConnection
(
OpalCall
&
call
,
void
*
userData
,
unsigned
options
,
OpalConnection
::
StringOptions
*
stringOptions
);
private
:
bool
CheckPatchAndLock
();
FSConnection
&
m_connection
;
switch_timer_t
*
m_switchTimer
;
switch_codec_t
*
m_switchCodec
;
switch_frame_t
m_readFrame
;
RTP_DataFrame
m_readRTP
;
};
#define DECLARE_CALLBACK0(name) \
static switch_status_t name(switch_core_session_t *session) { \
opal_private_t *tech_pvt = (opal_private_t
*) switch_core_session_get_private(session); \
return tech_pvt
&& tech_pvt->me != NULL ? tech_pvt->me
->name() : SWITCH_STATUS_FALSE; } \
switch_status_t name()
FSConnection *tech_pvt = (FSConnection
*) switch_core_session_get_private(session); \
return tech_pvt
!= NULL ? tech_pvt
->name() : SWITCH_STATUS_FALSE; } \
switch_status_t name()
#define DECLARE_CALLBACK1(name, type1, name1) \
static switch_status_t name(switch_core_session_t *session, type1 name1) { \
opal_private_t *tech_pvt = (opal_private_t
*) switch_core_session_get_private(session); \
return tech_pvt
&& tech_pvt->me != NULL ? tech_pvt->me
->name(name1) : SWITCH_STATUS_FALSE; } \
switch_status_t name(type1 name1)
FSConnection *tech_pvt = (FSConnection
*) switch_core_session_get_private(session); \
return tech_pvt
!= NULL ? tech_pvt
->name(name1) : SWITCH_STATUS_FALSE; } \
switch_status_t name(type1 name1)
#define DECLARE_CALLBACK3(name, type1, name1, type2, name2, type3, name3) \
static switch_status_t name(switch_core_session_t *session, type1 name1, type2 name2, type3 name3) { \
opal_private_t *tech_pvt = (opal_private_t
*) switch_core_session_get_private(session); \
return tech_pvt
&& tech_pvt->me != NULL ? tech_pvt->me
->name(name1, name2, name3) : SWITCH_STATUS_FALSE; } \
switch_status_t name(type1 name1, type2 name2, type3 name3)
FSConnection *tech_pvt = (FSConnection
*) switch_core_session_get_private(session); \
return tech_pvt
!= NULL ? tech_pvt
->name(name1, name2, name3) : SWITCH_STATUS_FALSE; } \
switch_status_t name(type1 name1, type2 name2, type3 name3)
class
FSConnection
:
public
OpalLocalConnection
{
PCLASSINFO
(
FSConnection
,
OpalLocalConnection
)
class
FSConnection
:
public
OpalLocalConnection
{
PCLASSINFO
(
FSConnection
,
OpalLocalConnection
)
public
:
FSConnection
(
OpalCall
&
call
,
FSEndPoint
&
endpoint
,
void
*
userData
,
unsigned
options
,
OpalConnection
::
StringOptions
*
stringOptions
,
switch_caller_profile_t
*
outbound_profile
,
switch_core_session_t
*
fsSession
,
switch_channel_t
*
fsChannel
);
virtual
bool
OnIncoming
();
virtual
void
OnReleased
();
virtual
PBoolean
SetAlerting
(
const
PString
&
calleeName
,
PBoolean
withMedia
);
virtual
void
OnAlerting
();
virtual
void
OnEstablished
();
virtual
OpalMediaStream
*
CreateMediaStream
(
const
OpalMediaFormat
&
,
unsigned
,
PBoolean
);
virtual
PBoolean
OnOpenMediaStream
(
OpalMediaStream
&
stream
);
virtual
OpalMediaFormatList
GetMediaFormats
()
const
;
virtual
PBoolean
SendUserInputTone
(
char
tone
,
unsigned
duration
);
virtual
PBoolean
SendUserInputString
(
const
PString
&
value
);
void
SetCodecs
();
DECLARE_CALLBACK0
(
on_init
);
DECLARE_CALLBACK0
(
on_routing
);
DECLARE_CALLBACK0
(
on_execute
);
DECLARE_CALLBACK0
(
on_exchange_media
);
DECLARE_CALLBACK0
(
on_soft_execute
);
DECLARE_CALLBACK1
(
kill_channel
,
int
,
sig
);
DECLARE_CALLBACK1
(
send_dtmf
,
const
switch_dtmf_t
*
,
dtmf
);
DECLARE_CALLBACK1
(
receive_message
,
switch_core_session_message_t
*
,
msg
);
DECLARE_CALLBACK1
(
receive_event
,
switch_event_t
*
,
event
);
DECLARE_CALLBACK0
(
state_change
);
DECLARE_CALLBACK3
(
read_audio_frame
,
switch_frame_t
**
,
frame
,
switch_io_flag_t
,
flags
,
int
,
stream_id
);
DECLARE_CALLBACK3
(
write_audio_frame
,
switch_frame_t
*
,
frame
,
switch_io_flag_t
,
flags
,
int
,
stream_id
);
DECLARE_CALLBACK3
(
read_video_frame
,
switch_frame_t
**
,
frame
,
switch_io_flag_t
,
flag
,
int
,
stream_id
);
DECLARE_CALLBACK3
(
write_video_frame
,
switch_frame_t
*
,
frame
,
switch_io_flag_t
,
flag
,
int
,
stream_id
);
switch_status_t
read_frame
(
const
OpalMediaType
&
mediaType
,
switch_frame_t
**
frame
,
switch_io_flag_t
flags
);
switch_status_t
write_frame
(
const
OpalMediaType
&
mediaType
,
const
switch_frame_t
*
frame
,
switch_io_flag_t
flags
);
switch_core_session_t
*
GetSession
()
const
{
return
m_fsSession
;
}
private
:
FSEndPoint
&
m_endpoint
;
switch_core_session_t
*
m_fsSession
;
switch_channel_t
*
m_fsChannel
;
PSyncPoint
m_rxAudioOpened
;
PSyncPoint
m_txAudioOpened
;
OpalMediaFormatList
m_switchMediaFormats
;
};
struct
outgoing_params
{
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_call_cause_t
fail_cause
;
};
FSConnection
(
OpalCall
&
call
,
FSEndPoint
&
endpoint
,
unsigned
options
,
OpalConnection
::
StringOptions
*
stringOptions
,
outgoing_params
*
params
);
virtual
bool
OnOutgoingSetUp
();
virtual
bool
OnIncoming
();
virtual
void
OnReleased
();
virtual
PBoolean
SetAlerting
(
const
PString
&
calleeName
,
PBoolean
withMedia
);
virtual
OpalMediaStream
*
CreateMediaStream
(
const
OpalMediaFormat
&
,
unsigned
,
PBoolean
);
virtual
void
OnPatchMediaStream
(
PBoolean
isSource
,
OpalMediaPatch
&
patch
);
virtual
OpalMediaFormatList
GetMediaFormats
()
const
;
virtual
PBoolean
SendUserInputTone
(
char
tone
,
unsigned
duration
);
void
SetCodecs
();
bool
WaitForMedia
();
DECLARE_CALLBACK0
(
on_init
);
DECLARE_CALLBACK0
(
on_destroy
);
DECLARE_CALLBACK0
(
on_routing
);
DECLARE_CALLBACK0
(
on_execute
);
DECLARE_CALLBACK0
(
on_hangup
);
DECLARE_CALLBACK0
(
on_exchange_media
);
DECLARE_CALLBACK0
(
on_soft_execute
);
DECLARE_CALLBACK1
(
kill_channel
,
int
,
sig
);
DECLARE_CALLBACK1
(
send_dtmf
,
const
switch_dtmf_t
*
,
dtmf
);
DECLARE_CALLBACK1
(
receive_message
,
switch_core_session_message_t
*
,
msg
);
DECLARE_CALLBACK1
(
receive_event
,
switch_event_t
*
,
event
);
DECLARE_CALLBACK0
(
state_change
);
DECLARE_CALLBACK3
(
read_audio_frame
,
switch_frame_t
**
,
frame
,
switch_io_flag_t
,
flags
,
int
,
stream_id
);
DECLARE_CALLBACK3
(
write_audio_frame
,
switch_frame_t
*
,
frame
,
switch_io_flag_t
,
flags
,
int
,
stream_id
);
DECLARE_CALLBACK3
(
read_video_frame
,
switch_frame_t
**
,
frame
,
switch_io_flag_t
,
flag
,
int
,
stream_id
);
DECLARE_CALLBACK3
(
write_video_frame
,
switch_frame_t
*
,
frame
,
switch_io_flag_t
,
flag
,
int
,
stream_id
);
switch_status_t
read_frame
(
const
OpalMediaType
&
mediaType
,
switch_frame_t
**
frame
,
switch_io_flag_t
flags
);
switch_status_t
write_frame
(
const
OpalMediaType
&
mediaType
,
const
switch_frame_t
*
frame
,
switch_io_flag_t
flags
);
__inline
switch_core_session_t
*
GetSession
()
const
{
return
m_fsSession
;
}
__inline
switch_channel_t
*
GetChannel
()
const
{
return
m_fsChannel
;
}
bool
IsChannelReady
()
const
{
return
m_fsChannel
!=
NULL
&&
switch_channel_ready
(
m_fsChannel
);
}
bool
NeedFlushAudio
()
{
if
(
!
m_flushAudio
)
return
false
;
m_flushAudio
=
false
;
return
true
;
}
private
:
FSEndPoint
&
m_endpoint
;
switch_core_session_t
*
m_fsSession
;
switch_channel_t
*
m_fsChannel
;
PSyncPoint
m_rxAudioOpened
;
PSyncPoint
m_txAudioOpened
;
OpalMediaFormatList
m_switchMediaFormats
;
class
FSMediaStream
:
public
OpalMediaStream
{
PCLASSINFO
(
FSMediaStream
,
OpalMediaStream
);
public
:
FSMediaStream
(
FSConnection
&
conn
,
const
OpalMediaFormat
&
mediaFormat
,
///< Media format for stream
unsigned
sessionID
,
///< Session number for stream
bool
isSource
///< Is a source stream
);
// If FS ever supports more than one audio and one video, this needs to change
switch_timer_t
m_read_timer
;
switch_codec_t
m_read_codec
;
switch_codec_t
m_write_codec
;
virtual
PBoolean
Open
();
virtual
PBoolean
Close
();
virtual
PBoolean
IsSynchronous
()
const
;
virtual
PBoolean
RequiresPatchThread
(
OpalMediaStream
*
)
const
;
switch_timer_t
m_vid_read_timer
;
switch_codec_t
m_vid_read_codec
;
switch_codec_t
m_vid_write_codec
;
switch_status_t
read_frame
(
switch_frame_t
**
frame
,
switch_io_flag_t
flags
);
switch_status_t
write_frame
(
const
switch_frame_t
*
frame
,
switch_io_flag_t
flags
);
bool
m_flushAudio
;
private
:
switch_core_session_t
*
m_fsSession
;
switch_channel_t
*
m_fsChannel
;
switch_timer_t
*
m_switchTimer
;
switch_codec_t
*
m_switchCodec
;
switch_frame_t
m_readFrame
;
unsigned
char
m_buf
[
SWITCH_RECOMMENDED_BUFFER_SIZE
];
RTP_DataFrame
m_readRTP
;
bool
m_callOnStart
;
uint32_t
m_timeStamp
;
bool
CheckPatchAndLock
();
friend
PBoolean
FSMediaStream
::
Open
();
};
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论