mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-04 05:53:26 +00:00 
			
		
		
		
	Merge branch 'zecke/features/sdp-codec-handling'
Move forward while preserving the legacy handling. Beging to extract SDP rtpmap information and select codecs atfer this. It is a foundation we can now build further and better check ons.
This commit is contained in:
		@@ -22,6 +22,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/select.h>
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CI_UNUSED 0
 | 
					#define CI_UNUSED 0
 | 
				
			||||||
@@ -203,11 +205,51 @@ struct mgcp_endpoint {
 | 
				
			|||||||
	} osmux;
 | 
						} osmux;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define for_each_line(line, save)			\
 | 
				
			||||||
 | 
						for (line = strline_r(NULL, &save); line;\
 | 
				
			||||||
 | 
						     line = strline_r(NULL, &save))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline char *strline_r(char *str, char **saveptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (str)
 | 
				
			||||||
 | 
							*saveptr = str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result = *saveptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*saveptr != NULL) {
 | 
				
			||||||
 | 
							*saveptr = strpbrk(*saveptr, "\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (*saveptr != NULL) {
 | 
				
			||||||
 | 
								char *eos = *saveptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if ((*saveptr)[0] == '\r' && (*saveptr)[1] == '\n')
 | 
				
			||||||
 | 
									(*saveptr)++;
 | 
				
			||||||
 | 
								(*saveptr)++;
 | 
				
			||||||
 | 
								if ((*saveptr)[0] == '\0')
 | 
				
			||||||
 | 
									*saveptr = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								*eos = '\0';
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
 | 
					#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_msg_ptr {
 | 
					/**
 | 
				
			||||||
	unsigned int start;
 | 
					 * Internal structure while parsing a request
 | 
				
			||||||
	unsigned int length;
 | 
					 */
 | 
				
			||||||
 | 
					struct mgcp_parse_data {
 | 
				
			||||||
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
 | 
						char *trans;
 | 
				
			||||||
 | 
						char *save;
 | 
				
			||||||
 | 
						int found;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_send_dummy(struct mgcp_endpoint *endp);
 | 
					int mgcp_send_dummy(struct mgcp_endpoint *endp);
 | 
				
			||||||
@@ -260,5 +302,21 @@ enum {
 | 
				
			|||||||
	MGCP_DEST_BTS,
 | 
						MGCP_DEST_BTS,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MGCP_DUMMY_LOAD 0x23
 | 
					#define MGCP_DUMMY_LOAD 0x23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * SDP related information
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* Assume audio frame length of 20ms */
 | 
				
			||||||
 | 
					#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
 | 
				
			||||||
 | 
					#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
 | 
				
			||||||
 | 
					#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
 | 
				
			||||||
 | 
					#define DEFAULT_RTP_AUDIO_DEFAULT_RATE  8000
 | 
				
			||||||
 | 
					#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PTYPE_UNDEFINED (-1)
 | 
				
			||||||
 | 
					int mgcp_parse_sdp_data(struct mgcp_endpoint *endp, struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p);
 | 
				
			||||||
 | 
					int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,
 | 
				
			||||||
 | 
								int payload_type, const char *audio_name);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,8 @@ noinst_LIBRARIES = libmgcp.a
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
noinst_HEADERS = g711common.h
 | 
					noinst_HEADERS = g711common.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libmgcp_a_SOURCES = mgcp_protocol.c mgcp_network.c mgcp_vty.c mgcp_osmux.c
 | 
					libmgcp_a_SOURCES = mgcp_protocol.c mgcp_network.c mgcp_vty.c mgcp_osmux.c \
 | 
				
			||||||
 | 
						mgcp_sdp.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if BUILD_MGCP_TRANSCODING
 | 
					if BUILD_MGCP_TRANSCODING
 | 
				
			||||||
    libmgcp_a_SOURCES += mgcp_transcode.c
 | 
					    libmgcp_a_SOURCES += mgcp_transcode.c
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,6 @@
 | 
				
			|||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
@@ -41,57 +40,9 @@
 | 
				
			|||||||
	for (line = strtok_r(NULL, "\r\n", &save); line;\
 | 
						for (line = strtok_r(NULL, "\r\n", &save); line;\
 | 
				
			||||||
	     line = strtok_r(NULL, "\r\n", &save))
 | 
						     line = strtok_r(NULL, "\r\n", &save))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define for_each_line(line, save)			\
 | 
					 | 
				
			||||||
	for (line = strline_r(NULL, &save); line;\
 | 
					 | 
				
			||||||
	     line = strline_r(NULL, &save))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
char *strline_r(char *str, char **saveptr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	char *result;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (str)
 | 
					 | 
				
			||||||
		*saveptr = str;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = *saveptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (*saveptr != NULL) {
 | 
					 | 
				
			||||||
		*saveptr = strpbrk(*saveptr, "\r\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (*saveptr != NULL) {
 | 
					 | 
				
			||||||
			char *eos = *saveptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if ((*saveptr)[0] == '\r' && (*saveptr)[1] == '\n')
 | 
					 | 
				
			||||||
				(*saveptr)++;
 | 
					 | 
				
			||||||
			(*saveptr)++;
 | 
					 | 
				
			||||||
			if ((*saveptr)[0] == '\0')
 | 
					 | 
				
			||||||
				*saveptr = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			*eos = '\0';
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Assume audio frame length of 20ms */
 | 
					 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
 | 
					 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
 | 
					 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
 | 
					 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_DEFAULT_RATE  8000
 | 
					 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define PTYPE_UNDEFINED (-1)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
 | 
					static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_parse_data {
 | 
					 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
	char *trans;
 | 
					 | 
				
			||||||
	char *save;
 | 
					 | 
				
			||||||
	int found;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_request {
 | 
					struct mgcp_request {
 | 
				
			||||||
	char *name;
 | 
						char *name;
 | 
				
			||||||
	struct msgb *(*handle_request) (struct mgcp_parse_data *data);
 | 
						struct msgb *(*handle_request) (struct mgcp_parse_data *data);
 | 
				
			||||||
@@ -599,72 +550,6 @@ static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp)
 | 
				
			|||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,
 | 
					 | 
				
			||||||
			  int payload_type, const char *audio_name)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int rate = codec->rate;
 | 
					 | 
				
			||||||
	int channels = codec->channels;
 | 
					 | 
				
			||||||
	char audio_codec[64];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	talloc_free(codec->subtype_name);
 | 
					 | 
				
			||||||
	codec->subtype_name = NULL;
 | 
					 | 
				
			||||||
	talloc_free(codec->audio_name);
 | 
					 | 
				
			||||||
	codec->audio_name = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (payload_type != PTYPE_UNDEFINED)
 | 
					 | 
				
			||||||
		codec->payload_type = payload_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!audio_name) {
 | 
					 | 
				
			||||||
		switch (payload_type) {
 | 
					 | 
				
			||||||
		case 3: audio_name = "GSM/8000/1"; break;
 | 
					 | 
				
			||||||
		case 8: audio_name = "PCMA/8000/1"; break;
 | 
					 | 
				
			||||||
		case 18: audio_name = "G729/8000/1"; break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			 /* Payload type is unknown, don't change rate and
 | 
					 | 
				
			||||||
			  * channels. */
 | 
					 | 
				
			||||||
			 /* TODO: return value? */
 | 
					 | 
				
			||||||
			 return 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (sscanf(audio_name, "%63[^/]/%d/%d",
 | 
					 | 
				
			||||||
		   audio_codec, &rate, &channels) < 1)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	codec->rate = rate;
 | 
					 | 
				
			||||||
	codec->channels = channels;
 | 
					 | 
				
			||||||
	codec->subtype_name = talloc_strdup(ctx, audio_codec);
 | 
					 | 
				
			||||||
	codec->audio_name = talloc_strdup(ctx, audio_name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!strcmp(audio_codec, "G729")) {
 | 
					 | 
				
			||||||
		codec->frame_duration_num = 10;
 | 
					 | 
				
			||||||
		codec->frame_duration_den = 1000;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
 | 
					 | 
				
			||||||
		codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (payload_type < 0) {
 | 
					 | 
				
			||||||
		payload_type = 96;
 | 
					 | 
				
			||||||
		if (rate == 8000 && channels == 1) {
 | 
					 | 
				
			||||||
			if (!strcmp(audio_codec, "GSM"))
 | 
					 | 
				
			||||||
				payload_type = 3;
 | 
					 | 
				
			||||||
			else if (!strcmp(audio_codec, "PCMA"))
 | 
					 | 
				
			||||||
				payload_type = 8;
 | 
					 | 
				
			||||||
			else if (!strcmp(audio_codec, "G729"))
 | 
					 | 
				
			||||||
				payload_type = 18;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		codec->payload_type = payload_type;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (channels != 1)
 | 
					 | 
				
			||||||
		LOGP(DMGCP, LOGL_NOTICE,
 | 
					 | 
				
			||||||
		     "Channels != 1 in SDP: '%s'\n", audio_name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
 | 
					static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
 | 
				
			||||||
			 struct mgcp_port_range *range,
 | 
								 struct mgcp_port_range *range,
 | 
				
			||||||
			 int (*alloc)(struct mgcp_endpoint *endp, int port))
 | 
								 int (*alloc)(struct mgcp_endpoint *endp, int port))
 | 
				
			||||||
@@ -735,103 +620,6 @@ static int allocate_ports(struct mgcp_endpoint *endp)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	char *line;
 | 
					 | 
				
			||||||
	int found_media = 0;
 | 
					 | 
				
			||||||
	/* TODO/XXX make it more generic */
 | 
					 | 
				
			||||||
	int audio_payload = -1;
 | 
					 | 
				
			||||||
	int audio_payload_alt = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for_each_line(line, p->save) {
 | 
					 | 
				
			||||||
		switch (line[0]) {
 | 
					 | 
				
			||||||
		case 'o':
 | 
					 | 
				
			||||||
		case 's':
 | 
					 | 
				
			||||||
		case 't':
 | 
					 | 
				
			||||||
		case 'v':
 | 
					 | 
				
			||||||
			/* skip these SDP attributes */
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case 'a': {
 | 
					 | 
				
			||||||
			int payload;
 | 
					 | 
				
			||||||
			int ptime, ptime2 = 0;
 | 
					 | 
				
			||||||
			char audio_name[64];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (audio_payload == -1)
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (sscanf(line, "a=rtpmap:%d %63s",
 | 
					 | 
				
			||||||
				   &payload, audio_name) == 2) {
 | 
					 | 
				
			||||||
				if (payload == audio_payload)
 | 
					 | 
				
			||||||
					set_audio_info(p->cfg, &rtp->codec,
 | 
					 | 
				
			||||||
							payload, audio_name);
 | 
					 | 
				
			||||||
				else if (payload == audio_payload_alt)
 | 
					 | 
				
			||||||
					set_audio_info(p->cfg, &rtp->alt_codec,
 | 
					 | 
				
			||||||
							payload, audio_name);
 | 
					 | 
				
			||||||
			} else if (sscanf(line, "a=ptime:%d-%d",
 | 
					 | 
				
			||||||
					  &ptime, &ptime2) >= 1) {
 | 
					 | 
				
			||||||
				if (ptime2 > 0 && ptime2 != ptime)
 | 
					 | 
				
			||||||
					rtp->packet_duration_ms = 0;
 | 
					 | 
				
			||||||
				else
 | 
					 | 
				
			||||||
					rtp->packet_duration_ms = ptime;
 | 
					 | 
				
			||||||
			} else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
 | 
					 | 
				
			||||||
				/* TODO/XXX: Store this per codec and derive it on use */
 | 
					 | 
				
			||||||
				if (ptime2 * rtp->codec.frame_duration_den >
 | 
					 | 
				
			||||||
				    rtp->codec.frame_duration_num * 1500)
 | 
					 | 
				
			||||||
					/* more than 1 frame */
 | 
					 | 
				
			||||||
					rtp->packet_duration_ms = 0;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		case 'm': {
 | 
					 | 
				
			||||||
			int port, rc;
 | 
					 | 
				
			||||||
			audio_payload = -1;
 | 
					 | 
				
			||||||
			audio_payload_alt = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			rc = sscanf(line, "m=audio %d RTP/AVP %d %d",
 | 
					 | 
				
			||||||
				   &port, &audio_payload, &audio_payload_alt);
 | 
					 | 
				
			||||||
			if (rc >= 2) {
 | 
					 | 
				
			||||||
				rtp->rtp_port = htons(port);
 | 
					 | 
				
			||||||
				rtp->rtcp_port = htons(port + 1);
 | 
					 | 
				
			||||||
				found_media = 1;
 | 
					 | 
				
			||||||
				set_audio_info(p->cfg, &rtp->codec, audio_payload, NULL);
 | 
					 | 
				
			||||||
				if (rc == 3)
 | 
					 | 
				
			||||||
					set_audio_info(p->cfg, &rtp->alt_codec,
 | 
					 | 
				
			||||||
							audio_payload_alt, NULL);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		case 'c': {
 | 
					 | 
				
			||||||
			char ipv4[16];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
 | 
					 | 
				
			||||||
				inet_aton(ipv4, &rtp->addr);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			if (p->endp)
 | 
					 | 
				
			||||||
				LOGP(DMGCP, LOGL_NOTICE,
 | 
					 | 
				
			||||||
				     "Unhandled SDP option: '%c'/%d on 0x%x\n",
 | 
					 | 
				
			||||||
				     line[0], line[0], ENDPOINT_NUMBER(p->endp));
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				LOGP(DMGCP, LOGL_NOTICE,
 | 
					 | 
				
			||||||
				     "Unhandled SDP option: '%c'/%d\n",
 | 
					 | 
				
			||||||
				     line[0], line[0]);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (found_media)
 | 
					 | 
				
			||||||
		LOGP(DMGCP, LOGL_NOTICE,
 | 
					 | 
				
			||||||
		     "Got media info via SDP: port %d, payload %d (%s), "
 | 
					 | 
				
			||||||
		     "duration %d, addr %s\n",
 | 
					 | 
				
			||||||
		     ntohs(rtp->rtp_port), rtp->codec.payload_type,
 | 
					 | 
				
			||||||
		     rtp->codec.subtype_name ? rtp->codec.subtype_name : "unknown",
 | 
					 | 
				
			||||||
		     rtp->packet_duration_ms, inet_ntoa(rtp->addr));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return found_media;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Set the LCO from a string (see RFC 3435).
 | 
					/* Set the LCO from a string (see RFC 3435).
 | 
				
			||||||
 * The string is stored in the 'string' field. A NULL string is handled excatly
 | 
					 * The string is stored in the 'string' field. A NULL string is handled excatly
 | 
				
			||||||
 * like an empty string, the 'string' field is never NULL after this function
 | 
					 * like an empty string, the 'string' field is never NULL after this function
 | 
				
			||||||
@@ -1036,13 +824,13 @@ mgcp_header_done:
 | 
				
			|||||||
	endp->allocated = 1;
 | 
						endp->allocated = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* set up RTP media parameters */
 | 
						/* set up RTP media parameters */
 | 
				
			||||||
	set_audio_info(p->cfg, &endp->bts_end.codec, tcfg->audio_payload, tcfg->audio_name);
 | 
						mgcp_set_audio_info(p->cfg, &endp->bts_end.codec, tcfg->audio_payload, tcfg->audio_name);
 | 
				
			||||||
	endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
 | 
						endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
 | 
				
			||||||
						tcfg->audio_fmtp_extra);
 | 
											tcfg->audio_fmtp_extra);
 | 
				
			||||||
	if (have_sdp)
 | 
						if (have_sdp)
 | 
				
			||||||
		parse_sdp_data(&endp->net_end, p);
 | 
							mgcp_parse_sdp_data(endp, &endp->net_end, p);
 | 
				
			||||||
	else if (endp->local_options.codec)
 | 
						else if (endp->local_options.codec)
 | 
				
			||||||
		set_audio_info(p->cfg, &endp->net_end.codec,
 | 
							mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
 | 
				
			||||||
			       PTYPE_UNDEFINED, endp->local_options.codec);
 | 
								       PTYPE_UNDEFINED, endp->local_options.codec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (p->cfg->bts_force_ptime) {
 | 
						if (p->cfg->bts_force_ptime) {
 | 
				
			||||||
@@ -1143,7 +931,7 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
		case '\0':
 | 
							case '\0':
 | 
				
			||||||
			/* SDP file begins */
 | 
								/* SDP file begins */
 | 
				
			||||||
			have_sdp = 1;
 | 
								have_sdp = 1;
 | 
				
			||||||
			parse_sdp_data(&endp->net_end, p);
 | 
								mgcp_parse_sdp_data(endp, &endp->net_end, p);
 | 
				
			||||||
			/* This will exhaust p->save, so the loop will
 | 
								/* This will exhaust p->save, so the loop will
 | 
				
			||||||
			 * terminate next time.
 | 
								 * terminate next time.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
@@ -1159,7 +947,7 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
			     local_options);
 | 
								     local_options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!have_sdp && endp->local_options.codec)
 | 
						if (!have_sdp && endp->local_options.codec)
 | 
				
			||||||
		set_audio_info(p->cfg, &endp->net_end.codec,
 | 
							mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
 | 
				
			||||||
			       PTYPE_UNDEFINED, endp->local_options.codec);
 | 
								       PTYPE_UNDEFINED, endp->local_options.codec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (setup_rtp_processing(endp) != 0)
 | 
						if (setup_rtp_processing(endp) != 0)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										294
									
								
								openbsc/src/libmgcp/mgcp_sdp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								openbsc/src/libmgcp/mgcp_sdp.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,294 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Some SDP file parsing...
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * (C) 2009-2015 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
				
			||||||
 | 
					 * (C) 2009-2014 by On-Waves
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/mgcp.h>
 | 
				
			||||||
 | 
					#include <openbsc/mgcp_internal.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sdp_rtp_map {
 | 
				
			||||||
 | 
						/* the type */
 | 
				
			||||||
 | 
						int payload_type;
 | 
				
			||||||
 | 
						/* null, static or later dynamic codec name */
 | 
				
			||||||
 | 
						char *codec_name;
 | 
				
			||||||
 | 
						/* A pointer to the original line for later parsing */
 | 
				
			||||||
 | 
						char *map_line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int rate;
 | 
				
			||||||
 | 
						int channels;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,
 | 
				
			||||||
 | 
								int payload_type, const char *audio_name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rate = codec->rate;
 | 
				
			||||||
 | 
						int channels = codec->channels;
 | 
				
			||||||
 | 
						char audio_codec[64];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						talloc_free(codec->subtype_name);
 | 
				
			||||||
 | 
						codec->subtype_name = NULL;
 | 
				
			||||||
 | 
						talloc_free(codec->audio_name);
 | 
				
			||||||
 | 
						codec->audio_name = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (payload_type != PTYPE_UNDEFINED)
 | 
				
			||||||
 | 
							codec->payload_type = payload_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!audio_name) {
 | 
				
			||||||
 | 
							switch (payload_type) {
 | 
				
			||||||
 | 
							case 3: audio_name = "GSM/8000/1"; break;
 | 
				
			||||||
 | 
							case 8: audio_name = "PCMA/8000/1"; break;
 | 
				
			||||||
 | 
							case 18: audio_name = "G729/8000/1"; break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								 /* Payload type is unknown, don't change rate and
 | 
				
			||||||
 | 
								  * channels. */
 | 
				
			||||||
 | 
								 /* TODO: return value? */
 | 
				
			||||||
 | 
								 return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sscanf(audio_name, "%63[^/]/%d/%d",
 | 
				
			||||||
 | 
							   audio_codec, &rate, &channels) < 1)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						codec->rate = rate;
 | 
				
			||||||
 | 
						codec->channels = channels;
 | 
				
			||||||
 | 
						codec->subtype_name = talloc_strdup(ctx, audio_codec);
 | 
				
			||||||
 | 
						codec->audio_name = talloc_strdup(ctx, audio_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!strcmp(audio_codec, "G729")) {
 | 
				
			||||||
 | 
							codec->frame_duration_num = 10;
 | 
				
			||||||
 | 
							codec->frame_duration_den = 1000;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
 | 
				
			||||||
 | 
							codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (payload_type < 0) {
 | 
				
			||||||
 | 
							payload_type = 96;
 | 
				
			||||||
 | 
							if (rate == 8000 && channels == 1) {
 | 
				
			||||||
 | 
								if (!strcmp(audio_codec, "GSM"))
 | 
				
			||||||
 | 
									payload_type = 3;
 | 
				
			||||||
 | 
								else if (!strcmp(audio_codec, "PCMA"))
 | 
				
			||||||
 | 
									payload_type = 8;
 | 
				
			||||||
 | 
								else if (!strcmp(audio_codec, "G729"))
 | 
				
			||||||
 | 
									payload_type = 18;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							codec->payload_type = payload_type;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (channels != 1)
 | 
				
			||||||
 | 
							LOGP(DMGCP, LOGL_NOTICE,
 | 
				
			||||||
 | 
							     "Channels != 1 in SDP: '%s'\n", audio_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < used; ++i) {
 | 
				
			||||||
 | 
							switch (codecs[i].payload_type) {
 | 
				
			||||||
 | 
							case 3:
 | 
				
			||||||
 | 
								codecs[i].codec_name = "GSM";
 | 
				
			||||||
 | 
								codecs[i].rate = 8000;
 | 
				
			||||||
 | 
								codecs[i].channels = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 8:
 | 
				
			||||||
 | 
								codecs[i].codec_name = "PCMA";
 | 
				
			||||||
 | 
								codecs[i].rate = 8000;
 | 
				
			||||||
 | 
								codecs[i].channels = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 18:
 | 
				
			||||||
 | 
								codecs[i].codec_name = "G729";
 | 
				
			||||||
 | 
								codecs[i].rate = 8000;
 | 
				
			||||||
 | 
								codecs[i].channels = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used, int payload, char *audio_name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < used; ++i) {
 | 
				
			||||||
 | 
							char audio_codec[64];
 | 
				
			||||||
 | 
							int rate = -1;
 | 
				
			||||||
 | 
							int channels = -1;
 | 
				
			||||||
 | 
							if (codecs[i].payload_type != payload)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (sscanf(audio_name, "%63[^/]/%d/%d",
 | 
				
			||||||
 | 
									audio_codec, &rate, &channels) < 1) {
 | 
				
			||||||
 | 
								LOGP(DMGCP, LOGL_ERROR, "Failed to parse '%s'\n", audio_name);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							codecs[i].map_line = talloc_strdup(ctx, audio_name);
 | 
				
			||||||
 | 
							codecs[i].codec_name = talloc_strdup(ctx, audio_codec);
 | 
				
			||||||
 | 
							codecs[i].rate = rate;
 | 
				
			||||||
 | 
							codecs[i].channels = channels;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload, audio_name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int is_codec_compatible(struct mgcp_endpoint *endp, struct sdp_rtp_map *codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *bts_codec;
 | 
				
			||||||
 | 
						char audio_codec[64];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * GSM, GSM/8000 and GSM/8000/1 should all be compatible.. let's go
 | 
				
			||||||
 | 
						 * by name first.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						bts_codec = endp->tcfg->audio_name;
 | 
				
			||||||
 | 
						if (sscanf(bts_codec, "%63[^/]/%*d/%*d", audio_codec) < 1)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return strcasecmp(audio_codec, codec->codec_name) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_parse_sdp_data(struct mgcp_endpoint *endp, struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sdp_rtp_map codecs[10];
 | 
				
			||||||
 | 
						int codecs_used = 0;
 | 
				
			||||||
 | 
						char *line;
 | 
				
			||||||
 | 
						int maxptime = -1;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int codecs_assigned = 0;
 | 
				
			||||||
 | 
						void *tmp_ctx = talloc_new(NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&codecs, 0, sizeof(codecs));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_line(line, p->save) {
 | 
				
			||||||
 | 
							switch (line[0]) {
 | 
				
			||||||
 | 
							case 'o':
 | 
				
			||||||
 | 
							case 's':
 | 
				
			||||||
 | 
							case 't':
 | 
				
			||||||
 | 
							case 'v':
 | 
				
			||||||
 | 
								/* skip these SDP attributes */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'a': {
 | 
				
			||||||
 | 
								int payload;
 | 
				
			||||||
 | 
								int ptime, ptime2 = 0;
 | 
				
			||||||
 | 
								char audio_name[64];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (sscanf(line, "a=rtpmap:%d %63s",
 | 
				
			||||||
 | 
									   &payload, audio_name) == 2) {
 | 
				
			||||||
 | 
									codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
 | 
				
			||||||
 | 
								} else if (sscanf(line, "a=ptime:%d-%d",
 | 
				
			||||||
 | 
										  &ptime, &ptime2) >= 1) {
 | 
				
			||||||
 | 
									if (ptime2 > 0 && ptime2 != ptime)
 | 
				
			||||||
 | 
										rtp->packet_duration_ms = 0;
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										rtp->packet_duration_ms = ptime;
 | 
				
			||||||
 | 
								} else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
 | 
				
			||||||
 | 
									maxptime = ptime2;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							case 'm': {
 | 
				
			||||||
 | 
								int port, rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								rc = sscanf(line, "m=audio %d RTP/AVP %d %d %d %d %d %d %d %d %d %d",
 | 
				
			||||||
 | 
										&port,
 | 
				
			||||||
 | 
										&codecs[0].payload_type,
 | 
				
			||||||
 | 
										&codecs[1].payload_type,
 | 
				
			||||||
 | 
										&codecs[2].payload_type,
 | 
				
			||||||
 | 
										&codecs[3].payload_type,
 | 
				
			||||||
 | 
										&codecs[4].payload_type,
 | 
				
			||||||
 | 
										&codecs[5].payload_type,
 | 
				
			||||||
 | 
										&codecs[6].payload_type,
 | 
				
			||||||
 | 
										&codecs[7].payload_type,
 | 
				
			||||||
 | 
										&codecs[8].payload_type,
 | 
				
			||||||
 | 
										&codecs[9].payload_type);
 | 
				
			||||||
 | 
								if (rc >= 2) {
 | 
				
			||||||
 | 
									rtp->rtp_port = htons(port);
 | 
				
			||||||
 | 
									rtp->rtcp_port = htons(port + 1);
 | 
				
			||||||
 | 
									codecs_used = rc - 1;
 | 
				
			||||||
 | 
									codecs_initialize(tmp_ctx, codecs, codecs_used);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							case 'c': {
 | 
				
			||||||
 | 
								char ipv4[16];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
 | 
				
			||||||
 | 
									inet_aton(ipv4, &rtp->addr);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								if (p->endp)
 | 
				
			||||||
 | 
									LOGP(DMGCP, LOGL_NOTICE,
 | 
				
			||||||
 | 
									     "Unhandled SDP option: '%c'/%d on 0x%x\n",
 | 
				
			||||||
 | 
									     line[0], line[0], ENDPOINT_NUMBER(p->endp));
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									LOGP(DMGCP, LOGL_NOTICE,
 | 
				
			||||||
 | 
									     "Unhandled SDP option: '%c'/%d\n",
 | 
				
			||||||
 | 
									     line[0], line[0]);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Now select the primary and alt_codec */
 | 
				
			||||||
 | 
						for (i = 0; i < codecs_used && codecs_assigned < 2; ++i) {
 | 
				
			||||||
 | 
							struct mgcp_rtp_codec *codec = codecs_assigned == 0 ?
 | 
				
			||||||
 | 
										&rtp->codec : &rtp->alt_codec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (endp->tcfg->no_audio_transcoding &&
 | 
				
			||||||
 | 
								!is_codec_compatible(endp, &codecs[i])) {
 | 
				
			||||||
 | 
								LOGP(DMGCP, LOGL_NOTICE, "Skipping codec %s\n",
 | 
				
			||||||
 | 
									codecs[i].codec_name);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mgcp_set_audio_info(p->cfg, codec,
 | 
				
			||||||
 | 
										codecs[i].payload_type,
 | 
				
			||||||
 | 
										codecs[i].map_line);
 | 
				
			||||||
 | 
							codecs_assigned += 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (codecs_assigned > 0) {
 | 
				
			||||||
 | 
							/* TODO/XXX: Store this per codec and derive it on use */
 | 
				
			||||||
 | 
							if (maxptime >= 0 && maxptime * rtp->codec.frame_duration_den >
 | 
				
			||||||
 | 
									rtp->codec.frame_duration_num * 1500) {
 | 
				
			||||||
 | 
								/* more than 1 frame */
 | 
				
			||||||
 | 
								rtp->packet_duration_ms = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							LOGP(DMGCP, LOGL_NOTICE,
 | 
				
			||||||
 | 
							     "Got media info via SDP: port %d, payload %d (%s), "
 | 
				
			||||||
 | 
							     "duration %d, addr %s\n",
 | 
				
			||||||
 | 
							     ntohs(rtp->rtp_port), rtp->codec.payload_type,
 | 
				
			||||||
 | 
							     rtp->codec.subtype_name ? rtp->codec.subtype_name : "unknown",
 | 
				
			||||||
 | 
							     rtp->packet_duration_ms, inet_ntoa(rtp->addr));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						talloc_free(tmp_ctx);
 | 
				
			||||||
 | 
						return codecs_assigned > 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -340,6 +340,31 @@ static void test_strline(void)
 | 
				
			|||||||
		 "a=rtpmap:101 FOO/8000\r\n"	\
 | 
							 "a=rtpmap:101 FOO/8000\r\n"	\
 | 
				
			||||||
		 "a=ptime:40\r\n"
 | 
							 "a=ptime:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CRCX_MULT_GSM_EXACT \
 | 
				
			||||||
 | 
							"CRCX 259260421 5@mgw MGCP 1.0\r\n"	\
 | 
				
			||||||
 | 
							"C: 1355c6041e\r\n"			\
 | 
				
			||||||
 | 
							"I: 3\r\n"				\
 | 
				
			||||||
 | 
							"L: p:20, a:GSM, nt:IN\r\n"		\
 | 
				
			||||||
 | 
							"M: recvonly\r\n"			\
 | 
				
			||||||
 | 
							"\r\n"					\
 | 
				
			||||||
 | 
							"v=0\r\n"				\
 | 
				
			||||||
 | 
							"o=- 1439038275 1439038275 IN IP4 192.168.181.247\r\n" \
 | 
				
			||||||
 | 
							"s=-\r\nc=IN IP4 192.168.181.247\r\n"	\
 | 
				
			||||||
 | 
							"t=0 0\r\nm=audio 29084 RTP/AVP 0 8 3 18 4 96 97 101\r\n" \
 | 
				
			||||||
 | 
							"a=rtpmap:0 PCMU/8000\r\n"		\
 | 
				
			||||||
 | 
							"a=rtpmap:8 PCMA/8000\r\n"		\
 | 
				
			||||||
 | 
							"a=rtpmap:3 gsm/8000\r\n"		\
 | 
				
			||||||
 | 
							"a=rtpmap:18 G729/8000\r\n"		\
 | 
				
			||||||
 | 
							"a=fmtp:18 annexb=no\r\n"		\
 | 
				
			||||||
 | 
							"a=rtpmap:4 G723/8000\r\n"		\
 | 
				
			||||||
 | 
							"a=rtpmap:96 iLBC/8000\r\n"		\
 | 
				
			||||||
 | 
							"a=fmtp:96 mode=20\r\n"			\
 | 
				
			||||||
 | 
							"a=rtpmap:97 iLBC/8000\r\n"		\
 | 
				
			||||||
 | 
							"a=fmtp:97 mode=30\r\n"			\
 | 
				
			||||||
 | 
							"a=rtpmap:101 telephone-event/8000\r\n"	\
 | 
				
			||||||
 | 
							"a=fmtp:101 0-15\r\n"			\
 | 
				
			||||||
 | 
							"a=recvonly\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_test {
 | 
					struct mgcp_test {
 | 
				
			||||||
	const char *name;
 | 
						const char *name;
 | 
				
			||||||
	const char *req;
 | 
						const char *req;
 | 
				
			||||||
@@ -1011,6 +1036,40 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	OSMO_ASSERT(endp->net_end.codec.payload_type == 18);
 | 
						OSMO_ASSERT(endp->net_end.codec.payload_type == 18);
 | 
				
			||||||
	OSMO_ASSERT(endp->net_end.alt_codec.payload_type == -1);
 | 
						OSMO_ASSERT(endp->net_end.alt_codec.payload_type == -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Allocate 5@mgw at select GSM.. */
 | 
				
			||||||
 | 
						last_endpoint = -1;
 | 
				
			||||||
 | 
						inp = create_msg(CRCX_MULT_GSM_EXACT);
 | 
				
			||||||
 | 
						talloc_free(cfg->trunk.audio_name);
 | 
				
			||||||
 | 
						cfg->trunk.audio_name = "GSM/8000";
 | 
				
			||||||
 | 
						cfg->trunk.no_audio_transcoding = 1;
 | 
				
			||||||
 | 
						resp = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
 | 
						msgb_free(inp);
 | 
				
			||||||
 | 
						msgb_free(resp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(last_endpoint == 5);
 | 
				
			||||||
 | 
						endp = &cfg->trunk.endpoints[last_endpoint];
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp->net_end.codec.payload_type == 3);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp->net_end.alt_codec.payload_type == -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check what happens without that flag */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Free the previous endpoint and the data ... */
 | 
				
			||||||
 | 
						mgcp_release_endp(endp);
 | 
				
			||||||
 | 
						talloc_free(endp->last_response);
 | 
				
			||||||
 | 
						talloc_free(endp->last_trans);
 | 
				
			||||||
 | 
						endp->last_response = endp->last_trans = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						last_endpoint = -1;
 | 
				
			||||||
 | 
						inp = create_msg(CRCX_MULT_GSM_EXACT);
 | 
				
			||||||
 | 
						cfg->trunk.no_audio_transcoding = 0;
 | 
				
			||||||
 | 
						resp = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
 | 
						msgb_free(inp);
 | 
				
			||||||
 | 
						msgb_free(resp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(last_endpoint == 5);
 | 
				
			||||||
 | 
						endp = &cfg->trunk.endpoints[last_endpoint];
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp->net_end.codec.payload_type == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	talloc_free(cfg);
 | 
						talloc_free(cfg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user