Exemple #1
0
static PayloadType * red_match(MSOfferAnswerContext *ctx, const MSList *local_payloads, const PayloadType *refpt, const MSList *remote_payloads, bool_t reading_response) {
	const MSList *elem_local, *elem_remote;
	PayloadType *red = NULL;

	for (elem_local = local_payloads; elem_local != NULL; elem_local = elem_local->next) {
		PayloadType *pt = (PayloadType*)elem_local->data;
		
		if (strcasecmp(pt->mime_type, payload_type_t140_red.mime_type) == 0) {
			red = payload_type_clone(pt);
			
			for (elem_remote = remote_payloads; elem_remote != NULL; elem_remote = elem_remote->next) {
				PayloadType *pt2 = (PayloadType*)elem_remote->data;
				if (strcasecmp(pt2->mime_type, payload_type_t140.mime_type) == 0) {
					int t140_payload_number = payload_type_get_number(pt2);
					char *red_fmtp = ms_strdup_printf("%i/%i/%i", t140_payload_number, t140_payload_number, t140_payload_number);
					/*modify the local payload and the return value*/
					payload_type_set_recv_fmtp(pt, red_fmtp);
					payload_type_set_recv_fmtp(red, red_fmtp);
					ms_free(red_fmtp);
					break;
				}
			}
			break;
		}
	}
	return red;
}
static RtpProfile *make_dummy_profile(int samplerate){
	RtpProfile *prof=rtp_profile_new("dummy");
	PayloadType *pt=payload_type_clone(&payload_type_l16_mono);
	pt->clock_rate=samplerate;
	rtp_profile_set_payload(prof,0,pt);
	return prof;
}
Exemple #3
0
static PayloadType * amr_match(MSOfferAnswerContext *ctx, const MSList *local_payloads, const PayloadType *refpt, const MSList *remote_payloads, bool_t reading_response){
	PayloadType *pt;
	char value[10];
	const MSList *elem;
	PayloadType *candidate=NULL;

	for (elem=local_payloads;elem!=NULL;elem=elem->next){
		pt=(PayloadType*)elem->data;
		
		if ( pt->mime_type && refpt->mime_type 
			&& strcasecmp(pt->mime_type, refpt->mime_type)==0
			&& pt->clock_rate==refpt->clock_rate
			&& pt->channels==refpt->channels) {
			int octedalign1=0,octedalign2=0;
			if (pt->recv_fmtp!=NULL && fmtp_get_value(pt->recv_fmtp,"octet-align",value,sizeof(value))){
				octedalign1=atoi(value);
			}
			if (refpt->send_fmtp!=NULL && fmtp_get_value(refpt->send_fmtp,"octet-align",value,sizeof(value))){
				octedalign2=atoi(value);
			}
			if (octedalign1==octedalign2) {
				candidate=pt;
				break; /*exact match */
			}
		}
	}
	return candidate ? payload_type_clone(candidate) : NULL;
}
Exemple #4
0
/*clone a profile and its payloads */
RtpProfile * rtp_profile_clone_full(RtpProfile *prof)
{
    int i;
    PayloadType *pt;
    RtpProfile *newprof=rtp_profile_new(prof->name);
    for (i=0; i<RTP_PROFILE_MAX_PAYLOADS; i++) {
        pt=rtp_profile_get_payload(prof,i);
        if (pt!=NULL) {
            rtp_profile_set_payload(newprof,i,payload_type_clone(pt));
        }
    }
    return newprof;
}
Exemple #5
0
/* the reason for this matcher is for some stupid uncompliant phone that offer G729a mime type !*/
static PayloadType * g729A_match(MSOfferAnswerContext *ctx, const MSList *local_payloads, const PayloadType *refpt, const MSList *remote_payloads, bool_t reading_response){
	PayloadType *pt;
	const MSList *elem;
	PayloadType *candidate=NULL;

	for (elem=local_payloads;elem!=NULL;elem=elem->next){
		pt=(PayloadType*)elem->data;
		
		if (strcasecmp(pt->mime_type,"G729")==0 && refpt->channels==pt->channels){
			candidate=pt;
		}
	}
	return candidate ? payload_type_clone(candidate) : NULL;
}
Exemple #6
0
static PayloadType * opus_match(MSOfferAnswerContext *ctx, const MSList *local_payloads, const PayloadType *refpt, const MSList *remote_payloads, bool_t reading_response){
	PayloadType *pt;
	const MSList *elem;
	PayloadType *legacy_opus=NULL;

	for (elem=local_payloads;elem!=NULL;elem=elem->next){
		pt=(PayloadType*)elem->data;
		
		/*workaround a bug in earlier versions of linphone where opus/48000/1 is offered, which is uncompliant with opus rtp draft*/
		if (strcasecmp(pt->mime_type,"opus")==0 ){
			if (refpt->channels==1){
				legacy_opus=pt;
			}else if (refpt->channels==2){
				return payload_type_clone(pt);
			}
		}
	}
	if (legacy_opus){
		legacy_opus = payload_type_clone(legacy_opus);
		legacy_opus->channels=1; /*so that we respond with same number of channels */
		return legacy_opus;
	}
	return NULL;
}
Exemple #7
0
static PayloadType * generic_match(const MSList *local_payloads, const PayloadType *refpt, const MSList *remote_payloads){
	PayloadType *pt;
	const MSList *elem;

	for (elem=local_payloads;elem!=NULL;elem=elem->next){
		pt=(PayloadType*)elem->data;
		
		if ( pt->mime_type && refpt->mime_type 
			&& strcasecmp(pt->mime_type, refpt->mime_type)==0
			&& pt->clock_rate==refpt->clock_rate
			&& pt->channels==refpt->channels)
			return payload_type_clone(pt);
	}
	return NULL;
}
Exemple #8
0
static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit){
	MSList *l=NULL;
	const MSList *it;
	for(it=codecs;it!=NULL;it=it->next){
		PayloadType *pt=(PayloadType*)it->data;
		if (pt->flags & PAYLOAD_TYPE_ENABLED){
			if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){
				ms_message("Codec %s/%i eliminated because of audio bandwidth constraint.",pt->mime_type,pt->clock_rate);
				continue;
			}
			if (linphone_core_check_payload_type_usability(lc,pt)){
				l=ms_list_append(l,payload_type_clone(pt));
			}
		}
	}
	return l;
}
Exemple #9
0
PayloadType * sipomatic_payload_is_supported(sdp_payload_t *payload,RtpProfile *local_profile,RtpProfile *dialog_profile)
{
	int localpt;
	if (payload->a_rtpmap!=NULL){
		localpt=rtp_profile_get_payload_number_from_rtpmap(local_profile,payload->a_rtpmap);
	}else{
		localpt=payload->pt;
		ms_warning("payload has no rtpmap.");
	}
	
	if (localpt>=0){
		/* this payload is supported in our local rtp profile, so add it to the dialog rtp
		profile */
		PayloadType *rtppayload;
		rtppayload=rtp_profile_get_payload(local_profile,localpt);
		if (rtppayload==NULL) return NULL;
		/*check if we have the appropriate coder/decoder for this payload */
		if (strcmp(rtppayload->mime_type,"telephone-event")!=0) {
			if (!ms_filter_codec_supported(rtppayload->mime_type)) {
				ms_message("Codec %s is not supported.", rtppayload->mime_type);
				return NULL;
			}
		}
		rtppayload=payload_type_clone(rtppayload);
		rtp_profile_set_payload(dialog_profile,payload->pt,rtppayload);
		/* add to the rtp payload type some other parameters (bandwidth) */
		if (payload->b_as_bandwidth!=0) rtppayload->normal_bitrate=payload->b_as_bandwidth*1000;
		if (payload->a_fmtp!=NULL)
			payload_type_set_send_fmtp(rtppayload,payload->a_fmtp);
		if (strcasecmp(rtppayload->mime_type,"iLBC")==0){
			/*default to 30 ms mode */
			payload->a_fmtp="ptime=30";
			payload_type_set_recv_fmtp(rtppayload,payload->a_fmtp);
		}
		return rtppayload;
	}
	return NULL;
}
Exemple #10
0
static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, LinphoneCall *call, unsigned int session_id, unsigned int session_ver){
	MSList *l;
	PayloadType *pt;
	const char *me=linphone_core_get_identity(lc);
	LinphoneAddress *addr=linphone_address_new(me);
	const char *username=linphone_address_get_username (addr);
	SalMediaDescription *md=sal_media_description_new();
	
	md->session_id=session_id;
	md->session_ver=session_ver;
	md->nstreams=1;
	strncpy(md->addr,call->localip,sizeof(md->addr));
	strncpy(md->username,username,sizeof(md->username));
	md->bandwidth=linphone_core_get_download_bandwidth(lc);
	
	/*set audio capabilities */
	strncpy(md->streams[0].addr,call->localip,sizeof(md->streams[0].addr));
	md->streams[0].port=call->audio_port;
	md->streams[0].proto=SalProtoRtpAvp;
	md->streams[0].type=SalAudio;
	md->streams[0].ptime=lc->net_conf.down_ptime;
	l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw);
	pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
	l=ms_list_append(l,pt);
	md->streams[0].payloads=l;
	

	if (call->params.has_video){
		md->nstreams++;
		md->streams[1].port=call->video_port;
		md->streams[1].proto=SalProtoRtpAvp;
		md->streams[1].type=SalVideo;
		l=make_codec_list(lc,lc->codecs_conf.video_codecs,0);
		md->streams[1].payloads=l;
	}
	linphone_address_destroy(addr);
	return md;
}
Exemple #11
0
static MSList *match_payloads(MSFactory *factory, const MSList *local, const MSList *remote, bool_t reading_response, bool_t one_matching_codec){
	const MSList *e2,*e1;
	MSList *res=NULL;
	PayloadType *matched;
	bool_t found_codec=FALSE;

	for(e2=remote;e2!=NULL;e2=e2->next){
		PayloadType *p2=(PayloadType*)e2->data;
		matched=find_payload_type_best_match(factory, local, p2, remote, reading_response);
		if (matched){
			int local_number=payload_type_get_number(matched);
			int remote_number=payload_type_get_number(p2);

			if (one_matching_codec){
				if (strcasecmp(matched->mime_type,"telephone-event")!=0){
					if (found_codec){/* we have found a real codec already*/
						continue; /*this codec won't be added*/
					}else found_codec=TRUE;
				}
			}

			if (p2->send_fmtp){
				payload_type_append_send_fmtp(matched,p2->send_fmtp);
			}
			matched->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV|PAYLOAD_TYPE_FLAG_CAN_SEND;
			if (p2->flags & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) {
				matched->flags |= PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED;
				/* Negotiation of AVPF features (keep common features) */
				matched->avpf.features &= p2->avpf.features;
				matched->avpf.rpsi_compatibility = p2->avpf.rpsi_compatibility;
				/* Take bigger AVPF trr interval */
				if (p2->avpf.trr_interval < matched->avpf.trr_interval) {
					matched->avpf.trr_interval = matched->avpf.trr_interval;
				}
			}
			res=ms_list_append(res,matched);
			/* we should use the remote numbering even when parsing a response */
			payload_type_set_number(matched,remote_number);
			payload_type_set_flag(matched, PAYLOAD_TYPE_FROZEN_NUMBER);
			if (reading_response && remote_number!=local_number){
				ms_warning("For payload type %s, proposed number was %i but the remote phone answered %i",
						  matched->mime_type, local_number, remote_number);
				/*
				 We must add this payload type with our local numbering in order to be able to receive it.
				 Indeed despite we must sent with the remote numbering, we must be able to receive with
				 our local one.
				*/
				matched=payload_type_clone(matched);
				payload_type_set_number(matched,local_number);
				payload_type_set_flag(matched, PAYLOAD_TYPE_FROZEN_NUMBER);
				res=ms_list_append(res,matched);
			}
		}else{
			if (p2->channels>0)
				ms_message("No match for %s/%i/%i",p2->mime_type,p2->clock_rate,p2->channels);
			else ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate);
		}
	}
	if (reading_response){
		/* add remaning local payload as CAN_RECV only so that if we are in front of a non-compliant equipment we are still able to decode the RTP stream*/
		for(e1=local;e1!=NULL;e1=e1->next){
			PayloadType *p1=(PayloadType*)e1->data;
			bool_t found=FALSE;
			for(e2=res;e2!=NULL;e2=e2->next){
				PayloadType *p2=(PayloadType*)e2->data;
				if (payload_type_get_number(p2)==payload_type_get_number(p1)){
					found=TRUE;
					break;
				}
			}
			if (!found){
				ms_message("Adding %s/%i for compatibility, just in case.",p1->mime_type,p1->clock_rate);
				p1=payload_type_clone(p1);
				payload_type_set_flag(p1, PAYLOAD_TYPE_FLAG_CAN_RECV);
				payload_type_set_flag(p1, PAYLOAD_TYPE_FROZEN_NUMBER);
				res=ms_list_append(res,p1);
			}
		}
	}
	return res;
}
Exemple #12
0
static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t reading_response, bool_t one_matching_codec){
	const MSList *e2,*e1;
	MSList *res=NULL;
	PayloadType *matched;
	bool_t found_codec=FALSE;
	
	for(e2=remote;e2!=NULL;e2=e2->next){
		PayloadType *p2=(PayloadType*)e2->data;
		matched=find_payload_type_best_match(local,p2);
		if (matched){
			PayloadType *newp;
			int local_number=payload_type_get_number(matched);
			int remote_number=payload_type_get_number(p2);

			if (one_matching_codec){
				if (strcasecmp(matched->mime_type,"telephone-event")!=0){
					if (found_codec){/* we have found a real codec already*/
						continue; /*this codec won't be added*/
					}else found_codec=TRUE;
				}
			}
			
			newp=payload_type_clone(matched);
			if (p2->send_fmtp)
				payload_type_set_send_fmtp(newp,p2->send_fmtp);
			newp->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV|PAYLOAD_TYPE_FLAG_CAN_SEND;
			res=ms_list_append(res,newp);
			/* we should use the remote numbering even when parsing a response */
			payload_type_set_number(newp,remote_number);
			if (reading_response && remote_number!=local_number){
				ms_warning("For payload type %s, proposed number was %i but the remote phone answered %i",
				          newp->mime_type, local_number, remote_number);
				/*
				 We must add this payload type with our local numbering in order to be able to receive it.
				 Indeed despite we must sent with the remote numbering, we must be able to receive with
				 our local one.
				*/
				newp=payload_type_clone(newp);
				payload_type_set_number(newp,local_number);
				res=ms_list_append(res,newp);
			}
		}else{
			ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate);
		}
	}
	if (reading_response){
		/* add remaning local payload as CAN_RECV only so that if we are in front of a non-compliant equipment we are still able to decode the RTP stream*/
		for(e1=local;e1!=NULL;e1=e1->next){
			PayloadType *p1=(PayloadType*)e1->data;
			bool_t found=FALSE;
			for(e2=res;e2!=NULL;e2=e2->next){
				PayloadType *p2=(PayloadType*)e2->data;
				if (payload_type_get_number(p2)==payload_type_get_number(p1)){
					found=TRUE;
					break;
				}
			}
			if (!found){
				ms_message("Adding %s/%i for compatibility, just in case.",p1->mime_type,p1->clock_rate);
				p1=payload_type_clone(p1);
				p1->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV;
				res=ms_list_append(res,p1);
			}
		}
	}
	return res;
}
Exemple #13
0
/*
 * This small program starts a video stream to either
 * - read an H264 video track from mkv file and stream it out with RTP to specified destination
 * - receive H264 RTP packets on a local port and record them into an mkv file
 */
