void sangoma_worker_loop(int proc_no) { struct sngtc_request req; int rc; close(sangoma_pipe[WRITE_END]); for (;;) { rc = 0; LM_DBG("reading from pipe\n"); if (read(sangoma_pipe[READ_END], &req, sizeof(req)) < 0) { LM_ERR("failed to read from pipe (%d - %s)\n", errno, strerror(errno)); continue; } switch (req.type) { case REQ_CREATE_SESSION: LM_DBG("CREATE request\n"); if (sngtc_create_transcoding_session(&req.sng_req, req.sng_reply, 0) != 0) { LM_ERR("failed to create sng transcoding session\n"); sngtc_print_request(L_ERR, req.sng_req); rc = 1; } break; case REQ_FREE_SESSION: LM_DBG("FREE request\n"); sngtc_print_reply(L_DBG, req.sng_reply); if (sngtc_free_transcoding_session(req.sng_reply) != 0) { LM_ERR("failed to free sng transcoding session\n"); sngtc_print_reply(L_ERR, req.sng_reply); rc = 1; } break; default: LM_ERR("dropping invalid sangoma request: %d\n", req.type); rc = 1; } if (write(req.response_fd, &rc, sizeof(rc)) < 0) LM_ERR("failed to write in response pipe fd %d (%d: %s)\n", req.response_fd, errno, strerror(errno)); } }
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; }