Пример #1
0
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;
}