add some inital v18 interface points

This commit is contained in:
Anthony Minessale 2012-06-23 18:48:20 -05:00
parent e38f0a1b02
commit 0f6647d278
3 changed files with 380 additions and 4 deletions

View File

@ -34,6 +34,8 @@
*
*/
#define MY_EVENT_TDD_SEND_MESSAGE "TDD::SEND_MESSAGE"
#include "mod_spandsp.h"
#include <spandsp/version.h>
#include "mod_spandsp_modem.h"
@ -51,7 +53,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_spandsp_shutdown);
SWITCH_MODULE_DEFINITION(mod_spandsp, mod_spandsp_init, mod_spandsp_shutdown, NULL);
static switch_event_node_t *NODE = NULL;
SWITCH_STANDARD_APP(spanfax_tx_function)
{
@ -74,6 +75,47 @@ SWITCH_STANDARD_APP(stop_dtmf_session_function)
}
SWITCH_STANDARD_APP(tdd_encode_function)
{
char *text = (char *) data;
if (!zstr(text)) {
spandsp_tdd_encode_session(session, text);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing text data\n");
}
}
SWITCH_STANDARD_APP(tdd_send_function)
{
char *text = (char *) data;
if (!zstr(text)) {
spandsp_tdd_send_session(session, text);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing text data\n");
}
}
SWITCH_STANDARD_APP(stop_tdd_encode_function)
{
spandsp_stop_tdd_encode_session(session);
}
SWITCH_STANDARD_APP(tdd_decode_function)
{
spandsp_tdd_decode_session(session);
}
SWITCH_STANDARD_APP(stop_tdd_decode_function)
{
spandsp_stop_tdd_decode_session(session);
}
SWITCH_STANDARD_APP(spandsp_fax_detect_session_function)
{
int argc = 0;
@ -117,6 +159,36 @@ SWITCH_STANDARD_APP(spandsp_stop_fax_detect_session_function)
spandsp_fax_stop_detect_session(session);
}
static void tdd_event_handler(switch_event_t *event)
{
const char *uuid = switch_event_get_header(event, "tdd-uuid");
const char *message = switch_event_get_body(event);
switch_core_session_t *session;
if (zstr(message)) {
message = switch_event_get_header(event, "tdd-message");
}
if (zstr(message)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No message for tdd handler\n");
return;
}
if (zstr(uuid)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No uuid for tdd handler\n");
return;
}
if ((session = switch_core_session_locate(uuid))) {
spandsp_tdd_encode_session(session, message);
switch_core_session_rwunlock(session);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No session for supplied uuid.\n");
}
}
static void event_handler(switch_event_t *event)
{
load_configuration(1);
@ -543,6 +615,16 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init)
SWITCH_ADD_APP(app_interface, "spandsp_stop_dtmf", "stop inband dtmf", "Stop detecting inband dtmf.", stop_dtmf_session_function, "", SAF_NONE);
SWITCH_ADD_APP(app_interface, "spandsp_start_dtmf", "Detect dtmf", "Detect inband dtmf on the session", dtmf_session_function, "", SAF_MEDIA_TAP);
SWITCH_ADD_APP(app_interface, "spandsp_stop_send_tdd", "stop sending tdd", "", stop_tdd_encode_function, "", SAF_NONE);
SWITCH_ADD_APP(app_interface, "spandsp_send_tdd", "Send TDD data", "Send TDD data", tdd_encode_function, "", SAF_MEDIA_TAP);
SWITCH_ADD_APP(app_interface, "spandsp_stop_detect_tdd", "stop sending tdd", "", stop_tdd_decode_function, "", SAF_NONE);
SWITCH_ADD_APP(app_interface, "spandsp_detect_tdd", "Detect TDD data", "Detect TDD data", tdd_decode_function, "", SAF_MEDIA_TAP);
SWITCH_ADD_APP(app_interface, "spandsp_send_tdd", "Send TDD data", "Send TDD data", tdd_send_function, "", SAF_NONE);
SWITCH_ADD_APP(app_interface, "spandsp_start_fax_detect", "start fax detect", "start fax detect", spandsp_fax_detect_session_function,
"<app>[ <arg>][ <timeout>][ <tone_type>]", SAF_NONE);
@ -562,13 +644,18 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init)
SWITCH_ADD_API(api_interface, "start_tone_detect", "Start background tone detection with cadence", start_tone_detect_api, "[name]");
SWITCH_ADD_API(api_interface, "stop_tone_detect", "Stop background tone detection with cadence", stop_tone_detect_api, "");
}
if ((switch_event_bind_removable(modname, SWITCH_EVENT_RELOADXML, NULL, event_handler, NULL, &NODE) != SWITCH_STATUS_SUCCESS)) {
if ((switch_event_bind(modname, SWITCH_EVENT_RELOADXML, NULL, event_handler, NULL) != SWITCH_STATUS_SUCCESS)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our reloadxml handler!\n");
/* Not such severe to prevent loading */
}
if (switch_event_bind(modname, SWITCH_EVENT_CUSTOM, MY_EVENT_TDD_SEND_MESSAGE, tdd_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
}
modem_global_init(module_interface, pool);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "mod_spandsp loaded, using spandsp library version [%s]\n", SPANDSP_RELEASE_DATETIME_STRING);
@ -578,7 +665,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init)
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_spandsp_shutdown)
{
switch_event_unbind(&NODE);
switch_event_unbind_callback(event_handler);
switch_event_unbind_callback(tdd_event_handler);
mod_spandsp_fax_shutdown();
mod_spandsp_dsp_shutdown();

View File

@ -140,3 +140,11 @@ switch_status_t spandsp_fax_stop_detect_session(switch_core_session_t *session);
void spanfax_log_message(void *user_data, int level, const char *msg);
switch_status_t load_configuration(switch_bool_t reload);
void mod_spandsp_indicate_data(switch_core_session_t *session, switch_bool_t self, switch_bool_t on);
switch_status_t spandsp_stop_tdd_encode_session(switch_core_session_t *session);
switch_status_t spandsp_tdd_encode_session(switch_core_session_t *session, const char *text);
switch_status_t spandsp_stop_tdd_decode_session(switch_core_session_t *session);
switch_status_t spandsp_tdd_decode_session(switch_core_session_t *session);
switch_status_t spandsp_tdd_send_session(switch_core_session_t *session, const char *text);

View File

@ -35,6 +35,285 @@
#include "mod_spandsp.h"
#define TDD_LEAD 10
typedef struct {
switch_core_session_t *session;
v18_state_t *tdd_state;
int head_lead;
int tail_lead;
} switch_tdd_t;
static switch_bool_t tdd_encode_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
switch_tdd_t *pvt = (switch_tdd_t *) user_data;
switch_frame_t *frame = NULL;
switch_bool_t r = SWITCH_TRUE;
switch (type) {
case SWITCH_ABC_TYPE_INIT: {
break;
}
case SWITCH_ABC_TYPE_CLOSE:
if (pvt->tdd_state) {
v18_free(pvt->tdd_state);
}
break;
case SWITCH_ABC_TYPE_WRITE_REPLACE:
if ((frame = switch_core_media_bug_get_write_replace_frame(bug))) {
int len;
if (pvt->tail_lead) {
if (!--pvt->tail_lead) {
r = SWITCH_FALSE;
}
memset(frame->data, 0, frame->datalen);
} else if (pvt->head_lead) {
pvt->head_lead--;
memset(frame->data, 0, frame->datalen);
} else {
len = v18_tx(pvt->tdd_state, frame->data, frame->samples);
if (!len) {
pvt->tail_lead = TDD_LEAD;
}
}
switch_core_media_bug_set_write_replace_frame(bug, frame);
}
break;
case SWITCH_ABC_TYPE_WRITE:
default:
break;
}
return r;
}
switch_status_t spandsp_stop_tdd_encode_session(switch_core_session_t *session)
{
switch_media_bug_t *bug;
switch_channel_t *channel = switch_core_session_get_channel(session);
if ((bug = switch_channel_get_private(channel, "tdd_encode"))) {
switch_channel_set_private(channel, "tdd_encode", NULL);
switch_core_media_bug_remove(session, &bug);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
static void put_text_msg(void *user_data, const uint8_t *msg, int len)
{
switch_tdd_t *pvt = (switch_tdd_t *) user_data;
switch_event_t *event, *clone;
switch_channel_t *channel = switch_core_session_get_channel(pvt->session);
switch_core_session_t *other_session;
switch_channel_add_variable_var_check(channel, "tdd_messages", (char *)msg, SWITCH_FALSE, SWITCH_STACK_PUSH);
if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", "mod_spandsp");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", "tdd");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "subject", "TDD MESSAGE");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(pvt->session));
switch_event_add_body(event, (char *)msg);
if (switch_core_session_get_partner(pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) {
if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
switch_core_session_receive_event(other_session, &clone);
}
if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
switch_core_session_queue_event(other_session, &clone);
}
switch_core_session_rwunlock(other_session);
}
switch_event_fire(&event);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "%s got TDD Message [%s]\n", switch_channel_get_name(channel), (char *)msg);
}
switch_status_t spandsp_tdd_send_session(switch_core_session_t *session, const char *text)
{
v18_state_t *tdd_state;
switch_frame_t *read_frame, write_frame = { 0 };
uint8_t write_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
switch_codec_implementation_t read_impl = { 0 };
switch_codec_t write_codec = { 0 };
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_status_t status;
switch_core_session_get_read_impl(session, &read_impl);
if (switch_core_codec_init(&write_codec,
"L16",
NULL,
read_impl.actual_samples_per_second,
read_impl.microseconds_per_packet / 1000,
read_impl.number_of_channels,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
write_frame.data = write_buf;
write_frame.buflen = sizeof(write_buf);
write_frame.datalen = read_impl.decoded_bytes_per_packet;
write_frame.samples = write_frame.datalen / 2;
write_frame.codec = &write_codec;
switch_core_session_set_read_codec(session, &write_codec);
} else {
return SWITCH_STATUS_FALSE;
}
tdd_state = v18_init(NULL, TRUE, V18_MODE_5BIT_45, put_text_msg, NULL);
v18_put(tdd_state, text, -1);
while(switch_channel_ready(channel)) {
status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
}
if (!v18_tx(tdd_state, (void *)write_buf, write_frame.samples)) {
break;
}
if (switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
break;
}
}
switch_core_codec_destroy(&write_codec);
switch_core_session_set_read_codec(session, NULL);
v18_free(tdd_state);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t spandsp_tdd_encode_session(switch_core_session_t *session, const char *text)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_media_bug_t *bug;
switch_status_t status;
switch_tdd_t *pvt;
//switch_codec_implementation_t read_impl = { 0 };
//switch_core_session_get_read_impl(session, &read_impl);
if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
return SWITCH_STATUS_MEMERR;
}
pvt->session = session;
pvt->tdd_state = v18_init(NULL, TRUE, V18_MODE_5BIT_45, put_text_msg, NULL);
pvt->head_lead = TDD_LEAD;
v18_put(pvt->tdd_state, text, -1);
if ((status = switch_core_media_bug_add(session, "spandsp_tdd_encode", NULL,
tdd_encode_callback, pvt, 0, SMBF_WRITE_REPLACE | SMBF_NO_PAUSE, &bug)) != SWITCH_STATUS_SUCCESS) {
v18_free(pvt->tdd_state);
return status;
}
switch_channel_set_private(channel, "tdd_encode", bug);
return SWITCH_STATUS_SUCCESS;
}
///XXX
static switch_bool_t tdd_decode_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
switch_tdd_t *pvt = (switch_tdd_t *) user_data;
switch_frame_t *frame = NULL;
switch_bool_t r = SWITCH_TRUE;
switch (type) {
case SWITCH_ABC_TYPE_INIT: {
break;
}
case SWITCH_ABC_TYPE_CLOSE:
if (pvt->tdd_state) {
v18_free(pvt->tdd_state);
}
break;
case SWITCH_ABC_TYPE_READ_REPLACE:
if ((frame = switch_core_media_bug_get_read_replace_frame(bug))) {
v18_rx(pvt->tdd_state, frame->data, frame->samples);
switch_core_media_bug_set_read_replace_frame(bug, frame);
}
break;
case SWITCH_ABC_TYPE_WRITE:
default:
break;
}
return r;
}
switch_status_t spandsp_stop_tdd_decode_session(switch_core_session_t *session)
{
switch_media_bug_t *bug;
switch_channel_t *channel = switch_core_session_get_channel(session);
if ((bug = switch_channel_get_private(channel, "tdd_decode"))) {
switch_channel_set_private(channel, "tdd_decode", NULL);
switch_core_media_bug_remove(session, &bug);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
switch_status_t spandsp_tdd_decode_session(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_media_bug_t *bug;
switch_status_t status;
switch_tdd_t *pvt;
//switch_codec_implementation_t read_impl = { 0 };
//switch_core_session_get_read_impl(session, &read_impl);
if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) {
return SWITCH_STATUS_MEMERR;
}
pvt->session = session;
pvt->tdd_state = v18_init(NULL, FALSE, V18_MODE_5BIT_45, put_text_msg, pvt);
if ((status = switch_core_media_bug_add(session, "spandsp_tdd_decode", NULL,
tdd_decode_callback, pvt, 0, SMBF_READ_REPLACE | SMBF_NO_PAUSE, &bug)) != SWITCH_STATUS_SUCCESS) {
v18_free(pvt->tdd_state);
return status;
}
switch_channel_set_private(channel, "tdd_decode", bug);
return SWITCH_STATUS_SUCCESS;
}
///XXX
typedef struct {
switch_core_session_t *session;
dtmf_rx_state_t *dtmf_detect;