int main(int argc, char *argv[]){
	const char *command;
	const char *file;
	const char *ip;
	int port;
	VideoStream *stream;
	RtpProfile *profile;
	PayloadType *pt;
	Mode mode = INVALID_MODE;
	int local_port = 7778;
	MSFactory *factory ;
	
	MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER;
	int err;
	
	/*parse command line arguments*/
	
	if (argc<4) usage(argv[0]);
	
	command = argv[1];
	if (strcasecmp(command,"play")==0) mode = PLAY_MODE;
	else if (strcasecmp(command, "record")==0) mode = RECORD_MODE;
	else usage(argv[0]);
	
	file = argv[2];
	
	if (mode == PLAY_MODE){
		ip = argv[3];
		if (argc<5) usage(argv[0]);
		port = atoi(argv[4]);
	}else{
		local_port = atoi(argv[3]);
		ip = "127.0.0.1"; port = 9990; /*dummy destination address, we won't send anything here anyway*/
	}
	
	/*set a signal handler to interrupt the program cleanly*/
	signal(SIGINT,stop_handler);
	
	/*initialize mediastreamer2*/
	factory = ms_factory_new_with_voip();
	
	/*create the video stream */
	stream = video_stream_new(factory, local_port, local_port+1, FALSE);
	
	/*define its local input and outputs with the MSMediaStreamIO structure*/
	if (mode == PLAY_MODE){
		io.input.type = MSResourceFile;
		io.input.file = file; /*the file we want to stream out via rtp*/
		io.output.type = MSResourceFile;
		io.output.file = NULL; /*we don't set a record file in PLAY_MODE, we just want the received video stream to be ignored, if something is received*/
	}else{
		io.input.type = MSResourceFile;
		io.input.file = NULL; /*We don't want to send anything via RTP in RECORD_MODE*/
		io.output.type = MSResourceFile;
		io.output.file = file; /*The file to which we want to record the received video stream*/
	}
	
	/*define the RTP profile to use: in this case we just want to use H264 codec*/
	profile = rtp_profile_new("My RTP profile");
	pt = payload_type_clone(&payload_type_h264);
	rtp_profile_set_payload(profile, payload_type_number, pt); /*we assign H264 to payload type number payload_type_number*/
	
	media_stream_set_target_network_bitrate(&stream->ms, 500000); /*set a target IP bitrate in bits/second */
	
	/*By default, the VideoStream will show up a display window where the received video is played, with a local preview as well.
	 * If you don't need this, assign (void*)-1 as window id, which explicitely disable the display feature.*/
	
	/*video_stream_set_native_window_id(stream, (void*)-1);*/
	
	/*start the video stream, given the RtpProfile and "io" definition */
	err = video_stream_start_from_io(stream, profile, ip, port, ip, port+1, payload_type_number, &io);
	if (err !=0 ){
		fprintf(stderr,"Could not start video stream.");
		goto end;
	}
	/*Register an event handler on the player to be notified of end of file*/
	ms_filter_add_notify_callback(stream->source, on_end_of_play, NULL, FALSE);
	
	/*program's main loop*/
	while (active){
		/*handle video stream background activity. This is non blocking*/
		video_stream_iterate(stream);
		/*process event callbacks*/
		ms_event_queue_pump(ms_factory_get_event_queue(factory));
		ms_usleep(50000); /*pause 50ms to avoid busy loop*/
	}
	
end:
	/*stop and destroy the video stream object*/
	if (stream) video_stream_stop(stream);
	/*free the RTP profile and payload type inside*/
	if (profile) rtp_profile_destroy(profile);
	
	ms_factory_destroy(factory);
	
	return err;
}