+++ /dev/null
-/*
- * Copyright (c) 2010, Sangoma Technologies
- * Moises Silva <moy@sangoma.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of the original author; nor the names of any contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "switch.h"
-
-#include <sng_tc/sngtc_node.h>
-
-SWITCH_MODULE_LOAD_FUNCTION(mod_sangoma_codec_load);
-SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sangoma_codec_shutdown);
-SWITCH_MODULE_DEFINITION(mod_sangoma_codec, mod_sangoma_codec_load, mod_sangoma_codec_shutdown, NULL);
-
-#define SANGOMA_SESS_HASH_KEY_FORMAT "sngtc%lu"
-
-/* it seemed we need higher PTIME than the calling parties, so we assume nobody will use higher ptime than 40 */
-#define SANGOMA_DEFAULT_SAMPLING_RATE 80
-#define SANGOMA_TRANSCODE_CONFIG "sangoma_codec.conf"
-
-/* \brief vocallos configuration */
-static sngtc_init_cfg_t g_init_cfg;
-
-/* configured RTP IP */
-static int g_rtpip = 0;
-
-static char g_soap_url[255] = "";
-
-/* \brief protect vocallo session creation and destroy */
-static switch_mutex_t *g_sessions_lock = NULL;
-
-/* \brief next unique session id (protected by g_sessions_lock) */
-unsigned long long g_next_session_id = 0;
-
-/* hash of sessions (I think a linked list suits better here, but FS does not have the data type) */
-static switch_hash_t *g_sessions_hash = NULL;
-
-typedef struct vocallo_codec_s {
- int codec_id; /* vocallo codec ID */
- int iana; /* IANA code to register in FS */
- const char *iana_name; /* IANA name to register in FS */
- const char *fs_name;
- int maxms; /* max supported ms (WARNING: codec impl from 10ms up to this value will be registered if autoinit=1) */
- int bps; /* bits per second */
-
- /* following values must be set assuming frames of 10ms */
- int mpf; /* microseconds per frame */
- int spf; /* samples per frame */
- int bpfd; /* bytes per frame decompressed */
- int bpfc; /* bytes per frame compressed */
-
- int sampling_rate; /* declared sampling rate */
- int actual_sampling_rate; /* true sampling rate */
- int autoinit; /* initialize on start loop or manually */
-} vocallo_codec_t;
-
-vocallo_codec_t g_codec_map[] =
-{
- /* auto-init codecs */
- { SNGTC_CODEC_PCMU, IANA_PCMU_A_8000_1, "PCMU", "Sangoma PCMU", 40, 64000, 10000, 80, 160, 80, 8000, 8000, 1 },
- { SNGTC_CODEC_PCMA, IANA_PCMA_A_8000_1, "PCMA", "Sangoma PCMA", 40, 64000, 10000, 80, 160, 80, 8000, 8000, 1 },
- { SNGTC_CODEC_L16_1, IANA_L16_A_8000_1, "L16", "Sangoma L16", 40, 120000, 10000, 80, 160, 160, 8000, 8000, 0 },
- { SNGTC_CODEC_L16_2, IANA_L16_A_16000_1, "L16", "Sangoma L16 2", 40, 320000, 10000, 160, 320, 320, 16000, 16000, 0 },
- { SNGTC_CODEC_G726_32, IANA_G726_32_8000_1, "G726-32", "Sangoma G.726 32k", 40, 32000, 10000, 80, 160, 40, 8000, 8000, 1 },
- { SNGTC_CODEC_G722, IANA_G722_A_8000_1, "G722", "Sangoma G722", 20, 64000, 10000, 80, 160, 80, 8000, 8000, 1 },
-
- /* manually initialized */
- { SNGTC_CODEC_GSM_FR, IANA_GSM_A_8000_1, "GSM", "Sangoma GSM", 20, 13200, 20000, 160, 320, 33, 8000, 8000, 0 },
- { SNGTC_CODEC_G723_1_63, IANA_G723_A_8000_1, "G723", "Sangoma G723", 90, 6300, 30000, 240, 480, 24, 8000, 8000, 0 },
- { SNGTC_CODEC_G729AB, IANA_G729_AB_8000_1, "G729", "Sangoma G729", 50, 8000, 10000, 80, 160, 10, 8000, 8000, 0 },
- { SNGTC_CODEC_AMR_1220, IANA_AMR_A_8000_1, "AMR", "Sangoma AMR", 20, 12200, 20000, 160, 320, 0, 8000, 8000, 0 },
- { SNGTC_CODEC_SIREN7_24, IANA_SIREN7, "G7221", "Sangoma G722.1", 20, 24000, 20000, 320, 640, 60, 16000, 16000, 0 },
- { SNGTC_CODEC_SIREN7_32, IANA_SIREN7, "G7221", "Sangoma G722.1", 20, 32000, 20000, 320, 640, 80, 16000, 16000, 0 },
- { SNGTC_CODEC_ILBC_133, IANA_ILBC_133_8000_1, "iLBC", "Sangoma iLBC", 30, 13330, 30000, 240, 480, 50, 8000, 8000, 0 },
- { SNGTC_CODEC_ILBC_152, IANA_ILBC_152_8000_1, "iLBC", "Sangoma iLBC", 20, 15200, 20000, 160, 320, 38, 8000, 8000, 0 },
- { -1, -1, NULL, NULL, -1, -1, -1, -1, -1, -1, -1, -1, 0 },
-};
-
-/* RFC3389 RTP Payload for Comfort Noise */
-#define IANACODE_CN 13
-
-/* default codec list to load, users may override, special codec 'all' registers everything available unless listed in noregister */
-static char g_codec_register_list[1024] = "G729";
-
-/* default codec list to NOT load, users may override */
-static char g_codec_noregister_list[1024] = "";
-
-#define SANGOMA_RTP_QUEUE_SIZE 4
-struct sangoma_rtp_payload {
- uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE];
- int32_t datalen;
-};
-
-struct codec_data {
- /* sngtc request and reply */
- sngtc_codec_request_t request;
- sngtc_codec_reply_t reply;
-
- /* rtp streams */
- void *txrtp;
- void *rxrtp;
-
- /* packet counters */
- unsigned long tx;
- unsigned long rx;
- unsigned long ticks;
-
- /* Lost packets */
- long lastrxseqno;
- unsigned long rxlost;
-
- /* discarded silence packets */
- unsigned long rxdiscarded;
-
- /* avg Rx time */
- switch_time_t avgrxus;
- switch_time_t last_rx_time;
- switch_time_t last_func_call_time;
-
- /* RTP queue. The bigger the queue, the bigger the possible delay */
- struct sangoma_rtp_payload rtp_queue[SANGOMA_RTP_QUEUE_SIZE];
- uint8_t queue_windex;
- uint8_t queue_rindex;
- uint8_t queue_size;
- uint8_t queue_max_ever;
- unsigned debug_timing:1;
-};
-
-struct sangoma_transcoding_session {
- /* unique session id */
- unsigned long sessid;
- char hashkey[25];
-
- /* encoder and decoder */
- struct codec_data encoder;
- struct codec_data decoder;
-
- /* codec implementation */
- const switch_codec_implementation_t *impl;
-
- /* memory pool */
- switch_memory_pool_t *pool;
-};
-
-static int codec_id_to_iana(int codec_id)
-{
- int i;
- for (i = 0; g_codec_map[i].codec_id != -1; i++) {
- if (codec_id == g_codec_map[i].codec_id) {
- return g_codec_map[i].iana;
- }
- }
- return -1;
-}
-
-static vocallo_codec_t *get_codec_from_iana(int iana, int bitrate)
-{
- int i;
- for (i = 0; g_codec_map[i].codec_id != -1; i++) {
- if (iana == g_codec_map[i].iana && !bitrate) {
- return &g_codec_map[i];
- }
- if (iana == g_codec_map[i].iana && bitrate == g_codec_map[i].bps) {
- return &g_codec_map[i];
- }
- }
- return NULL;
-}
-
-static vocallo_codec_t *get_codec_from_id(int id)
-{
- int i;
- for (i = 0; g_codec_map[i].codec_id != -1; i++) {
- if (id == g_codec_map[i].codec_id) {
- return &g_codec_map[i];
- }
- }
- return NULL;
-}
-
-static int sangoma_create_rtp_port(void *usr_priv, uint32_t host_ip, uint32_t *p_rtp_port, void **rtp_fd)
-{
- struct in_addr local_ip_addr = { 0 };
- char local_ip[255];
- switch_port_t rtp_port;
-
- local_ip_addr.s_addr = htonl(host_ip);
-
- switch_inet_ntop(AF_INET, &local_ip_addr, local_ip, sizeof(local_ip));
-
- /* request a port */
- if (!(rtp_port = switch_rtp_request_port(local_ip))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to allocate RTP port for IP %s\n", local_ip);
- return -1;
- }
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "New allocated port %d for IP %s/%d.%d.%d.%d\n", rtp_port, local_ip,
- SNGTC_NIPV4(host_ip));
- *p_rtp_port = rtp_port;
- *rtp_fd = NULL;
- return 0;
-}
-
-static int sangoma_release_rtp_port(void *usr_priv, uint32_t host_ip, uint32_t p_rtp_port, void *rtp_fd)
-{
- struct in_addr local_ip_addr = { 0 };
- char local_ip[255];
- switch_port_t rtp_port = p_rtp_port;
-
- local_ip_addr.s_addr = htonl(host_ip);
-
- switch_inet_ntop(AF_INET, &local_ip_addr, local_ip, sizeof(local_ip));
-
- /* release the port */
- switch_rtp_release_port(local_ip, rtp_port);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Released port %d for IP %s/%d.%d.%d.%d\n", rtp_port, local_ip,
- SNGTC_NIPV4(host_ip));
- return 0;
-}
-
-static int sangoma_create_rtp(void *usr_priv, sngtc_codec_request_leg_t *codec_req_leg, sngtc_codec_reply_leg_t* codec_reply_leg, void **rtp_fd)
-{
- switch_status_t status;
- switch_memory_pool_t *sesspool = NULL;
- switch_rtp_t *rtp_session = NULL;
- char codec_ip[255];
- switch_rtp_flag_t flags[SWITCH_RTP_FLAG_INVALID] = {0};
- int iana = 0;
- const char *err = NULL;
- struct in_addr local_ip_addr = { 0 };
- char local_ip[255];
- switch_port_t rtp_port;
- struct sangoma_transcoding_session *sess = usr_priv;
-
- rtp_port = codec_req_leg->host_udp_port;
- *rtp_fd = NULL;
-
- /*
- * We *MUST* use a new pool
- * Do not use the session pool since the session may go away while the RTP socket should linger around
- * until sangoma_transcode decides to kill it (possibly because the same RTP session is used for a different call)
- * also do not use the module pool otherwise memory would keep growing because switch_rtp_destroy does not
- * free the memory used (is assumed it'll be freed when the pool is destroyed)
- */
- status = switch_core_new_memory_pool(&sesspool);
- if (status != SWITCH_STATUS_SUCCESS) {
- return -1;
- }
-
- local_ip_addr.s_addr = htonl(codec_req_leg->host_ip);
- switch_inet_ntop(AF_INET, &local_ip_addr, local_ip, sizeof(local_ip));
- sngtc_codec_ipv4_hex_to_str(codec_reply_leg->codec_ip, codec_ip);
-
- iana = codec_id_to_iana(codec_req_leg->codec_id);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Creating RTP session for host (%s/%d) vocallo(%s/%d) Iana=%d CodecId=%d ms=%d idx=%lu\n",
- local_ip, rtp_port, codec_ip, codec_reply_leg->codec_udp_port, iana, codec_req_leg->codec_id,
- codec_req_leg->ms*1000, sess->sessid);
-
- /* create the RTP socket */
- rtp_session = switch_rtp_new(local_ip, rtp_port,
- codec_ip, codec_reply_leg->codec_udp_port,
- iana,
- sess->impl->samples_per_packet,
- codec_req_leg->ms * 1000, /* microseconds per packet */
- flags, NULL, &err, sesspool, 0, 0);
-
- if (!rtp_session) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create switch rtp session: %s\n", err);
- switch_core_destroy_memory_pool(&sesspool);
- return -1;
- }
- switch_rtp_set_private(rtp_session, sesspool);
- *rtp_fd = rtp_session;
-
- return 0;
-}
-
-static int sangoma_destroy_rtp(void *usr_priv, void *fd)
-{
- switch_memory_pool_t *sesspool;
- switch_rtp_t *rtp = fd;
- if (!rtp) {
- return 0;
- }
- sesspool = switch_rtp_get_private(rtp);
- switch_rtp_destroy(&rtp);
- switch_core_destroy_memory_pool(&sesspool);
- return 0;
-}
-
-static switch_status_t switch_sangoma_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
-{
- uint32_t encoding, decoding;
- struct sangoma_transcoding_session *sess = NULL;
- vocallo_codec_t *vcodec;
-
- encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
- decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sangoma init called (encoding = %d, decoding = %d, iana = %d)\n", encoding ? 1 : 0, decoding ? 1 : 0, codec->implementation->ianacode);
-
- if (!(encoding || decoding)) {
- return SWITCH_STATUS_FALSE;
- }
-
- if (!(sess = switch_core_alloc(codec->memory_pool, sizeof(*sess)))) {
- return SWITCH_STATUS_FALSE;
- }
- sess->encoder.lastrxseqno = -1;
- sess->decoder.lastrxseqno = -1;
-
- sess->pool = codec->memory_pool;
- sess->impl = codec->implementation;
- switch_assert(sess->pool);
- switch_assert(sess->impl);
-
- vcodec = get_codec_from_iana(codec->implementation->ianacode, codec->implementation->bits_per_second);
-
- if (encoding) {
- sess->encoder.request.usr_priv = sess;
- sess->encoder.request.a.host_ip = g_rtpip;
- sess->encoder.request.a.codec_id = vcodec->actual_sampling_rate == 16000
- ? SNGTC_CODEC_L16_2 : SNGTC_CODEC_L16_1;
- sess->encoder.request.a.ms = codec->implementation->microseconds_per_packet/1000;
-
- sess->encoder.request.b.host_ip = g_rtpip;
- sess->encoder.request.b.codec_id = vcodec->codec_id;
- sess->encoder.request.b.ms = codec->implementation->microseconds_per_packet/1000;
- }
-
- if (decoding) {
- sess->decoder.request.usr_priv = sess;
- sess->decoder.request.a.host_ip = g_rtpip;
- sess->decoder.request.a.codec_id = vcodec->codec_id;
- sess->decoder.request.a.ms = codec->implementation->microseconds_per_packet/1000;
-
- sess->decoder.request.b.host_ip = g_rtpip;
- sess->decoder.request.b.codec_id = vcodec->actual_sampling_rate == 16000
- ? SNGTC_CODEC_L16_2 : SNGTC_CODEC_L16_1;
- sess->decoder.request.b.ms = codec->implementation->microseconds_per_packet/1000;
-
- }
-
- switch_mutex_lock(g_sessions_lock);
-
- sess->sessid = g_next_session_id++;
- switch_snprintf(sess->hashkey, sizeof(sess->hashkey), SANGOMA_SESS_HASH_KEY_FORMAT, sess->sessid);
- switch_core_hash_insert(g_sessions_hash, sess->hashkey, sess);
-
- switch_mutex_unlock(g_sessions_lock);
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sangoma init done for codec %s/%s, iana = %d\n", codec->implementation->iananame, vcodec->fs_name, codec->implementation->ianacode);
- codec->private_info = sess;
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t switch_sangoma_init_ilbc(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
-{
- int mode = codec->implementation->microseconds_per_packet / 1000;
- if (codec->fmtp_in) {
- int x, argc;
- char *argv[10];
- argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0])));
- for (x = 0; x < argc; x++) {
- char *data = argv[x];
- char *arg;
- switch_assert(data);
- while (*data == ' ') {
- data++;
- }
- if ((arg = strchr(data, '='))) {
- *arg++ = '\0';
- if (!strcasecmp(data, "mode")) {
- mode = atoi(arg);
- }
- }
- }
- }
- codec->fmtp_out = switch_core_sprintf(codec->memory_pool, "mode=%d", mode);
- return switch_sangoma_init(codec, flags, codec_settings);
-}
-
-static switch_status_t switch_sangoma_init_siren7(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
-{
- int bit_rate = codec->implementation->bits_per_second;
- codec->fmtp_out = switch_core_sprintf(codec->memory_pool, "bitrate=%d", bit_rate);
- return switch_sangoma_init(codec, flags, codec_settings);
-}
-
-static switch_status_t switch_sangoma_init_g729(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
-{
- if (codec->fmtp_in) {
- codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in);
- }
-
- return switch_sangoma_init(codec, flags, codec_settings);
-}
-
-static void flush_rtp(switch_rtp_t *rtp)
-{
- switch_status_t sres;
- switch_frame_t read_frame;
- int flushed = 0;
- int sanity = 1000;
- while (sanity--) {
- sres = switch_rtp_zerocopy_read_frame(rtp, &read_frame, SWITCH_IO_FLAG_NOBLOCK);
- if (sres == SWITCH_STATUS_GENERR) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to read on Sangoma encoder RTP session while flushing: %d\n", sres);
- return;
- }
- if (!read_frame.datalen) {
- break;
- }
- flushed++;
- }
- if (!sanity) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Insanely big UDP queue!\n");
- }
-}
-
-#define SAFE_INDEX_INC(array, index) \
- (index)++; \
- if ((index) == switch_arraylen((array))) { \
- (index) = 0; \
- }
-
-static switch_status_t switch_sangoma_encode(switch_codec_t *codec, switch_codec_t *other_codec, /* codec that was used by the other side */
- void *decoded_data, /* decoded data that we must encode */
- uint32_t decoded_data_len /* decoded data length */ ,
- uint32_t decoded_rate /* rate of the decoded data */ ,
- void *encoded_data, /* here we will store the encoded data */
- uint32_t *encoded_data_len, /* here we will set the length of the encoded data */
- uint32_t *encoded_rate /* here we will set the rate of the encoded data */ ,
- unsigned int *flag /* frame flag, see switch_frame_flag_enum_t */ )
-{
- /* FS core checks the actual samples per second and microseconds per packet to determine the buffer size in the worst case scenario, no need to check
- * whether the buffer passed in by the core (encoded_data) will be big enough */
- switch_frame_t linear_frame;
- switch_frame_t encoded_frame;
- switch_status_t sres = SWITCH_STATUS_FALSE;
- uint16_t decoded_byteswapped_data[SWITCH_RECOMMENDED_BUFFER_SIZE];
- uint16_t *decoded_data_linear = decoded_data;
- switch_time_t now_time = 0, difftime = 0;
- switch_time_t func_start_time = 0, func_end_time = 0;
- int i = 0;
- int res = 0;
- int linear_payload = codec->implementation->actual_samples_per_second == 8000 ? IANA_L16_A_8000_1 : IANA_L16_A_16000_1;
- struct sangoma_transcoding_session *sess = codec->private_info;
-
- if (sess->encoder.debug_timing) {
- func_start_time = switch_micro_time_now();
- }
-
- sess->encoder.ticks++;
-
- /* start assuming we will not encode anything */
- *encoded_data_len = 0;
-
- /* initialize on first use */
- if (!sess->encoder.txrtp) {
- int err = 0;
- switch_mutex_lock(g_sessions_lock);
- err = sngtc_create_transcoding_session(&sess->encoder.request, &sess->encoder.reply, 0);
- if (err) {
- memset(&sess->encoder, 0, sizeof(sess->encoder));
- switch_mutex_unlock(g_sessions_lock);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create Sangoma encoding session.\n");
- return SWITCH_STATUS_FALSE;
- }
- sess->encoder.txrtp = sess->encoder.reply.tx_fd;
- sess->encoder.rxrtp = sess->encoder.reply.rx_fd;
- switch_mutex_unlock(g_sessions_lock);
- flush_rtp(sess->encoder.rxrtp);
- }
-
- if (sess->encoder.debug_timing && sess->encoder.last_func_call_time) {
- difftime = func_start_time - sess->encoder.last_func_call_time;
- if (difftime > 25000 || difftime < 15000) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%ldus since last read on encoding session %lu\n", (long)difftime, sess->sessid);
- }
- }
-
- /* do the writing */
- memset(&linear_frame, 0, sizeof(linear_frame));
- linear_frame.source = __SWITCH_FUNC__;
- linear_frame.data = decoded_byteswapped_data;
- linear_frame.datalen = decoded_data_len;
- linear_frame.payload = linear_payload;
-
- /* copy and byte-swap */
- for (i = 0; i < decoded_data_len/2; i++) {
- decoded_byteswapped_data[i] = (decoded_data_linear[i] << 8) | (decoded_data_linear[i] >> 8);
- }
-
-
- res = switch_rtp_write_frame(sess->encoder.txrtp, &linear_frame);
- if (-1 == res) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to write to Sangoma encoder RTP session.\n");
- return SWITCH_STATUS_FALSE;
- }
-
- if (res < i) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
- "Requested to write %d bytes to Sangoma encoder RTP session, but wrote %d bytes.\n", i, res);
- return SWITCH_STATUS_FALSE;
- }
- sess->encoder.tx++;
-
- /* do the reading */
- for ( ; ; ) {
-#if 0
- prevread_time = switch_micro_time_now();
-#endif
- sres = switch_rtp_zerocopy_read_frame(sess->encoder.rxrtp, &encoded_frame, SWITCH_IO_FLAG_NOBLOCK);
- if (sres == SWITCH_STATUS_GENERR) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to read on Sangoma encoder RTP session: %d\n", sres);
- return SWITCH_STATUS_FALSE;
- }
-
-#if 0
- afterread_time = switch_micro_time_now();
- difftime = afterread_time - prevread_time;
- if (difftime > 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%ldus to read on encoding session %lu.\n", (long)difftime, sess->sessid);
- }
-#endif
- if (0 == encoded_frame.datalen) {
- break;
- }
-
- if (encoded_frame.payload == IANACODE_CN) {
- /* confort noise is treated as silence by us */
- continue;
- }
-
- if (codec->implementation->encoded_bytes_per_packet && encoded_frame.datalen != codec->implementation->encoded_bytes_per_packet) {
- /* seen when silence suppression is enabled */
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring encoded frame of %d bytes intead of %d bytes\n", encoded_frame.datalen, codec->implementation->encoded_bytes_per_packet);
- continue;
- }
-
- if (encoded_frame.payload != codec->implementation->ianacode) {
- if (sess->encoder.request.b.codec_id == SNGTC_CODEC_ILBC_152 || sess->encoder.request.b.codec_id == SNGTC_CODEC_ILBC_133) {
- /* since we moved to SOAP based communications, the mapping between vocallo IANA and our IANA does not work,
- * some codecs checks cannot be completely done, like iLBC */
- if (encoded_frame.payload != IANA_ILBC_152_8000_1 && encoded_frame.payload != IANA_ILBC_133_8000_1) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Read unexpected payload %d in Sangoma encoder RTP session, expecting either %d or %d\n",
- encoded_frame.payload, IANA_ILBC_152_8000_1, IANA_ILBC_133_8000_1);
- break;
- }
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Read unexpected payload %d in Sangoma encoder RTP session, expecting %d\n",
- encoded_frame.payload, codec->implementation->ianacode);
- break;
- }
- }
-
- if (sess->encoder.queue_windex == sess->encoder.queue_rindex) {
- if (sess->encoder.rtp_queue[sess->encoder.queue_rindex].datalen) {
- /* if there is something where we want to write, we're dropping it */
- sess->encoder.rxdiscarded++;
-#if 0
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Discarding encoded frame of %d bytes from RTP session %lu, windex = %d, rindex = %d\n",
- sess->encoder.rtp_queue[sess->encoder.queue_rindex].datalen, sess->sessid, sess->encoder.queue_windex, sess->encoder.queue_rindex);
-#endif
- SAFE_INDEX_INC(sess->encoder.rtp_queue, sess->encoder.queue_rindex);
- sess->encoder.queue_size--;
- }
- }
-
- memcpy(sess->encoder.rtp_queue[sess->encoder.queue_windex].data, encoded_frame.data, encoded_frame.datalen);
- sess->encoder.rtp_queue[sess->encoder.queue_windex].datalen = encoded_frame.datalen;
- SAFE_INDEX_INC(sess->encoder.rtp_queue, sess->encoder.queue_windex);
-
- /* monitor the queue size */
- sess->encoder.queue_size++;
- if (sess->encoder.queue_size > sess->encoder.queue_max_ever) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Encoder Rx queue for RTP session %lu is now %d, windex = %d, rindex = %d\n", sess->sessid, sess->encoder.queue_size,
- sess->encoder.queue_windex, sess->encoder.queue_rindex);
- sess->encoder.queue_max_ever = sess->encoder.queue_size;
- }
- }
-
- /* update encoding stats if we have a frame to give */
- if (sess->encoder.rtp_queue[sess->encoder.queue_rindex].datalen) {
- sess->encoder.rx++;
- now_time = switch_micro_time_now();
- if (!sess->encoder.last_rx_time) {
- sess->encoder.last_rx_time = now_time;
- } else {
- difftime = now_time - sess->encoder.last_rx_time;
- sess->encoder.avgrxus = sess->encoder.avgrxus ? ((sess->encoder.avgrxus + difftime)/2) : difftime;
- sess->encoder.last_rx_time = now_time;
- }
-
- /* check sequence and bump lost rx packets count if needed */
- if (sess->encoder.lastrxseqno >= 0) {
- if (encoded_frame.seq > (sess->encoder.lastrxseqno + 2) ) {
- sess->encoder.rxlost += encoded_frame.seq - sess->encoder.lastrxseqno - 1;
- }
- }
- sess->encoder.lastrxseqno = encoded_frame.seq;
-
- /* pop the data from the queue */
- *encoded_data_len = sess->encoder.rtp_queue[sess->encoder.queue_rindex].datalen;
- memcpy(encoded_data, sess->encoder.rtp_queue[sess->encoder.queue_rindex].data, *encoded_data_len);
- sess->encoder.rtp_queue[sess->encoder.queue_rindex].datalen = 0;
- SAFE_INDEX_INC(sess->encoder.rtp_queue, sess->encoder.queue_rindex);
- sess->encoder.queue_size--;
- if (codec->implementation->encoded_bytes_per_packet && *encoded_data_len != codec->implementation->encoded_bytes_per_packet) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Returning odd encoded frame of %d bytes intead of %d bytes\n", *encoded_data_len, codec->implementation->encoded_bytes_per_packet);
- }
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No output from sangoma encoder\n");
- }
-
- if (sess->encoder.debug_timing) {
- func_end_time = switch_micro_time_now();
- difftime = func_end_time - func_start_time;
- if (difftime > 5000) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%ldus to execute encoding function in session %lu.\n", (long)difftime, sess->sessid);
- }
- sess->encoder.last_func_call_time = func_end_time;
- }
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t switch_sangoma_decode(switch_codec_t *codec, /* codec session handle */
- switch_codec_t *other_codec, /* what is this? */
- void *encoded_data, /* data that we must decode into slinear and put it in decoded_data */
- uint32_t encoded_data_len, /* length in bytes of the encoded data */
- uint32_t encoded_rate, /* at which rate was the data encoded */
- void *decoded_data, /* buffer where we must put the decoded data */
- uint32_t *decoded_data_len, /* we must set this value to the size of the decoded data */
- uint32_t *decoded_rate, /* rate of the decoded data */
- unsigned int *flag /* frame flag, see switch_frame_flag_enum_t */ )
-{
- /* FS core checks the actual samples per second and microseconds per packet to determine the buffer size in the worst case scenario, no need to check
- * whether the buffer passed in by the core will be enough */
- switch_frame_t encoded_frame;
- switch_frame_t linear_frame;
- switch_status_t sres = SWITCH_STATUS_FALSE;
- switch_time_t now_time = 0, difftime = 0;
- switch_time_t func_start_time = 0, func_end_time = 0;
- uint16_t *dbuf_linear;
- uint16_t *linear_frame_data;
- uint16_t *rtp_data_linear;
- int res = 0;
- int i = 0;
- int linear_payload = codec->implementation->actual_samples_per_second == 8000 ? IANA_L16_A_8000_1 : IANA_L16_A_16000_1;
- struct sangoma_transcoding_session *sess = codec->private_info;
-
- if (sess->decoder.debug_timing) {
- func_start_time = switch_micro_time_now();
- }
-
- dbuf_linear = decoded_data;
- sess->decoder.ticks++;
-
- /* start assuming we will not decode anything */
- *decoded_data_len = 0;
- if (*flag & SWITCH_CODEC_FLAG_SILENCE) {
- memset(dbuf_linear, 0, codec->implementation->decoded_bytes_per_packet);
- *decoded_data_len = codec->implementation->decoded_bytes_per_packet;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Returned silence on request\n");
- return SWITCH_STATUS_SUCCESS;
- }
-
- /* initialize on first use */
- if (!sess->decoder.txrtp) {
- int err = 0;
- switch_mutex_lock(g_sessions_lock);
- err = sngtc_create_transcoding_session(&sess->decoder.request, &sess->decoder.reply, 0);
- if (err) {
- memset(&sess->decoder, 0, sizeof(sess->decoder));
- switch_mutex_unlock(g_sessions_lock);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create Sangoma decoding session.\n");
- return SWITCH_STATUS_FALSE;
- }
- sess->decoder.txrtp = sess->decoder.reply.tx_fd;
- sess->decoder.rxrtp = sess->decoder.reply.rx_fd;
- switch_mutex_unlock(g_sessions_lock);
- flush_rtp(sess->decoder.rxrtp);
- }
-
- if (sess->decoder.debug_timing && sess->decoder.last_func_call_time) {
- difftime = func_start_time - sess->decoder.last_func_call_time;
- if (difftime > 25000 || difftime < 15000) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%ldms since last read on decoding session %lu.\n", (long)difftime, sess->sessid);
- }
- }
-
- /* do the writing */
- memset(&encoded_frame, 0, sizeof(encoded_frame));
- encoded_frame.source = __SWITCH_FUNC__;
- encoded_frame.data = encoded_data;
- encoded_frame.datalen = encoded_data_len;
- encoded_frame.payload = codec->implementation->ianacode;
-
- res = switch_rtp_write_frame(sess->decoder.txrtp, &encoded_frame);
- if (-1 == res) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to write to Sangoma decoder RTP session.\n");
- return SWITCH_STATUS_FALSE;
- }
-
- if (res < encoded_data_len) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
- "Requested to write %d bytes to Sangoma decoder RTP session, but wrote %d bytes.\n",
- encoded_data_len, res);
- return SWITCH_STATUS_FALSE;
- }
- sess->decoder.tx++;
-
- /* do the reading */
- for ( ; ; ) {
-#if 0
- prevread_time = switch_micro_time_now();
-#endif
- sres = switch_rtp_zerocopy_read_frame(sess->decoder.rxrtp, &linear_frame, SWITCH_IO_FLAG_NOBLOCK);
- if (sres == SWITCH_STATUS_GENERR) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to read on Sangoma decoder RTP session: %d\n", sres);
- return SWITCH_STATUS_FALSE;
- }
-
-#if 0
- afterread_time = switch_micro_time_now();
- difftime = afterread_time - prevread_time;
- if (difftime > 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%ldus to read on decoding session %lu.\n", (long)difftime, sess->sessid);
- }
-#endif
- if (0 == linear_frame.datalen) {
- break;
- }
-
- if (linear_frame.payload == IANACODE_CN) {
- /* confort noise is treated as silence by us */
- continue;
- }
-
- if (linear_frame.payload != linear_payload) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Read unexpected payload %d in Sangoma decoder RTP session, expecting %d\n",
- linear_frame.payload, linear_payload);
- break;
- }
-
-
- if (sess->decoder.queue_windex == sess->decoder.queue_rindex) {
- if (sess->decoder.rtp_queue[sess->decoder.queue_rindex].datalen) {
- /* if there is something where we want to write, we're dropping it */
- sess->decoder.rxdiscarded++;
-#if 0
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Discarding decoded frame of %d bytes from RTP session %lu, windex = %d, rindex = %d\n",
- sess->decoder.rtp_queue[sess->decoder.queue_rindex].datalen, sess->sessid, sess->decoder.queue_windex, sess->decoder.queue_rindex);
-#endif
- SAFE_INDEX_INC(sess->decoder.rtp_queue, sess->decoder.queue_rindex);
- sess->decoder.queue_size--;
- }
- }
-
- /* byteswap the received data */
- rtp_data_linear = (unsigned short *)sess->decoder.rtp_queue[sess->decoder.queue_windex].data;
- linear_frame_data = linear_frame.data;
- for (i = 0; i < linear_frame.datalen/2; i++) {
- rtp_data_linear[i] = (linear_frame_data[i] << 8) | (linear_frame_data[i] >> 8);
- }
- sess->decoder.rtp_queue[sess->decoder.queue_windex].datalen = linear_frame.datalen;
-
- SAFE_INDEX_INC(sess->decoder.rtp_queue, sess->decoder.queue_windex);
-
- /* monitor the queue size */
- sess->decoder.queue_size++;
- if (sess->decoder.queue_size > sess->decoder.queue_max_ever) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Encoder Rx queue for RTP session %lu is now %d, windex = %d, rindex = %d\n", sess->sessid, sess->decoder.queue_size,
- sess->decoder.queue_windex, sess->decoder.queue_rindex);
- sess->decoder.queue_max_ever = sess->decoder.queue_size;
- }
- }
-
- if (sess->decoder.rtp_queue[sess->decoder.queue_rindex].datalen) {
- /* update decoding stats */
- sess->decoder.rx++;
-
- now_time = switch_micro_time_now();
- if (!sess->decoder.last_rx_time) {
- sess->decoder.last_rx_time = now_time;
- } else {
- difftime = now_time - sess->decoder.last_rx_time;
- sess->decoder.avgrxus = sess->decoder.avgrxus ? ((sess->decoder.avgrxus + difftime)/2) : difftime;
- sess->decoder.last_rx_time = now_time;
- }
-
- /* check sequence and bump lost rx packets count if needed */
- if (sess->decoder.lastrxseqno >= 0) {
- if (linear_frame.seq > (sess->decoder.lastrxseqno + 2) ) {
- sess->decoder.rxlost += linear_frame.seq - sess->decoder.lastrxseqno - 1;
- }
- }
- sess->decoder.lastrxseqno = linear_frame.seq;
-
- /* pop the data from the queue */
- memcpy(dbuf_linear, sess->decoder.rtp_queue[sess->decoder.queue_rindex].data, sess->decoder.rtp_queue[sess->decoder.queue_rindex].datalen);
- *decoded_data_len = sess->decoder.rtp_queue[sess->decoder.queue_rindex].datalen;
- sess->decoder.rtp_queue[sess->decoder.queue_rindex].datalen = 0;
- SAFE_INDEX_INC(sess->decoder.rtp_queue, sess->decoder.queue_rindex);
- sess->decoder.queue_size--;
-
- if (*decoded_data_len != codec->implementation->decoded_bytes_per_packet) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Returning odd decoded frame of %d bytes intead of %d bytes\n", *decoded_data_len, codec->implementation->decoded_bytes_per_packet);
- }
- } else {
- *decoded_data_len = codec->implementation->decoded_bytes_per_packet;
- memset(dbuf_linear, 0, *decoded_data_len);
- }
-
- if (sess->decoder.debug_timing) {
- func_end_time = switch_micro_time_now();
- difftime = func_end_time - func_start_time;
- if (difftime > 5000) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%ldus to execute decoding function in session %lu.\n", (long)difftime, sess->sessid);
- }
- sess->decoder.last_func_call_time = func_end_time;
- }
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t switch_sangoma_destroy(switch_codec_t *codec)
-{
- struct sangoma_transcoding_session *sess = codec->private_info;
- /* things that you may do here is closing files, sockets or other resources used during the codec session
- * no need to free memory allocated from the pool though, the owner of the pool takes care of that */
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sangoma destroy called.\n");
-
- switch_mutex_lock(g_sessions_lock);
-
- if (sess->encoder.txrtp) {
- sngtc_free_transcoding_session(&sess->encoder.reply);
- }
- if (sess->decoder.txrtp) {
- sngtc_free_transcoding_session(&sess->decoder.reply);
- }
-
- switch_core_hash_delete(g_sessions_hash, sess->hashkey);
- memset(sess, 0, sizeof(*sess));
-
- switch_mutex_unlock(g_sessions_lock);
- return SWITCH_STATUS_SUCCESS;
-}
-
-static struct sangoma_transcoding_session *sangoma_find_session(unsigned long sessid)
-{
- char hashkey[50];
- snprintf(hashkey, sizeof(hashkey), SANGOMA_SESS_HASH_KEY_FORMAT, sessid);
- return switch_core_hash_find(g_sessions_hash, hashkey);
-}
-
-static void sangoma_print_stats(switch_stream_handle_t *stream, switch_rtp_numbers_t *stats)
-{
- stream->write_function(stream, "Raw bytes: %lu\n", stats->raw_bytes);
- stream->write_function(stream, "Media bytes: %lu\n", stats->media_bytes);
- stream->write_function(stream, "Packet count: %lu\n", stats->packet_count);
- stream->write_function(stream, "Media packet count: %lu\n", stats->media_packet_count);
- stream->write_function(stream, "Skip packet count: %lu\n", stats->skip_packet_count);
- stream->write_function(stream, "Jitter buffer packet count: %lu\n", stats->jb_packet_count);
- stream->write_function(stream, "DTMF packet count: %lu\n", stats->dtmf_packet_count);
- stream->write_function(stream, "CNG packet count: %lu\n", stats->cng_packet_count);
- stream->write_function(stream, "Flush packet count: %lu\n\n\n", stats->flush_packet_count);
-}
-
-#define SANGOMA_SYNTAX "settings|sessions|stats <session>|debug <session>|nodebug <session>"
-SWITCH_STANDARD_API(sangoma_function)
-{
- char *argv[10] = { 0 };
- int argc = 0;
- char *mycmd = NULL;
- switch_bool_t locked = SWITCH_FALSE;
-
- if (zstr(cmd)) {
- stream->write_function(stream, "%s", SANGOMA_SYNTAX);
- return SWITCH_STATUS_SUCCESS;
- }
-
- if (!(mycmd = strdup(cmd))) {
- return SWITCH_STATUS_MEMERR;
- }
-
- if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) {
- stream->write_function(stream, "%s", SANGOMA_SYNTAX);
- switch_safe_free(mycmd);
- return SWITCH_STATUS_SUCCESS;
- }
-
- /* Most operations in this API require the global session lock anyways since sessions can disappear at any moment ... */
- switch_mutex_lock(g_sessions_lock);
- locked = SWITCH_TRUE;
-
- if (!strcasecmp(argv[0], "settings")) {
- char addrbuff[50];
- int addr;
- addr = htonl(g_rtpip);
- stream->write_function(stream, "\tRTP IP Address: %s\n",
- switch_inet_ntop(AF_INET, &addr, addrbuff, sizeof(addrbuff)));
- } else if (!strcasecmp(argv[0], "sessions")) {
- /* iterate over sessions hash */
- switch_hash_index_t *hi;
- const void *var;
- void *val;
- unsigned totalsess = 0;
-#define STATS_FORMAT "%-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-15.15s %-15.15s\n"
- stream->write_function(stream, STATS_FORMAT,
- "Session", "Codec", "Enc", "Dec", "Enc Tx", "Enc Rx", "Dec Tx", "Dec Rx", "Enc Lost", "Dec Lost", "Enc AvgRxMs", "Dec AvgRxMs");
- for (hi = switch_core_hash_first(g_sessions_hash); hi; hi = switch_core_hash_next(&hi)) {
- struct sangoma_transcoding_session *sess;
- char sessid_str[25];
- char encoder_tx_str[25];
- char encoder_rx_str[25];
- char decoder_tx_str[25];
- char decoder_rx_str[25];
- char encoder_lostrx_str[25];
- char decoder_lostrx_str[25];
- char encoder_avgrxus_str[25];
- char decoder_avgrxus_str[25];
-
- switch_core_hash_this(hi, &var, NULL, &val);
- sess = val;
-
- snprintf(sessid_str, sizeof(sessid_str), "%lu", sess->sessid);
- snprintf(encoder_tx_str, sizeof(encoder_tx_str), "%lu", sess->encoder.tx);
- snprintf(encoder_rx_str, sizeof(encoder_rx_str), "%lu", sess->encoder.rx);
- snprintf(decoder_tx_str, sizeof(decoder_tx_str), "%lu", sess->decoder.tx);
- snprintf(decoder_rx_str, sizeof(decoder_rx_str), "%lu", sess->decoder.rx);
- snprintf(encoder_lostrx_str, sizeof(encoder_lostrx_str), "%lu", sess->encoder.rxlost);
- snprintf(decoder_lostrx_str, sizeof(decoder_lostrx_str), "%lu", sess->decoder.rxlost);
- snprintf(encoder_avgrxus_str, sizeof(encoder_avgrxus_str), "%ld", (long)(sess->encoder.avgrxus/1000));
- snprintf(decoder_avgrxus_str, sizeof(encoder_avgrxus_str), "%ld", (long)(sess->decoder.avgrxus/1000));
-
-
- stream->write_function(stream, STATS_FORMAT,
- sessid_str,
- sess->impl->iananame,
- sess->encoder.txrtp ? "Yes" : "No",
- sess->decoder.txrtp ? "Yes" : "No",
- encoder_tx_str,
- encoder_rx_str,
- decoder_tx_str,
- decoder_rx_str,
- encoder_lostrx_str,
- decoder_lostrx_str,
- encoder_avgrxus_str,
- decoder_avgrxus_str);
- totalsess++;
- }
- stream->write_function(stream, "Total sessions: %d\n", totalsess);
- } else if (!strcasecmp(argv[0], "stats")) {
- struct sangoma_transcoding_session *sess;
- unsigned long sessid = 0;
- switch_rtp_stats_t *stats = NULL;
- int ret = 0;
- if (argc < 2) {
- stream->write_function(stream, "%s", SANGOMA_SYNTAX);
- goto done;
- }
- ret = sscanf(argv[1], "%lu", &sessid);
- if (ret != 1) {
- stream->write_function(stream, "%s", SANGOMA_SYNTAX);
- goto done;
- }
-
- sess = sangoma_find_session(sessid);
- if (!sess) {
- stream->write_function(stream, "Failed to find session %lu\n", sessid);
- goto done;
- }
- stream->write_function(stream, "Stats for transcoding session: %lu\n", sessid);
-
- if (sess->encoder.rxrtp) {
- stats = switch_rtp_get_stats(sess->encoder.rxrtp, NULL);
- stream->write_function(stream, "=== %s Encoder ===\n", sess->impl->iananame);
-
- stream->write_function(stream, "Tx L16 from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n\n", SNGTC_NIPV4(sess->encoder.reply.a.host_ip), sess->encoder.reply.a.host_udp_port,
- SNGTC_NIPV4(sess->encoder.reply.a.codec_ip), sess->encoder.reply.a.codec_udp_port);
- stream->write_function(stream, "Rx %s at %d.%d.%d.%d:%d from %d.%d.%d.%d:%d\n\n", sess->impl->iananame, SNGTC_NIPV4(sess->encoder.reply.b.host_ip), sess->encoder.reply.b.host_udp_port,
- SNGTC_NIPV4(sess->encoder.reply.b.codec_ip), sess->encoder.reply.b.codec_udp_port);
-
- stream->write_function(stream, "Ticks: %lu\n", sess->encoder.ticks);
-
- stream->write_function(stream, "-- Inbound Stats --\n");
- stream->write_function(stream, "Rx Discarded: %lu\n", sess->encoder.rxdiscarded);
- sangoma_print_stats(stream, &stats->inbound);
-
-
- stats = switch_rtp_get_stats(sess->encoder.txrtp, NULL);
- stream->write_function(stream, "-- Outbound Stats --\n");
- sangoma_print_stats(stream, &stats->outbound);
- }
-
- if (sess->decoder.rxrtp) {
- stats = switch_rtp_get_stats(sess->decoder.rxrtp, NULL);
-
- stream->write_function(stream, "=== %s Decoder ===\n", sess->impl->iananame);
- stream->write_function(stream, "Tx %s from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n\n", sess->impl->iananame, SNGTC_NIPV4(sess->decoder.reply.a.host_ip), sess->decoder.reply.a.host_udp_port,
- SNGTC_NIPV4(sess->decoder.reply.a.codec_ip), sess->decoder.reply.a.codec_udp_port);
- stream->write_function(stream, "Rx L16 at %d.%d.%d.%d:%d from %d.%d.%d.%d:%d\n\n", SNGTC_NIPV4(sess->decoder.reply.b.host_ip), sess->decoder.reply.b.host_udp_port,
- SNGTC_NIPV4(sess->decoder.reply.b.codec_ip), sess->decoder.reply.b.codec_udp_port);
- stream->write_function(stream, "Ticks: %lu\n", sess->decoder.ticks);
-
- stream->write_function(stream, "-- Inbound Stats --\n");
- stream->write_function(stream, "Rx Discarded: %lu\n", sess->decoder.rxdiscarded);
- sangoma_print_stats(stream, &stats->inbound);
-
- stats = switch_rtp_get_stats(sess->decoder.txrtp, NULL);
- stream->write_function(stream, "-- Outbound Stats --\n");
- sangoma_print_stats(stream, &stats->outbound);
- }
- } else if (!strcasecmp(argv[0], "debug")) {
- struct sangoma_transcoding_session *sess;
- unsigned long sessid = 0;
- int ret = 0;
- if (argc < 2) {
- stream->write_function(stream, "%s", SANGOMA_SYNTAX);
- goto done;
- }
- ret = sscanf(argv[1], "%lu", &sessid);
- if (ret != 1) {
- stream->write_function(stream, "%s", SANGOMA_SYNTAX);
- goto done;
- }
- sess = sangoma_find_session(sessid);
- if (!sess) {
- stream->write_function(stream, "Failed to find session %lu\n", sessid);
- goto done;
- }
- sess->encoder.debug_timing = 1;
- sess->decoder.debug_timing = 1;
- stream->write_function(stream, "Debug enabled for transcoding session: %lu\n", sessid);
- } else if (!strcasecmp(argv[0], "nodebug")) {
- struct sangoma_transcoding_session *sess;
- unsigned long sessid = 0;
- int ret = 0;
- if (argc < 2) {
- stream->write_function(stream, "%s", SANGOMA_SYNTAX);
- goto done;
- }
- ret = sscanf(argv[1], "%lu", &sessid);
- if (ret != 1) {
- stream->write_function(stream, "%s", SANGOMA_SYNTAX);
- goto done;
- }
- sess = sangoma_find_session(sessid);
- if (!sess) {
- stream->write_function(stream, "Failed to find session %lu\n", sessid);
- goto done;
- }
- sess->encoder.debug_timing = 0;
- sess->decoder.debug_timing = 0;
- stream->write_function(stream, "Debug disabled for transcoding session: %lu\n", sessid);
- } else {
- stream->write_function(stream, "Unknown Command [%s]\n", argv[0]);
- }
-
-done:
- if (locked) {
- switch_mutex_unlock(g_sessions_lock);
- }
- switch_safe_free(mycmd);
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static int sangoma_logger(int level, char *fmt, ...)
-{
- char *data;
- int ret = 0;
- va_list ap;
-
- va_start(ap, fmt);
- ret = switch_vasprintf(&data, fmt, ap);
- if (ret == -1) {
- return -1;
- }
- va_end(ap);
-
- switch (level) {
- case SNGTC_LOGLEVEL_DEBUG:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s\n", data);
- break;
- case SNGTC_LOGLEVEL_WARN:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s\n", data);
- break;
- case SNGTC_LOGLEVEL_INFO:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", data);
- break;
- case SNGTC_LOGLEVEL_STATS:
- break;
- case SNGTC_LOGLEVEL_ERROR:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", data);
- break;
- case SNGTC_LOGLEVEL_CRIT:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%s\n", data);
- break;
- default:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unexpected msg with loglevel %d: %s\n", level, data);
- }
-
- free(data);
- return 0;
-}
-
-static int sangoma_parse_config(void)
-{
- switch_xml_t cfg, settings, param, xml;
- struct in_addr rtpaddr;
- char localip[255];
- int mask = 0;
- int rc = 0;
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Reading sangoma codec configuration\n");
- if (!(xml = switch_xml_open_cfg(SANGOMA_TRANSCODE_CONFIG, &cfg, NULL))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to open sangoma codec configuration %s\n", SANGOMA_TRANSCODE_CONFIG);
- return -1;
- }
-
- memset(&g_init_cfg, 0, sizeof(g_init_cfg));
-
- if ((settings = switch_xml_child(cfg, "settings"))) {
- for (param = switch_xml_child(settings, "param"); param; param = param->next) {
- char *var = (char *)switch_xml_attr_soft(param, "name");
- char *val = (char *)switch_xml_attr_soft(param, "value");
-
- /* this parameter overrides the default list of codecs to load */
- if (!strcasecmp(var, "register")) {
- strncpy(g_codec_register_list, val, sizeof(g_codec_register_list)-1);
- g_codec_register_list[sizeof(g_codec_register_list)-1] = 0;
- } else if (!strcasecmp(var, "noregister")) {
- strncpy(g_codec_noregister_list, val, sizeof(g_codec_noregister_list)-1);
- g_codec_noregister_list[sizeof(g_codec_noregister_list)-1] = 0;
- } else if (!strcasecmp(var, "soapserver")) {
- strncpy(g_soap_url, val, sizeof(g_soap_url)-1);
- g_soap_url[sizeof(g_soap_url)-1] = 0;
- } else if (!strcasecmp(var, "rtpip")) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Found Sangoma RTP IP %s\n", val);
- if (switch_inet_pton(AF_INET, val, &rtpaddr) <= 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid Sangoma RTP IP %s\n", val);
- break;
- }
- g_rtpip = ntohl(rtpaddr.s_addr);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignored unknown Sangoma codec setting %s\n", var);
- }
- }
- }
-
- if (!g_rtpip) {
- if (SWITCH_STATUS_SUCCESS != switch_find_local_ip(localip, sizeof(localip), &mask, AF_INET)) {
- rc = -1;
- goto done;
- }
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "No RTP IP specified, using %s\n", localip);
- switch_inet_pton(AF_INET, localip, &rtpaddr);
- g_rtpip = ntohl(rtpaddr.s_addr);
- }
-
-done:
- switch_xml_free(xml);
-
- g_init_cfg.host_nic_vocallo_sz = 0;
-
- return rc;
-}
-
-SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sangoma_codec_shutdown)
-{
- switch_core_hash_destroy(&g_sessions_hash);
- return SWITCH_STATUS_SUCCESS;
-}
-
-SWITCH_MODULE_LOAD_FUNCTION(mod_sangoma_codec_load)
-{
- /* the codec interface that will be registered with the core */
- switch_codec_interface_t *codec_interface = NULL;
- switch_api_interface_t *api_interface = NULL;
- int i = 0, c = 0;
- int ilbc_done = 0;
- int siren_done = 0;
- vocallo_codec_t *ilbc_codec = NULL;
- vocallo_codec_t *siren_codec = NULL;
- int detected = 0, activated = 0;
-
- /* make sure we have valid configuration */
- if (sangoma_parse_config()) {
- return SWITCH_STATUS_FALSE;
- }
-
- g_init_cfg.log = sangoma_logger;
- g_init_cfg.create_rtp = sangoma_create_rtp;
- g_init_cfg.create_rtp_port = sangoma_create_rtp_port;
- g_init_cfg.destroy_rtp = sangoma_destroy_rtp;
- g_init_cfg.release_rtp_port = sangoma_release_rtp_port;
-
- if (sngtc_detect_init_modules(&g_init_cfg, &detected)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to detect vocallo modules\n");
- return SWITCH_STATUS_FALSE;
- }
-
- if (sngtc_activate_modules(&g_init_cfg, &activated)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to activate vocallo modules\n");
- return SWITCH_STATUS_FALSE;
- }
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Detected %d and activated %d Sangoma codec vocallo modules\n", detected, activated);
-
- if (strlen(g_soap_url)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Using %s SOAP server\n", g_soap_url);
- sngtc_set_soap_server_url(g_soap_url);
- }
-
- switch_mutex_init(&g_sessions_lock, SWITCH_MUTEX_UNNESTED, pool);
-
- switch_core_hash_init(&g_sessions_hash);
-
- *module_interface = switch_loadable_module_create_module_interface(pool, modname);
-
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading codecs, register='%s', noregister='%s'\n", g_codec_register_list, g_codec_noregister_list);
- for (c = 0; g_codec_map[c].codec_id != -1; c++) {
-
- if (g_codec_map[c].codec_id == SNGTC_CODEC_L16_1 || g_codec_map[c].codec_id == SNGTC_CODEC_L16_2) {
- /* registering L16 does not make any sense */
- continue;
- }
-
- /* check if the codec is in the load list, otherwise skip it */
- if (strcasecmp(g_codec_register_list, "all") && !strcasestr(g_codec_register_list, g_codec_map[c].iana_name)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Not loading codec %s because was not found in the load list\n",
- g_codec_map[c].iana_name);
- continue;
- }
-
- /* load it unless is named in the noload list */
- if (strcasestr(g_codec_noregister_list, g_codec_map[c].iana_name)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Not loading codec %s because was not found in the noload list\n",
- g_codec_map[c].iana_name);
- continue;
- }
-
- /* special check for iLBC to add a single codec interface for both ILBC bitrate versions */
- if ((g_codec_map[c].codec_id == SNGTC_CODEC_ILBC_152 || g_codec_map[c].codec_id == SNGTC_CODEC_ILBC_133) && ilbc_done) {
- continue;
- }
-
- /* special check for siren to add a single codec interface for all siren bitrate versions */
- if ((g_codec_map[c].codec_id == SNGTC_CODEC_SIREN7_24 || g_codec_map[c].codec_id == SNGTC_CODEC_SIREN7_32) && siren_done) {
- continue;
- }
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Registering implementations for codec %s\n", g_codec_map[c].iana_name);
-
- /* SWITCH_ADD_CODEC allocates a codec interface structure from the pool the core gave us and adds it to the internal interface
- * list the core keeps, gets a codec id and set the given codec name to it.
- * At this point there is an empty shell codec interface registered, but not yet implementations */
- SWITCH_ADD_CODEC(codec_interface, g_codec_map[c].fs_name);
-
- /* Now add as many codec implementations as needed, just up to 200ms for now */
- if (g_codec_map[c].autoinit) {
- int ms = 0;
- for (i = 1; i <= 20; i++) {
- ms = i * 10;
- if (g_codec_map[c].maxms < ms) {
- break;
- }
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding %dms implementation of codec %s\n", ms, g_codec_map[c].fs_name);
- switch_core_codec_add_implementation(pool, codec_interface, /* the codec interface we allocated and we want to register with the core */
- SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
- g_codec_map[c].iana, /* the IANA code number, ie http://www.iana.org/assignments/rtp-parameters */
- g_codec_map[c].iana_name, /* the IANA code name */
- NULL, /* default fmtp to send (can be overridden by the init function), fmtp is used in SDP for format specific parameters */
- g_codec_map[c].sampling_rate, /* samples transferred per second */
- g_codec_map[c].actual_sampling_rate, /* actual samples transferred per second */
- g_codec_map[c].bps, /* bits transferred per second */
- g_codec_map[c].mpf * i, /* microseconds per frame */
- g_codec_map[c].spf * i, /* samples per frame */
- g_codec_map[c].bpfd * i, /* number of bytes per frame decompressed */
- g_codec_map[c].bpfc * i, /* number of bytes per frame compressed */
- 1, /* number of channels represented */
- g_codec_map[c].spf * i, /* number of frames per network packet (I dont think this is used at all) */
- switch_sangoma_init, /* function to initialize a codec session using this implementation */
- switch_sangoma_encode, /* function to encode slinear data into encoded data */
- switch_sangoma_decode, /* function to decode encoded data into slinear data */
- switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */
-
- }
- } else {
-
- /* custom implementation for some codecs */
- switch (g_codec_map[c].codec_id) {
- case SNGTC_CODEC_GSM_FR:
- switch_core_codec_add_implementation(pool, codec_interface, /* the codec interface we allocated and we want to register with the core */
- SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
- g_codec_map[c].iana, /* the IANA code number, ie http://www.iana.org/assignments/rtp-parameters */
- g_codec_map[c].iana_name, /* the IANA code name */
- NULL, /* default fmtp to send (can be overridden by the init function), fmtp is used in SDP for format specific parameters */
- 8000, /* samples transferred per second */
- 8000, /* actual samples transferred per second */
- g_codec_map[c].bps, /* bits transferred per second */
- g_codec_map[c].mpf, /* microseconds per frame */
- g_codec_map[c].spf, /* samples per frame */
- g_codec_map[c].bpfd, /* number of bytes per frame decompressed */
- g_codec_map[c].bpfc, /* number of bytes per frame compressed */
- 1, /* number of channels represented */
- g_codec_map[c].spf, /* number of frames per network packet (I dont think this is used at all) */
- switch_sangoma_init, /* function to initialize a codec session using this implementation */
- switch_sangoma_encode, /* function to encode slinear data into encoded data */
- switch_sangoma_decode, /* function to decode encoded data into slinear data */
- switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */
-
- break;
- case SNGTC_CODEC_ILBC_133:
- case SNGTC_CODEC_ILBC_152:
- ilbc_codec = get_codec_from_id(SNGTC_CODEC_ILBC_152);
- switch_core_codec_add_implementation(pool, codec_interface, /* the codec interface we allocated and we want to register with the core */
- SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
- ilbc_codec->iana, /* the IANA code number, ie http://www.iana.org/assignments/rtp-parameters */
- ilbc_codec->iana_name, /* the IANA code name */
- "mode=20", /* default fmtp to send (can be overridden by the init function), fmtp is used in SDP for format specific parameters */
- 8000, /* samples transferred per second */
- 8000, /* actual samples transferred per second */
- 15200, /* bits transferred per second */
- 20000, /* microseconds per frame */
- 160, /* samples per frame */
- 320, /* number of bytes per frame decompressed */
- 38, /* number of bytes per frame compressed */
- 1, /* number of channels represented */
- 1, /* number of frames per network packet (I dont think this is used at all) */
- switch_sangoma_init_ilbc, /* function to initialize a codec session using this implementation */
- switch_sangoma_encode, /* function to encode slinear data into encoded data */
- switch_sangoma_decode, /* function to decode encoded data into slinear data */
- switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */
-
- ilbc_codec = get_codec_from_id(SNGTC_CODEC_ILBC_133);
- switch_core_codec_add_implementation(pool, codec_interface, /* the codec interface we allocated and we want to register with the core */
- SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
- ilbc_codec->iana, /* the IANA code number, ie http://www.iana.org/assignments/rtp-parameters */
- ilbc_codec->iana_name, /* the IANA code name */
- "mode=30", /* default fmtp to send (can be overridden by the init function), fmtp is used in SDP for format specific parameters */
- 8000, /* samples transferred per second */
- 8000, /* actual samples transferred per second */
- 13330, /* bits transferred per second */
- 30000, /* microseconds per frame */
- 240, /* samples per frame */
- 480, /* number of bytes per frame decompressed */
- 50, /* number of bytes per frame compressed */
- 1, /* number of channels represented */
- 1, /* number of frames per network packet (I dont think this is used at all) */
- switch_sangoma_init_ilbc, /* function to initialize a codec session using this implementation */
- switch_sangoma_encode, /* function to encode slinear data into encoded data */
- switch_sangoma_decode, /* function to decode encoded data into slinear data */
- switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */
- ilbc_done = 1;
- break;
-
- case SNGTC_CODEC_G723_1_63:
-
- for (i = 1; i <= 3; i++) {
- switch_core_codec_add_implementation(pool, codec_interface, /* the codec interface we allocated and we want to register with the core */
- SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
- g_codec_map[c].iana, /* the IANA code number, ie http://www.iana.org/assignments/rtp-parameters */
- g_codec_map[c].iana_name, /* the IANA code name */
- NULL, /* default fmtp to send (can be overridden by the init function), fmtp is used in SDP for format specific parameters */
- g_codec_map[c].sampling_rate, /* samples transferred per second */
- g_codec_map[c].actual_sampling_rate, /* actual samples transferred per second */
- g_codec_map[c].bps, /* bits transferred per second */
- g_codec_map[c].mpf * i, /* microseconds per frame */
- g_codec_map[c].spf * i, /* samples per frame */
- g_codec_map[c].bpfd * i, /* number of bytes per frame decompressed */
- g_codec_map[c].bpfc * i, /* number of bytes per frame compressed */
- 1, /* number of channels represented */
- g_codec_map[c].spf * i, /* number of frames per network packet (I dont think this is used at all) */
- switch_sangoma_init, /* function to initialize a codec session using this implementation */
- switch_sangoma_encode, /* function to encode slinear data into encoded data */
- switch_sangoma_decode, /* function to decode encoded data into slinear data */
- switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */
- }
-
- break;
-
- case SNGTC_CODEC_AMR_1220:
- switch_core_codec_add_implementation(pool, codec_interface, /* the codec interface we allocated and we want to register with the core */
- SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
- g_codec_map[c].iana, /* the IANA code number, ie http://www.iana.org/assignments/rtp-parameters */
- g_codec_map[c].iana_name, /* the IANA code name */
- NULL, /* default fmtp to send (can be overridden by the init function), fmtp is used in SDP for format specific parameters */
- g_codec_map[c].sampling_rate, /* samples transferred per second */
- g_codec_map[c].actual_sampling_rate, /* actual samples transferred per second */
- g_codec_map[c].bps, /* bits transferred per second */
- g_codec_map[c].mpf, /* microseconds per frame */
- g_codec_map[c].spf, /* samples per frame */
- g_codec_map[c].bpfd, /* number of bytes per frame decompressed */
- g_codec_map[c].bpfc, /* number of bytes per frame compressed */
- 1, /* number of channels represented */
- g_codec_map[c].spf, /* number of frames per network packet (I dont think this is used at all) */
- switch_sangoma_init, /* function to initialize a codec session using this implementation */
- switch_sangoma_encode, /* function to encode slinear data into encoded data */
- switch_sangoma_decode, /* function to decode encoded data into slinear data */
- switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */
- break;
-
- case SNGTC_CODEC_SIREN7_24:
- case SNGTC_CODEC_SIREN7_32:
-
- siren_codec = get_codec_from_id(SNGTC_CODEC_SIREN7_24);
- switch_core_codec_add_implementation(pool, codec_interface, /* the codec interface we allocated and we want to register with the core */
- SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
- siren_codec->iana, /* the IANA code number, ie http://www.iana.org/assignments/rtp-parameters */
- siren_codec->iana_name, /* the IANA code name */
- "bitrate=24000", /* default fmtp to send (can be overridden by the init function), fmtp is used in SDP for format specific parameters */
- siren_codec->sampling_rate, /* samples transferred per second */
- siren_codec->actual_sampling_rate, /* actual samples transferred per second */
- siren_codec->bps, /* bits transferred per second */
- siren_codec->mpf, /* microseconds per frame */
- siren_codec->spf, /* samples per frame */
- siren_codec->bpfd, /* number of bytes per frame decompressed */
- siren_codec->bpfc, /* number of bytes per frame compressed */
- 1, /* number of channels represented */
- siren_codec->spf, /* number of frames per network packet (I dont think this is used at all) */
- switch_sangoma_init_siren7, /* function to initialize a codec session using this implementation */
- switch_sangoma_encode, /* function to encode slinear data into encoded data */
- switch_sangoma_decode, /* function to decode encoded data into slinear data */
- switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */
-
- siren_codec = get_codec_from_id(SNGTC_CODEC_SIREN7_32);
- switch_core_codec_add_implementation(pool, codec_interface, /* the codec interface we allocated and we want to register with the core */
- SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
- siren_codec->iana, /* the IANA code number, ie http://www.iana.org/assignments/rtp-parameters */
- siren_codec->iana_name, /* the IANA code name */
- "bitrate=32000", /* default fmtp to send (can be overridden by the init function), fmtp is used in SDP for format specific parameters */
- siren_codec->sampling_rate, /* samples transferred per second */
- siren_codec->actual_sampling_rate, /* actual samples transferred per second */
- siren_codec->bps, /* bits transferred per second */
- siren_codec->mpf, /* microseconds per frame */
- siren_codec->spf, /* samples per frame */
- siren_codec->bpfd, /* number of bytes per frame decompressed */
- siren_codec->bpfc, /* number of bytes per frame compressed */
- 1, /* number of channels represented */
- siren_codec->spf, /* number of frames per network packet (I dont think this is used at all) */
- switch_sangoma_init_siren7, /* function to initialize a codec session using this implementation */
- switch_sangoma_encode, /* function to encode slinear data into encoded data */
- switch_sangoma_decode, /* function to decode encoded data into slinear data */
- switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */
- siren_done = 1;
- break;
-
- case SNGTC_CODEC_G729AB:
- for (i = 1; i <= 20; i++) {
- if (g_codec_map[c].maxms < (i * 10)) {
- break;
- }
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding %dms implementation of codec %s\n", (i * 10), g_codec_map[c].fs_name);
- switch_core_codec_add_implementation(pool, codec_interface, /* the codec interface we allocated and we want to register with the core */
- SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
- g_codec_map[c].iana, /* the IANA code number, ie http://www.iana.org/assignments/rtp-parameters */
- g_codec_map[c].iana_name, /* the IANA code name */
- NULL, /* default fmtp to send (can be overridden by the init function), fmtp is used in SDP for format specific parameters */
- g_codec_map[c].sampling_rate, /* samples transferred per second */
- g_codec_map[c].actual_sampling_rate, /* actual samples transferred per second */
- g_codec_map[c].bps, /* bits transferred per second */
- g_codec_map[c].mpf * i, /* microseconds per frame */
- g_codec_map[c].spf * i, /* samples per frame */
- g_codec_map[c].bpfd * i, /* number of bytes per frame decompressed */
- g_codec_map[c].bpfc * i, /* number of bytes per frame compressed */
- 1, /* number of channels represented */
- g_codec_map[c].spf * i, /* number of frames per network packet (I dont think this is used at all) */
- switch_sangoma_init_g729, /* function to initialize a codec session using this implementation */
- switch_sangoma_encode, /* function to encode slinear data into encoded data */
- switch_sangoma_decode, /* function to decode encoded data into slinear data */
- switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */
- }
- break;
-
- default:
- break;
- }
- }
- }
-
-
- SWITCH_ADD_API(api_interface, "sangoma_codec", "Sangoma Codec Commands", sangoma_function, SANGOMA_SYNTAX);
- switch_console_set_complete("add sangoma_codec");
- switch_console_set_complete("add sangoma_codec settings");
- switch_console_set_complete("add sangoma_codec sessions");
- switch_console_set_complete("add sangoma_codec stats");
- switch_console_set_complete("add sangoma_codec debug");
- switch_console_set_complete("add sangoma_codec nodebug");
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */