Beispiel #1
0
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;
}