提交 9ab2b1db authored 作者: Anthony Minessale's avatar Anthony Minessale

Media Management (Sponsored By Front Logic)

This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan.
It adds some API interface calls usable from a remote client such as mod_event_socket or the test console.

1) media [off] <uuid>

   Turns on/off the media on the call described by <uuid>
   The media will be redirected as desiered either into the switch or point to point.

2) hold [off] <uuid>

   Turns on/off endpoint specific hold state on the session described by <uuid>

3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both]

   A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated.

   If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified
   will hear the message.

   During playback when only one side is hearing the message the other end will hear silence.

   If media is not flowing across the switch when the message is broadcasted, the media will be directed to the
   switch for the duration of the call and then returned to it's previous state.


Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session
description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media
on the switch.

<action application="set" data="no_media=true"/>
<action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/>


*NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled,
the media for the first leg will be engaged with the switch until the second leg has answered and the other session description
is available to establish a point to point connection at which time point-to-point mode will be enabled.

*NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core.



git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 1e4ad3c5
......@@ -274,7 +274,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_t *session, char *extension, char *dialplan, char *context);
/*!
\brief Bridge two existing sessions
\param originator_uuid the uuid of the originator
......@@ -283,6 +282,59 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(char *originator_uuid, char *originatee_uuid);
/*!
\brief Signal a session to request direct media access to it's remote end
\param uuid the uuid of the session to request
\param flags flags to influence behaviour (SMF_REBRIDGE to rebridge the call in media mode)
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_media(char *uuid, switch_media_flag_t flags);
/*!
\brief Signal a session to request indirect media allowing it to exchange media directly with another device
\param uuid the uuid of the session to request
\param flags flags to influence behaviour (SMF_REBRIDGE to rebridge the call in no_media mode)
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_nomedia(char *uuid, switch_media_flag_t flags);
/*!
\brief Signal the session with a protocol specific hold message.
\param uuid the uuid of the session to hold
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_hold_uuid(char *uuid);
/*!
\brief Signal the session with a protocol specific unhold message.
\param uuid the uuid of the session to hold
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_unhold_uuid(char *uuid);
/*!
\brief Signal the session with a protocol specific hold message.
\param session the session to hold
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_hold(switch_core_session_t *session);
/*!
\brief Signal the session with a protocol specific unhold message.
\param uuid the uuid of the session to unhold
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_unhold(switch_core_session_t *session);
/*!
\brief Signal the session to broadcast audio
\param uuid the uuid of the session to broadcast on
\param path the path data of the broadcast "/path/to/file.wav [<timer name>]" or "speak:<engine>|<voice>|<Text to say>"
\param flags flags to send to the request (SMF_ECHO_BRIDGED to send the broadcast to both sides of the call)
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_broadcast(char *uuid, char *path, switch_media_flag_t flags);
/*!
\brief Transfer variables from one session to another
\param sessa the original session
......
......@@ -60,6 +60,8 @@ struct switch_state_handler_table {
switch_state_handler_t on_transmit;
/*! executed when the state changes to hold*/
switch_state_handler_t on_hold;
/*! executed when the state changes to hibernate*/
switch_state_handler_t on_hibernate;
};
struct switch_stream_handle {
......
......@@ -74,12 +74,25 @@ SWITCH_BEGIN_EXTERN_C
#define SWITCH_R_SDP_VARIABLE "_switch_r_sdp_"
#define SWITCH_L_SDP_VARIABLE "_switch_l_sdp_"
#define SWITCH_BRIDGE_VARIABLE "BRIDGETO"
#define SWITCH_SIGNAL_BRIDGE_VARIABLE "SIGNAL_BRIDGETO"
#define SWITCH_B_SDP_VARIABLE "_switch_m_sdp_"
#define SWITCH_BRIDGE_VARIABLE "_bridge_to_"
#define SWITCH_SIGNAL_BRIDGE_VARIABLE "_signal_bridge_to_"
#define SWITCH_ORIGINATOR_VARIABLE "_originator_"
#define SWITCH_LOCAL_MEDIA_IP_VARIABLE "_local_media_ip_"
#define SWITCH_LOCAL_MEDIA_PORT_VARIABLE "_local_media_port_"
#define SWITCH_REMOTE_MEDIA_IP_VARIABLE "_remote_media_ip_"
#define SWITCH_REMOTE_MEDIA_PORT_VARIABLE "_remote_media_port_"
#define SWITCH_BITS_PER_BYTE 8
typedef uint8_t switch_byte_t;
typedef enum {
SMF_NONE = 0,
SMF_REBRIDGE = (1 << 0),
SMF_ECHO_BRIDGED = (1 << 1)
} switch_media_flag_t;
typedef enum {
SWITCH_BITPACK_MODE_RFC3551,
SWITCH_BITPACK_MODE_AAL2
......@@ -246,6 +259,10 @@ typedef enum {
SWITCH_MESSAGE_INDICATE_BRIDGE - indicate a bridge starting
SWITCH_MESSAGE_INDICATE_UNBRIDGE - indicate a bridge ending
SWITCH_MESSAGE_INDICATE_TRANSFER - indicate a transfer is taking place
SWITCH_MESSAGE_INDICATE_MEDIA - indicate media is required
SWITCH_MESSAGE_INDICATE_NOMEDIA - indicate no-media is required
SWITCH_MESSAGE_INDICATE_HOLD - indicate hold
SWITCH_MESSAGE_INDICATE_UNHOLD - indicate unhold
</pre>
*/
typedef enum {
......@@ -255,7 +272,11 @@ typedef enum {
SWITCH_MESSAGE_INDICATE_BRIDGE,
SWITCH_MESSAGE_INDICATE_UNBRIDGE,
SWITCH_MESSAGE_INDICATE_TRANSFER,
SWITCH_MESSAGE_INDICATE_RINGING
SWITCH_MESSAGE_INDICATE_RINGING,
SWITCH_MESSAGE_INDICATE_MEDIA,
SWITCH_MESSAGE_INDICATE_NOMEDIA,
SWITCH_MESSAGE_INDICATE_HOLD,
SWITCH_MESSAGE_INDICATE_UNHOLD,
} switch_core_session_message_types_t;
......@@ -376,6 +397,7 @@ CS_TRANSMIT - Channel is in a passive transmit state
CS_EXECUTE - Channel is executing it's dialplan
CS_LOOPBACK - Channel is in loopback
CS_HOLD - Channel is on hold
CS_HIBERNATE - Channel is in a sleep state
CS_HANGUP - Channel is flagged for hangup and ready to end
CS_DONE - Channel is ready to be destroyed and out of the state machine
</pre>
......@@ -388,6 +410,7 @@ typedef enum {
CS_EXECUTE,
CS_LOOPBACK,
CS_HOLD,
CS_HIBERNATE,
CS_HANGUP,
CS_DONE
} switch_channel_state_t;
......@@ -412,6 +435,8 @@ CF_TAGGED = (1 << 10) - Channel is tagged
CF_WINNER = (1 << 11) - Channel is the winner
CF_CONTROLLED = (1 << 12) - Channel is under control
CF_NOMEDIA = (1 << 13) - Channel has no media
CF_SUSPEND = (1 << 14) - Suspend i/o
CF_EVENT_PARSE = (1 << 15) - Suspend control events
</pre>
*/
......@@ -429,7 +454,9 @@ typedef enum {
CF_TAGGED = (1 << 10),
CF_WINNER = (1 << 11),
CF_CONTROLLED = (1 << 12),
CF_NOMEDIA = (1 << 13)
CF_NOMEDIA = (1 << 13),
CF_SUSPEND = (1 << 14),
CF_EVENT_PARSE = (1 << 15)
} switch_channel_flag_t;
......
......@@ -44,6 +44,9 @@ static switch_api_interface_t load_api_interface;
static switch_api_interface_t reload_api_interface;
static switch_api_interface_t kill_api_interface;
static switch_api_interface_t originate_api_interface;
static switch_api_interface_t media_api_interface;
static switch_api_interface_t hold_api_interface;
static switch_api_interface_t broadcast_api_interface;
static switch_status_t status_function(char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream)
{
......@@ -235,6 +238,97 @@ static switch_status_t transfer_function(char *cmd, switch_core_session_t *isess
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t uuid_media_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
{
char *argv[4] = {0};
int argc = 0;
switch_status_t status = SWITCH_STATUS_FALSE;
if (isession) {
return status;
}
argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 1) {
stream->write_function(stream, "USAGE: %s\n", media_api_interface.syntax);
} else {
if (!strcmp(argv[0], "off")) {
status = switch_ivr_nomedia(argv[1], SMF_REBRIDGE);
} else {
status = switch_ivr_media(argv[0], SMF_REBRIDGE);
}
}
if (status == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK Success\n");
} else {
stream->write_function(stream, "-ERR Operation Failed\n");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t uuid_broadcast_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
{
char *argv[4] = {0};
int argc = 0;
switch_status_t status = SWITCH_STATUS_FALSE;
if (isession) {
return status;
}
argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 2) {
stream->write_function(stream, "USAGE: %s\n", broadcast_api_interface.syntax);
} else {
switch_media_flag_t flags = SMF_NONE;
if (argv[2] && !strcmp(argv[2], "both")) {
flags |= SMF_ECHO_BRIDGED;
}
status = switch_ivr_broadcast(argv[0], argv[1], flags);
stream->write_function(stream, "+OK Message Sent\n");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t uuid_hold_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
{
char *argv[4] = {0};
int argc = 0;
switch_status_t status = SWITCH_STATUS_FALSE;
if (isession) {
return status;
}
argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 1) {
stream->write_function(stream, "USAGE: %s\n", hold_api_interface.syntax);
} else {
if (!strcmp(argv[0], "off")) {
status = switch_ivr_unhold_uuid(argv[1]);
} else {
status = switch_ivr_hold_uuid(argv[0]);
}
}
if (status == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK Success\n");
} else {
stream->write_function(stream, "-ERR Operation Failed\n");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t uuid_bridge_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
{
char *argv[4] = {0};
......@@ -535,12 +629,36 @@ static switch_api_interface_t ctl_api_interface = {
/*.next */ &help_api_interface
};
static switch_api_interface_t media_api_interface = {
/*.interface_name */ "media",
/*.desc */ "media",
/*.function */ uuid_media_function,
/*.syntax */ "<uuid>",
/*.next */ &ctl_api_interface
};
static switch_api_interface_t hold_api_interface = {
/*.interface_name */ "hold",
/*.desc */ "hold",
/*.function */ uuid_hold_function,
/*.syntax */ "<uuid>",
/*.next */ &media_api_interface
};
static switch_api_interface_t broadcast_api_interface = {
/*.interface_name */ "broadcast",
/*.desc */ "broadcast",
/*.function */ uuid_broadcast_function,
/*.syntax */ "<uuid> <path> [both]",
/*.next */ &hold_api_interface
};
static switch_api_interface_t uuid_bridge_api_interface = {
/*.interface_name */ "uuid_bridge",
/*.desc */ "uuid_bridge",
/*.function */ uuid_bridge_function,
/*.syntax */ "<uuid> <other_uuid>",
/*.next */ &ctl_api_interface
/*.next */ &broadcast_api_interface
};
static switch_api_interface_t status_api_interface = {
......
......@@ -88,7 +88,16 @@ static void speak_function(switch_core_session_t *session, char *data)
timer_name = argv[3];
if (!(engine && voice && text)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Params!\n");
if (!engine) {
engine = "NULL";
}
if (!voice) {
voice = "NULL";
}
if (!text) {
text = "NULL";
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Params! [%s][%s][%s]\n", engine, voice, text);
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
......
OS_ARCH := $(subst /,_,$(shell uname -s | sed /\ /s//_/))
VERSION = sofia-sip-1.12
TARBALL = sofia-sip-1.12.3.8.tar.gz
TARBALL = sofia-sip-1.12.3.9.tar.gz
CFLAGS += -I. -I$(PREFIX)/include/$(VERSION)
LDFLAGS += -lsofia-sip-ua
LINKER=$(CC)
......
......@@ -462,6 +462,7 @@ static const char *state_names[] = {
"CS_EXECUTE",
"CS_LOOPBACK",
"CS_HOLD",
"CS_HIBERNATE",
"CS_HANGUP",
"CS_DONE",
NULL
......@@ -543,6 +544,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
case CS_RING:
case CS_EXECUTE:
case CS_HOLD:
case CS_HIBERNATE:
ok++;
default:
break;
......@@ -555,6 +557,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
case CS_RING:
case CS_EXECUTE:
case CS_HOLD:
case CS_HIBERNATE:
ok++;
default:
break;
......@@ -567,6 +570,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
case CS_RING:
case CS_EXECUTE:
case CS_HOLD:
case CS_HIBERNATE:
ok++;
default:
break;
......@@ -579,6 +583,19 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
case CS_RING:
case CS_EXECUTE:
case CS_TRANSMIT:
case CS_HIBERNATE:
ok++;
default:
break;
}
break;
case CS_HIBERNATE:
switch (state) {
case CS_LOOPBACK:
case CS_RING:
case CS_EXECUTE:
case CS_TRANSMIT:
case CS_HOLD:
ok++;
default:
break;
......@@ -592,6 +609,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
case CS_EXECUTE:
case CS_TRANSMIT:
case CS_HOLD:
case CS_HIBERNATE:
ok++;
default:
break;
......@@ -604,6 +622,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
case CS_TRANSMIT:
case CS_RING:
case CS_HOLD:
case CS_HIBERNATE:
ok++;
default:
break;
......
......@@ -1367,6 +1367,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_outgoing_channel(switch_core
switch_event_t *event;
switch_channel_t *peer_channel = switch_core_session_get_channel(*new_session);
if (session && channel) {
profile = switch_channel_get_caller_profile(channel);
}
......@@ -1375,7 +1376,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_outgoing_channel(switch_core
}
if (channel && peer_channel) {
char *export_vars;
char *export_vars, *val;
switch_channel_set_variable(peer_channel, SWITCH_ORIGINATOR_VARIABLE, switch_core_session_get_uuid(session));
/* A comma (,) separated list of variable names that should ne propagated from originator to originatee */
if ((export_vars = switch_channel_get_variable(channel, "export_vars"))) {
char *cptmp = switch_core_session_strdup(session, export_vars);
......@@ -1394,6 +1398,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_outgoing_channel(switch_core
}
}
if ((val = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE))) {
switch_channel_set_variable(peer_channel, SWITCH_B_SDP_VARIABLE, val);
}
if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
switch_channel_set_flag(peer_channel, CF_NOMEDIA);
}
if (profile) {
if ((cloned_profile = switch_caller_profile_clone(*new_session, profile)) != 0) {
switch_channel_set_originator_caller_profile(peer_channel, cloned_profile);
......@@ -1608,9 +1620,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_dequeue_private_event(switch
{
switch_status_t status = SWITCH_STATUS_FALSE;
void *pop;
switch_channel_t *channel;
assert(session != NULL);
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
if (switch_channel_test_flag(channel, CF_EVENT_PARSE)) {
return status;
}
if (session->private_event_queue) {
if ((status = (switch_status_t) switch_queue_trypop(session->private_event_queue, &pop)) == SWITCH_STATUS_SUCCESS) {
*event = (switch_event_t *) pop;
......@@ -1880,7 +1901,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
assert(session != NULL);
assert(frame != NULL);
assert(frame->codec != NULL);
if (switch_channel_test_flag(session->channel, CF_HOLD)) {
return SWITCH_STATUS_SUCCESS;
......@@ -1895,6 +1916,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
return SWITCH_STATUS_SUCCESS;
}
assert(frame->codec != NULL);
if ((session->write_codec && frame->codec && session->write_codec->implementation != frame->codec->implementation)) {
need_codec = TRUE;
......@@ -2587,6 +2609,12 @@ static void switch_core_standard_on_hold(switch_core_session_t *session)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard HOLD\n");
}
static void switch_core_standard_on_hibernate(switch_core_session_t *session)
{
assert(session != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard HIBERNATE\n");
}
SWITCH_DECLARE(void) switch_core_session_signal_state_change(switch_core_session_t *session)
{
......@@ -2976,6 +3004,43 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
}
}
break;
case CS_HIBERNATE: /* wait in limbo */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State HIBERNATE\n", switch_channel_get_name(session->channel));
if (!driver_state_handler->on_hibernate ||
(driver_state_handler->on_hibernate &&
driver_state_handler->on_hibernate(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
while((application_state_handler = switch_channel_get_state_handler(session->channel, index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_hibernate ||
(application_state_handler->on_hibernate &&
application_state_handler->on_hibernate(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
index = 0;
while(proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_hibernate ||
(application_state_handler->on_hibernate &&
application_state_handler->on_hibernate(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
if (proceed) {
switch_core_standard_on_hibernate(session);
}
}
break;
}
if (midstate == CS_DONE) {
......
差异被折叠。
......@@ -117,6 +117,8 @@ SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char
char *ptr;
int quot = 0;
char qc = '"';
char *e;
int x;
if (!buf || !array || !arraylen) {
return 0;
......@@ -143,14 +145,17 @@ SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char
}
if (*ptr) {
char *e;
if (*ptr == qc) {
ptr++;
array[argc++] = ptr;
}
if ((e = strchr(ptr, qc))) {
/* strip quotes */
for(x = 0; x < argc; x++) {
if (*(array[x]) == qc) {
(array[x])++;
if ((e = strchr(array[x], qc))) {
*e = '\0';
}
array[argc++] = ptr;
}
}
return argc;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论