static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) { crtp_private_t *tech_pvt; switch_channel_t *channel; switch_status_t status; channel = switch_core_session_get_channel(session); assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); if (!tech_pvt->rtp_session || tech_pvt->mode == RTP_SENDONLY) { switch_yield(20000); /* replace by local timer XXX */ goto cng; } if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) { switch_dtmf_t dtmf = { 0 }; switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, &dtmf); switch_channel_queue_dtmf(channel, &dtmf); } tech_pvt->read_frame.flags = SFF_NONE; tech_pvt->read_frame.codec = &tech_pvt->read_codec; status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags); if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { goto cng; } *frame = &tech_pvt->read_frame; return SWITCH_STATUS_SUCCESS; cng: *frame = &tech_pvt->read_frame; tech_pvt->read_frame.codec = &tech_pvt->read_codec; tech_pvt->read_frame.flags |= SFF_CNG; tech_pvt->read_frame.datalen = 0; 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 ulaw_frame; switch_status_t sres; switch_time_t now_time, difftime; short *dbuf_linear; int i = 0; int res = 0; struct sangoma_transcoding_session *sess = codec->private_info; dbuf_linear = decoded_data; /* 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); } /* do the writing */ memset(&encoded_frame, 0, sizeof(encoded_frame)); encoded_frame.source = __FUNCTION__; 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 ( ; ; ) { sres = switch_rtp_zerocopy_read_frame(sess->decoder.rxrtp, &ulaw_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 == ulaw_frame.datalen) { break; } if (ulaw_frame.payload != IANA_ULAW && ulaw_frame.payload != IANACODE_CN) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Read unexpected payload %d in Sangoma decoder RTP session, expecting %d\n", ulaw_frame.payload, IANA_ULAW); break; } if (*decoded_data_len) { sess->decoder.rxdiscarded++; } /* transcode to linear */ for (i = 0; i < ulaw_frame.datalen; i++) { dbuf_linear[i] = ulaw_to_linear(((char *)ulaw_frame.data)[i]); } *decoded_data_len = i * 2; } /* 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 (ulaw_frame.seq > (sess->decoder.lastrxseqno + 2) ) { sess->decoder.rxlost += ulaw_frame.seq - sess->decoder.lastrxseqno - 1; } } sess->decoder.lastrxseqno = ulaw_frame.seq; return SWITCH_STATUS_SUCCESS; }
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 ulaw_frame; switch_frame_t encoded_frame; switch_status_t sres; switch_time_t now_time, difftime; unsigned char ebuf_ulaw[decoded_data_len / 2]; short *dbuf_linear; int i = 0; int res = 0; struct sangoma_transcoding_session *sess = codec->private_info; /* 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); } /* transcode to ulaw first */ dbuf_linear = decoded_data; for (i = 0; i < decoded_data_len / sizeof(short); i++) { ebuf_ulaw[i] = linear_to_ulaw(dbuf_linear[i]); } /* do the writing */ memset(&ulaw_frame, 0, sizeof(ulaw_frame)); ulaw_frame.source = __FUNCTION__; ulaw_frame.data = ebuf_ulaw; ulaw_frame.datalen = i; ulaw_frame.payload = IANA_ULAW; res = switch_rtp_write_frame(sess->encoder.txrtp, &ulaw_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 ( ; ; ) { 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 == encoded_frame.datalen) { break; } if (encoded_frame.payload != codec->implementation->ianacode && encoded_frame.payload != IANACODE_CN) { 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 (*encoded_data_len) { sess->encoder.rxdiscarded++; } memcpy(encoded_data, encoded_frame.data, encoded_frame.datalen); *encoded_data_len = encoded_frame.datalen; } /* update encoding stats */ 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; return SWITCH_STATUS_SUCCESS; }